Skip to content

feat(policy): classify risk from trusted MCP annotations - #64

Merged
mohanagy merged 3 commits into
developmentfrom
feat/issue-26-risk-classification
Jul 13, 2026
Merged

feat(policy): classify risk from trusted MCP annotations#64
mohanagy merged 3 commits into
developmentfrom
feat/issue-26-risk-classification

Conversation

@mohanagy

@mohanagy mohanagy commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Closes #26

Summary

  • Classify risk in a documented precedence order: exact local override, explicitly trusted MCP annotations, name heuristic, then a configurable conservative unknown-tool fallback.
  • Keep upstream annotations untrusted by default and scope trust to each base upstream; profile overrides cannot grant that trust.
  • Record safe classification provenance (riskSource / riskConfidence) in route preview and audit events without exposing raw annotations.
  • Normalize and snapshot only MCP behavioral booleans, preserving profile/fingerprint compatibility checks and no-upstream-start route previews.
  • Export/configure UnknownToolRisk, update generated schema and docs, and add unit, integration, contract, type, and package coverage.

Validation

  • npm run lint
  • npm run typecheck
  • npm run build
  • npm run smoke:cli
  • npm_config_cache=/private/tmp/miftah-npm-cache npm run check:pack
  • NODE_OPTIONS=--require=<temporary localhost-only shim> npm run test:core — 232 passed, 11 expected platform skips
  • Full non-network/non-package suite: 612 passed, 11 expected platform skips

This sandbox cannot resolve localhost, bind 127.0.0.1, or complete a fresh npm consumer install. The shim was untracked and removed; full package and remote transport validation remains required CI gating.

Summary by CodeRabbit

  • New Features

    • Added configurable tool-risk classification with a safer default for unknown tools (destructive risk by default).
    • Added opt-in support for trusting upstream tool annotations to influence risk.
    • Route previews and audit trail entries now include risk source and risk confidence.
    • Added the UnknownToolRisk public configuration/type surface.
  • Documentation

    • Updated routing/safety docs to describe what route previews and audit evidence include/exclude, and clarified risk-classification precedence and trust boundaries.
  • Bug Fixes

    • Fails closed more consistently for missing profiles, missing/contradictory hints, and untrusted annotations.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 19416798-a0b1-4c70-87fc-c1a9d7bdf789

📥 Commits

Reviewing files that changed from the base of the PR and between f86bca8 and 6c1d35d.

📒 Files selected for processing (2)
  • src/mcp/server/miftah-server.ts
  • tests/mcp-wrapper.test.ts
📝 Walkthrough

Walkthrough

The change adds annotation-aware tool risk classification with provenance and confidence, configurable unknown-tool defaults, trusted upstream controls, routing and audit propagation, public configuration types, validation tests, and updated documentation.

Changes

Risk classification

