Skip to content

feat(mcp): FR-MR-8 — auto-allow read-only MCP servers#32

Open
frits-v wants to merge 8 commits intomainfrom
feat/fr-mr-8-readonly-mcp-servers
Open

feat(mcp): FR-MR-8 — auto-allow read-only MCP servers#32
frits-v wants to merge 8 commits intomainfrom
feat/fr-mr-8-readonly-mcp-servers

Conversation

@frits-v
Copy link
Copy Markdown
Owner

@frits-v frits-v commented Mar 20, 2026

Summary

  • Auto-allow all tools from context7, datadog-mcp, and codebase-memory-mcp MCP servers
  • These servers are exclusively read-only (doc lookups, log/metric queries, code graph queries)
  • Previously fell through to FR-MR-7 (unknown MCP → Ask), prompting on every call
  • 3 new tests (26 total MCP routing tests)

Test plan

  • cargo test mcp::tests — 26/26 passing
  • Verified live: echo '{"session_id":"test","tool_name":"mcp__plugin_context7_context7__query-docs","tool_input":{}}' | permissionspermissionDecision: "allow"
  • Same verification for mcp__datadog-mcp__search_datadog_logs
  • Unknown MCP tools still return Ask (FR-MR-7 unchanged)

Add routing for context7, datadog-mcp, and codebase-memory-mcp to the
MCP permission router. All three servers expose exclusively read-only
tools (documentation lookups, log/metric queries, code graph queries),
so they are unconditionally allowed without per-action routing.

Previously these fell through to FR-MR-7 (unknown MCP → Ask), requiring
manual confirmation on every call.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 20, 2026

Greptile Summary

This PR implements FR-MR-8 and FR-MR-9, adding auto-allow routing for three MCP servers — context7, datadog-mcp, and codebase-memory-mcp — that previously fell through to the FR-MR-7 catch-all Ask. It also removes a large set of transitive dependencies from Cargo.lock (chrono, csv, url, uuid, wasm-bindgen, icu_*, etc.) that were previously pulled in by optional rusqlite feature flags.

  • route_context7 (FR-MR-8): enumerates two known tools (resolve-library-id, query-docs) with a comment clarifying that the plugin renames upstream's get-library-docs; unknown tools fall through to Ask.
  • route_datadog_mcp (FR-MR-8b): uses verb-prefix matching (analyze_, search_, get_, check_, list_) consistent with FR-MR-3; unknown prefixes fall through to Ask.
  • route_codebase_memory (FR-MR-9): explicitly separates read-only graph/search queries (Allow) from write operations like index_repository, ingest_traces, delete_project, manage_adr, and detect_changes (Ask); unknown tools also fall through to Ask.
  • All concerns from prior review rounds are addressed: write operations are correctly classified as Ask, blanket prefix matches are replaced with explicit or prefix-guarded routing, and the missing unknown-tool catch-all test is added.
  • One minor inconsistency: route_datadog (FR-MR-3) allows the query_ verb prefix as read-only, but route_datadog_mcp does not include it — if datadog-mcp adds any query_* tools, they would receive spurious Ask prompts.

Confidence Score: 4/5

  • Safe to merge — all write operations require confirmation, catch-all Ask fallbacks are present everywhere, and 26 tests pass.
  • The routing logic is correct and conservative: every new path either explicitly allows known read-only tools or falls back to Ask. All previously-raised concerns (index_repository write classification, blanket prefix risk, missing unknown-tool test, query-docs naming) are addressed. The only remaining gap is the missing query_ prefix in route_datadog_mcp, which is safe-by-default (causes Ask rather than erroneous Allow) but creates a minor inconsistency with the sibling FR-MR-3 router.
  • No files require special attention.

Important Files Changed

Filename Overview
hooks/src/mcp.rs Adds three new routing functions (route_context7, route_datadog_mcp, route_codebase_memory) with explicit tool enumeration or verb-prefix matching and catch-all Ask fallbacks. All previously-flagged concerns from prior review threads are addressed; one minor inconsistency remains where query_ prefix is allowed in route_datadog (FR-MR-3) but absent from route_datadog_mcp (FR-MR-8b).
Cargo.lock Removes a large set of now-unused transitive dependencies (chrono, csv, url, uuid, wasm-bindgen, icu_*, idna, time, etc.) that were previously pulled in by optional rusqlite feature flags. No functional impact; reduces the dependency surface area.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[tool_name] --> B{strip prefix}

    B -->|mcp__plugin_context7_context7__| C[route_context7]
    B -->|mcp__datadog-mcp__| D[route_datadog_mcp]
    B -->|mcp__codebase-memory-mcp__| E[route_codebase_memory]
    B -->|other mcp__*| F[FR-MR-7: Ask]
    B -->|non-mcp| G[Allow]

    C --> C1{"action?"}
    C1 -->|resolve-library-id\nquery-docs| C2[Allow]
    C1 -->|_| C3[Ask]

    D --> D1{"prefix?"}
    D1 -->|analyze_ / search_\nget_ / check_ / list_| D2[Allow]
    D1 -->|other| D3[Ask]

    E --> E1{"action?"}
    E1 -->|get_architecture\nget_code_snippet\nget_graph_schema\nsearch_code / search_graph\nquery_graph / trace_call_path\nlist_projects / index_status| E2[Allow]
    E1 -->|index_repository\ningest_traces\ndelete_project\nmanage_adr\ndetect_changes| E3[Ask - write op]
    E1 -->|_| E4[Ask - unknown]
