Skip to content

fix: fail closed on unclassified MCP tools - #277

Merged
dgenio merged 12 commits into
mainfrom
agent/fail-closed-mcp-discovery
Aug 14, 2026
Merged

fix: fail closed on unclassified MCP tools#277
dgenio merged 12 commits into
mainfrom
agent/fail-closed-mcp-discovery

Conversation

@dgenio

@dgenio dgenio commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Closes #181.

What changed

  • MCPDriver.discover() no longer silently classifies a tool with missing safety metadata as SafetyClass.READ.
  • Default discovery now rejects any tool that lacks both an explicit safety_class_map entry and a useful MCP safety hint.
  • Operators can deliberately choose unannotated_safety=SafetyClass.WRITE|DESTRUCTIVE|READ; every tool receiving that fallback is named in a warning.
  • Explicit operator classifications remain highest precedence; destructive MCP hints beat read-only hints.
  • Classification logic lives in a small mcp_classification.py helper rather than inflating the driver module.
  • Existing MCP tests now classify intentionally unannotated fixtures explicitly.
  • Added focused fail-closed regression tests and a migration/security guide.

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:

await driver.discover(unannotated_safety=SafetyClass.READ)

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:

  • default rejection + affected tool names;
  • explicit per-tool classification;
  • explicit fallback + warning containing all affected tools;
  • read/destructive hint inference;
  • invalid fallback configuration;
  • existing discover/register/invoke and real FastMCP fixtures updated to classify intentionally.

This PR should merge independently of the broader MCP v2 migration in #263; #173 remains the real-server interoperability gate.

@dgenio
dgenio marked this pull request as ready for review August 11, 2026 06:10
Copilot AI lite review requested due to automatic review settings August 11, 2026 06:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 expose unannotated_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.

Comment thread src/weaver_kernel/drivers/mcp_classification.py Outdated
Comment thread src/weaver_kernel/drivers/mcp_classification.py
Comment thread src/weaver_kernel/drivers/mcp_classification.py

@dgenio dgenio left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posted as COMMENT (self-review). See inline comments; also add a CHANGELOG Unreleased entry for this breaking default behavior change.

@dgenio dgenio left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up inline notes (comment-only self-review).

Comment thread tests/test_mcp_discovery_safety.py
Comment thread docs/mcp-safety-classification.md
@dgenio
dgenio merged commit dffb7a9 into main Aug 14, 2026
11 checks passed
@dgenio
dgenio deleted the agent/fail-closed-mcp-discovery branch August 14, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Require explicit safety classification for auto-discovered MCP tools

2 participants