MetaMCP: Self-Hosted MCP Gateway (2026)
MetaMCP is a proxy you run yourself that turns a pile of MCP servers into a single endpoint. Group servers into a namespace, expose it over SSE or Streamable HTTP, filter the tools your model needs, and point every client at one URL. This is the practical “how to run MetaMCP” guide: the Docker quick start, connecting Claude Code and Claude Desktop, the middleware and auth model, the scaling gotchas from its own issue tracker, and when a self-hosted gateway earns the extra moving part.

TL;DR + what you actually need
- What it is: a self-hosted MCP proxy from metatool-ai/metamcp (MIT). It aggregates upstream MCP servers into namespaces and serves each namespace as one authenticated endpoint.
- How you run it: Docker Compose.
git clone→cp example.env .env→docker compose up -d. Admin UI onhttp://localhost:12008, backed by Postgres. - How clients connect: point them at
http://localhost:12008/metamcp/<endpoint>/sse(or/mcpfor Streamable HTTP). stdio-only clients like Claude Desktop need a localmcp-proxybridge. - The one hard rule: endpoints are remote transports only. If your client speaks stdio, you bridge; you never get a raw
npx metamcpthat a stdio client launches directly.
A note on naming before you go looking: the active project is metatool-ai/metamcp, the Docker app described here. An older npm package, @metamcp/mcp-server-metamcp, still exists and is what the install card further down generates — it is the original stdio bridge, useful but not the current primary path. When this guide says “MetaMCP,” it means the self-hosted gateway.
What MetaMCP is (and the problem it removes)
Every MCP client keeps its own list of servers. Add GitHub, Postgres, Linear, a filesystem server, and a search server, and you have configured the same five servers in Claude Desktop, in Cursor, in Claude Code, and in whatever else your team runs. Each config carries its own secrets. Each new hire repeats the whole ritual. Rotate one API key and you edit it in four places.
MetaMCP collapses that. You register the upstream servers once, inside MetaMCP, group them into a namespace, and publish that namespace as a single endpoint. Because MetaMCP is itself an MCP server, any client connects to that one endpoint and sees every tool behind it. The maintainer’s framing on the project’s README is blunt about the goal: use MetaMCP “as infrastructure to host dynamically composed MCP servers through a unified endpoint, and build agents on top of it.”
That is the whole pitch — one endpoint, many servers, central control — and enough of a recognized gap that other teams cite MetaMCP as the reference design. When Firecrawl teased its own MCP gateway, an early reply was simply “Is this based on MetaMCP?” A concise third-party summary of what it does:
MetaMCP turns multiple MCP servers into one unified endpoint.
— Shubham Saboo (@Saboo_Shubham_) July 25, 2025
Organize servers into namespaces, filter tools, and add middleware layers with Docker deployment support.
100% opensource.
The five pieces (mental model)
MetaMCP has a small vocabulary. Learn these five nouns and the UI stops being mysterious.
- MCP Server — a config telling MetaMCP how to start one upstream server:
type(STDIO / Streamable HTTP / SSE), command, args, and env. Example:{ "HackerNews": { "type": "STDIO", "command": "uvx", "args": ["mcp-hn"] } }. - Namespace — a group of MCP servers. You enable or disable servers (and individual tools) inside it, attach middleware, and override tool names or descriptions per namespace.
- Endpoint — a public URL bound to a namespace. It aggregates the namespace’s servers and emits them over SSE, Streamable HTTP, or an OpenAPI route, with API-key or OAuth auth.
- Middleware — a function that intercepts MCP requests and responses at the namespace level. The shipped example, “Filter inactive tools,” trims the tool list before it reaches the model.
- Inspector — a built-in MCP inspector with your saved configs preloaded, so you can hit an endpoint and confirm the tools resolve before wiring a real client.
The dataflow is one hop. A client talks to the endpoint; MetaMCP fans the call out to the upstream servers in the namespace and merges the result:
Claude Code ──┐
Cursor ──┼──► MetaMCP endpoint ──► GitHub MCP (stdio)
Claude Desktop ┘ /metamcp/<ns>/sse ├─► Postgres MCP (stdio)
(one SSE/HTTP URL) │ └─► Linear MCP (http)
│
middleware:
filter inactive toolsTakeaway: the namespace is the unit you actually design around. It is where tool filtering, renaming, and auth live — servers are just its ingredients, and the endpoint is just its public face.
Quick start (Docker, end to end)
MetaMCP is distributed to run, not installed as a dependency. The recommended path is Docker Compose, and the sequence from a clean machine is short:
git clone https://github.com/metatool-ai/metamcp.git
cd metamcp
cp example.env .env
docker compose up -d
# admin UI now on http://localhost:12008
# (a Postgres container comes up alongside it)One gotcha the README calls out explicitly: MetaMCP enforces CORS against the APP_URL you set in .env. If you change it, access the UI only from that exact URL, or the app refuses the origin. A second one for people who already run Postgres in Docker — the default volume name is global and can collide, so rename metamcp_postgres_data in docker-compose.yml if you have an existing postgres_data volume.
Inside the UI the flow mirrors the five pieces: register your MCP servers, create a namespace and add the servers to it, then create an endpoint and assign the namespace. The Inspector tab lets you fire a tools/list at the endpoint immediately. For a visual pass through the same steps, the maintainer’s own walkthrough is short and shows the real UI:
Connect a client
This is the step people trip on, because MetaMCP endpoints are remote transports only — SSE, Streamable HTTP, and OpenAPI. There is no stdio endpoint. How you connect depends on whether your client speaks a remote transport natively.
Clients that speak SSE / HTTP (Cursor, VS Code)
Point them straight at the endpoint URL. For Cursor, that is a two-line mcp.json:
{
"mcpServers": {
"MetaMCP": {
"url": "http://localhost:12008/metamcp/<YOUR_ENDPOINT>/sse"
}
}
}stdio-only clients (Claude Desktop)
Claude Desktop speaks stdio, so it needs a local bridge that turns the remote endpoint into a stdio subprocess. The README is specific here: mcp-remote is not the answer because it is built for OAuth and does not handle MetaMCP’s API-key auth — use mcp-proxy instead. Pass the key as API_ACCESS_TOKEN (keys look like sk_mt_…):
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport", "streamablehttp",
"http://localhost:12008/metamcp/<YOUR_ENDPOINT>/mcp"
],
"env": { "API_ACCESS_TOKEN": "<YOUR_API_KEY>" }
}
}
}For Claude Code specifically, register that same bridge command with claude mcp add — the full flag reference and config paths live at /clients/claude-code. One auth footgun worth memorizing: the ?api_key= query parameter works for Streamable HTTP and OpenAPI but not for SSE; for anything reliable, send the key in the Authorization: Bearer header.
The npm-proxy install card
MCP.Directory’s catalog tracks the published npm package @metamcp/mcp-server-metamcp — the original stdio bridge — and the card below generates its config for every client. It is the fastest way to get a stdio client pointed at a MetaMCP instance with an API key, without hand-writing mcp-proxy arguments. Treat it as a convenience on-ramp; the Docker app above is the thing doing the actual aggregation.
One-line install · MetaMCP
Open server pageInstall
Whichever bridge you use, the client ends up seeing one server — MetaMCP — whose tool list is the merged, filtered set from your namespace. Add a server to the namespace later and the tools appear without touching client config. That is the entire payoff.
Middleware & tool filtering
Middleware is where MetaMCP earns its keep beyond “one URL.” It sits at the namespace level and rewrites MCP traffic in flight. The one shipped today is Filter Inactive Tools, and it targets a real, measurable problem: tool-list bloat.
Every tool a server advertises is spent input tokens on every request the model reasons about, whether or not it gets called. Aggregate five servers naively and you might dump eighty tools into the context window; the model gets slower and less accurate at picking the right one. This is the exact failure our MCP context-bloat guide is about, and a gateway is one of the cleaner places to fix it: turn a tool off in the namespace and it never reaches any client.
Alongside filtering, MetaMCP lets you override a tool’s name, title, and description per namespace, and attach custom MCP annotations — for example marking a tool { "readOnlyHint": false } so a client’s approval UI treats it as write-capable. Overrides merge with whatever the upstream server returns, so you add hints without losing provider metadata. The roadmap lists more middleware (logging, validation, scanning) as “coming soon,” so today filtering plus renaming is the honest extent of it.
Takeaway: the middleware layer is the reason to prefer a gateway over a hand-written config merge. Filtering and tool overrides are policy you set once, centrally, instead of hoping every client behaves.
Auth, OIDC & multi-tenancy
MetaMCP is built to be shared, so the auth surface is larger than a typical single-user server. Three layers matter.
Endpoint auth is what your MCP clients use. Each endpoint chooses API-key auth (header or, for HTTP/OpenAPI, query param) or standard MCP OAuth per the 2025-06-18 spec revision. Admin auth is separate: the web app uses Better Auth with session cookies, and supports OpenID Connect for SSO — the README documents working configs for Auth0, Keycloak, Azure AD, Google, and Okta, with PKCE enabled by default.
Multi-tenancy is the third layer. MetaMCP is designed for organizations to deploy on their own machines, with public and private scopes: users create servers, namespaces, endpoints, and API keys for themselves or for everyone, and public keys cannot reach private MetaMCPs. Registration controls let an admin block manual UI signups while allowing corporate SSO. Run it solo and most of this is invisible; it is there for the team case.
Scaling & cold start (with real numbers)
Aggregation moves work to a long-lived server, which creates problems a stdio server never has: warm sessions, connection caps, and memory. MetaMCP’s own issue tracker is the most honest documentation of where the edges are, and you should read it before putting a fleet behind one instance.
Cold start. MetaMCP pre-allocates idle sessions for each configured server (default one each) so the first tool call does not pay full spin-up latency. If an upstream server needs a runtime beyond uvx or npx, you have to bake it into a custom Dockerfile — the base image won’t have it.
The connection cap. The pool has a total-connection ceiling that older builds hardcoded near 100 and did not expose as an env var. On a busy deployment, one operator reported the pool creeping to 103/100 after about 36 hours, at which point every namespace’s tools/list started returning an empty array with a 200 OK — a silent failure, because MCP-compliant clients cache the first schema and assume the backends simply have nothing to offer. The operator workaround is blunt: docker restart metamcp, often on a nightly timer (issues #294 and #272).
Memory. STDIO servers are spawned once per namespace, not shared, so the same filesystem or search server can run three times if it sits in three namespaces. Users have watched a single container hold triplicate uvx and npx processes. The maintainer has said publicly that a “docker-per-mcp architecture” is in progress specifically to keep the main app free from out-of-memory pressure. Rate limiting exists to protect the shared endpoint — per-endpoint limits return 503, per-user limits return 429 — which is the right knob but also a reminder that you are now running a service, not a subprocess.
Takeaway: for a solo setup none of this bites. For a team fronting many HTTP backends, plan a restart strategy and watch the pool before you trust it in a critical path.
What we got wrong
Three assumptions cost time when we first ran it.
We expected an npx metamcp stdio server. MetaMCP is a MCP server, so we assumed a client could launch it directly over stdio like any other. It can’t — the endpoints are remote-only. The self-hosted app is the product; the stdio story is a mcp-proxy bridge you add on top. Once that clicked, the connection docs made sense.
We pointed the GitHub link at the wrong repo. Search “metamcp” and you find both mcp-server-metamcp (the older, smaller npm proxy) and metamcp (the active Docker app). They share an author and a name; only the second is under real development. We read the old README first and were confused why it said nothing about namespaces.
We treated empty tools/list as a config bug. It was the idle-session pool saturating. We rechecked the namespace, the API key, the endpoint URL — all fine. A container restart fixed it instantly, which is the tell that it’s the pool, not your config. Knowing that failure mode up front saves an afternoon.
Common mistakes
Tools vanish after a while, then a restart fixes it
Root cause: idle-session pool saturation past its ~100 cap. Empty tools/list returns a 200, so clients see “no tools,” not an error. Until the pooling fix lands, schedule a container restart and keep an eye on the connection-limit WARN lines.
SSE is flaky behind Nginx / a reverse proxy
Root cause: long-lived SSE connections need proxy buffering off and long timeouts. Multiple users hit “works then suddenly no tools” behind Nginx Proxy Manager. Use the SSE config in the MetaMCP deployment docs, or prefer Streamable HTTP, which is less sensitive to proxy tuning.
A server is stuck in ERROR after a restart
Root cause: the error state is persisted in Postgres and not always recomputed on boot (issue #264). The reported unstick is a direct SQL update — UPDATE mcp_servers SET error_status = 'NONE' WHERE name = '<server>' — after fixing whatever caused the original failure.
OAuth / discovery URLs point at localhost
Root cause: behind TLS-terminating reverse proxies, the dynamic-client-registration endpoint has returned localhost URLs instead of the public host (issues #265, #263). Set your public APP_URL correctly and forward the right host headers; check the open issues if discovery still breaks.
Who it’s for (and who it isn’t)
Reach for MetaMCP if you run more than a couple of MCP servers across more than one client; you want tool filtering and renaming as central policy rather than per-client hope; you need self-hosting for compliance or data-locality reasons; or you are a team that wants SSO, namespaces, and API keys around a shared pool of tools.
Skip it if you use one client and three servers — the direct configs are simpler and have no extra process to babysit; if you can’t own a long-running container and its Postgres; or if you want a managed, zero-ops experience, in which case a hosted marketplace fits better than a self-hosted proxy. A gateway is a real piece of infrastructure. Add it when the config sprawl actually hurts, not before.
Community signal
The clearest signal is the maintainer’s own r/mcp thread announcing the 2.0 rewrite. It reads like a genuine course-correction: “the previous version was released too early… now it is easier to continue to improve.” Replies are warm and specific — one calls it “the best mcp proxy aggregator option for self hosting I have used,” another “such an obvious gap in the ecosystem that I couldn’t fathom it wasn’t being worked on.”
Practitioners who self-host echo the appeal, and quietly surface the ops reality of exposing it safely:
MetaMCP is handy as heck. Going through the motion of slowly setting it up as a central store of all the MCP servers I use. Then to try work out how to allow access to it from other servers outside of my home. Currently have all IP addresses blocked apart from my home IP via CF
— Danny (@danjones) May 30, 2026
The contrarian read is worth taking seriously. A gateway is another moving part, and MetaMCP’s README opens with the maintainer apologizing for a maintenance delay while noting that PRs still get merged and a community fork exists. The SSE-behind-a-proxy flakiness and the restart-to-recover pool are real, reported, and not yet fully solved. None of that is disqualifying — it is what an actively developed, single-maintainer self-hosted project looks like — but if you need boring reliability today, weigh it honestly against a managed option.
How it stacks up
MetaMCP is one of several answers to “too many MCP servers.” We compare the field — MCPJungle, Obot, Docker MCP Gateway, and Composio — head-to-head in a separate piece; rather than repeat it, read MCPJungle vs Obot vs Docker MCP Gateway vs Composio for where each fits. The short version: MetaMCP’s distinctives are the namespace model, per-namespace tool overrides, and being a fully self-hostable Docker app with SSO — versus lighter CLIs or managed platforms.
On the marketplace question specifically, the maintainer is clear that MetaMCP is not trying to compete with a catalog like Smithery: “you can use this with Smithery together… sometimes you want to remix a few toolsets combining MCP servers from Smithery and apply middlewares.” MetaMCP is the composition and hosting layer; where the servers come from is orthogonal. You can browse the canonical entry any time at /servers/metamcp.
The Verdict
Our Take
MetaMCP is the strongest open-source answer if you specifically want to own the gateway: namespaces, per-namespace tool filtering, SSO, and a real admin UI, all under an MIT license on your own Docker host. Use it when config sprawl across multiple clients or a team is the actual pain, and you can operate a container plus Postgres. Skip it — for now — if you run a single client with a handful of servers, or if you need zero-ops reliability today, where the session-pool and reverse-proxy rough edges will frustrate more than the sprawl they remove.
Frequently Asked Questions
What is MetaMCP?
MetaMCP is an open-source MCP proxy you self-host with Docker. It aggregates several MCP servers into a namespace, exposes that namespace as one endpoint (SSE, Streamable HTTP, or OpenAPI), and can filter or rename tools through middleware. Any MCP client connects once instead of wiring up every server.
How do I install MetaMCP?
Clone the repo, copy example.env to .env, and run `docker compose up -d`. The web UI comes up on http://localhost:12008, backed by its own Postgres. From there you register upstream MCP servers, group them into a namespace, and create an endpoint. No account with a vendor is required — it runs entirely on your machine.
How do I connect Claude Desktop to MetaMCP?
MetaMCP endpoints are remote-only (SSE / Streamable HTTP), and Claude Desktop speaks stdio, so you need a local bridge. The maintainer recommends `mcp-proxy` (via `uvx`), not `mcp-remote` — the latter only handles OAuth, not MetaMCP's API-key auth. Point mcp-proxy at your `/mcp` endpoint and pass the key as `API_ACCESS_TOKEN`.
Is MetaMCP free and open source?
Yes. MetaMCP is MIT-licensed and self-hostable, so there is no per-seat pricing and no usage cap you don't set yourself. The trade is that you run and maintain the container, the Postgres volume, and the reverse proxy. It is infrastructure you own, not a managed service.
Why do MetaMCP's tools suddenly return empty?
Almost always idle-session pool saturation. MetaMCP keeps warm sessions per server and per namespace; stale ones accumulate until the pool hits its cap (hardcoded near 100 in older builds), after which `tools/list` returns an empty array with a 200. Operators restart the container to reclaim sessions. Track it in GitHub issues #294 and #272.
Does MetaMCP support OAuth and SSO?
Yes on both. Endpoints can require standard MCP OAuth (spec revision 2025-06-18) instead of an API key, and the admin app supports OpenID Connect for login — tested against Auth0, Keycloak, Azure AD, Google, and Okta, with PKCE on by default. Registration controls let you allow SSO while blocking manual signups.
MetaMCP vs Smithery — which do I use?
They solve overlapping problems differently. Smithery is a serverless marketplace; MetaMCP is a self-hosted proxy you run in your own network. The maintainer's own position is that they are complementary — you can pull servers from Smithery into a MetaMCP namespace, then filter and remix them. Pick MetaMCP when you need to own the host.
Glossary
- MCP
- Model Context Protocol — the JSON-RPC wire format between an LLM client and a tool server.
- Gateway / proxy
- A server that sits between clients and other MCP servers and presents them as one.
- Aggregate
- Merge the tools of several MCP servers into a single tool list behind one endpoint.
- Namespace
- A named group of MCP servers inside MetaMCP; the unit filtering and auth attach to.
- Endpoint
- A public URL bound to a namespace, served over SSE, Streamable HTTP, or OpenAPI.
- Middleware
- A function that rewrites MCP requests/responses at a namespace, e.g. filtering tools.
- SSE
- Server-Sent Events — a remote MCP transport MetaMCP endpoints can use.
- Streamable HTTP
- The current remote MCP transport; supports API-key auth via query param and headers.
- mcp-proxy
- A local bridge that lets stdio-only clients talk to a remote MetaMCP endpoint.
- Idle session
- A pre-warmed upstream connection MetaMCP keeps to cut cold-start latency.
- OIDC
- OpenID Connect — the SSO standard MetaMCP's admin app supports for team login.
- Tool override
- A per-namespace rename or re-annotation of an upstream tool, merged with its metadata.
Sources
- Active repo & README: github.com/metatool-ai/metamcp (MIT) and docs at docs.metamcp.com
- Scaling / pooling issues: #294, #272, error-state persistence #264, reverse-proxy discovery #265
- Maintainer’s 2.0 announcement & Q&A: r/mcp thread
- Community: tweets by @Saboo_Shubham_ and @danjones; demo video by James Devlog (youtu.be/Cf6jVd2saAs)
- Canonical MCP.Directory entry: /servers/metamcp
- Related reading: MCP gateway comparison and the context-bloat fix
Comparison
MCP Gateways compared: MCPJungle, Obot, Docker, Composio
ReadDeep dive
Fixing MCP context bloat: tool search & filtering
ReadClient
Claude Code — MCP client reference
OpenFound an issue?
MetaMCP moves quickly — if a namespace flow, a transport default, or the session-pool behavior has changed, email [email protected] or read more on our about page. We keep these guides current.