Loading

Last reviewed commit: "fix(mcp): address fi..."

Address Greptile review: `index_repository`, `ingest_traces`,
`delete_project`, and `manage_adr` are write operations that modify
persistent storage. These now require user confirmation (Ask) instead
of being blanket-allowed.

Read-only tools (search, query, get, trace, list, detect, index_status)
remain auto-allowed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frits-v
Copy link
Copy Markdown
Owner Author

frits-v commented Mar 20, 2026

@greptile review

Address Greptile iteration 2:
- datadog-mcp: replace blanket Allow with per-prefix routing (analyze_,
  search_, get_, check_ → Allow; unknown → Ask). Consistent with
  FR-MR-3 defensiveness against future write tools.
- codebase-memory-mcp: move detect_changes to Ask — may update a
  persistent change-detection baseline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frits-v
Copy link
Copy Markdown
Owner Author

frits-v commented Mar 20, 2026

@greptile review

frits-v and others added 2 commits March 20, 2026 09:28
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add get_code_snippet, get_graph_schema, search_graph, and list_projects
to the read-allow test. All 9 explicitly-allowed tools now have test
coverage, preventing silent regressions if entries are accidentally removed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frits-v
Copy link
Copy Markdown
Owner Author

frits-v commented Mar 20, 2026

@greptile review

Replace blanket prefix Allow with explicit tool enumeration
(resolve-library-id, query-docs) + Ask fallthrough for unknown tools.
All three new servers now use the same defensive pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frits-v
Copy link
Copy Markdown
Owner Author

frits-v commented Mar 20, 2026

@greptile review

context7 and codebase-memory-mcp use explicit tool enumeration;
datadog-mcp uses verb-prefix matching (consistent with FR-MR-3).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frits-v
Copy link
Copy Markdown
Owner Author

frits-v commented Mar 20, 2026

@greptile review

- context7: document that query-docs comes from context7@claude-plugins-official
  (upstream uses get-library-docs)
- datadog-mcp: add list_ prefix for consistency with FR-MR-3
- codebase-memory-mcp: add unknown-tool catch-all test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@frits-v
Copy link
Copy Markdown
Owner Author

frits-v commented Mar 20, 2026

@greptile review

Comment on lines +304 to +317
fn route_datadog_mcp(action: &str) -> McpDecision {
if action.starts_with("analyze_")
|| action.starts_with("search_")
|| action.starts_with("get_")
|| action.starts_with("check_")
|| action.starts_with("list_")
{
return McpDecision::Allow;
}
McpDecision::Ask(format!(
"datadog-mcp tool '{}' — unknown operation, requires confirmation",
action
))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 query_ prefix omitted from route_datadog_mcp

route_datadog (FR-MR-3, line 224) treats query_ as a read-only prefix alongside get_, list_, and search_. route_datadog_mcp deliberately added list_ to address the previous reviewer's concern, but still does not include query_. If datadog-mcp exposes any query_* tools (e.g. a query_metrics or query_logs — a natural naming pattern for an observability server), those calls would silently fall through to Ask despite being semantically identical to the read-only query_ operations already allowed for mcp__datadog__.

The safe-by-default fallback means this won't cause incorrect allows, but it will produce spurious confirmation prompts for what should be unconditionally-allowed read operations, inconsistent with the policy applied to the sister Datadog router.

Consider adding query_ for consistency:

Suggested change
fn route_datadog_mcp(action: &str) -> McpDecision {
if action.starts_with("analyze_")
|| action.starts_with("search_")
|| action.starts_with("get_")
|| action.starts_with("check_")
|| action.starts_with("list_")
{
return McpDecision::Allow;
}
McpDecision::Ask(format!(
"datadog-mcp tool '{}' — unknown operation, requires confirmation",
action
))
}
fn route_datadog_mcp(action: &str) -> McpDecision {
if action.starts_with("analyze_")
|| action.starts_with("search_")
|| action.starts_with("get_")
|| action.starts_with("check_")
|| action.starts_with("list_")
|| action.starts_with("query_")
{
return McpDecision::Allow;
}
McpDecision::Ask(format!(
"datadog-mcp tool '{}' — unknown operation, requires confirmation",
action
))
}

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.

1 participant