7 min read

MCP tool name collisions and safer agent behavior

MCP tool name collisions cause confused agent behavior when similar actions hide different access. Learn naming, description, schema, and testing rules.

MCP tool name collisions and safer agent behavior

An agent does not read an MCP tool catalog like a careful engineer reads an SDK. It routes from a compressed instruction to a likely action. If you give it get_user, get_users, user_lookup, and admin_get_user, then rely on a paragraph of caveats to separate them, you have designed a guessing game around authority.

MCP tool name collisions are not only duplicate identifiers that make a client reject a catalog. The worse collision is semantic: two callable actions sound interchangeable, but one reaches a broader system, carries a stronger credential, or changes state. I have seen teams call this a prompting issue after an agent picks the wrong action. Most of the time, it is an interface issue they shipped themselves.

The cure is not a giant taxonomy or a ceremonial naming committee. Give every action a name that says what it does, where it does it, and how far its authority reaches. Then write descriptions that define the boundary the name cannot carry. Make ambiguity visible in tests before it becomes an approval card, an unexpected API call, or a messy incident review.

A collision is semantic before it is syntactic

A syntactic collision occurs when two MCP servers both publish a tool called search. Depending on the client, that may overwrite one entry, force a namespace, or produce a confusing catalog. You should fix it because behavior may vary between clients.

A semantic collision survives even when every identifier is technically unique. Consider these tools:

search_customer
search_customer_records
lookup_customer
customer_admin_search

All four may appear valid to a compiler and understandable to the team that built them. To an agent asked, "Find the customer record for Maya Chen and update her address," they give weak routing signals. The agent must infer which system owns the truth, whether the action is read-only, whether it can search a whole tenant, and whether an administrative credential is acceptable.

Tool schemas do not rescue a vague catalog. A model may inspect argument names, but similar schemas often make the ambiguity worse. Both a read-only directory search and a production CRM search may accept query, limit, and organization_id. The fact that one returns data and the other can trigger enrichment or write an audit event may live only in a description that the model weighs less heavily than the apparent task match.

Treat these as different defects:

  • Identifier collision: the client cannot present two tools consistently.
  • Intent collision: two tools appear to satisfy the same user request.
  • Authority collision: a broad credential sits behind a tool that sounds like a narrow one.
  • Environment collision: similar labels conceal different accounts, regions, or production status.

The last three cause the expensive mistakes. A client can reject duplicate names. It cannot reliably tell you that sync_contact means "patch a production CRM record using an organization-wide token" while update_contact means "write to a local test fixture."

Tool names must carry the routing facts

A useful name gives the agent the facts needed to choose before it reads a long description. For actions that touch external systems, I use this order: target system, object, verb, then scope when scope changes authority or consequence.

crm_contact_update is better than update_contact because it identifies the system. crm_production_contact_update may be better still if the same catalog includes a sandbox. github_org_member_remove is clearer than manage_member because it says which resource changes and that the outcome is removal.

Do not stuff every implementation detail into the name. Agents do not need crm_v3_contacts_patch_with_bearer_auth. They need distinctions that change selection. Versioning, transport, and authentication usually belong in the server implementation or description. Account, environment, side effect, and privilege boundary often belong in the name.

A practical pattern looks like this:

<system>_<object>_<verb>[_<scope>]

Examples:

billing_invoice_get
billing_invoice_send_customer
billing_production_refund_create
source_control_repo_issue_list
source_control_org_member_remove
warehouse_inventory_adjust
warehouse_inventory_adjust_dry_run

The pattern is not sacred. What matters is that neighboring names differ at the point where their effect differs. If billing_invoice_send_customer and billing_invoice_preview_email sit next to each other, the verbs and objects tell the model which one actually contacts a person. If the only difference appears in a boolean parameter buried in a schema, the catalog asks too much of routing.

Avoid vague verbs such as process, manage, handle, run, execute, sync, and apply unless the object itself makes the effect unambiguous. They are popular because product teams use them as umbrellas for several operations. That is exactly why they are poor tool names. A model treats an umbrella as permission to choose the broadest interpretation that completes the request.

Descriptions define the boundary, not the marketing

The Model Context Protocol tool specification defines a tool with a name, description, and input schema. That is an interface contract, not a place for product copy. The description should answer four operational questions: what action occurs, what external target receives it, what scope applies, and what the tool refuses to do.

Compare these two descriptions:

{
  "name": "crm_contact_update",
  "description": "Updates customer contact information in the CRM.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "contact_id": {"type": "string"},
      "address": {"type": "string"}
    },
    "required": ["contact_id"]
  }
}
{
  "name": "crm_production_contact_update",
  "description": "Changes address, phone, or email fields for one existing contact in the production CRM. This writes immediately. Use crm_contact_search first when the caller supplies a name rather than a contact ID. It cannot create contacts, merge records, or update more than one contact per call.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "contact_id": {
        "type": "string",
        "description": "Stable production CRM contact ID, not an email address or display name."
      },
      "changes": {
        "type": "object",
        "properties": {
          "address": {"type": "string"},
          "phone": {"type": "string"},
          "email": {"type": "string"}
        },
        "minProperties": 1,
        "additionalProperties": false
      }
    },
    "required": ["contact_id", "changes"],
    "additionalProperties": false
  }
}

The second description gives the agent a sequence, names the consequence, and rules out tempting substitutions. It also places the disambiguating details close to the action rather than burying them in a separate operations manual the agent may never see.

Be blunt about side effects. Write "sends email immediately," "creates a charge," "deletes the remote branch," or "writes to production." Do not write "persists changes" or "performs the requested operation." Those phrases let a reviewer sound precise while hiding the only thing an agent and a human need to notice.

Input field descriptions matter for the same reason. If a field accepts a resource ID, say that a display name is invalid. If a date defaults to UTC, say so. Loose schemas with optional strings shift meaning into prose and let an agent improvise arguments that happen to parse.

Broad access must never look like a convenient fallback

The most dangerous catalog contains a narrow tool and a broader tool that both appear to solve the same request. The broad one often exists for good reasons: an administrator needs emergency access, a migration needs cross-account search, or a support workflow needs an override. The mistake is exposing it as a peer with a friendly name.

Imagine these entries:

support_ticket_get
support_ticket_update
support_admin_query

An agent wants context for a ticket. support_admin_query may search tickets, users, billing history, internal notes, and deleted records. If its description begins with "Query the support platform," the agent can select it because its broad coverage looks useful. The tool did what you named it to do. The design failed before the call.

Rename and constrain it:

support_internal_cross_account_search

Its description should state that it searches internal support data across accounts, returns material outside the ticket record, and requires an explicit instruction naming the account boundary. If the workflow permits it, require an account ID in the schema rather than accepting a free-text query alone.

I argue against the usual recommendation to expose one "power tool" for flexibility. It is popular because it reduces server code and lets experienced operators do more with fewer calls. For an autonomous agent, it erases the distinction between ordinary work and exceptional authority. Make separate tools for materially different authority. More catalog entries are cheaper than explaining why a broad search disclosed the wrong customer history.

This applies to environments too. Do not offer deploy with an environment argument that defaults to production. Use separate action names when a wrong value has a different blast radius:

release_staging_deploy
release_production_deploy

A schema enum still helps, but distinct names make production visible in the selection phase, the approval phase, and later in the audit record.

Parameters cannot carry all the safety meaning

Put a gateway behind MCP
Route MCP-capable agents through sp mcp while Sallyport performs the actual HTTP or SSH action.

A parameter changes an action after the agent has chosen the tool. A name and description affect the choice itself. Teams blur those jobs when they build one universal tool with a large argument object.

This design looks compact:

{
  "name": "repository_action",
  "description": "Performs repository operations.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "operation": {"enum": ["read_file", "create_branch", "delete_branch", "open_pull_request"]},
      "repository": {"type": "string"},
      "branch": {"type": "string"}
    },
    "required": ["operation", "repository"]
  }
}

It also puts a read operation, a write operation, and a destructive operation behind the same routing label. An agent that chose repository_action has already crossed the meaningful boundary. A reviewer sees an approval for an opaque umbrella action and must inspect arguments under time pressure.

Split it where the action changes class:

repository_file_read
repository_branch_create
repository_branch_delete
repository_pull_request_create

Keep parameters for facts that vary within one action: repository ID, branch name, file path, commit message, or a page cursor. Do not make a parameter choose whether the call reads, writes, sends, charges, deletes, or reaches production.

The same rule applies to scope. report_export with scope: all_accounts turns a harmless-looking export into a cross-account extraction. If scope alters who can be affected or what data can leave, give that scope its own tool or require a stronger authorization path. The agent should not discover the authority difference only after it has filled a JSON field.

Tool selection needs an ambiguity test suite

You cannot inspect a catalog once and declare it understandable. Test it with the requests users actually make, especially the incomplete requests that force an agent to infer scope.

Build a small selection suite for each server. You can run it manually with the agent client you support, or feed the catalog and prompts into a controlled evaluation harness. Record the selected tool, the proposed arguments, and whether a human would accept the call. Do not score only whether the task eventually succeeded. A broad tool that returns a correct answer is still a wrong selection when a narrower one existed.

Use prompts such as these:

  1. "Find the invoice for order 1842." The expected choice should be a read-only billing lookup, not a general ledger search.
  2. "Update Priya's phone number." The agent should ask which Priya if a stable contact ID is absent, rather than search and modify a likely match.
  3. "Deploy the fix." The agent should ask for environment when the catalog includes staging and production actions.
  4. "Remove Alex from the repository." The agent should distinguish repository membership from organization membership.
  5. "Send the invoice." The agent should select a send action, not a preview generator or a generic invoice update call.

Add adversarial wording that resembles the bad tool's description. If internal_cross_account_search wins when a prompt says "find everything we have on this customer," your description may be technically honest but still too inviting. The correct behavior may be to choose a scoped search or ask the user to identify an account.

Keep the test transcript when you rename tools. It exposes regressions that a schema validator cannot catch. A catalog can remain valid while an innocent rename turns billing_invoice_get into get_invoice, where it competes with purchase, logistics, and legal systems.

Approval screens should repeat the action in plain language

Avoid another rules engine
Use one fixed decision ladder instead of trying to encode every ambiguous tool boundary in policy rules.

A human approval is a last checkpoint, not permission to make tool labels sloppy. If the approval presents only a low-level request such as POST /v1/contacts/123, the person approving must reconstruct intent from an endpoint and payload. That is a poor place to notice that the agent selected production CRM instead of a sandbox.

Carry the same business meaning through every layer. The tool name says crm_production_contact_update. The description says it writes immediately to one existing production record. The approval should say that the agent wants to change a named field on one production contact, identify the target account when available, and show the proposed changed values. The audit event should retain the tool identity plus the actual executed channel and target.

Do not make the approval wording more reassuring than the action. "Allow CRM update" conceals the difference between correcting a phone number and replacing an email address used for account recovery. Show the meaningful arguments, with secrets removed. If an argument contains sensitive customer data, display enough structure for review while respecting your data handling rules.

Sallyport's per-session authorization can establish that a particular agent process may act during its run, while per-call keys can require a separate approval for credentials that deserve scrutiny on every use. That division works best when the action labels give the person approving an immediate, accurate account of what the agent is requesting.

Credentials and tool identity solve different problems

Keeping credentials out of an agent prevents a common failure: the agent cannot copy an API key into a log, source file, issue, or chat reply because it never receives the secret. That control does not make every request safe. The agent can still ask a gateway to execute the wrong tool with a legitimate credential.

Separate these questions during design:

  • Can the agent obtain or expose the credential?
  • Can the agent request an action outside the user's intended scope?
  • Can a human see which process requested the action?
  • Can an investigator verify what happened after the run?

A tool catalog addresses the second question. Session identity and approvals address the third. A tamper-evident record addresses the fourth. Each layer has a job, and none substitutes for another.

Sallyport keeps HTTP and SSH credentials in its encrypted vault and executes the action without handing those secrets to the agent. That reduces credential exposure, but the agent still needs a catalog whose names prevent it from asking a broader action merely because the name sounded close enough.

This distinction matters when teams say, "The agent cannot see the token, so the tool is safe." The token may be protected while the action is still overpowered. A read-only reporting credential and a production refund credential should not sit behind nearly identical entries just because both are isolated from the model.

Namespaces help operators but do not excuse vague actions

Keep credentials out of routing
Keep API and SSH credentials in Sallyport's encrypted vault, not behind similarly named agent tools.

Many clients display tools with a server-derived prefix, such as crm.search_contacts or billing.search_contacts. Use a namespace when your client supports it. It gives the agent and the operator one more routing clue, and it reduces literal duplicate names.

Do not depend on it as the only clue. Clients can shorten labels, flatten server catalogs, or show server names that mean little to a person reading an approval. A tool called search_contacts remains vague if one server reaches a test database and another reaches live customer data.

A better pair is:

crm_production_contact_search
marketing_audience_contact_search

These names remain intelligible after a client adds or removes a prefix. They also make mixed catalogs safer when an agent connects to more servers over time.

Use server boundaries to group related authority, not to hide it. A server called operations that exposes billing refunds, production deployment, customer export, and personnel changes may be convenient for the team that owns it. It produces a crowded catalog with unrelated verbs and a wide credential surface. Split servers when separate domains have separate owners, credentials, approval expectations, or review paths.

A catalog review catches the failures before deployment

Review a tool catalog beside a list of natural-language tasks, not in isolation. A name that feels obvious to its author often relies on context that disappears when thirty tools from six servers appear in one agent session.

Use this short review before you ship a new action:

  1. Read the name alone. Can a person tell the external system, object, side effect, and unusual scope?
  2. Put it next to every similar tool. Does one name describe broader access with a softer verb?
  3. Remove the description mentally. Does the schema hide a read versus write, sandbox versus production, or single-record versus cross-account choice in an argument?
  4. Ask an ambiguous user request. Should the agent ask a clarifying question, and have you made that safer than guessing?
  5. Check the approval and audit labels. Do they preserve the same distinction as the tool name?

The right answer is often to reject a request for a convenient catch-all action. That refusal frustrates someone once, during implementation. An ambiguous tool frustrates the people who must investigate the unexpected call later, when the context has already vanished.

Keep the name specific, write the boundary plainly, and make broad authority hard to select by accident. An agent does not need more plausible choices. It needs fewer ways to mistake one permission for another.

FAQ

Are MCP tool names globally unique across servers?

No. The protocol allows a server to publish tools, but it does not make names globally unique across every connected server. The client presents an available tool set to the model, and the model must distinguish similar entries from their names, descriptions, schemas, and whatever context the client preserves.

Is it safe to use generic MCP tool names such as get_user?

A name like get_user is acceptable only inside a small, tightly scoped set of read-only tools. Once another tool can search external identities, edit records, or call an administrative API, the generic name stops carrying enough information for safe selection. Include the object, system, operation, and access boundary instead.

Should I fix a collision by renaming the tool or improving its description?

Usually, rename the tool rather than writing a longer description. Models often use the tool name as the first routing signal, especially when a prompt asks for an action in a few words. A precise description still matters because it tells the model what the tool will and will not do.

Do server prefixes solve MCP tool name collisions?

No. A server prefix helps operators, but it can become meaningless to an agent if the client removes it, abbreviates it, or presents dozens of similarly prefixed tools. Put the important distinction in the action name and description, then treat the server identity as supporting context.

Should read-only and write-capable MCP actions be separate tools?

Separate them when they differ in authority, side effects, or target scope. A single tool with a mode parameter forces the agent to infer the safety meaning of a value such as dry_run, apply, or admin. Separate names make the decision visible before the model fills arguments.

How should I expose staging and production tools to an agent?

Do not expose both as ordinary choices if they point at the same destination with different authority. Give the low-authority path a distinct name and description, and require an explicit authorization boundary for the broader path. Similar labels invite the model to treat the broader credential as a convenient substitute.

How do I test whether an agent will choose the right MCP tool?

Use a fixed test corpus of ambiguous natural-language requests and record the selected tool, arguments, and result. Include names that sound alike, requests with missing scope, and requests where a broad tool could technically complete the task. Review wrong selections as interface defects, not merely model mistakes.

What makes an MCP tool name dangerous?

A dangerous tool needs a name that states the side effect, target system, and scope of authority. github_org_remove_member communicates far more than manage_member, even before the description explains the irreversible consequence. Do not hide broad access behind a harmless verb such as sync or update.

Should MCP tool names match approval and audit labels?

Use the same action vocabulary in the tool name, description, approval prompt, and audit record. If an agent calls crm_contacts_search but the approval says only POST /query, a human cannot reliably catch a routing mistake. The interface should retain the business meaning through execution and review.

Can credential isolation alone prevent confused agent actions?

Yes. A gateway can keep credentials out of the agent while still receiving a poorly selected action request. Credential isolation limits what the agent can exfiltrate, but clear tool boundaries and human authorization limit what it can ask the gateway to do.

Sallyport

Sallyport runs API calls and SSH commands for your AI agent. The keys stay in a local vault on your Mac; you approve each run and every action lands in a sealed journal.

© 2026 Sallyport · Open source under Apache-2.0 · Oleg Sotnikov