mcp-hub
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-hublist available servers"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-hub
One MCP connection. Every server. Loaded only when needed.
mcp-hub is a meta-MCP server that sits between your MCP host (Claude Code, Claude Desktop, Cursor, …) and all of your individual MCP servers. Instead of wiring a dozen servers directly into your client — each one spawning a process at launch and flooding the model's context with tool definitions — you connect to a single hub that exposes a handful of discovery tools and spawns child servers lazily, on first use.
Table of contents
Related MCP server: programmatic-mcp
Quick start
# 1. Install (from Git — see Installation for options)
uv tool install git+https://github.com/igrybkov/mcp-hub.git
# 2. Describe your servers
mkdir -p ~/.config/mcp-hub
cat > ~/.config/mcp-hub/servers.yml <<'YAML'
everything:
command: npx
args: ["-y", "@modelcontextprotocol/server-everything"]
description: "Reference MCP server for testing"
tags: [example]
YAML
# 3. Verify from the shell
mcp-hub list
mcp-hub tools everything --summary
# 4. Register the hub with your client (writes .mcp.json by default)
mcp-hub installThat's it — your host now talks to one server (mcp-hub), and everything only starts when the model actually calls one of its tools.
Why mcp-hub?
Connecting many MCP servers directly to a host has two costs that grow with every server you add:
Context bloat. Every server's full tool schema is injected into the model's context up front. Twenty servers can burn tens of thousands of tokens before the user types a word.
Process bloat. Every server is spawned at startup, even the ones you won't touch this session — slow launches, idle Docker containers, wasted memory.
mcp-hub collapses all of that behind one connection:
Direct wiring | With mcp-hub | |
Connections in the host | one per server | one, total |
Tools in context at startup | all tools, all servers | ~8 meta-tools |
Child process spawn | eager, at launch | lazy, on first use |
Add/remove a server | edit + restart the host | edit config + |
Secrets | per-client env plumbing | central OS keychain |
The model discovers what it needs through cheap, progressive tool calls — and the hub only spawns the child servers a task actually touches.
Architecture
flowchart LR
Host["MCP Host<br/>Claude Code · Desktop · Cursor"]
subgraph HUB["mcp-hub (single connection)"]
direction TB
Meta["Discovery meta-tools<br/>list · search · get · call · recommend"]
Cat["Catalog cache<br/>prompts + resources"]
Auth["Keychain auth"]
end
Host <==>|"stdio · ~8 tools"| HUB
HUB -.->|spawn on first use| G["github"]
HUB -.->|spawn on first use| J["jira"]
HUB -.->|lazy| S["slack"]
HUB -.->|lazy| N["… N servers"]Child servers stay dormant until a tool call (or an opt-in prompt/resource enumeration) reaches them. The hub also relays the full duplex of MCP capabilities — sampling, elicitation, roots, logging, and completions — between the host and each child, so wrapping a server in the hub doesn't take features away.
Features
Lazy proxying — child servers spawn on first use, each in its own supervised connection task.
Progressive discovery —
list_servers,get_server_tools(summary or full schema),search, andcall_toollet the model drill down without paying for every schema up front.LLM-backed routing —
recommend_serversasks the host's own model (via MCP sampling) which servers fit a task, with a graceful fallback when sampling is unavailable.Keychain-native auth — secrets live in your OS keychain (via
keyring), are injected into child environments on spawn, and are collected through MCP elicitation so they never enter the model's context.Opt-in prompts & resources — surface a child's prompts/resources through the hub with a flat, namespaced view, backed by an on-disk catalog for instant warm starts and a self-healing recovery daemon for cold ones.
Full capability relay — bidirectional sampling, elicitation, roots, logging, and completions pass through transparently.
Three transports —
stdio,streamable-http, andssechildren.Hot reload — add, remove, or edit servers and pick up the change with a single
reload, no host restart.First-class CLI — script everything (
list,tools,call,search,auth,add,validate,install) with JSON output.Bundled agent skill — ships a "managing MCP servers" skill so an assistant can add, configure, and troubleshoot servers from a vendor's docs; install it with
mcp-hub skill install.
Installation
Note:
mcp-hubis not yet published to PyPI. Install from Git for now.
Requires Python 3.11+.
# Recommended: install as an isolated tool with uv
uv tool install git+https://github.com/igrybkov/mcp-hub.git
# Run ephemerally without installing (great for trying it out)
uvx --from git+https://github.com/igrybkov/mcp-hub.git mcp-hub list
# Or with pip / pipx
pip install git+https://github.com/igrybkov/mcp-hub.git
pipx install git+https://github.com/igrybkov/mcp-hub.gitA single mcp-hub entry point is installed, with two roles:
mcp-hub <command>— the CLI (list,tools,call,auth,install, …).mcp-hub server— the MCP server (stdio) your host launches.
From source
git clone https://github.com/igrybkov/mcp-hub.git
cd mcp-hub
uv sync --dev
uv run mcp-hub listUse mcp-hub in your client
With the install command
install writes (or updates) an mcpServers entry and auto-detects the runner from how you launched it. If you ran via uvx --from <spec>, it reuses the same --from spec so the generated entry matches exactly; otherwise it writes a plain mcp-hub server.
# Claude Code — project-level (.mcp.json in CWD, checked into the repo)
mcp-hub install
# User-level / other clients — point at any config file
mcp-hub install --config ~/.mcp.json
mcp-hub install --config ~/Library/Application\ Support/Claude/claude_desktop_config.json
mcp-hub install --config ~/.cursor/mcp.json
# Preview without writing
mcp-hub install --config .mcp.json --dry-run
# Force a specific runner ("mcp-hub server" is appended automatically)
mcp-hub install --runner 'uvx --from git+https://github.com/igrybkov/mcp-hub.git'Manual configuration
If you installed mcp-hub as a tool, the entry is simply:
{
"mcpServers": {
"mcp-hub": {
"command": "mcp-hub",
"args": ["server"]
}
}
}To run straight from Git without a prior install:
{
"mcpServers": {
"mcp-hub": {
"command": "uvx",
"args": ["--from", "git+https://github.com/igrybkov/mcp-hub.git", "mcp-hub", "server"]
}
}
}Agent skill
mcp-hub ships a bundled agent skill that teaches an assistant the full lifecycle of managing servers — discover/search, add & configure from a vendor's docs (secrets to the keychain, never inline), authenticate, reload, verify, and troubleshoot. With it installed, you can just say "add the MongoDB MCP to mcp-hub: " or "find me an MCP server for Postgres" and the agent knows the rest.
# Install for Claude (default) — writes ./.claude/skills/mcp-hub/
mcp-hub skill install
# Install for Cursor — writes ./.cursor/skills/mcp-hub/
mcp-hub skill install --client cursor
# Or an explicit directory
mcp-hub skill install --dir ~/.config/skills
# Print the guide to stdout (no install) — pull it on demand or pipe to a file
mcp-hub skill show
mcp-hub skill listThe skill travels inside the package, so every install has it. It's also surfaced to the model automatically: the hub's instructions always point at mcp-hub skill show.
Configuration
Servers are described in JSON or YAML. By default the hub merges these sources, in order, with later sources overriding earlier ones by server name:
~/.config/mcp-hub/servers.json~/.config/mcp-hub/servers.yml./.mcp.local.json(project-level, resolved from the working directory)./.mcp.local.yml
Point the hub at different files with the CONFIG_FILE environment variable (comma-separated paths):
export CONFIG_FILE="~/.config/mcp-hub/servers.yml,./team-servers.yml"Both the wrapped ({"mcpServers": {…}}) and unwrapped (top-level mapping) shapes are accepted, so you can reuse an existing .mcp.json-style file as-is.
Examples
# stdio child
github:
command: gh-mcp
args: ["--stdio"]
env:
GH_HOST: github.com
description: "GitHub issues, PRs, and repos"
tags: [dev, vcs]
# streamable-http child (default transport when `url` is set)
everything:
url: https://everything.mcp.run/mcp
headers:
Authorization: "Bearer ${TOKEN}"
# sse child
metrics:
url: https://metrics.example.com/sse
transport: sse
# opt in to prompts/resources and give a slow (Docker) server more time
obsidian:
command: docker
args: ["run", "-i", "--rm", "obsidian-mcp"]
expose_prompts: true
expose_resources: true
connect_timeout_seconds: 20
# temporarily turn a server off without deleting it
legacy:
command: old-mcp
disabled: trueField reference
Field | Type | Applies to | Default | Description |
| string | stdio | — | Executable to launch. |
| string[] | stdio |
| Arguments passed to |
| map | stdio |
| Extra environment for the child (merged over the hub's own env). |
| string | http/sse | — | Endpoint URL. Presence selects an HTTP transport. |
| string | http/sse |
|
|
| map | http/sse |
| Headers sent with each request. |
| string | all | — | Shown in discovery and used for search/recommendations. |
| string[] | all |
| Free-form labels, matched by |
| bool | all |
| Skip this server entirely. |
| bool | all |
| Surface the child's prompts through the hub. |
| bool | all |
| Surface the child's resources/templates through the hub. |
| number | exposed |
| Per-server connect + enumerate budget. Raise for slow/Docker cold starts. |
| list | all | — | Secret schema for keychain injection (see Authentication). |
Managing servers (agent workflow)
You rarely need to hand-edit config. mcp-hub add translates a vendor's docs snippet into the hub's shape and moves likely-secret env vars into the keychain schema automatically (the rule below), validate lints before you reload, and config path shows where things get written. The bundled agent skill drives the whole flow.
mcp-hub config path # resolved sources + the file `add` writes to
# Translate a docs snippet (wrapped or single-entry). Secret env vars matching
# *TOKEN/KEY/SECRET/PASSWORD/CONNECTION_STRING* (with a real value) are moved to
# auth.secrets and their raw values dropped; --keep-env-secrets opts out.
mcp-hub add mongodb \
--from-json '{"mcpServers":{"MongoDB":{"command":"npx","args":["-y","mongodb-mcp-server@latest"],"env":{"MDB_MCP_CONNECTION_STRING":"mongodb+srv://user:pass@host/db"}}}}' \
--arg --readOnly --description "MongoDB / Atlas" --tag database
# Or build from flags (no snippet):
mcp-hub add linear --command npx --arg -y --arg linear-mcp-server \
--secret 'LINEAR_API_KEY:Linear API key:https://linear.app/settings/api'
mcp-hub auth provision mongodb # store the secret(s) in the keychain
mcp-hub validate # lint; flags any raw secrets left in env/headers
# …then call the `reload` tool (or restart the host) and verify with `list`/`tools`/`call`.Secret-vs-env rule — API keys, tokens, passwords, client secrets, and connection strings with embedded credentials belong in auth.secrets (keychain). Base URLs, hostnames, account/team IDs, emails, regions, and flags stay in plaintext env/headers. Run mcp-hub skill show for the full guide.
Meta-tools
The hub exposes a small, fixed set of tools to the host. The model uses them to discover and reach everything else.
Tool | What it does |
| List configured servers with descriptions, tags, transport, and auth status. Optional substring |
| List a server's tools. |
| Invoke |
| Keyword-rank across server metadata and already-loaded tool descriptions. |
| Ask the host LLM to rank servers for a |
| Re-read config and reconcile the server set, or reload a single |
| Collect and store a server's secrets in the OS keychain via elicitation, then refresh the session. |
| Report auth state (authenticated / partial / unauthenticated) for one or all servers. |
The discovery funnel
The intended flow keeps token usage low by only loading detail when it's needed:
list_servers(filter?) → which servers exist
│
get_server_tools(server, → which tools exist (names + descriptions only)
summary_only=true)
│
get_server_tools(server, → full input schema for the 1–2 tools you'll call
tools=[names])
│
call_tool(server, tool, arguments) → run it (spawns the child if needed)When you're unsure which server fits, recommend_servers("deploy the staging branch") returns a ranked shortlist with one-line rationales.
Authentication
Secrets are never stored in config files or passed through the model. Instead the hub uses a schema-as-source-of-truth model:
A server declares which environment variables it needs in an
auth.secretsblock.Values are stored in your OS keychain (
keyring; macOS Keychain, Windows Credential Locker, Secret Service, …) under the service namemcp-hub.On spawn, the hub injects only the declared secrets into the child's environment.
linear:
command: linear-mcp
auth:
secrets:
- env_var: LINEAR_API_KEY
label: "Linear API key"
create_url: "https://linear.app/settings/api"
sensitive: true # default; masks terminal inputEach secret supports env_var, label, create_url, sensitive (default true), and state (present or absent; absent reconciles the value out of the keychain).
Storing secrets
From the assistant (in-session, no terminal): call authenticate with the server name. The hub asks the host to prompt you via MCP elicitation, stores the answer in the keychain, and refreshes the session — the value never touches the model's context.
From the shell:
mcp-hub auth status # what's stored, what's missing
mcp-hub auth provision linear # prompt for and store linear's secrets
mcp-hub auth provision linear --force # overwrite stored secrets (rotated/expired keys)
mcp-hub auth provision --all # provision every server with a schema
mcp-hub auth rm linear # delete linear's stored secrets
mcp-hub auth rm linear LINEAR_API_KEYBy default provision skips secrets that are already in the keychain. Pass --force to re-prompt and overwrite them — use this to rotate an expired or revoked key. In-session, the authenticate tool takes an equivalent force: true.
Learned schemas
If you provision secrets for a server that has no declared schema, the hub records a learned schema at ~/.local/state/mcp-hub/learned-auth.json (honoring XDG_STATE_HOME). Promote it into your config to make it canonical:
mcp-hub auth promote linear # prints the YAML auth block to paste into your configPrompts & resources
By default, child prompts and resources stay hidden behind the meta-tools — the host's UI stays clean. Set expose_prompts: true and/or expose_resources: true on a server to surface them natively, where they appear in one flat, namespaced list:
Prompts:
obsidian__daily-note(<server>__<prompt>)Resources:
mcphub://obsidian/<percent-encoded-original-uri>
The hub decodes these on get_prompt / read_resource and routes back to the right child. Resource templates and argument completions are proxied too.
To make this fast and resilient, exposed metadata is cached on disk at ~/.cache/mcp-hub/catalog.json:
Warm start (cache valid for the current config): prompts/resources are served instantly.
Cold start (no cache or config changed): the hub serves whatever has enumerated so far, then a background recovery daemon keeps trying — with exponential backoff (5s → 5min, jittered) for slow or flaky children — and emits
list_changedas servers come online. Degraded servers keep serving their last-known-good entries.
The cache key is a hash of your config files, so editing config (or running reload) automatically invalidates stale entries.
Advanced MCP support
Wrapping a server in the hub keeps its full feature set. The hub relays every MCP capability in both directions:
Capability | Direction | Behaviour |
Tools | host → child | Proxied on demand via |
Sampling | child → host | Forwarded to the host LLM ( |
Elicitation | child → host | Forwarded to the host ( |
Roots | child → host & host → children |
|
Logging | child → host & host → children | Child log messages forwarded (prefixed with the server name); |
Prompts | child → host | Opt-in ( |
Resources | child → host | Opt-in ( |
Completions | host → child | Proxied for exposed prompts and resource templates. |
Errors from children are mapped to clean JSON-RPC errors rather than crashing the hub, and capabilities a child doesn't implement degrade gracefully (e.g. "method not found" becomes "no suggestions").
CLI reference
Run any command with -h/--help for details. Add -v/--verbose for debug logging to stderr — this also raises mcp-hub server from INFO to DEBUG (e.g. mcp-hub -v server, or "args": ["-v", "server"] in a client config). Most commands print JSON to stdout, so they compose well with jq.
# Discover
mcp-hub list # all configured servers
mcp-hub list --filter monitoring # substring filter on name/description/tags
mcp-hub list --names-only # one name per line (scripting)
mcp-hub tools <server> # full tool schemas for a server
mcp-hub tools <server> --summary # names + descriptions only
mcp-hub tools <server> --tool <name> # full schema for specific tool(s)
mcp-hub search "deploy" # search metadata + loaded tools
mcp-hub search "deploy" --load # load every server's tools first (slow)
# Invoke
mcp-hub call <server> <tool> --args '{"key": "value"}'
mcp-hub call <server> <tool> --args-file ./args.json
# Auth
mcp-hub auth status [--server <name>]
mcp-hub auth provision <server> | --all [--force]
mcp-hub auth rm <server> [<ENV_VAR>]
mcp-hub auth promote <server>
# Manage config (see "Managing servers" above)
mcp-hub config path # resolved sources + write target
mcp-hub add <name> [--from-json '<snippet>'] [flags] [--dry-run]
mcp-hub validate [--config PATH] # lint specs; non-zero exit on error
# Bundled agent skill
mcp-hub skill show [name] # print SKILL.md to stdout (default: mcp-hub)
mcp-hub skill list # list bundled skills
mcp-hub skill install [name] [--client claude|cursor] [--dir PATH] [--force]
# Install into a client config
mcp-hub install [--config PATH] [--name KEY] [--runner CMD] [--dry-run]How it works
A few design choices worth knowing:
One task per connection. Each child connection is owned by a dedicated supervisor task that opens the transport, initializes the
ClientSession, parks until shutdown, then tears everything down in the same task. This respects an anyio constraint (cancel scopes must be exited in the task that entered them) and prevents orphaned child processes.Schema-driven secret injection. Only environment variables named in a server's (declared or learned) auth schema are pulled from the keychain and injected — nothing implicit leaks into a child.
Atomic, self-describing catalog. Exposed prompts/resources are serialized (with metadata) and written atomically (tempfile +
os.replace), so the hub never needs to re-call a child to reconstruct a listing, and a crash can't corrupt the cache.Buffered notifications. The host's
ServerSessiononly exists once a request arrives, so background notifications produced during startup (e.g. a late server finishing enumeration) are buffered in a bounded queue and flushed the moment the host connects.
File locations
Path | Purpose | Override |
| Default global config |
|
| Project-level config (CWD) |
|
| Cached exposed prompts/resources | — |
| Learned auth schemas |
|
| Server log (created on start) |
|
OS keychain, service | Stored secrets | keyring backend |
Development
uv sync --dev # install dev dependencies
uv run pytest # run the test suite
uv run ruff check . # lint
uv run ruff format . # format
# optional: install git hooks (ruff lint + format on commit)
uv run pre-commit installThe Build & Test workflow (GitHub Actions) runs ruff check, ruff format --check, and pytest on every push and pull request to main.
Contributing
Contributions are welcome! Please:
Open an issue to discuss substantial changes first.
Keep PRs focused, and add or update tests where it makes sense.
Use Conventional Commit messages (they drive the automated release).
Make sure
uv run ruff check .,uv run ruff format --check ., anduv run pytestpass before opening a PR.
Releasing
Releases are fully automated with python-semantic-release driven by Conventional Commits. When Build & Test passes on main, the Publish workflow computes the next version from commit messages, updates the changelog and version, tags the release, publishes a GitHub release, and attaches the built wheel and sdist to it as release assets.
Commit message prefixes that affect versioning:
fix:→ patch releasefeat:→ minor releasefeat!:/BREAKING CHANGE:→ major releasechore:,docs:,refactor:,test:, … → no release
Troubleshooting
A child won't start / connection error. Run the child's
commandby hand to confirm it works, thenmcp-hub tools <server>— the child's own stderr is surfaced. Detailed logs are at~/Library/Logs/mcp-hub.log(or$MCP_HUB_LOG_FILE).Edited config isn't picked up. Call the
reloadtool (or restart the host). Adding the first exposed server requires a host reconnect to register the prompts/resources capability.A server needs more startup time. Raise its
connect_timeout_seconds(slow Docker images especially).Auth says "partial". One or more declared secrets aren't stored yet — run
mcp-hub auth provision <server>or theauthenticatetool.A stored key expired or was rotated.
provisionskips secrets that already exist; re-store withmcp-hub auth provision <server> --force(orauthenticatewithforce: true).
License
MIT © Illia Grybkov
Available Tools
8 toolsauthenticateA
Authenticate a server by collecting and storing its required secrets in macOS Keychain. If the server has no auth schema, asks Claude to infer it. Uses MCP elicitation so secrets never enter the assistant's context. After storing, the server session is refreshed automatically. Set force=true to re-collect and overwrite secrets that are already stored (e.g. rotated or expired keys).
| Name | Required | Description | Default |
|---|---|---|---|
| force | No | Re-collect and overwrite already-stored secrets (e.g. expired keys). | |
| server | Yes | Server name to authenticate |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations to rely on, the description carries the full burden and does so admirably. It discloses that secrets are stored in macOS Keychain, never enter the assistant context via MCP elicitation, sessions auto-refresh, and force re-collects/overwrites existing secrets. These are meaningful behavioral traits beyond the bare action of 'authenticate'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four compact sentences, each adding distinct value: core purpose, inference behavior, secret-handling guarantee, and force semantics. It is front-loaded and free of fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with no output schema and no annotations, the description covers all essential call-time knowledge: what secrets are, where they are stored, how inference works, context safety, auto-refresh, and when to use force. An agent has enough to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents both parameters. The description adds a concrete example for force ('rotated or expired keys') but mostly repeats the schema's own description, so it does not significantly extend parameter understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Authenticate a server') and adds concrete resource details: collecting and storing required secrets in macOS Keychain, with a distinct mechanism (MCP elicitation) and a force flag for re-collection. This clearly differentiates it from siblings like auth_status, search, and call_tool, which serve different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear operational context: when to use force=true, how it handles missing auth schemas, and the fact that sessions refresh automatically. It does not explicitly name alternatives or state when not to use this tool, but the intended context is evident and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
auth_statusA
Show authentication status for one or all servers with auth schemas. Returns per-server status: authenticated, partial, or unauthenticated.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | If set, return status for this server only. Otherwise all servers. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must carry the behavioral burden. It states output values but does not explicitly say the tool has no side effects or that it does not trigger authentication. The word 'Show' implies read-only, and the three statuses are useful, but 'partial' is undefined and no side-effect guarantee is stated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence without filler. It states the verb, resource, scope, and output format in 18 words, making it easy for an agent to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity tool with one optional parameter, the description covers purpose, scope, and return values. Minor gaps remain—such as what 'partial' means and whether the tool modifies state—but these are not critical for an agent to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% because the only parameter, 'server', has a description ('If set, return status for this server only. Otherwise all servers.'). The tool description merely mirrors that behavior without adding new meaning, so a baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a clear verb ('Show') and a specific resource ('authentication status') with an explicit scope ('one or all servers'). It even enumerates the return states (authenticated, partial, unauthenticated), which fully differentiates it from siblings like authenticate (which modifies auth state) and list_servers (which lists servers).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly implies when to use the tool: whenever an agent needs to inspect which servers are already authenticated versus those that are not. It does not explicitly contrast with authenticate, but the verb 'Show' and the return-state list make the use case obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
call_toolA
Call a tool on a specific server. The server is spawned on first call. The tool must exist on the server — use get_server_tools to discover first.
| Name | Required | Description | Default |
|---|---|---|---|
| tool | Yes | Tool name | |
| server | Yes | Server name | |
| arguments | No | Tool arguments as a JSON object. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are minimal (just readOnly and destructive hints), but the description adds behavioral context: the server is spawned on first call, and the tool must exist (implying failure if not). It doesn't disclose other behaviors like authentication requirements or side effects, but the annotations likely provide basic safety info. The description adds value but not exhaustive detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, concise and front-loaded with the primary action. The second sentence provides important usage guidance without wasting words. It's efficient but could be slightly more structured with explicit 'when to use' formatting.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that it's a dynamic call tool with a nested object parameter, the description is decently complete. It mentions the need to discover tools, but does not describe return values or error handling. However, the lack of an output schema means it could do more, but the combination of schema and description is sufficient for an agent to proceed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented in the schema. The description adds little beyond that, such as the implication of the 'server' parameter being a server reference, but it doesn't add significant meaning beyond the schema. Hence, baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool calls a tool on a specific server, which is more specific than a generic 'call tool'. It also mentions the need for the tool to exist on the server, but doesn't explicitly differentiate from siblings like get_server_tools. Overall, it provides a clear verb and resource.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage guidance: use get_server_tools to discover tools before calling. It also implies that the server is spawned on first call, which is an important context. This is strong guidance for when to use this tool versus alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_server_toolsA
Get tools from a specific server. Lazily connects if not already connected. Use summary_only=true for cheap discovery (~100 tokens), then fetch full schemas for specific tools you plan to call.
| Name | Required | Description | Default |
|---|---|---|---|
| tools | No | If set, return full schemas only for the named tools. | |
| server | Yes | Server name | |
| summary_only | No | If true, return only tool names and descriptions (no input schemas). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral disclosure burden. It reveals an important behavior: lazy connection to the server if not already connected. It also adds a token-cost hint (~100 tokens), which goes beyond the schema. It does not detail auth requirements or error behavior, but the read-only nature of 'Get' is apparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler, front-loaded with the core purpose and key behavioral note. The second sentence earns its place by giving strategic invocation guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simple 3-parameter schema and no output schema, the description is largely complete: it covers purpose, lazy-connect behavior, and the optimal calling strategy. It could mention that server names likely come from list_servers or clarify auth prerequisites, but these are minor gaps for such a focused discovery tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema by explaining summary_only's purpose ('cheap discovery') and the workflow of fetching full schemas for specific tools. This adds real semantic value over the structured parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Get tools from a specific server.' It is clearly distinct from siblings like list_servers, call_tool, and search, so an agent can identify this as the tool-discovery operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives actionable usage guidance: use summary_only=true for cheap discovery, then fetch full schemas for specific tools. It does not explicitly contrast this tool with siblings, but the intended workflow is clear and appropriately scoped.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_serversA
List configured MCP servers with their descriptions and tags. Optionally filter by substring match on name/description/tags.
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No | Optional substring to filter on name, description, or tags. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It only states the function and does not mention whether the operation is read-only, requires authentication, returns paginated data, or has any side effects. For a tool that lists configuration, the agent is left without explicit safety or state-change context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The primary action is stated first, and the optional filter is added in the second sentence. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple list tool with one optional parameter, the description covers the core function but lacks context about return value shape (no output schema exists), whether authentication is needed, or whether this is a safe read-only operation. Given the absence of annotations, a complete description should at least hint at these aspects.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (filter is fully described as 'Optional substring to filter on name, description, or tags.'). The description essentially restates the parameter without adding extra semantics like default behavior, match case-sensitivity, or wildcard support. Baseline 3 is appropriate since the schema already does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List') and resource ('configured MCP servers'), and clarifies the fields returned (descriptions and tags). It clearly distinguishes this tool from siblings like 'search' or 'recommend_servers' by framing it as an enumeration of configured servers, not a search or recommendation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for listing servers and optionally filtering, but it does not explicitly state when to choose this tool over siblings (e.g., 'use search for semantic queries' or 'use get_server_tools to inspect a specific server'). There is no exclusion or conditional guidance, leaving some inference to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recommend_serversA
Given a natural-language task description, asks the host's LLM (via MCP sampling) to rank configured servers by relevance. Returns up to max_results recommendations with scores and rationale. Falls back to a raw catalog dump if the host doesn't support sampling. Use this when the user's request spans domains and you're not sure which server(s) to reach for.
| Name | Required | Description | Default |
|---|---|---|---|
| max_results | No | Max recommendations to return (default 5). | |
| task_description | Yes | Plain-English description of what the user wants to do. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full transparency burden. It discloses the sampling mechanism, the fallback behavior when sampling is unsupported, and the return structure (recommendations with scores and rationale). This provides good insight into how the tool behaves and its limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: the first defines the action, the second defines the output and fallback, the third gives usage guidance. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only recommendation tool with no output schema, the description covers the input, mechanism, output, fallback, and usage context. It doesn't detail error conditions or the shape of the fallback catalog, but these are minor given the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents both parameters (task_description and max_results) with clear descriptions, so the description adds no extra parameter context. It restates that the input is a natural-language task description without adding syntax or format details, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('recommend'), a resource (servers), and the input (a natural-language task description). It explains the mechanism (host LLM sampling) and output (ranked recommendations with scores and rationale), which clearly distinguishes it from siblings like search and list_servers that are direct retrieval operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use: when the user's request spans domains and you're unsure which server to use. It does not mention when not to use or name alternatives explicitly, but the use case is clear enough for an agent to decide without confusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reloadA
Reload mcp-hub: re-reads config files and reconciles the server set (added/removed/changed), tears down stale child connections, and drops cached tool schemas. Use after editing the hub's config, or after a child server's tools have changed (code edits, new tool registered). If server is given, only that server is reloaded (faster — no config re-read). For exposed servers, the catalog is re-enumerated and prompts/list_changed + resources/list_changed notifications are emitted so the host re-fetches. Tool schema changes on non-exposed servers are picked up on the next get_server_tools call. Caveat: if the hub started with no exposed servers, the prompts/resources capabilities aren't registered for the session — adding an exposed server via reload won't surface until the host reconnects.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | If set, only reload this server. Otherwise, reconcile all servers against config files. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses side effects: tears down stale child connections, drops cached tool schemas, re-enumerates catalog, emits notifications, and notes the caveat about capabilities not being registered if the hub started with no exposed servers. This is rich behavioral context beyond a simple 'reload' statement. It doesn't mention auth requirements or rate limits, but for a reload tool those are less critical.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but well-organized: main effect, use cases, parameter behavior, exposed-server behavior, and caveat. It's longer than the typical one-liner but every sentence adds information. The caveat is a bit long but valuable. Slight deduction for the caveat being somewhat verbose and the sentence about non-exposed servers being a bit dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one optional parameter and no output schema, the description covers the main action, side effects, when to use, parameter semantics, and edge cases. The caveat about exposed servers and host reconnection is exactly the kind of context an agent needs to avoid incorrect assumptions. Nothing critical is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter `server` is described in the schema. The description adds meaning by explaining the behavioral difference when `server` is set: only that server is reloaded, faster, no config re-read. This goes beyond the schema's 'only reload this server' and gives the agent a decision-relevant semantic.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('reload'), a resource ('mcp-hub'), and enumerates concrete effects: re-reads config files, reconciles the server set, tears down stale child connections, and drops cached tool schemas. It clearly distinguishes itself from siblings like list_servers or get_server_tools by describing the reconciliation and cache-dropping behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use: after editing the hub's config, or after a child server's tools have changed. It also gives the alternative path: if `server` is given, only that server is reloaded (faster, no config re-read). It even notes a caveat about exposed servers and host reconnection, which helps an agent decide when reload is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchA
Search all configured servers and their known tools for a keyword. Returns ranked hits across server metadata and tool descriptions. Only searches servers whose tools have been loaded via get_server_tools or call_tool — server-level metadata is always searched.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (default 20). | |
| query | Yes | Keywords (space-separated). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses the search scope, the dependency on previously loaded tools, and the ranking behavior. It does not explicitly state that this is a read-only operation, nor does it mention authentication or error behavior, but the semantics of a search imply safety.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences with no filler. It front-loads the core purpose, then adds the important scope limitation. Every sentence contributes meaningful information, making it concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with two well-documented parameters, but there is no output schema and no annotations. The description explains the search scope and result type at a high level, but it does not describe the structure of individual hits or how 'limit' affects pagination. For a simple search tool this is adequate, though not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the input schema already documents 'query' as 'Keywords (space-separated)' and 'limit' as 'Max results (default 20).' The description adds no additional meaning to the parameters beyond what the schema provides, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Search all configured servers and their known tools') and the result ('Returns ranked hits across server metadata and tool descriptions'). It clearly distinguishes this from sibling tools like list_servers or get_server_tools by describing the search scope and behavior, even without naming alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context: it searches all configured servers but only tool descriptions if tools were loaded via get_server_tools or call_tool, while server-level metadata is always searched. This implies when the tool is appropriate and includes an exclusion (servers with unloaded tools), though it doesn't explicitly compare against siblings like recommend_servers.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.1.0- First observed
auth_status - First observed
authenticate - First observed
call_tool - First observed
get_server_tools - First observed
list_servers - First observed
recommend_servers - First observed
reload - First observed
search
TDQS
Scored across 8 tools
Each tool targets a distinct action: discovery (search/recommend_servers/list_servers), tool introspection (get_server_tools), execution (call_tool), lifecycle (reload), and auth (authenticate/auth_status). While search, recommend_servers, and list_servers all support discovery, their input modes and outputs are clearly differentiated. No two tools appear to do the same thing.
Most tools follow a clear verb_noun pattern: recommend_servers, list_servers, get_server_tools, call_tool. Minor deviations exist: search, reload, and authenticate are bare verbs, and auth_status is a noun phrase rather than get_auth_status, but overall the names are predictable and readable.
Eight tools is a well-scoped size for an MCP hub, covering discovery, introspection, execution, reload, and authentication. Every tool addresses a distinct operational need with no redundant helpers or filler.
The tool surface covers the core hub lifecycle: discover servers, inspect tools, call tools, reload configuration, and manage authentication. Minor gaps exist, such as no explicit deauthentication/credential removal or direct server config editing, but these are reasonably handled via the host's config files and OS keychain.
Maintenance
Related MCP Connectors
The MCP server that finds MCP servers. Aggregates Official Registry, Glama, and Smithery.
Trust, freshness, policy, and discovery layer for public MCP servers.
The official MCP Server for the Mux API
Related MCP Servers
- AlicenseBqualityCmaintenanceA flexible proxy server that aggregates multiple backend MCP servers into a single interface using STDIO or SSE transports. It supports dynamic server management via an HTTP API and utilizes namespacing to prevent tool conflicts across connected services.31MIT
- AlicenseNot gradedqualityDmaintenanceA meta MCP server that orchestrates other MCP servers by lazily connecting to them and exposing their tools as JavaScript libraries. It allows users to execute JavaScript code that programmatically interacts with multiple MCP servers within a unified environment.12 npm1MIT
- AlicenseNot gradedqualityDmaintenanceMetaMCP is a MCP proxy that dynamically aggregates MCP servers into a unified endpoint, with middlewares and namespaces.2,662MIT
- AlicenseNot gradedqualityCmaintenanceUnifies multiple MCP servers behind a single endpoint with lazy loading, auto-cleanup, Python plugins, and role-based filtering.2MIT