MCP Integration
The Model Context Protocol (MCP) integration allows claw-code to connect to external tool servers. The runtime crate provides utilities for tool naming, server identification, and config management.
MCP Tool Naming
MCP tools are namespaced to prevent collisions between different servers:
mcp__{server_name}__{tool_name}For example, a tool called weather from a server called github.com becomes:
mcp__github_com__weatherName Normalization
Server and tool names are normalized by replacing non-alphanumeric characters (except _ and -) with underscores:
pub fn normalize_name_for_mcp(name: &str) -> String {
name.chars().map(|ch| match ch {
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' => ch,
_ => '_',
}).collect()
}For claude.ai prefixed servers, consecutive underscores are collapsed and leading/trailing underscores are trimmed:
"claude.ai Example Server!!" → "claude_ai_Example_Server"Server Types
The MCP config supports multiple server transports:
Server Signatures
Each server has a signature used for deduplication and identity:
pub fn mcp_server_signature(config: &McpServerConfig) -> Option<String> {
match config {
Stdio(c) => Some(format!("stdio:[{}]", command_signature)),
Sse(c) => Some(format!("url:{}", unwrap_ccr_proxy(c.url))),
Http(c) => Some(format!("url:{}", unwrap_ccr_proxy(c.url))),
Ws(c) => Some(format!("url:{}", unwrap_ccr_proxy(c.url))),
ClaudeAiProxy(c) => Some(format!("url:{}", unwrap_ccr_proxy(c.url))),
Sdk(_) => None, // SDK servers have no external identity
}
}CCR Proxy Unwrapping
Claude's CCR (Cloud Code Runner) proxy URLs wrap the actual MCP server URL as a query parameter. The unwrap_ccr_proxy_url() function extracts the real URL:
Input: https://api.anthropic.com/v2/session_ingress/shttp/mcp/123?mcp_url=https%3A%2F%2Fvendor.example%2Fmcp
Output: https://vendor.example/mcpThis ensures that two servers pointing to the same underlying MCP endpoint (one direct, one via proxy) get the same signature.
Config Hashing
Server configs are hashed for change detection using FNV-1a:
fn stable_hex_hash(value: &str) -> String {
let mut hash = 0xcbf2_9ce4_8422_2325_u64; // FNV offset basis
for byte in value.as_bytes() {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(0x0100_0000_01b3); // FNV prime
}
format!("{hash:016x}")
}The hash includes transport type, URL, headers, helpers, and OAuth config — but not the scope (user vs. local). This means the same server configured at both user and project level gets the same hash.
Scoped Configuration
MCP servers are scoped to configuration sources:
pub struct ScopedMcpServerConfig {
pub scope: ConfigSource, // User, Local, etc.
pub config: McpServerConfig,
}The scope tracks where the config came from but doesn't affect the server's identity or behavior.