feat(mcp): implement MCP Roots protocol and cap tool descriptions (#2445, #2450)#2454
Merged
feat(mcp): implement MCP Roots protocol and cap tool descriptions (#2445, #2450)#2454
Conversation
This was referenced Mar 30, 2026
…caps (#2445, #2450) Add MCP Roots protocol support: McpRootEntry config struct, roots field on McpServerConfig, ToolListChangedHandler advertises roots capability (list_changed=false) and responds to roots/list requests with configured roots. Roots validated at connection time: non-file:// URIs rejected, missing paths warned. Add configurable tool description and server instructions length caps: max_description_bytes and max_instructions_bytes on McpConfig (default 2048), truncate_instructions() helper, server instructions stored after handshake and accessible via McpManager::server_instructions. Fix double-sanitization: handler now uses self.max_description_bytes instead of a stale hardcoded constant, matching the configurable limit used in ingest_tools.
- Remove unused `use rmcp::ClientHandler` import (client.rs)
- Introduce `HandlerConfig { roots, max_description_bytes }` to reduce argument
count on connect_url (8→7) and unify handler params across connect/connect_url/
connect_url_with_headers/connect_url_oauth
- Introduce `ConnectState<'a>` struct to collapse 4 mutable ref params in
handle_connect_result (9 args → 5 args, resolves too_many_arguments)
- Extract `run_probe()` method to reduce body line count in handle_connect_result
and add_server (resolves too_many_lines in both)
- Add #[allow(clippy::too_many_lines)] to connect_url_oauth (OAuth flow is
inherently stateful; extraction would obscure the multi-step protocol)
- Add #[must_use] to truncate_instructions
- Fix implicit-clone lint: use to_owned() on &str, remove spurious .to_string()
on already-owned String from truncate_to_bytes
- Update module doc: 1024 bytes → 2048 bytes
423ad1c to
a5a47d2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
roots/listhandler responds with operator-configured filesystem roots; capability advertised withlist_changed: false(static MVP)max_description_bytes, default 2048) and server instructions (max_instructions_bytes, default 2048); fixed double-sanitization bug where handler used hardcoded 1024Changes
zeph-config:McpRootEntry { uri, name },rootsfield onMcpServerConfig,max_description_bytes/max_instructions_bytesonMcpConfigzeph-mcp/client.rs:ToolListChangedHandleradvertises roots capability, responds toroots/list;HandlerConfigstruct reduces arg count across 4 connect methodszeph-mcp/manager.rs:validate_roots()filters non-file://URIs;ConnectStateandrun_probe()refactor reduce arg counts and line counts; server instructions stored and accessible viaMcpManager::server_instructions()zeph-mcp/sanitize.rs:truncate_utf8()helper (UTF-8 safe),truncate_instructions(), configurable limit plumbed throughsanitize_tools()zeph-core/bootstrap/mcp.rs,src/init.rs: roots and limits wired from configTest plan
cargo +nightly fmt --check— cleancargo clippy --workspace --features full -- -D warnings— 0 warningscargo nextest run --workspace --features full --lib --bins— 7299 passedvalidate_roots_*tests covering URI filtering edge casesroots/listand capability advertisement[[mcp.servers]]withroots = [{uri="file:///path", name="project"}]and verify a root-aware MCP server receives correct rootsFollow-up
std::fs::canonicalize()tovalidate_roots()for path traversal hardeningsanitize_string()to server instructions intruncate_instructions()Closes #2445, #2450