Skip to main content
Glama
arthurkatcher

meta-mcp-manager

Meta MCP Manager

CI License: MIT Python 3.11+

One MCP endpoint for every tool you own.

Self-hosted control plane that federates stdio and remote MCP servers, keeps them warm, indexes tools for retrieval, and exposes a single Streamable HTTP surface to Cursor, Claude, ChatGPT, and other agents.

Cursor / Claude / ChatGPT
        │  one connection
        ▼
   Meta MCP Manager  ──► GitHub · Logfire · Context7 · your stdio servers · …
        │
   search → schema → call
   manage_servers · manage_auth (admin)
  • Scale past client tool caps — agents see a small fixed meta-tool set, not 500 schemas.

  • Cursor-compatible config — drop in an mcp.json you already use.

  • Inbound OAuth — Claude/ChatGPT paste your URL; PKCE + DCR + consent page.

  • Outbound OAuth — connect protected upstreams (e.g. Logfire) via manage_auth.

  • Open source, single binary-ish Docker image — MIT, no phone-home.


Table of contents


Related MCP server: mcp-gw

Why

AI clients hard-cap tools and burn tokens on every schema. Loading dozens of MCPs directly:

  1. Hits limits (e.g. ~40 tools in some IDEs).

  2. Degrades tool selection accuracy.

  3. Makes OAuth, restarts, and inventory unmanageable.

Meta sits in the middle: one public MCP, many upstreams, search-first discovery.


Features

Area

Capability

Transports

Warm stdio pool; remote Streamable HTTP (+ SSE where configured)

Discovery

BM25 search_tools, paginated list_servers / list_tools

Admin

manage_servers CRUD; enable/disable/reload

Outbound auth

OAuth 2.1 + PKCE to upstreams; encrypted token vault; refresh

Inbound auth

OAuth AS + PRM for Claude/ChatGPT; API key for local clients

Scopes

meta:read (catalog), meta:invoke (call), meta:admin (manage_*)

Ops

Health JSON, audit log (arg keys only), Docker Compose

Packaging

Logo SVG, docs/legal pages, CSP + security headers


Quick start

Requirements

  • Python 3.11+

  • Optional: Node (npx) if your upstream MCPs need it

  • Optional: uv

Install & run

git clone https://github.com/arthurkatcher/meta-mcp-manager.git
cd meta-mcp-manager

python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate

pip install -e ".[dev]"
# or: uv pip install -e ".[dev]"

cp config/mcp.example.json mcp.json
# Edit paths / servers as needed

export META_API_KEY="$(openssl rand -hex 16)"
meta serve --config mcp.json --host 127.0.0.1 --port 8080 --data-dir ./data

URL

Description

http://127.0.0.1:8080/mcp

MCP endpoint

http://127.0.0.1:8080/health

Health + stats

http://127.0.0.1:8080/docs

Human docs

http://127.0.0.1:8080/static/logo.svg

Logo

curl -s http://127.0.0.1:8080/health | jq .

Docker

export META_API_KEY="$(openssl rand -hex 16)"
docker compose up --build

Compose mounts config/mcp.docker.json and persists /data. For public clients (Claude/ChatGPT) set:

export META_PUBLIC_URL=https://your.domain.example
export META_OAUTH_PASSWORD="$META_API_KEY"   # or a separate consent password
docker compose up --build

Connect clients

Cursor / VS Code (API key)

{
  "mcpServers": {
    "meta": {
      "url": "http://127.0.0.1:8080/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_META_API_KEY"
      }
    }
  }
}

Grok (~/.grok/config.toml)

[mcp_servers.meta]
url = "http://127.0.0.1:8080/mcp"
enabled = true

[mcp_servers.meta.headers]
Authorization = "Bearer YOUR_META_API_KEY"

Or: grok mcp add --transport http meta http://127.0.0.1:8080/mcp --header "Authorization: Bearer YOUR_META_API_KEY"

Claude Desktop (stdio bridge + API key)

{
  "mcpServers": {
    "meta": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://127.0.0.1:8080/mcp",
        "--header",
        "Authorization: Bearer YOUR_META_API_KEY"
      ]
    }
  }
}

Claude / ChatGPT (remote + inbound OAuth)

  1. Expose Meta with HTTPS (tunnel or reverse proxy):

    ngrok http 8080
    export META_PUBLIC_URL=https://YOUR_SUBDOMAIN.ngrok-free.dev
    meta serve --config mcp.json --host 0.0.0.0 --port 8080 \
      --public-url "$META_PUBLIC_URL" --api-key "$META_API_KEY"
  2. In the client, add remote MCP URL:
    https://YOUR_SUBDOMAIN.ngrok-free.dev/mcp

  3. Complete browser consent with META_OAUTH_PASSWORD or META_API_KEY.

No static Bearer header required for that path.


Meta tools

Tool

Purpose

search_tools

BM25 search over the catalog

get_tool_schema

Full JSON schema for server/tool

call_tool

Invoke upstream tool

list_servers

Paginated server inventory

list_tools

Paginated tool catalog (server filter optional)

stats

Counts / health

manage_servers

create · update · delete · get · list · enable · disable · reload

manage_auth

login · status · logout · refresh (no raw tokens to the model)

Agent path: search_toolsget_tool_schemacall_tool.

Add an upstream MCP (+ OAuth)

manage_servers(action="create", server_id="logfire",
               url="https://logfire-us.pydantic.dev/mcp")

# if runtime_status == "auth_required":
manage_auth(action="login", server_id="logfire")
# open authorization_url → Meta /oauth/callback completes

manage_auth(action="status", server_id="logfire")
search_tools(query="list projects")
call_tool(tool_id="logfire/project_list", arguments={})

Admin tools require scope meta:admin. API keys grant full admin.


Configuration

mcp.json (Cursor-compatible)

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"]
    },
    "context7": {
      "url": "https://mcp.context7.com/mcp"
    },
    "protected": {
      "url": "https://example.com/mcp",
      "headers": {
        "Authorization": "Bearer ${env:SERVICE_TOKEN}"
      },
      "auth": {
        "CLIENT_ID": "${env:OAUTH_CLIENT_ID}",
        "CLIENT_SECRET": "${env:OAUTH_CLIENT_SECRET}",
        "scopes": ["read", "write"]
      }
    }
  }
}

${env:NAME} is interpolated at load time.

Environment variables

Variable

Description

META_API_KEY

Bearer key for local clients; default consent password if unset

META_OAUTH_PASSWORD

Consent password for inbound OAuth (optional)

META_PUBLIC_URL

Public base URL (required for OAuth redirects / PRM)

META_CONFIG

Path to mcp.json

META_DATA_DIR

SQLite, vaults, logs

META_HOST / META_PORT

Bind address

META_OAUTH_ENABLED

Inbound OAuth AS (default true)

META_ALLOW_API_KEY

Accept API key on /mcp (default true)

META_REQUIRE_API_KEY

Require auth on /mcp (default true)

META_STRICT_STDIO

Require absolute stdio commands (default false)

META_STDIO_ALLOW_PREFIXES

:-separated path prefixes allowed when strict

CLI:

meta serve --config mcp.json --host 127.0.0.1 --port 8080 \
  --api-key "$META_API_KEY" --public-url "$META_PUBLIC_URL"

OAuth

Two directions

Direction

Meaning

Outbound

Meta → upstream MCP (Logfire, Linear, …) via manage_auth + /oauth/callback

Inbound

Claude/ChatGPT → Meta via PRM/AS + /oauth/authorize + /oauth/token

Inbound discovery endpoints

Endpoint

Spec role

GET /.well-known/oauth-protected-resource

RFC 9728 PRM

GET /.well-known/oauth-authorization-server

RFC 8414 AS metadata

POST /oauth/register

Dynamic client registration

GET/POST /oauth/authorize

Authorization code + consent

POST /oauth/token

Code exchange / refresh

Scopes

Scope

Access

meta:read

search, list, schema, stats (catalog)

meta:invoke

call_tool when META_REQUIRE_INVOKE_SCOPE=true

meta:admin

manage_servers, manage_auth

Default OAuth consent grants meta:read + meta:invoke (catalog + call tools).
meta:admin is never default — must be requested explicitly. API keys get all scopes.
Set META_REQUIRE_INVOKE_SCOPE=true to enforce that call_tool needs meta:invoke (recommended when you also issue read-only tokens).

Rate limits (defaults, per principal / min)

Surface

Default

Env

call_tool

60

META_RATE_CALL_TOOL

manage_*

30

META_RATE_MANAGE

catalog (search / list_* / stats)

180

META_RATE_CATALOG

OAuth register / token / authorize

separate

(built-in)

Window: META_RATE_WINDOW_SEC (default 60). Set a limit to 0 to disable that bucket. Exceeded tools return error: rate_limited.

Product database (one SQLite file)

Everything durable lives in {META_DATA_DIR}/meta.db (WAL). Multiple tables, one file for backup/UI:

Table(s)

Purpose

servers, tools

Catalog of upstream MCPs + tool schemas

activity

Meta-tool call log (Activity UI)

oauth_tokens, oauth_pending

Outbound OAuth (token blobs Fernet-encrypted)

oauth_clients, auth_codes, access_tokens, …

Inbound OAuth AS

meta_schema

Schema version

Still separate on disk: mcp.json (config templates), token.key (Fernet key, mode 0600), optional JSONL mirror logs/audit.jsonl.

