fix: fail closed on unclassified MCP tools - #277
Conversation
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Implements fail-closed safety classification for MCP tool discovery so tools without explicit operator mapping or usable MCP safety hints are rejected by default (fixing #181).
Changes:
- Adds centralized classification logic (
mcp_classification.py) with a default “reject unannotated” policy and explicit fallback option + warning. - Updates
MCPDriver.discover()to use the new classifier and exposeunannotated_safety. - Updates and adds tests + new migration/security documentation for the breaking default.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_mcp_driver.py | Updates existing MCP tests to explicitly classify previously-unannotated fixtures. |
| tests/test_mcp_discovery_safety.py | Adds focused regression tests for fail-closed behavior, warnings, and invalid configs. |
| src/weaver_kernel/drivers/mcp_classification.py | Introduces helper for precedence-based safety classification, rejection, and fallback logging. |
| src/weaver_kernel/drivers/mcp.py | Wires new classification into MCPDriver.discover() and adds unannotated_safety parameter. |
| docs/mcp-safety-classification.md | Documents the new default behavior, precedence rules, and migration path. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
dgenio
left a comment
There was a problem hiding this comment.
Posted as COMMENT (self-review). See inline comments; also add a CHANGELOG Unreleased entry for this breaking default behavior change.
dgenio
left a comment
There was a problem hiding this comment.
Follow-up inline notes (comment-only self-review).
Closes #181.
What changed
MCPDriver.discover()no longer silently classifies a tool with missing safety metadata asSafetyClass.READ.safety_class_mapentry and a useful MCP safety hint.unannotated_safety=SafetyClass.WRITE|DESTRUCTIVE|READ; every tool receiving that fallback is named in a warning.mcp_classification.pyhelper rather than inflating the driver module.Why
The previous fallback was opposite to least privilege: absence of MCP metadata became the least-restricted safety class. MCP annotations are advisory and missing metadata is not evidence that an operation is read-only.
Compatibility
Deliberate breaking security default. Previous behavior can be requested explicitly:
The recommended migration is an operator-reviewed
safety_class_map.Security boundary
This fixes missing-metadata classification. It does not make server-provided annotations trustworthy; a dishonest server can still mislabel a tool. High-assurance deployments should use reviewed operator classification.
Validation
CI adds tests for:
This PR should merge independently of the broader MCP v2 migration in #263; #173 remains the real-server interoperability gate.