Layer / File(s) Summary
Risk contracts and classification
src/policy/*, src/config/*, src/index.ts
Risk decisions now include source and confidence; trusted annotations, local overrides, heuristics, and configurable unknown-risk defaults are applied in order.
Tool metadata and audit propagation
src/mcp/server/tool-registry.ts, src/mcp/server/operation-pipeline.ts, src/audit/*
Tool annotations are normalized and defensively copied, passed into policy evaluation, and recorded in audit events.
Server routing and preview integration
src/mcp/server/miftah-server.ts
Tool calls and route previews use risk metadata, trust configuration, compatible snapshots, and enriched audit output.
Validation and documented contracts
tests/*, README.md, docs/*, CHANGELOG.md
Tests and documentation cover schemas, classification precedence, annotation conflicts, route previews, audit fields, metadata copying, public type exports, and trust boundaries.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • mohanagy/miftah#41: Intersects the updated PolicyEngine.evaluate fail-closed and decision-return paths.
  • mohanagy/miftah#47: Overlaps with the deterministic ToolRegistry snapshot and routing changes.
  • mohanagy/miftah#53: Intersects the audit-trail and OperationPipeline audit wiring.

Poem

A rabbit hops through tools so bright,
With trusted hints to judge them right.
Risk and confidence join the trail,
Safe defaults guard each passing veil.
Audit carrots neatly grow—
Hippity-hop, the routes now know! 🐇


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Linked Issues check ❌ Error Issue [#26] is only partially met: overrides, annotations, conflicts, source/confidence, and fallback are covered, but provider matcher/plugin classification is missing. Implement the provider matcher/plugin classification stage before the heuristic fallback and add tests covering that path for [#26].
Docstring Coverage ❌ Error Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description is missing the required Security impact section and does not fully mirror the template’s validation checklist. Add a Security impact section and complete the template’s validation checklist with exact commands and results.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main change: classifying risk from trusted MCP annotations.
Out of Scope Changes check ✅ Passed The code, docs, and tests all relate to the risk-classification and trust-boundary work; no unrelated changes are evident.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-26-risk-classification

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Owner Author

CodeRabbit exception documented before merge: its only current-head marker has remained “processing” since 2026-07-12T19:45:58Z (over four hours) with no submitted review or inline thread. Current head 9ca6946 has a fully successful CI run (#114: Linux quality/coverage/package, Ubuntu/macOS/Windows Node 20/22/24, and Verify), and an independent security/correctness review found no blockers. No CodeRabbit or human review threads exist. Proceeding under the repository policy’s demonstrably-stuck exception.

Copy link
Copy Markdown
Owner Author

@coderabbitai review

The required CodeRabbit check has remained in progress without a review for over four hours. Please retry the current head 9ca6946dad3f2c098c934cb391fdec03c64661e1.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

@mohanagy Understood — I'll retry the review on the current head commit 9ca6946.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp/server/miftah-server.ts`:
- Line 535: Update the routed-call metadata construction around
riskMetadata(mapped) to recompute trust from the resolved target/upstream rather
than inheriting the source snapshot’s trusted flag; apply the same correction to
the route preview’s riskMetadata(sourceTool). Ensure resolveTarget() or the
relevant riskMetadata path validates upstream identity in addition to schema
compatibility before marking the target trusted.

In `@tests/config-runtime-parity.test.ts`:
- Around line 100-110: Hoist the three inline regex literals used by the
validateConfig toThrow assertions into module-scope constants in
tests/config-runtime-parity.test.ts, then reuse those constants in the
assertions near the shown tests. Preserve each existing pattern and assertion
behavior.

In `@tests/fixtures/fake-upstream.mjs`:
- Around line 143-146: Update the TEST_CREATE_ITEM_ANNOTATIONS parsing near
createItemAnnotations to catch malformed JSON and rethrow or report a clear
test-fixture-specific error message. Preserve undefined when the environment
variable is absent and continue returning the parsed value for valid JSON.

In `@tests/risk-classification-docs-contract.test.ts`:
- Line 32: Hoist the static regular expression used by the changelog assertion
in the risk classification contract test to module scope, then reuse that named
regex in the toMatch call. Preserve the existing pattern and matching behavior
while satisfying e18e/prefer-static-regex.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 162de235-d23d-4f12-8487-9de529a6c699

📥 Commits

Reviewing files that changed from the base of the PR and between af4fffc and 9ca6946.

📒 Files selected for processing (26)
  • CHANGELOG.md
  • README.md
  • docs/architecture.md
  • docs/config.md
  • docs/library-api.md
  • docs/security.md
  • src/audit/audit-trail.ts
  • src/audit/audit-types.ts
  • src/config/schema.ts
  • src/config/types.ts
  • src/index.ts
  • src/mcp/server/miftah-server.ts
  • src/mcp/server/operation-pipeline.ts
  • src/mcp/server/tool-registry.ts
  • src/policy/policy-engine.ts
  • src/policy/policy-types.ts
  • src/policy/risk-classifier.ts
  • tests/config-runtime-parity.test.ts
  • tests/config-schema-contract.test.ts
  • tests/fixtures/fake-upstream.mjs
  • tests/mcp-wrapper.test.ts
  • tests/package-contract.test.ts
  • tests/public-api.test.ts
  • tests/risk-classification-docs-contract.test.ts
  • tests/routing-policy.test.ts
  • tests/tool-registry.test.ts

Comment thread src/mcp/server/miftah-server.ts Outdated
Comment thread tests/config-runtime-parity.test.ts Outdated
Comment thread tests/fixtures/fake-upstream.mjs Outdated
Comment thread tests/risk-classification-docs-contract.test.ts Outdated

Copy link
Copy Markdown
Owner Author

Addressed all CodeRabbit findings in remote commit f86bca8.

  • Routed calls now derive annotation trust only from a compatible cached target snapshot; an uncached/mismatched target falls back conservatively and is never discovered before policy. The actual target resolver also rejects an upstream-identity mismatch. Route preview uses the same target-only rule.
  • Added a regression proving an untrusted routed target is blocked before target resolution or upstream contact.
  • Hoisted static test regexes and made malformed fixture annotation JSON fail with a clear, non-echoing message plus coverage.

Validated: focused pipeline/MCP tests, npm run test:core (232 passed, 11 platform skips), npm run typecheck, npm run lint, npm run build, npm run smoke:cli, and npm run check:pack. Full local npm test has only sandbox blockers: loopback binding is denied for remote-transport tests and fresh npm consumer install times out without registry access.

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/mcp/server/miftah-server.ts (1)

714-729: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

src/mcp/server/miftah-server.ts:714-729 Add originalName to the cached-target match in miftah_route_preview. fingerprint is based on the exposed client name, so a different underlying tool can still match on fingerprint + upstreamName; without the same originalName guard used in handleUpstreamTool, preview/audit can surface trusted-upstream-annotation for the wrong tool.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mcp/server/miftah-server.ts` around lines 714 - 729, Update the
hasCompatibleCachedTarget calculation in miftah_route_preview to also require
sourceTool.originalName and targetTool.originalName to match. Preserve the
existing fingerprint and upstreamName checks, ensuring preview/audit only uses
target risk metadata when all three tool identity fields match.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/mcp/server/miftah-server.ts`:
- Around line 714-729: Update the hasCompatibleCachedTarget calculation in
miftah_route_preview to also require sourceTool.originalName and
targetTool.originalName to match. Preserve the existing fingerprint and
upstreamName checks, ensuring preview/audit only uses target risk metadata when
all three tool identity fields match.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 29b578b4-1a5c-4aeb-a183-260c814110cc

📥 Commits

Reviewing files that changed from the base of the PR and between 9ca6946 and f86bca8.

📒 Files selected for processing (7)
  • src/mcp/server/miftah-server.ts
  • src/mcp/server/operation-pipeline.ts
  • tests/config-runtime-parity.test.ts
  • tests/fake-upstream-fixture.test.ts
  • tests/fixtures/fake-upstream.mjs
  • tests/operation-pipeline.test.ts
  • tests/risk-classification-docs-contract.test.ts

Copy link
Copy Markdown
Owner Author

Follow-up CodeRabbit identity finding addressed in 6c1d35d: cached target compatibility now requires matching fingerprint, named upstream, and underlying originalName. The same helper is used for routed-call metadata and route preview, with a focused regression for a same-shape/different-original-name target. tests/mcp-wrapper.test.ts, typecheck, and lint are green.

@mohanagy
mohanagy merged commit f798f66 into development Jul 13, 2026
12 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Aug 12, 2026
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.

[Policy] Prefer MCP tool annotations over name heuristics for risk classification

1 participant