Meta Manager
БесплатноНе проверенFederates multiple MCP servers into a single endpoint with search, call, and admin tools, plus inbound/outbound OAuth.
Описание
Federates multiple MCP servers into a single endpoint with search, call, and admin tools, plus inbound/outbound OAuth.
README
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.jsonyou 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
- Why
- Features
- Quick start
- Docker
- Connect clients
- Meta tools
- Configuration
- OAuth
- Brand & connector packaging
- Architecture
- Development
- Security notes
- Status & roadmap
- Contributing
- Security
- License
Why
AI clients hard-cap tools and burn tokens on every schema. Loading dozens of MCPs directly:
- Hits limits (e.g. ~40 tools in some IDEs).
- Degrades tool selection accuracy.
- 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)
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"In the client, add remote MCP URL:
https://YOUR_SUBDOMAIN.ngrok-free.dev/mcpComplete browser consent with
META_OAUTH_PASSWORDorMETA_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_tools → get_tool_schema → call_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_PASSWORDand 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:adminlike 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
Установка Meta Manager
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/arthurkatcher/meta-mcp-managerFAQ
Meta Manager MCP бесплатный?
Да, Meta Manager MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Meta Manager?
Нет, Meta Manager работает без API-ключей и переменных окружения.
Meta Manager — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Meta Manager в Claude Desktop, Claude Code или Cursor?
Открой Meta Manager на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Meta Manager with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
