One directory, one gate. Members: server/ (the openhuman mcp stdio/HTTP
server), registry/ (dynamic, SQLite-backed Smithery installs), audit/ (the
write-audit log), config_servers/ (the static, TOML-declared server set +
stdio transport), and http_client/ (the HTTP transport primitive). Each of
server/registry/audit has its own README.
The family root mcp/mod.rs is ungated: http_client is always compiled
(always-compiled consumers outside the MCP subsystem reach it), and the three
facades each ship a stub.rs that must resolve in an mcp-less build. The
gate is pushed onto each member — config_servers is leaf-gated, http_client
is not gated at all.
sanitize is not in this family: it moved to util/sanitize.rs, because
the orchestrator prompt runs skill descriptions through it.
The rest of this page documents config_servers/ + http_client/ — the halves
that were the old mcp_client directory.
Reusable MCP client transport library plus a read-only static server set declared in the user's TOML config. This module knows how to talk to a remote MCP server over two transports — Streamable HTTP (with OAuth discovery + SSE per the MCP spec) and subprocess JSON-RPC over stdin/stdout — and exposes the servers the user pinned under [[mcp_client.servers]] as a queryable registry. It owns no RPC surface, no persistence, and no event-bus subscribers; it is a building block consumed by other domains. Its sibling mcp::registry reuses config_servers' McpStdioClient for all stdio transport of dynamically-installed Smithery servers.
- Implement the MCP Streamable HTTP client (
McpHttpClient):initializehandshake + protocol-version negotiation,tools/list,tools/call, SSE event draining, session lifecycle (Mcp-Session-Id),notifications/initialized, and gracefulclose_sessionvia HTTP DELETE. - Implement the MCP stdio client (
McpStdioClient): spawn a subprocess, speak newline-delimited JSON-RPC over stdin/stdout, and cache a single long-lived session. - Handle OAuth / authorization discovery on HTTP transport: parse
WWW-Authenticatechallenges on 401, fetch protected-resource metadata and authorization-server metadata (OIDC.well-known+ OAuth.well-known). - Apply per-server auth (bearer / basic / custom header / query param) to outbound requests.
- Reinitialize-and-retry once on a 404 indicating an expired HTTP session.
- Mirror tool-schema parameters tagged
x-mcp-headerintoMcp-Param-*request headers. - Render raw MCP
tools/callresults into the skillsToolResultshape. - Build a static
McpServerRegistryfromConfig([[mcp_client.servers]]+ a legacygitbooksserver), enforce per-server allow/deny tool lists, and pick HTTP vs stdio transport per entry. - Redact endpoints in logs/errors (scheme + authority only; credentials →
<redacted>).
| File | Role |
|---|---|
src/openhuman/mcp/mod.rs |
Family root (ungated). Declares the five members and documents where the gate sits. |
src/openhuman/mcp/http_client/mod.rs |
Ungated carve-out. Re-exports the HTTP transport + protocol types. |
src/openhuman/mcp/config_servers/mod.rs |
Leaf-gated on mcp. Re-exports the static registry + stdio transport. |
src/openhuman/mcp/http_client/client.rs |
McpHttpClient (Streamable HTTP transport), shared MCP protocol types, SSE/WWW-Authenticate parsing, render_tool_result, redact_endpoint, x-mcp-header mirroring. Largest file; carries the inline test suite. |
src/openhuman/mcp/config_servers/stdio.rs |
McpStdioClient — subprocess spawn + newline-delimited JSON-RPC over stdin/stdout, single cached StdioSession. |
src/openhuman/mcp/config_servers/spawn_env.rs |
PATH reconstruction for stdio children: probes the user's login shell ($SHELL -ilc) + well-known version-manager dirs (nvm/volta/bun/Homebrew), caches the result, and resolves the command up front so missing npx/uvx fails with actionable guidance. |
src/openhuman/mcp/config_servers/registry.rs |
McpServerRegistry, McpServerDefinition, McpTransportClient (Http/Stdio dispatch enum), McpRegistrySource; builds the static set from Config, applies allow/deny tool filtering. |
Re-exported from the two member mod.rs files:
- HTTP transport / protocol types (
http_client/client.rs, ungated):McpHttpClient,McpInitializeResult,McpRemoteTool,McpServerToolResult,McpSseEvent,McpAuthChallenge,McpAuthorizationContext,ProtectedResourceMetadata,AuthorizationServerMetadata, and the helperredact_endpoint. - Stdio transport (
config_servers/stdio.rs, gated):McpStdioClient. - Registry (
config_servers/registry.rs, gated):McpServerRegistry,McpServerDefinition,McpTransportClient,McpRegistrySource.
Key entry points:
McpHttpClient::new(endpoint, timeout_secs)/with_options(endpoint, timeout_secs, auth, identity)→initialize,list_tools,call_tool,discover_authorization,drain_events,close_session,initialize_snapshot.McpStdioClient::new(command, args, env, cwd, identity)→initialize,list_tools,call_tool,close_session.McpServerRegistry::from_config(&Config)→list,get,list_tools,call_tool,initialize,discover_authorization,is_empty.McpTransportClient— enum unifyingHttp/Stdio, forwardinginitialize/list_tools/call_tool/discover_authorization(stdio always returnsNonefor authorization discovery).
Reads config.mcp_client (McpClientConfig): enabled, servers (Vec<McpServerConfig>), and client_identity (McpClientIdentityConfig → client name/title/version sent in the initialize handshake). Each McpServerConfig supplies name, endpoint, command/args/env/cwd (stdio), description, enabled, allowed_tools, disallowed_tools, timeout_secs, and auth (McpAuthConfig). Also reads config.gitbooks (enabled, endpoint, timeout_secs) to seed a legacy gitbooks HTTP server when no explicit server of that name exists. HTTP clients apply the runtime proxy via config::apply_runtime_proxy_to_builder(builder, "tool.mcp_client").
Transport selection in build_transport_client: a non-empty command ⇒ stdio; otherwise HTTP against endpoint.
None. This module exposes no JSON-RPC controllers or schemas of its own. RPC-facing MCP work lives in the sibling mcp::registry and in the generic bridge tools.
None owned here. The generic bridge tools that drive this registry (mcp_list_servers, mcp_list_tools, mcp_call_tool) live in src/openhuman/tools/impl/network/mcp.rs; the bespoke gitbooks tool (tools/impl/network/gitbooks.rs) consumes McpHttpClient directly.
None. No bus.rs; publishes/subscribes to no DomainEvents.
None. No store.rs. The static registry is rebuilt from Config in memory; HTTP/stdio session state (session id, negotiated protocol version, cached tool list, child process) lives only in the in-memory client instances.
crate::openhuman::config—Config,McpClientConfig,McpServerConfig,McpAuthConfig,McpClientIdentityConfig, andapply_runtime_proxy_to_builder(proxy-aware reqwest builder). Source of the static server set and per-server auth/identity.crate::openhuman::skills::types::ToolResult— the rendered result shape returned fromtools/call(viarender_tool_result).
External crates: reqwest (HTTP), tokio (process + async IO + sync::Mutex), parking_lot::Mutex (HTTP session state), serde/serde_json, base64, anyhow, tracing.
src/openhuman/mcp/registry/(mod.rs,connections.rs,setup_ops.rs) — reusesMcpStdioClient(and HTTP client) for all transport of dynamically-installed servers; carries no transport code of its own.src/openhuman/tools/impl/network/mcp.rsandtools/ops.rs— genericmcp_*bridge tools driving the static registry.src/openhuman/tools/impl/network/gitbooks.rs— usesMcpHttpClientdirectly for the GitBook docs server.src/openhuman/mcp/server/http.rs— references this module.
- Latest protocol version is
2025-11-25, sent on everyinitialize; the server's negotiated version must be one of the fourSUPPORTED_PROTOCOL_VERSIONSorinitializefails. The constant is duplicated in bothhttp_client/client.rsandconfig_servers/stdio.rs. - HTTP transport uses
redirect::Policy::none()and a 10s connect timeout; the per-request timeout comes from the server'stimeout_secs. - A 404 on a request while a session id is held triggers exactly one reinitialize + retry (
allow_reinitializeguards against loops); after that the error propagates. Acceptis alwaysapplication/json, text/event-stream; the client transparently parses an SSE-framed single response (parse_sse_message) or a plain JSON body based onContent-Type.- Tool allow/deny enforcement is fail-closed and pre-transport:
is_tool_allowedrejects empty names, anything indisallowed_tools, and (whenallowed_toolsis non-empty) anything not allow-listed;registry.call_toolblocks before any network/subprocess I/O. - The legacy
gitbooksserver is only auto-seeded whenconfig.gitbooks.enabledand no explicit server namedgitbooksexists (explicit config wins, flippingsourcefromLegacyGitbookstoConfig). redact_endpointreturns<redacted>for any URL containing userinfo (@) or a non-http(s)scheme — used in all log/error output so endpoints never leak credentials.McpStdioClientdiscards child stderr (Stdio::null()) and skips non-JSON stdout lines (logged at debug); the session is a single cachedStdioSessionguarded by a tokioMutex.- Stdio children inherit a reconstructed PATH (
spawn_env::spawn_path), not the GUI-stripped process PATH, sonpx/uvxservers spawn the same way a terminal would. A config-providedPATHenv still overrides it. The command is resolved before spawn; a missing Node/uv runtime surfaces actionable install guidance instead of a rawENOENT(#4279).