This release is a pre-release and may not be stable for production use.
MCPWatch for Python
The MCPWatch security guard for MCP servers written in Python. It checks every JSON-RPC message between any MCP client and your server, in both directions. It works with:
- the official MCP Python SDK (
MCPServer,FastMCP, the low-levelServer) - Django
- Flask
- FastAPI and Starlette
- any ASGI or WSGI app
Clients need no changes.
The checks are the same as for Node servers. They run in the MCPWatch engine, which the package starts as a small child process (mcpwatch engine). The same engine also provides the AI reviewer, the dashboard reporting and the live settings. Node.js 20+ must be installed on the machine running the server.
pip install --pre vedhaai-mcpwatch # beta: --pre until 0.1.0 is released
npm install -g @vedhaai/mcpwatch@beta # the engine; without it, the package falls back to npx
Official MCP SDK (stdio, SSE, Streamable HTTP)
from mcp.server.mcpserver import MCPServer # mcp 1.x: from mcp.server.fastmcp import FastMCP
from mcpwatch import mcpwatch
server = MCPServer("my-tools")
# ... @server.tool() as usual
mcpwatch(server) # ← the only line added, before run()
server.run() # or uvicorn.run(server.streamable_http_app())
- stdio and SSE: every message on the server's streams is checked.
- Streamable HTTP:
server.streamable_http_app()returns the app already wrapped byMcpWatchASGI.
A blocked call gets a JSON-RPC error (-32001 blocked, -32002 throttled), and your tool never runs.
Django
Add the middleware first in settings.py, so it sees exactly what the client sent:
MIDDLEWARE = ["mcpwatch.django.McpWatchMiddleware", ...]
MCPWATCH = {"name": "my-tools", "path": "/mcp"} # optional; project_key, mode, deny_tools, …
To guard at the server boundary instead, wrap the app in wsgi.py or asgi.py:
application = McpWatchWSGI(get_wsgi_application(), name="my-tools") # or McpWatchASGI(get_asgi_application())
Flask
from mcpwatch.flask import McpWatch
app = Flask(__name__)
McpWatch(app, path="/mcp") # or McpWatch().init_app(app)
app.config keys MCPWATCH_PROJECT_KEY, MCPWATCH_SERVER and MCPWATCH_MODE are used when set.
FastAPI, Starlette, any ASGI or WSGI app
from mcpwatch import McpWatchASGI, McpWatchWSGI
app.add_middleware(McpWatchASGI, name="my-tools", path="/mcp") # FastAPI / Starlette
app = McpWatchWSGI(app, name="my-tools", path="/mcp") # any WSGI app
Only requests under path (default /mcp) are checked. Pass a list for several endpoints, or None for every path. Both JSON and SSE (text/event-stream) responses are checked.
Options
Every adapter takes the Node middleware's options in snake_case. Options you leave out come from the same MCPWATCH_* environment variables, listed in the main README.
| Option | Variable | Meaning |
|---|---|---|
project_key |
MCPWATCH_PROJECT_KEY |
Dashboard project key. Events go there, and the project's mode and client lists apply live |
server |
MCPWATCH_SERVER |
Dashboard URL (default http://127.0.0.1:9100) |
enabled |
MCPWATCH_ENABLED=0 |
False leaves the server untouched |
mode |
MCPWATCH_MODE |
off, observe, protect, enforce (default) |
deny_tools, allow_tools |
Tool names that may never / only be called | |
allowed_origins, allowed_hosts, require_auth, expected_audience |
MCPWATCH_ALLOWED_ORIGINS, … |
HTTP transport checks (MW030–MW036) |
ai |
MCPWATCH_AI=1, … |
AI reviewer, e.g. {"enabled": True, "model": "qwen2.5:7b"} |
fail_open |
True (default): if the engine can't run, messages pass unchecked and an error is logged. False: requests are refused |
|
command |
MCPWATCH_ENGINE |
How to start the engine, e.g. node C:/path/to/MCP-Watch/dist/cli.js. Default: mcpwatch on PATH, else npx -y @vedhaai/mcpwatch@beta |
How it works
MCP client ──► your Python server ─────────────────────────────────────────────┐
adapter (SDK hook / ASGI / WSGI / Django) │
│ each JSON-RPC message, one JSON line ▲ forward / reply │
▼ │ │
mcpwatch engine (Node child process): rules, AI reviewer, ───────┼──► dashboard
sessions, pins, reporting │
allowed messages ──► your tools ───────────────────────────────┘
- One engine per guarded server. Every connection to the server shares it. A worker process started by forking (gunicorn, uwsgi) starts its own engine.
- Order kept. Each connection waits for each message's verdict, so messages are never reordered.
- If the engine stops, the next message starts it again, at most once every 10 seconds. Session scores start over.
Tests
cd ..; npm install; npm run build; cd python
python -m venv .venv; .venv\Scripts\pip install -e ".[test]"
.venv\Scripts\python -m pytest
The tests run the engine from the checkout's dist/cli.js. They cover:
- an SDK server over stdio and Streamable HTTP
- Flask, Django, plain ASGI and WSGI apps
- options reaching the engine
- the engine being unavailable (fail open and fail closed)
Metadata
Release files for vedhaai-mcpwatch 0.1.0b0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| vedhaai_mcpwatch-0.1.0b0.tar.gz | 20.2 kB | Without provenance | Details for vedhaai_mcpwatch-0.1.0b0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| vedhaai_mcpwatch-0.1.0b0-py3-none-any.whl | Python 3 | none | any | Details for vedhaai_mcpwatch-0.1.0b0-py3-none-any.whl |
Total release size: 40.3 kB
Release files / vedhaai_mcpwatch-0.1.0b0.tar.gz
| Download URL | vedhaai_mcpwatch-0.1.0b0.tar.gz |
|---|---|
| Size | 20.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4656fe28d25045bcf6ddde20e9de1cbf5f2b8a57811f3fe69afce3526a27615f
|
|
BLAKE2b-256 checksum How to use checksums |
502e1ec7d536c8c357c2206cadee2bf88f6e06c03230ab702831fb533ee9820c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Release files / vedhaai_mcpwatch-0.1.0b0-py3-none-any.whl
| Download URL | vedhaai_mcpwatch-0.1.0b0-py3-none-any.whl |
|---|---|
| Size | 20.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
66f35177b05c27a9243805f658a32b94b588c23288db90ef4a0309c42c175f5c
|
|
BLAKE2b-256 checksum How to use checksums |
35d32c79ff93f3c08375bc5e5647eb42076193aa059c3bc921e4727adbd4be9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Security for vedhaai-mcpwatch 0.1.0b0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.