aiMCPGate

aiMCPGate

MCP gateway/proxy: multiplexes tool calls across upstream MCP servers into one aggregated, namespaced catalog and logs every call. Local, single-user, $0/month by default.

Category
Visit Server

README

aiMCPGate

Русская версия — README_RU.md.

A gateway / proxy for MCP servers (Model Context Protocol) written in Go. It presents itself to an MCP client (Claude Code, Cursor, etc.) as one MCP server, while under the hood it multiplexes calls across several upstream MCP servers, aggregates their tool catalogs into one, and logs every call. (Resource aggregation across upstreams is not implemented yet — resources/list returns an empty catalog; see internal/transport/dispatch.go.)

Status: MVP complete (Stages 0–6). Phase 1 — multiplexing stdio upstreams behind a stdio endpoint with a call log; Phase 2 — HTTP/SSE client-facing transport, HTTP upstreams, a CLI log viewer (mcp-gate logs); release pipeline (goreleaser, cross-compiled for linux/darwin/windows × amd64/arm64, no CGO).

Releases

Cross-platform binaries are built via goreleaser (.goreleaser.yaml): linux/darwin/windows × amd64/arm64, no CGO, the version is baked in via -ldflags -X main.version=..., checksums land in SHA256SUMS. Local dry run: goreleaser release --snapshot --clean.

Install from MCP registry

Besides the raw release binaries, the gateway ships as an OCI image on GitHub Container Registry and as an npm wrapper package — the two formats MCP registries install from.

Docker:

docker run --rm -i -v $(pwd)/config.yaml:/config.yaml ghcr.io/akomyagin/aimcpgate serve

-i is mandatory: the gateway talks MCP over stdio, so the client must keep stdin open (without it the container sees EOF and exits immediately). The image has no config of its own, so mount yours — the example above mounts it onto the default path /config.yaml; any other path works with serve -c.

To reproduce a registry sandbox check (Glama.ai etc.) without any real upstream, use the demo config baked into the image — this exact command is what a sandbox should run:

docker run --rm -i ghcr.io/akomyagin/aimcpgate serve -c /demo.config.yaml

npx (downloads the prebuilt binary for your platform on first install and verifies its SHA256 checksum):

npx aimcpgate serve -c ./config.yaml

Image policy: the OCI image contains only the mcp-gate binary — no runtimes for stdio upstreams (no node/npx, python, shells). If your config launches stdio upstream servers, extend the image yourself and install what they need; HTTP upstreams work out of the box (CA certificates are included).

Demo config: demo.config.yaml and the hidden __demo-echo subcommand exist only so registry sandboxes (Glama.ai) can introspect the gateway without any real upstream — never use them in a real deployment.

Why

An active MCP user typically has several servers configured (filesystem, GitHub, search, custom ones), each one duplicated in every client's own config. aiMCPGate gives you:

  • One entry point — a single MCP endpoint instead of N entries in the client config.
  • One catalog — every upstream server's tools merged together (namespaced as <upstream>__<tool> so names never collide).
  • A call log — which upstream, which tool, when, success/failure. This is the value added on top of "just a proxy".

Solo pet project: the priority is learning Go (concurrency, os/exec, JSON-RPC 2.0, the stdio and HTTP/SSE transports). Cost — $0/month by default (a local process), no telemetry.

How it works (short version)

MCP client ──stdio/HTTP──▶ aiMCPGate ──JSON-RPC──▶ upstream A (stdio)
                              │        ├─────────▶ upstream B (stdio)
                          call log     └─────────▶ upstream C (http, Phase 2)

MVP (two phases)

  • Phase 1 — multiplexing 2+ stdio upstreams behind one stdio endpoint (the same transport Claude Code speaks) plus basic logging.
  • Phase 2 — HTTP/SSE transport, HTTP upstream servers, a log viewer (CLI/web), optionally an access policy.

Build

export PATH="$HOME/sdk/go/bin:$PATH"   # if go isn't already on PATH
go build ./...
go vet ./...
go test -race ./...

go run ./cmd version

Usage

# stdio mode (the client launches the gateway as a subprocess):
mcp-gate serve --config ./config.yaml

