Skip to main content
Glama

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/.

Related MCP server: MCPHubs

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 .
F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    C
    quality
    D
    maintenance
    A powerful gateway for the Model Context Protocol (MCP) that unifies AI toolchains by federating multiple MCP servers, wrapping REST APIs as MCP tools, and supporting multiple transport methods with an admin dashboard.
    1
  • A
    license
    Not graded
    quality
    C
    maintenance
    A unified gateway and web dashboard that aggregates multiple MCP servers into a single Streamable HTTP endpoint. It supports stdio, SSE, and HTTP protocols, featuring optimized tool exposure modes to reduce token consumption for AI clients.
    5
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCPGate aggregates multiple MCP servers into a single unified endpoint, enabling centralized tool management with granular filtering, automatic namespacing, and observability. Features a real-time web dashboard and optional PostgreSQL-backed audit trails for monitoring and controlling AI tool access across local and remote deployments.
    17
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Self-hosted MCP governance gateway that aggregates 150+ tools behind policy profiles (strict/balanced/dev) with a per-call audit trail. Python 3.12/FastAPI, Docker-deployable, built for regulated environments that need observability over agent tool calls.
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • Self-hosted MCP gateway: turn any API, database or MCP server into AI connectors — no code.

  • Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.

  • AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/danielsmag/aisafenet'

If you have feedback or need assistance with the MCP directory API, please join our Discord server