Legacy split files (activity.db, oauth.db, inbound_oauth.db) are merged into meta.db once on startup and renamed *.migrated.

Activity columns: event_id, ts, duration_ms, meta_tool, actor_label (oauth · Claude, …), ok, error_code, args_keys (names only), target_tool_id, …

OAuth actors use registered client_name from DCR when available.

Inbound bearer secrets (access/refresh/auth codes/client_secret) are stored as SHA-256 digests in SQLite (plaintext only at issuance).

Production checklist

Control

Env / action

Strong API key

META_API_KEY ≥16 chars, unique

Consent password

META_OAUTH_PASSWORD (separate from API key preferred)

Public bind

Auto strict_stdio; refuse weak keys

DCR lock

META_DCR_TOKEN=… and/or META_DCR_REDIRECT_ALLOWLIST=claude.ai,.openai.com

Disable DCR

META_DCR_ENABLED=false

Catalog-only OAuth

META_REQUIRE_INVOKE_SCOPE=true + grant meta:invoke when needed

SSRF

META_ALLOW_PRIVATE_URLS=false when not needing localhost MCPs

Activity retention

META_ACTIVITY_RETENTION_DAYS=30 (default)

Single worker

Do not set WEB_CONCURRENCY>1 (refused at start)

Backup

meta backup --out /safe/path (copies meta.db, token.key, mcp.json)

TLS

Terminate at reverse proxy / tunnel


Brand & connector packaging

Asset

Path

Logo

/static/logo.svg

Favicon

/static/favicon.svg

Docs

/docs

Terms

/legal/terms

Privacy

/legal/privacy

Brand pack

/brand

PRM includes logo_uri, resource_documentation, resource_tos_uri, resource_policy_uri.
HTML/OAuth responses send CSP and standard security headers.

See docs/CONNECTOR.md for the full surface and production checklist.


Architecture

src/meta_manager/
  app.py              # HTTP routes, lifespan
  main.py             # CLI: meta serve
  config/             # mcp.json load/save, settings
  runtime/            # stdio + HTTP session pool
  catalog/            # SQLite catalog + BM25
  edge/               # meta tools, auth middleware, CSP
  oauth/              # outbound vault + inbound AS
  admin/              # manage_servers / manage_auth
  brand/              # docs/legal HTML
  static/             # logo, favicon

Design notes: ARCHITECTURE.md.


Development

source .venv/bin/activate
pip install -e ".[dev]"

pytest -q --timeout=90
# optional real-MCP stress (Meta must be running):
# META_URL=http://127.0.0.1:8080/mcp META_API_KEY=... python scripts/hardcore_eval_real.py

Fixtures under fixtures/ provide stdio math/echo/many-tools and an HTTP time server for CI without flaky public remotes.


Security notes

  • Self-hosted: you operate the instance; protect META_API_KEY / META_OAUTH_PASSWORD and network exposure.

  • Prefer HTTPS and a stable domain for inbound OAuth (not long-term free tunnels).

  • Upstream tokens are stored under META_DATA_DIR (Fernet-encrypted vault); back up and restrict that directory.

  • Admin tools can add arbitrary commands (stdio) and URLs — treat meta:admin like root.

  • Audit log records tool ids and argument keys, not secret values.

  • Legal pages under /legal/* are OSS self-host templates, not formal counsel.


Status & roadmap

v0.1 — production-capable for single-operator self-host: federation, BM25 search, warm stdio, remote HTTP, outbound OAuth, inbound OAuth (PRM/AS/DCR/PKCE), admin tools with scope gates, Docker, connector branding, unified SQLite, activity log, rate limits, resource-bound tokens.

Still out of scope for multi-tenant SaaS: external IdP, distributed rate limits (Redis), multi-replica HA, marketplace listings.

See CHANGELOG.md for release notes.


Contributing

See CONTRIBUTING.md and CODE_OF_CONDUCT.md. PRs and issues welcome.


Security

Please report vulnerabilities privately — SECURITY.md.


License

MIT — Copyright (c) 2026 Meta MCP Manager contributors

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Aggregates multiple MCP servers behind a single, secure endpoint with unified tool/resource discovery, OAuth authentication, and resilient request routing. Enables users to manage and interact with multiple MCP backends through one centralized interface with load balancing and circuit breakers.
    2
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Aggregates multiple MCP servers into a single HTTP endpoint with tool namespacing, dashboard, and REST API for management.
    11 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Aggregates multiple MCP servers into a single unified endpoint with hot-plugging, multi-protocol support, and management via web and CLI.
    26 npm
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enterprise MCP gateway that unifies multiple MCP servers behind one governed endpoint, providing federation, authentication, policy enforcement, caching, rate limiting, and audit.
    1
    Apache 2.0