# http mode (transport: http in the config) — endpoint at http://<listen_addr>/mcp:
mcp-gate serve --config ./config-http.yaml

# check every enabled upstream once (launch → handshake → tools/list) and print
# a per-upstream OK/FAIL table; exit code is non-zero if any upstream failed
# (scriptable for CI/cron), no auto-restart, no call logging — one pass then exit:
mcp-gate doctor --config ./config.yaml

# view the call log (last 50 records; filter by upstream/tool/status):
mcp-gate logs --file ./logs/calls.jsonl --tail 50
mcp-gate logs --config ./config.yaml --upstream github --status err

# generate a random auth token (for the HTTP transport) and see how to wire it in:
mcp-gate token --generate
# print the auth token currently set in the config:
mcp-gate token --config ./config-http.yaml

# print ready-to-paste MCP client config snippets (Claude Code / Cursor); requires
# transport: http in the config, and includes the Bearer header when auth_token is set:
mcp-gate client-config --config ./config-http.yaml

# print a SKILL.md teaching an agent how to use the aggregated catalog
# (built-in text by default; overridable via skill_file in the config):
mcp-gate skill > .claude/skills/mcp-gate/SKILL.md

All commands except token --generate and skill (which falls back to a built-in guide) load the config: pass --config, or drop a config.yaml next to the binary (see Configuration below).

Reloading config (SIGHUP)

The gateway reloads its configuration live on SIGHUP — no restart, no dropped client connection. Edit config.yaml and send the signal:

kill -HUP $(pgrep -f 'mcp-gate serve')

On reload the gateway diffs the new config against the running upstreams and applies the minimum change: newly added upstreams are launched, removed (or enabled: false) ones are shut down, upstreams whose launch fields (command/args/url/env/headers) changed are relaunched, and upstreams where only the tool allow/deny/rename filter changed are re-projected without any restart. Unchanged upstreams keep running untouched. A bad edit (invalid YAML, failed validation) is logged and ignored — the currently running config stays live, so a typo never takes the gateway down.

Behavioural note: since the gateway installs a SIGHUP handler, SIGHUP no longer terminates the process the way the OS default would. To stop the gateway use Ctrl-C, SIGINT, or SIGTERM. SIGHUP is Unix-only; on Windows it does not exist and reload is unavailable (the process serves the config it started with until restarted).

Configuration

Without --config, the gateway looks for config.yaml next to its own binary (e.g. if mcp-gate is installed at /etc/gate/, it looks for /etc/gate/config.yaml — regardless of the working directory it was launched from). If that file doesn't exist and --config wasn't passed either, it errors explicitly instead of starting an empty gateway. Relative paths inside the config (log_file, skill_file) resolve against the config file's own directory, not the current working directory.

Note: the "next to the binary" lookup uses the path of the running executable. Under go run ./cmd ... that executable is a throwaway build in a temp directory, so the default lookup will not find your config.yaml — pass --config explicitly when using go run, or run a built binary.

Full example with every field — config.example.yaml. The set of upstream servers is declared in YAML; secrets (tokens) go through env/.env (${VAR} expansion at load time), never committed in the config. Each upstream sets exactly one of command (stdio subprocess) or url (HTTP server, Streamable HTTP) — the connection kind is inferred automatically.

transport: stdio            # stdio (Phase 1) | http (Phase 2)
listen_addr: "127.0.0.1:28080"  # only used for transport: http; loopback by default
# auth_token: ${AIMCPGATE_TOKEN}  # required if you widen listen_addr past loopback
log_file: ./logs/calls.jsonl
upstreams:
  - name: filesystem        # stdio upstream
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"]
    enabled: true
  - name: github
    command: github-mcp-server
    env:
      GITHUB_TOKEN: ${GITHUB_TOKEN}   # from the environment, not hardcoded
    enabled: true
  - name: remote            # http upstream (Phase 2)
    url: https://mcp.example.com/mcp
    headers:
      Authorization: "Bearer ${REMOTE_MCP_TOKEN}"   # secret, never logged
    enabled: true

License

MIT — see LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured