ax-check rule

AXC-D014: Duplicate name

Two entries share the same name or operationId, so a call by name is ambiguous.

ax-check is a checker being prepared for release. This page documents the rule ahead of that release; see all 50 rules.

Severityerror
KindConformance. A finding is a fact about the input.
Modeax-check lint
Applies toMCP tool lists, OpenAPI, SKILL.md, CLI help
Pattern tagsselection, discovery
Fix in one lineGive every tool, operation, command or skill a unique, stable name.

Two entries on the same surface share a name, so a call by that name is ambiguous. An agent picks a tool, operation, command or skill by its name, and the client routes the call by the same name. When two entries share it, at least one of them can never be reached reliably.

What it checks

Within one surface, ax-check compares the names of all selectable entries:

  • MCP: the name of each tool in a tools/list result.
  • OpenAPI: the operationId of each operation.
  • Agent Skills: the name in each SKILL.md frontmatter.
  • CLI help: the subcommand names listed in the root --help output.

Any name used by more than one entry is reported.

Why it matters

The name is the handle for everything else. A client looks a tool up by name, an agent writes the name into its call, and instructions files and skills mention it by name. If two tools are both called search_orders, the client may keep the first, keep the last or reject the list, and the agent cannot tell which description belongs to the tool it will actually reach.

The specifications treat names as identifiers. The OpenAPI 3.1 specification says an operationId “MUST be unique among all operations described in the API”. The MCP specification says tool names are case-sensitive. The Agent Skills specification requires a skill’s name to match its parent folder, which keeps names unique inside one skills folder.

How to fix

  • Give every tool, operation, command or skill a unique, stable name.
  • When two entries do similar jobs, name the difference (for example search_orders and search_archived_orders) and say in each description when to use the other.
  • If you rename an entry, update the instructions, skills and manifests that refer to the old name.

Example

Before

{
  "tools": [
    { "name": "search_orders", "description": "Search open orders by customer email. Use this when a customer asks about a current order." },
    { "name": "search_orders", "description": "Search orders closed more than 90 days ago. Use this for refund history questions." }
  ]
}

After

{
  "tools": [
    { "name": "search_orders", "description": "Search open orders by customer email. Use this when a customer asks about a current order. For orders closed more than 90 days ago, use search_archived_orders instead." },
    { "name": "search_archived_orders", "description": "Search orders closed more than 90 days ago. Use this for refund history questions. For current orders, use search_orders instead." }
  ]
}

How ax-check detects it

ax-check groups the entries by exact name. The comparison is case-sensitive and does no trimming or normalising, so getUser and getuser count as different names. It reports one finding for the second and each later entry that reuses a name, and the finding lists the location of every entry with that name.

Details per surface:

  • OpenAPI operations with no operationId are named after their method and path (for example GET /orders), so they never collide with each other.
  • A skill with no frontmatter name is named after its folder or file path for this check.
  • For CLI help, the help subcommand and command aliases are ignored. A command listed under two headings of the same help text (for example “Common commands” and “All commands”) is read once, from its first listing, so it is not reported.

Known false negatives: names that differ only in case or punctuation are not reported, although they can still confuse an agent.

If the finding does not apply, silence it with --disable AXC-D014.

Sources

Records in the AX evidence register that share a pattern tag with this rule. A shared tag means the record is about the same pattern, not that it tests this rule. Read the evidence class before the number.

  • EV-0019: Skill selection precision collapses as the skill pool grows (Preprint). A preprint reports that as the pool of available skills grew from 5 to 100, the precision with which agents actually used the right skill fell from 29.6% to 3.3%.
  • EV-0013: FAQ blocks and structured data showed no citation effect within a domain (Preprint). An observational study of about 2 million AI-engine citations (preprint) found that FAQ blocks, structured data and Core Web Vitals had positive effects on citation in pooled data that reversed or fell to zero once domain fixed effects were applied.
  • EV-0020: Praise and list order move tool selection (Preprint). A preregistered preprint with two small OpenAI models found that stacked praise in a tool description raised its pick rate by about 43 percentage points, and that with identical listings the first-listed tool was picked about 72 points more often.
  • EV-0021: Agents leave available tools unused: the adoption gap (Preprint). On OSWorld-MCP (preprint), a reasoning model given MCP tools called one on only 55 of 309 tasks, 23.9% of the tasks a tool could reach, and the same tools made a non-reasoning model 5.9 points worse.
  • EV-0023: Hiding tools is not enforcing permissions (Preprint). Across 2,160 attempts with four frontier models (preprint), a server with only in-body permission checks exposed forbidden tools in 152 of 720 trials and permission-aware visibility cut that to 0 of 720, yet models named a hidden tool in up to 94% of settings when it was inferable from the prompt.
  • EV-0027: A capable agent skipped the index and guessed the page (Preprint). A preregistered ablation on a 709-page Markdown wiki (preprint) found that a capable tool-using agent never loaded the compact catalogue index, inferring page paths from the question instead, while retrieval-based access kept answer quality non-inferior and cut cost by about a third to over half.