MCP Client — manages MCP server child processes via rmcp.
Uses rmcp (1.4.x) RunningService<RoleClient, AgentBlockClientHandler> internally.
AgentBlockClientHandler provides custom notification handling via Lua callbacks
(wired in Subtask 2/3). For Subtask 1, all notification methods are default no-ops.
All rmcp round-trips are wrapped in a per-call timeout so a hung child cannot block a Lua coroutine indefinitely.
Concurrency contract
list_tools and call_tool take &self, so the manager can be held
under tokio::sync::RwLock and multiple RPCs — including against the
same server — can proceed in parallel via read guards. Request/response
multiplexing on a single server is handled by rmcp's Peer, which
pairs each outbound request with a oneshot receiver keyed by request
ID. connect and disconnect are mutating (&mut self) and must take
the write guard.
This contract is covered by in-process unit tests in #[cfg(test)] at
the bottom of this file. If rmcp alters its Peer concurrency model,
or if this module is refactored to re-serialize RPCs, those tests fail.
Child environment
Stdio servers are spawned as child processes and inherit the host's
environment, minus the host's own credential variables
([agent_block_types::creds::OWN_CREDENTIAL_ENV_VARS]), which
[McpManager::connect] removes — the same set sh.exec strips. A server
that legitimately needs one of those keys must be handed it explicitly via
the env argument (mcp.connect(name, cmd, args, { env = {...} }) from
Lua), which is applied after the removals.
Usage from Lua
mcp.
local tools = mcp.
local result = mcp.
mcp.