Namespace MCP tools at the point where several upstream servers become one tool surface. The namespace should identify the source before the action, keep names stable for logs and policy, and avoid collisions such as three different tools called search. Treat the namespace as an execution boundary, not just a naming convention.
The Collision To Prevent
MCP tool names are unique inside one server, not across every server an agent might use. The tools specification says clients discover tools with tools/list, then call one by sending tools/call with the selected name and arguments. It also warns that clients or proxies aggregating multiple servers can encounter collisions, such as two upstreams each exposing search, and should implement a disambiguation strategy such as prefixing names with a server identifier.
That means namespacing belongs in the aggregation layer, before the model has to choose among ambiguous verbs. A raw list containing search, search, fetch and fetch forces the model to read descriptions to infer where each call goes. A list containing github.search_code, linear.search_issues, drive.fetch_file and stripe.fetch_invoice gives the model, log pipeline and permission engine the same first branch: source, then action.
The namespace is not cosmetic. It becomes the join key between tool discovery, approvals, audit events, source health and access policy. If the same upstream tool is later renamed by a vendor, you can keep a stable local namespace while changing the upstream mapping behind it. If a team connects two GitHub organizations or two Postgres databases, the namespace is what keeps production and sandbox calls from looking interchangeable.
Choose The Source Boundary First
Start with source ids, not delimiters. A source id should match the thing a human would grant, revoke, troubleshoot or explain: github_app, linear_product, stripe_billing, postgres_reporting or drive_board_docs. Do not use vague prefixes such as api, server1 or tools. They may be unique in code, but they do not help an agent understand which system it is about to touch.
Once the source id is clear, pick a delimiter that works in your clients. The MCP spec recommends names use ASCII letters, digits, underscore, hyphen and dot, and avoid spaces and special characters. For literal MCP tool names, source.tool or source_tool tends to be more interoperable than a decorative separator. Keep the action part close to the upstream operation, but remove vendor-local ambiguity. linear.search_issues is better than linear.search; github.search_code is better than github.search.
Do not encode authorization in the name. Names like readonly_stripe_list_invoices age poorly because permissions can change per key. Put stable identity in the name, then enforce read and write policy outside the name. If you need to expose both safe and committing operations, use distinct actions such as stripe.preview_invoice_change and stripe.apply_invoice_change. The sibling guide on read-only versus write tools covers the policy side; namespacing gives that policy a clean source field to evaluate.
Keep The Protocol Shape Boring
A namespace does not require a new protocol. The client can still ask one MCP server for tools and call one tool by name. The aggregation layer changes the names it returns and keeps a routing table behind them:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "linear.search_issues",
"description": "Search Linear issues in the product workspace by text, label, assignee or status.",
"inputSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"query": { "type": "string" },
"limit": { "type": "integer", "minimum": 1, "maximum": 50 }
},
"required": ["query"]
}
},
{
"name": "github.search_code",
"description": "Search repository code and file paths; do not use for issue triage.",
"inputSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"query": { "type": "string" },
"repo": { "type": "string" }
},
"required": ["query"]
}
}
]
}
}The call path stays ordinary:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "linear.search_issues",
"arguments": {
"query": "label:bug status:triage auth redirect",
"limit": 10
}
}
}Internally, store source and tool as separate fields even if the model sees one combined name. That avoids brittle string parsing in policy code and makes logs easier to query. A good route record has publicName, sourceId, upstreamServerId, upstreamToolName, schemaVersion and risk. The public name is for discovery. The separated fields are for enforcement.
Wire Clients To One Surface
Namespacing pays off when the client configuration is small. Claude Code can add a remote HTTP MCP server with claude mcp add --transport http, including an authorization header. A single workspace endpoint looks like this:
claude mcp add --transport http workspace-tools https://api.example.com/mcp \
--header "Authorization: Bearer $WORKSPACE_MCP_KEY"Cursor's manual setup uses .cursor/mcp.json for a project or ~/.cursor/mcp.json globally. A remote server can be configured with a url, and headers can carry the token:
{
"mcpServers": {
"workspace-tools": {
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer ${WORKSPACE_MCP_KEY}"
}
}
}
}VS Code supports MCP configuration in several locations, including workspace .vscode/mcp.json with a top-level servers object and portable root .mcp.json with mcpServers. The VS Code workspace shape for one remote endpoint is:
{
"servers": {
"workspace-tools": {
"type": "http",
"url": "https://api.example.com/mcp"
}
}
}The important property is that none of these files lists every upstream system. The client knows one MCP server. The names returned by that server tell the agent whether a call will reach GitHub, Linear, Drive, Stripe or a generated database connector. That is the same architectural move described in MCP gateway design, but namespacing is the part the model sees on every tool choice.
Use Names In Logs And Policy
Every proxied call should produce an event that preserves both the public namespace and the resolved upstream identity. A useful record is more specific than tool called:
{
"callerKey": "key_123",
"sourceId": "linear_product",
"publicTool": "linear.search_issues",
"upstreamTool": "search_issues",
"permission": "call:tools",
"readOnlyHint": true,
"durationMs": 412,
"status": "ok"
}That shape lets security review ask source-level questions without reconstructing them from prose: which keys called Stripe, which tools wrote to GitHub, which source produced timeouts, and which tool names changed after an upstream upgrade. It also supports clearer errors. If a key can see stripe_billing but lacks write permission, the gateway can report that the source exists and the committing tool is withheld. Hiding the source entirely teaches the model an inaccurate map of the workspace.
Namespacing also helps with failure isolation. If github.search_code is unreachable, do not remove github.* from the tool list and leave the agent guessing. Mark the source unreachable, keep the route visible where appropriate, and fail calls with a source-specific error. The related article on surfacing upstream failures goes deeper on that behavior. The namespace is how the user, agent and operator agree which upstream is in trouble.
How SPYN3 handles the boundary
SPYN3 names every federated tool <source>/<tool>, where the source is the connector's label in lower case, so two upstreams can both offer search. Some clients rewrite the separator. Claude Code, in our test, showed deepwiki/ask_wiki_question as mcp__spyn3__deepwiki_ask_wiki_question. So when you write prompts or review logs, refer to tools by source and tool name, not by the client's rewritten form.
A Rollout Checklist
- Inventory every upstream MCP server and generated connector that will share one client surface.
- Assign stable source ids that match operational ownership, not temporary server names.
- Pick one literal naming convention, such as
source.tool, and reserve the source part for routing. - Rename generic actions to include the resource, for example
search_issues,search_codeorfetch_invoice. - Store source id, public tool name and upstream tool name as separate fields in route tables and logs.
- Test duplicate upstream names by connecting two servers that both expose
searchand confirming the model sees distinct choices. - Test permission mismatch, unreachable upstreams and client sessions that do not refresh
tools/listafter startup.
The last test is the one that catches most paper designs. A namespace is successful when a fresh agent can choose the right source, an operator can read the log without guessing, and a policy rule can deny the wrong source before any upstream credential is used.
Built for the next step
Make every tool show its source
Use source namespaces so agents and logs keep upstream identity intact.
Source foldersSPYN3 is a consolidated MCP layer: one hosted endpoint in front of every system you connect — MCP servers, Postgres, REST APIs, Google Drive — with tools foldered by source and read/write permissions per key. Switching agents means moving one URL. Free plan available; current capabilities are documented on the product facts page.
Sources
- MCP specification: tools — tool discovery, invocation and security considerations. Verified 14 Oct 2026
- Anthropic: writing effective tools for agents — namespacing, response design and tool evaluations. Verified 14 Oct 2026
- Anthropic docs: Claude Code MCP setup — Claude Code MCP commands, scopes, transports and JSON configuration. Verified 14 Oct 2026
- VS Code documentation: add and manage MCP servers — VS Code MCP configuration, trust and logging behavior. Verified 14 Oct 2026
- Cursor documentation: MCP integrations — Cursor MCP configuration locations, remote URL entries, headers and approval behavior. Verified 14 Oct 2026
