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: Master MCP Server

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

A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (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.

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/arthurkatcher/meta-mcp-manager'

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