Skip to content

fix(introspector): bound discover_server awaits with timeouts, fix mcp-server lock DoS#127

Merged
bug-ops merged 1 commit into
masterfrom
fix/120-introspector-timeout
Jul 9, 2026
Merged

fix(introspector): bound discover_server awaits with timeouts, fix mcp-server lock DoS#127
bug-ops merged 1 commit into
masterfrom
fix/120-introspector-timeout

Conversation

@bug-ops

@bug-ops bug-ops commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Introspector::discover_server connected to downstream MCP servers and awaited list_all_tools with no timeout, so a hung or malicious server blocked the call forever.
  • In mcp-execution-server, this was made worse by a single global Arc<Mutex<Introspector>>: one hung server blocked introspect_server for every session, not just the caller who triggered it.
  • Adds connect_timeout/discover_timeout fields to ServerConfig (30s defaults) and wraps both awaits in tokio::time::timeout, mapping expiry to the existing Error::Timeout variant.
  • Replaces the global mutex in GeneratorService with a per-server-id keyed lock (introspector_for), evicting each entry once discover_server completes (success or error) so unrelated server ids never contend and the map stays bounded against caller-supplied ids.

Test plan

  • cargo +nightly fmt --check
  • cargo +stable clippy --all-targets --all-features --workspace -- -D warnings
  • cargo nextest run --all-features --workspace --no-fail-fast
  • cargo test --doc --all-features --workspace
  • RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace
  • New tests cover connect-timeout and discover-timeout firing via a cross-platform fixture server, per-server-id lock concurrency, and that the introspector map entry is evicted after each call

Closes #120

@bug-ops
bug-ops enabled auto-merge (squash) July 9, 2026 14:57
@github-actions github-actions Bot added area: bridge MCP bridge and integration area: core Core types and infrastructure crate: mcp-core Changes to mcp-core crate (foundation types, traits, errors) crate: mcp-introspector Changes to mcp-introspector crate (MCP server analysis) type: documentation Documentation changes (*.md, docs/, comments) type: dependencies Dependency updates (Cargo.toml, Cargo.lock) type: tests Test changes (tests/, *_test.rs) breaking change Contains breaking API changes (requires major version bump) release Release preparation (changelog, version bumps) labels Jul 9, 2026
…p-server lock DoS

Introspector::discover_server connected to downstream MCP servers and
awaited list_all_tools with no timeout, so a hung or malicious server
blocked the call forever. In mcp-execution-server this was serialized
behind a single global Arc<Mutex<Introspector>>, letting one bad server
block introspect_server for every session indefinitely.

Add connect_timeout/discover_timeout to ServerConfig (30s defaults) and
wrap both awaits in tokio::time::timeout, mapping expiry to the existing
Error::Timeout variant. Replace the global mutex in GeneratorService with
a per-server-id keyed lock, evicting each entry once discover_server
completes so unrelated server ids never contend and the map stays bounded.

Closes #120
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: bridge MCP bridge and integration area: core Core types and infrastructure breaking change Contains breaking API changes (requires major version bump) crate: mcp-core Changes to mcp-core crate (foundation types, traits, errors) crate: mcp-introspector Changes to mcp-introspector crate (MCP server analysis) release Release preparation (changelog, version bumps) type: dependencies Dependency updates (Cargo.toml, Cargo.lock) type: documentation Documentation changes (*.md, docs/, comments) type: tests Test changes (tests/, *_test.rs)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

introspector: discover_server has no timeout, serialized behind a single Mutex in mcp-server

1 participant