zeph-mcp 0.18.1

MCP client with multi-server lifecycle and Qdrant tool registry for Zeph
Documentation

zeph-mcp

Crates.io docs.rs License: MIT MSRV

MCP client with multi-server lifecycle and Qdrant tool registry for Zeph.

Overview

Implements the Model Context Protocol client for Zeph, managing connections to multiple MCP servers, discovering their tools at startup, and routing tool calls through a unified executor. Built on rmcp 0.17.

Key Modules

  • client — low-level MCP transport and session handling; ToolListChangedHandler receives tools/list_changed notifications, applies sanitize_tools() (rate-limited to once per 5 s per server, capped at 100 tools), and forwards the sanitized list to McpManager via a refresh channel
  • managerMcpManager, McpTransport, ServerEntry for multi-server lifecycle; command allowlist validation (npx, uvx, node, python3, docker, mcpls, etc.), env var blocklist (LD_PRELOAD, DYLD_*, NODE_OPTIONS, etc.), and path separator rejection; statically configured servers (from [[mcp.servers]]) bypass SSRF validation to allow connections to localhost and private IPs — dynamically added servers retain full SSRF protection
  • sanitizesanitize_tools() applied to all tool definitions at registration time and again on every tools/list_changed refresh; strips 17 injection-detection patterns, Unicode Cf-category characters, and caps descriptions at 1024 bytes; fields triggering a pattern are replaced with "[sanitized]" — tool registration is never blocked
  • executorMcpToolExecutor bridging MCP tools into the ToolExecutor trait
  • registryMcpToolRegistry for tool lookup and optional Qdrant-backed search
  • toolMcpTool wrapper with schema and metadata
  • prompt — MCP prompt template support
  • errorMcpError error types

Semantic tool discovery

SemanticToolIndex indexes all registered MCP tool definitions as embedding vectors in Qdrant (or the SQLite vector backend). On each LLM turn, only the top-K most relevant tools — ranked by cosine similarity to the current query — are included in the tools array sent to the model. This keeps the tools payload small for models with narrow context windows and reduces prompt injection surface area.

[mcp.tool_discovery]
enabled      = true
top_k        = 20         # max tools sent per request (0 = all tools, disables discovery)
min_score    = 0.55       # minimum similarity threshold
collection   = "zeph_mcp_tools"

[!NOTE] Tool discovery requires an embedding model. Configure [llm.orchestrator] embedding_model or set a dedicated embedding_provider for the mcp subsystem. When Qdrant is unavailable the index falls back to BM25 keyword matching.

Per-message pruning cache

PruningCache tracks which tool set was sent in the previous LLM request. If the ranked tool list for the current turn is identical, the cache returns the pre-serialized JSON blob directly, skipping re-serialization and re-ranking.

Cache invalidation triggers on: new tool registered, tool removed, tools/list_changed notification, or config reload. No manual configuration is required; the cache is always active when [mcp.tool_discovery] enabled = true.

Tool attestation

expected_tools in a server config entry declares the tool names that server is authorised to expose. If a tool name appears in tools/list that is not in expected_tools, it is logged as a security warning and excluded from the registry.

[[mcp.servers]]
id             = "filesystem"
command        = "npx"
args           = ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
expected_tools = ["read_file", "write_file", "list_directory"]

[!IMPORTANT] Leave expected_tools empty (or omit it) to allow all tools from a server. Setting it to an empty list [] blocks all tools from that server.

MCPShield trust calibration

MCPShield assigns a per-server trust score that starts at 1.0 and degrades on anomalous events: tool definition mutations between tools/list_changed cycles, sanitization hits, unexpected tool names, and tool execution errors. When the trust score drops below shield.quarantine_threshold, the server is quarantined and its tools are excluded from the registry until the score recovers (exponential half-life decay).

[mcp.shield]
enabled               = true
quarantine_threshold  = 0.4    # score below which a server is quarantined
decay_half_life_secs  = 3600   # half-life for trust score recovery

[!TIP] View per-server trust scores in the TUI with mcp:list from the command palette — the trust column shows the current score and a coloured indicator (green ≥ 0.7, yellow ≥ 0.4, red < 0.4).

Configuration

[[mcp.servers]]
id = "filesystem"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
env = {}

[[mcp.servers]]
id = "fetch"
command = "uvx"
args = ["mcp-server-fetch"]

[!NOTE] Statically configured servers (from [[mcp.servers]]) bypass SSRF validation to allow connections to localhost and private IPs. Dynamically added servers retain full SSRF protection.

Features

Feature Description
mock Enables MockMcpClient for downstream tests

Installation

cargo add zeph-mcp

Documentation

Full documentation: https://bug-ops.github.io/zeph/

License

MIT