feat(mcp): FR-MR-8 — auto-allow read-only MCP servers#32
feat(mcp): FR-MR-8 — auto-allow read-only MCP servers#32
Conversation
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 SummaryThis PR implements FR-MR-8 and FR-MR-9, adding auto-allow routing for three MCP servers —
Confidence Score: 4/5
Important Files Changed
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]
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>
|
@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>
|
@greptile review |
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>
|
@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>
|
@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>
|
@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>
|
@greptile review |
| 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 | ||
| )) | ||
| } |
There was a problem hiding this comment.
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:
| 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 | |
| )) | |
| } |
Summary
context7,datadog-mcp, andcodebase-memory-mcpMCP serversTest plan
cargo test mcp::tests— 26/26 passingecho '{"session_id":"test","tool_name":"mcp__plugin_context7_context7__query-docs","tool_input":{}}' | permissions→permissionDecision: "allow"mcp__datadog-mcp__search_datadog_logs