Repository navigation
feat(skills-audit): flag hardcoded MCP tool names whose server is installed under another prefix - #801
Conversation
…talled under another prefix (#758) Invoke-SkillAudit gains an mcp-tool-name finding: a skill that writes mcp__<server>__<tool> while the agent has that server as mcp__plugin_<plugin>_<server>__ (or the reverse) gets the working name and the server-agnostic wording to use instead. Get-McpServerNames.ps1 lists the real prefixes from ~/.claude.json, the project's .mcp.json and enabled plugins' manifests. Pester tests run on fixtures only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… settings and manifest shapes (#758) Review round 1: pick the newest install by DateTime (not its MM/dd/yyyy text), count project/local installs only in their project, merge enabledPlugins user < project < local, resolve -Root against the PowerShell location, read array-valued plugin.json mcpServers, and normalize names the way Claude Code builds tool names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… servers that are not loaded (#758) Review round 2: read config -AsHashtable (a case-variant project key used to drop all of ~/.claude.json), apply disabledMcpServers and .mcp.json approval, and skip a plugin skill's reference to its own plugin prefix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t already give the working name (#758) Review round 3: a discovery error now warns and skips only the mcp-tool-name check; a skill listing both install forms is not flagged; the self-reference test carries a control so it cannot pass vacuously. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r-only references, harden tests (#758) Review round 4: discovered records keep their server name instead of a lossy re-split; a referenced plugin prefix is split on the known server names; the bare mcp__<server> form of allowed-tools is checked. Tests now drive the audit's own discovery through a stub, prove an empty -McpServers never falls back to it, cover the wrapped .mcp.json shape and assert no local path reaches a finding detail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review (sha 1f06ff3) — check En general está bien: es solo lectura, no expone valores de config (solo nombres de servidores), degrada con
Tests: la cobertura nueva ( |
…enabledPlugins true and honors CLAUDE_CONFIG_DIR (#758) Review round 5: tools under one hardcoded prefix fold into one finding; a skill giving the working prefix in any form is not flagged; working prefixes are de-duplicated. Discovery counts only plugins enabledPlugins sets to true, reads CLAUDE_CONFIG_DIR, and a stale plugin entry costs that plugin only. Tests: positive controls for every negative case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Sin hallazgos bloqueantes. Revisé
|
…if the MCP check ran (#758) Review round 6: a plugin prefix is split only at the kebab-case boundary (a suffix guess reported servers that are not installed); markdown beside SKILL.md is scanned; summary.mcpCheck = ran | no-servers | discovery-failed; the remediation covers literal allowed-tools lists; enableAllProjectMcpServers follows the most specific level. Tests pin CLAUDE_CONFIG_DIR plugins/settings and no longer touch C:/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review (sha 0ffda07) Sin hallazgos bloqueantes. El check Observaciones menores, no bloqueantes:
|
…e docs, rank the project entry as local (#758) Review round 7: the prefix no longer absorbs the __ separator, so mcp__srv__<tool> is flagged; README/CHANGELOG/CONTRIBUTING/LICENSE beside SKILL.md are not scanned; mcpCheck is initialized; the ~/.claude.json project entry ranks after the settings files for .mcp.json approval. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Revisé el diff (Get-McpServerNames.ps1, el check |
…e config errors fail loudly (#758) Review round 8: prefixes compare with exact case; mcp__srv, mcp__srv__ and mcp__srv__* are one name; partial wildcards keep their star; mcp__ needs a word boundary; repo docs beside SKILL.md are skipped; the own plugin name is also read from a source tree's manifest. Discovery throws when a core config file is unreadable instead of returning a partial set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review (sha a7fd0f5): sin hallazgos bloqueantes. La lógica de descubrimiento y de detección ( Notas menores, no bloqueantes:
|
…exact-case refs; placeholder covers plugin forms (#758) Review round 9: a plugin skill's own prefix is skipped only when none of that plugin's servers are loaded; refs use an ordinal dictionary; a mcp__plugin_<plugin>_srv placeholder counts as documenting the plugin install; a source-tree manifest name replaces the folder name. Tests add controls for these and the inline plugin.json mcpServers shape. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Sin hallazgos bloqueantes. Revisé el diff leyéndolo, sin ejecutar los Pester (el entorno no me dejó correr
Nit, no bloqueante: |
…le detail (#758) Review round 10: the detail describes a plugin-provided alternative by its form only; the exact working names go to a local-only 'working' field, like paths. A case-only spelling no longer excuses a wrong-case name, and the plugin-form placeholder reads server keys holding _. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Revisé el diff (
|
…plugin refs; case tests compare exactly (#758) Review round 11: the plugin form and the operation text use the installed server's spelling, so a wrong-case reference gets the right case in the fileable detail too; a plugin-form placeholder also excuses a plugin reference whose alternatives are all plugin forms. Tests use exact-case assertions, add a positive control for the placeholder case and check that no plugin name leaks into a detail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Sin hallazgos bloqueantes. Revisé Nota menor, no bloqueante: |
…records and native projectPath covered (#758) Review round 12 (tests): the plugin-name leak check compares against what each fixture skill wrote, not against backtick formatting; record server/plugin fields are asserted (normalized names, a plugin name with _); a backslash, other-drive-case projectPath still matches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
External review - claude-review (Claude API, clean context)Reviewed commit: 12 rounds with claude-review (Claude API, Opus 5.5, xhigh, clean context; same model family as the implementer, an independent context, not another vendor). R1-4 on the whole diff, R5-12 per file with tests separate. Every finding verified in the source; about 45 fixed with tests, and 6 rejected with a reason: inventory paths are already forward-slash; existing fixtures have no mcp refs; strict:false marketplace mcpServers are out of scope; the local-plugin-names finding was rejected 3 times, then adopted in R10 (local-only 'working' field). Final state: Get-McpServerNames reviewed clean in R9 and unchanged since. The tests file was 'patch is correct' in R12, and its 3 findings are fixed in da0e962. Invoke-SkillAudit.ps1 was last reviewed in full in R11; its R11 fixes (installed server spelling, placeholder covers plugin refs) were NOT re-reviewed by the API, because R12 hit max_tokens twice (mechanical; stopped per coordinator rule). They are covered by new exact-case tests. 54 fixture tests in SkillAudit.McpToolNames.Tests.ps1; 62 green with Invoke-SkillAudit.Tests.ps1. |
|
Revisión del diff ( Observaciones menores, no bloqueantes:
|
…nux runner can (#758) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
External review - claude-review (Claude API, clean context)Reviewed commit: 12 rounds with claude-review (Claude API, Opus 5.5, xhigh, clean context; same model family as the implementer, an independent context, not another vendor). R1-4 on the whole diff, R5-12 per file with tests separate. Every finding verified in the source; about 45 fixed with tests, and 6 rejected with a reason (inventory paths are already forward-slash; existing fixtures have no mcp refs; strict:false marketplace mcpServers are out of scope); the local-plugin-names finding was adopted in R10 (local-only 'working' field). Get-McpServerNames reviewed clean in R9 and unchanged since. The tests file was 'patch is correct' in R12; its 3 findings are fixed, plus a Linux dot-file fix found by CI. Invoke-SkillAudit.ps1 was last reviewed in full in R11; its R11 fixes (installed server spelling, placeholder covers plugin refs) were NOT re-reviewed by the API, because R12 hit max_tokens twice (mechanical; stopped per coordinator rule). They are covered by exact-case tests. 54 fixture tests, 62 green locally with Invoke-SkillAudit.Tests.ps1. |
|
Sin hallazgos bloqueantes. Revisé
No ejecuté los tests (los 54 de Nit opcional: |
|
On hold: waiting for the Anthropic plugin directory review. Do not merge yet. The agentic-board plugin is in its first review in the Anthropic plugin directory, and the directory tracks Batch waiting together: #799, #800, #801, #802, #803, #804.
|
|
Review (solo lectura del diff; no ejecuté los tests): Sin bugs bloqueantes. La lógica es coherente: lectura de config de solo lectura, sin ejecución de comandos externos ni input sin validar, y los fallos de descubrimiento degradan solo este check ( Observaciones menores, no bloqueantes:
|
Closes #758
What
skills-auditgets a new static finding,mcp-tool-name. It catches a skill whoseSKILL.mdorreferences/hardcode an MCP tool name under a prefix the agent does not have. The typical case ismcp__powerbi-modeling-mcp__connection_operationswhile the server comes from a plugin asmcp__plugin_fabric-skills_powerbi-modeling-mcp__…, or the reverse. The finding gives the name that works on this machine (in a local-onlyworkingfield; the detail that may be filed names only the install form) and recommends the server-agnostic wording ("the powerbi-modeling-mcpconnection_operationstool").Get-McpServerNames.ps1(new) lists the prefixes the agent really sees. It reads~/.claude.json(user and per-project entries), the project.mcp.jsonand the enabled plugins' manifests. It skips what is not loaded:disabledMcpServers;.mcp.jsonservers.Names are normalized the way Claude Code builds tool names. It does not call
claude mcp list, because that command health-checks every server and does not show the plugin prefix.Invoke-SkillAudit.ps1checks these forms:mcp__<prefix>__<tool>,__*and the baremcp__<server>used inallowed-tools. It reports only when the server IS available under another prefix: a server that is not installed says nothing. It does not flag:Copies of a skill are folded into one finding. A discovery failure skips only this check.
-McpServersinjects the prefix set.Tests
tests/agentic-board/SkillAudit.McpToolNames.Tests.ps1has 54 tests, all on fixtures. The audit's own discovery path is driven through a stub copy of the scripts, never the live config. A live run on the maintainer's machine flagged real skills that hardcodemcp__powerbi-modeling-mcp__*where that server comes from a plugin.Closes #758
🤖 Generated with Claude Code