MCP Gateway
A FastAPI-based MCP gateway that aggregates multiple MCP servers, applies per-server tool allow/block policies, and re-exposes them as streamable HTTP MCP endpoints. It includes a local LLM safety guard for SQL/PII checks and a request history UI.
README
MCP Gateway
A FastAPI app that reads MCP server definitions from a dedicated folder
(mcp-servers/), connects to each source server (local stdio process or remote
http/sse endpoint), applies a per-server tool allow/block policy, and
re-exposes each one as a streamable-HTTP MCP endpoint at /mcp/<name>.
Docs: make docs (local MkDocs at http://127.0.0.1:8001), make docs-build,
or make docs-up / docker compose up --build docs (Nginx at
http://localhost:8001).
mcp-servers/github.yaml -> http://localhost:8000/mcp/github
mcp-servers/docs.yaml -> http://localhost:8000/mcp/docs
mcp-servers/postgres.yaml -> http://localhost:8000/mcp/postgres
Quick start
uv sync
cp .env.example .env # fill in any tokens your YAML files reference
uv run uvicorn aisafenet.app.main:create_app --factory --reload
Then enable a definition in mcp-servers/ (enabled: true) and restart. Check
what is mounted:
curl localhost:8000/api/v1/health
curl localhost:8000/servers
Point an MCP client at the new URL with a Bearer API key. Local seed key
(dev only): aisk_dev_local_00000000000000000001.
{
"mcpServers": {
"github-via-gateway": {
"url": "http://localhost:8000/mcp/github",
"headers": {
"Authorization": "Bearer aisk_dev_local_00000000000000000001"
}
}
}
}
Python / FastMCP:
from fastmcp import Client
async with Client(
"http://localhost:8000/mcp/postgres",
auth="aisk_dev_local_00000000000000000001",
) as client:
tools = await client.list_tools()
Each successful connect opens a row in {SAFE_DB_SCHEMA}.sessions bound to the
API key and MCP mcp-session-id. Gateway logs include session, mcp_session,
and key fields. DB connection knobs: GATEWAY_DATABASE__* and SAFE_DB_SCHEMA
(see .env.example).
Sessions expire after GATEWAY_SESSION__IDLE_TTL_SECONDS with no requests
(default 24 hours; 0 disables). Clients that send HTTP DELETE with
mcp-session-id (Streamable HTTP session terminate) also close the row
immediately.
Request history UI
Build the React console, then open http://localhost:8000/ui/ and authenticate
with the local development user:
username: admin
password: changeme
The UI exchanges these credentials at POST /api/login for a server-side
session carried by an HttpOnly, SameSite=Lax cookie. POST /api/logout
revokes that session. Change the seeded credentials before non-local use.
make ui-install
make ui-build
make dev
The console shows request history across API keys owned by the signed-in user,
including original and protected SQL, session metadata, PII transformations,
guard decisions, status, and latency. MCP clients still authenticate with
Bearer API keys.
For frontend development, run make ui-dev; Vite proxies /api to port 8000.
Docker Compose also runs the console as a separate Nginx service at
http://localhost:5173 (FRONTEND_PORT overrides the port). Nginx proxies
/api to the gateway service. The gateway-embedded build remains available at
http://localhost:8000/ui/.
Defining a server
One YAML file per source server; see mcp-servers/README.md for the full field reference. A stdio example:
name: github
enabled: true
source:
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: ${GITHUB_TOKEN}
tools:
allow: [] # empty = all tools
block: [delete_*]
The policy is enforced in both directions: blocked tools are removed from
tools/list, and a direct tools/call for one is rejected.
Local LLM safety guard
The optional guard layers deterministic SQL/PII checks with a local model classification. It inspects both tool arguments and results, uses validated JSON verdicts, caches repeat decisions, redacts payloads at INFO level, and fails closed by default.
On Apple Silicon, install and run Ollama on the host so it can use Metal. Docker Desktop cannot pass the Mac GPU into an Ollama container:
brew install ollama
ollama serve
ollama pull qwen3:4b
ollama pull qwen3.6:35b-a3b
Enable the guard in settings.toml ([guard] enabled = true) or via .env:
GATEWAY_GUARD__ENABLED=true
GATEWAY_LLM__BASE_URL=http://localhost:11434/v1
When the gateway itself runs in Compose, its base URL defaults to
http://host.docker.internal:11434/v1. Linux hosts with an NVIDIA GPU can
instead run docker compose --profile llm up; that profile is intentionally
not suitable for macOS.
Per-server behavior can override global settings:
guard:
enabled: true
inspect_results: true
The connector uses the OpenAI-compatible API rather than an Ollama-specific
SDK. To use vLLM, llama.cpp, or LM Studio later, change
GATEWAY_LLM__BASE_URL. Guard classifications send
reasoning_effort: "none" to avoid thinking-token latency; red-team agent
calls retain each model's default reasoning behavior.
Tracing tool calls
Every tool call gets a short trace id (see aisafenet/core/tracing.py)
that's attached to every log line produced while handling it — the tool-policy
check, the guard's call/result review, and the underlying LLM request. Log
lines carry it as [trace=<id>]:
2026-07-31 14:50:01,123 INFO aisafenet [trace=9f3a1c2b0e77]: tool_call start server='postgres' tool='query'
2026-07-31 14:50:01,124 INFO aisafenet [trace=9f3a1c2b0e77]: Tool call on server 'postgres': 'query' argument_keys=['sql']
2026-07-31 14:50:01,210 INFO aisafenet [trace=9f3a1c2b0e77]: Guard verdict kind=call model=guard decision=allow confidence=0.95 latency_ms=85.4
2026-07-31 14:50:01,255 INFO aisafenet [trace=9f3a1c2b0e77]: tool_call done latency_ms=132.1
Set GATEWAY_LOG_LEVEL=DEBUG to also see the nested spans (guard.review_call,
llm.complete, llm.http_post, tool.execute, guard.review_result) with
their own latencies and the full guard-model system prompt, user payload, and
JSON answer. Debug logs can contain SQL, tool results, PII, or secrets; use them
only in controlled development environments. This is log-based, not
OpenTelemetry — there's no external tracing backend to run.
Call reports
Every guarded tool call comes back with a record of what the gateway did to it.
The structured form sits in the result's _meta under the aisafenet key, and a
one-line summary is appended as a final text block so the calling model sees it
too:
aisafenet: dropped columns credit_card; hashed in query email; guard call=allow; guard result=allow
The executed_sql field holds the statement actually sent downstream with the
session data_key replaced by __DATA_KEY__, so reports are safe to log or
persist. See aisafenet/guards/reporting.py for the full model. The report
is assembled outside the guard, so its contents never enter the guard prompt.
Red-team agent
With the gateway and Ollama running, execute the included bounded PII exfiltration scenario:
uv run python -m app.agents --scenario exfiltrate-pii
The agent obtains tool schemas from /mcp/postgres, never connects directly to
Postgres, and writes a JSONL audit transcript under runs/. Scenario files set
hard step and wall-clock limits. Use GATEWAY_LLM__AGENT_MODEL to select the
tool-calling model. Transcripts may contain sensitive test data; runs/ is
gitignored and should be handled as restricted audit output.
Configuration
Non-secret defaults live in settings.toml. Secrets and deploy overrides use
.env / GATEWAY_* environment variables (nested fields use __).
See docs/configuration.md for the full list.
| Source | Use for |
|---|---|
settings.toml |
Models, guard, TTLs, dirs, mount prefix |
.env / GATEWAY_* |
DB credentials, tokens, per-machine overrides |
Definitions are validated at startup: an invalid file, or a ${VAR} with no
value and no ${VAR:-fallback} default, aborts the boot with the offending file
name instead of silently serving a broken endpoint.
Docker
docker compose up --build gateway
The mcp-servers/ folder is mounted read-only, and the image includes Node.js so
npx-based stdio servers work.
Postgres MCP (aisafenet)
mcp-servers/postgres.yaml is enabled by default and proxies the official
@modelcontextprotocol/server-postgres server to your Docker Postgres instance.
Start the database first, then the gateway:
docker compose up -d postgres
uv run uvicorn aisafenet.app.main:create_app --factory --reload
# or: docker compose up gateway
Connect a client to http://localhost:8000/mcp/postgres.
Open scripts/mcp_test_client.ipynb with the
project's .venv kernel to list tools/resources and run the included read-only
Postgres query. Change MCP_URL, tool_name, or arguments in the notebook to
test another endpoint or tool.
To use the mcp/postgres Docker image directly (outside the gateway), build it
with docker compose build postgres-mcp and run:
docker run -i --rm --add-host=host.docker.internal:host-gateway \
mcp/postgres postgresql://aisafe:aisafe@host.docker.internal:5432/aisafenet
Layout
| Path | Role |
|---|---|
| aisafenet/main.py | Thin Uvicorn application-factory entry point |
| aisafenet/core/bootstrap.py | Startup sequence for logging, dependency wiring, and app assembly |
| aisafenet/core/container.py | Dependency-injector providers and dependency lifetimes |
| aisafenet/core/config.py | Validated, environment-driven Pydantic settings |
| aisafenet/app/application.py | Loads configs, mounts MCP apps, and registers gateway routes |
| aisafenet/catalog/mcp_config.py | YAML schema (McpServerConfig, HttpSource, StdioSource, ToolPolicy) |
| aisafenet/catalog/config_loader.py | Folder scan, validation, ${VAR} expansion |
| aisafenet/mcp/proxy_factory.py | Builds a FastMCP proxy + transport per definition |
| aisafenet/mcp/middleware.py | Tool policy and LLM guard enforcement |
| aisafenet/guards/reporting.py | Per-call report of applied transforms and guard verdicts |
| aisafenet/core/llm/ | OpenAI-compatible local-model adapter |
| aisafenet/guards/ | Python guard script pool and dispatcher |
| aisafenet/agents/ | Bounded red-team agent and scenarios |
| aisafenet/core/exceptions/ | Gateway error hierarchy |
Tests
uv sync --all-groups
uv run pytest
uv run ruff check .
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。