pub struct McpManager {
pub servers: HashMap<String, RunningService<RoleClient, AgentBlockClientHandler>>,
pub handler: AgentBlockClientHandler,
/* private fields */
}Fields§
§servers: HashMap<String, RunningService<RoleClient, AgentBlockClientHandler>>Server connections keyed by name. pub(crate) so integration tests
can insert in-process test servers directly (same as concurrency_tests
in this module).
handler: AgentBlockClientHandlerShared handler instance — all connections share the same registry Arc.
Implementations§
Source§impl McpManager
impl McpManager
pub fn new() -> Self
Sourcepub fn with_rpc_timeout(rpc_timeout: Duration) -> BlockResult<Self>
pub fn with_rpc_timeout(rpc_timeout: Duration) -> BlockResult<Self>
Construct a manager with a caller-specified RPC timeout.
Applies to connect, list_tools, and call_tool alike.
rpc_timeout must be non-zero. Duration::ZERO would cause every
tokio::time::timeout to fire immediately, silently turning every
MCP round-trip into a timeout error — for an autonomous agent that
is a “everything looks broken” failure mode. We reject it at
construction time so the misconfiguration surfaces loudly at
startup instead of being swallowed at the first RPC.
Sourcepub async fn connect(
&mut self,
name: &str,
command: &str,
args: &[String],
trace_context: bool,
cwd: Option<&Path>,
) -> BlockResult<()>
pub async fn connect( &mut self, name: &str, command: &str, args: &[String], trace_context: bool, cwd: Option<&Path>, ) -> BlockResult<()>
Spawn the MCP server process and complete the MCP initialize handshake.
trace_context: if true, __ab_obs observability context will be
injected into call_tool arguments for this server. Defaults to false
(opt-in) so that third-party / untrusted stdio servers do not receive agent
identity metadata unless explicitly enabled.
cwd: if Some, the spawned subprocess inherits this as its current
working directory; if None, the subprocess inherits the parent
process’s CWD. Callers driven through agent-block-core typically
pass BlockConfig.project_root so the MCP server sees the same
project root as the Lua script (matters for servers that rely on
path-based discovery such as git rev-parse --show-toplevel).
Sourcepub async fn list_tools(&self, name: &str) -> BlockResult<Value>
pub async fn list_tools(&self, name: &str) -> BlockResult<Value>
Call tools/list and return the tools as a JSON array.
Immutable receiver so concurrent readers can share an RwLock<McpManager>.
Sourcepub async fn call_tool(
&self,
name: &str,
tool_name: &str,
arguments: Value,
) -> BlockResult<Value>
pub async fn call_tool( &self, name: &str, tool_name: &str, arguments: Value, ) -> BlockResult<Value>
Call tools/call with the given tool name and arguments.
Returns the full rmcp CallToolResult serialized to JSON
({"content": [...], "isError": bool, ...}) on success, including
the isError flag — tool-execution errors are passed through to
the caller, following the MCP spec’s intent that the LLM sees them
and self-corrects. Only protocol / transport / timeout failures
surface as Err(BlockError::*).
arguments must be a JSON Object or Null. Null is treated as
“no arguments”; any other shape (array, scalar) returns an error
rather than silently dropping the payload.
Immutable receiver so concurrent readers can share an RwLock<McpManager>.
Sourcepub async fn disconnect(&mut self, name: &str) -> BlockResult<()>
pub async fn disconnect(&mut self, name: &str) -> BlockResult<()>
Cancel the named server and remove it from the manager.
The server is removed from the internal map before the cancel
round-trip begins, so a slow or failed cancel never leaves a
zombie entry behind. If graceful cancel exceeds rpc_timeout,
the service handle is dropped at the end of the match arm —
rmcp’s Drop impl cancels the peer’s cancellation token, which
terminates the internal task and closes the transport — and
BlockError::Timeout is returned.
The same rpc_timeout is reused here so callers have a single
knob governing every MCP round-trip (see with_rpc_timeout).
Callers may re-connect the same name safely after any outcome.
Sourcepub async fn disconnect_all(&mut self) -> BlockResult<()>
pub async fn disconnect_all(&mut self) -> BlockResult<()>
Cancel all managed servers.
Every server is disconnected regardless of individual failures.
The first error encountered is returned so shutdown can signal
a problem; subsequent errors are logged at warn level so
they are not silently discarded.
Sourcepub fn set_handler_isle(&mut self, isle: Arc<AsyncIsle>)
pub fn set_handler_isle(&mut self, isle: Arc<AsyncIsle>)
Wire the handler Isle into this manager’s AgentBlockClientHandler.
Must be called after both the McpManager and the AsyncIsle are
constructed. The handler Isle is used to dispatch Lua notification
callbacks (on_progress etc.) from the rmcp task thread.
Idempotent: a second call replaces the previous Isle reference.
Sourcepub fn set_main_isle(&mut self, isle: Arc<AsyncIsle>)
pub fn set_main_isle(&mut self, isle: Arc<AsyncIsle>)
Wire the main Isle into the shared AgentBlockClientHandler.
Must be called after construction and before connect / connect_http
so that progress/log notification dispatchers can call user Lua callbacks
stored in the main Isle’s globals (upvalue-safe path).
Also starts the bounded notification dispatch task (M-3: capacity-128 channel that prevents unbounded memory growth from chatty notification sources).
Idempotent: a second call replaces the previous Isle reference and restarts the dispatch task on the new channel.
Sourcepub async fn connect_http(
&mut self,
name: &str,
url: &str,
opts: Value,
) -> BlockResult<()>
pub async fn connect_http( &mut self, name: &str, url: &str, opts: Value, ) -> BlockResult<()>
Connect to an MCP server via Streamable HTTP transport.
opts may contain:
auth_header(string): bearer-token authentication header value.trace_context(bool): iftrue, inject__ab_obsobservability context intocall_toolarguments. Default:false(opt-in).
The handler Isle must be wired via set_handler_isle before calling
this method if on_progress callbacks are needed.
Sourcepub async fn list_resources(&self, name: &str) -> BlockResult<Value>
pub async fn list_resources(&self, name: &str) -> BlockResult<Value>
Call resources/list and return resources as a JSON array.
Immutable receiver — usable under RwLock::read alongside concurrent RPCs.
Sourcepub async fn list_resource_templates(&self, name: &str) -> BlockResult<Value>
pub async fn list_resource_templates(&self, name: &str) -> BlockResult<Value>
Call resources/templates/list and return resource templates as a JSON array.
Immutable receiver — usable under RwLock::read alongside concurrent RPCs.
Sourcepub async fn ping(&self, name: &str) -> BlockResult<u64>
pub async fn ping(&self, name: &str) -> BlockResult<u64>
Send a ping keepalive to the named server and return the round-trip
latency in milliseconds.
Uses send_request(ClientRequest::PingRequest(...)) — rmcp 1.4.0 has
no dedicated Peer::ping() method. Latency is measured with
Instant::now() immediately before the send and elapsed() immediately
after the EmptyResult is received (crux must_not_simplify).
Immutable receiver — usable under RwLock::read alongside concurrent RPCs.
Sourcepub async fn read_resource(&self, name: &str, uri: &str) -> BlockResult<Value>
pub async fn read_resource(&self, name: &str, uri: &str) -> BlockResult<Value>
Call resources/read and return the resource contents as JSON.
Immutable receiver — usable under RwLock::read.
Sourcepub async fn subscribe_resource(&self, name: &str, uri: &str) -> BlockResult<()>
pub async fn subscribe_resource(&self, name: &str, uri: &str) -> BlockResult<()>
Call resources/subscribe to subscribe to updates for the given URI.
Immutable receiver — usable under RwLock::read.
Sourcepub async fn unsubscribe_resource(
&self,
name: &str,
uri: &str,
) -> BlockResult<()>
pub async fn unsubscribe_resource( &self, name: &str, uri: &str, ) -> BlockResult<()>
Call resources/unsubscribe to stop receiving updates for the given URI.
Immutable receiver — usable under RwLock::read.
Sourcepub async fn list_prompts(&self, name: &str) -> BlockResult<Value>
pub async fn list_prompts(&self, name: &str) -> BlockResult<Value>
Call prompts/list and return prompts as a JSON array.
Immutable receiver — usable under RwLock::read.
Sourcepub async fn get_prompt(
&self,
name: &str,
prompt_name: &str,
args: Value,
) -> BlockResult<Value>
pub async fn get_prompt( &self, name: &str, prompt_name: &str, args: Value, ) -> BlockResult<Value>
Call prompts/get with the given prompt name and optional arguments.
args must be a JSON Object or Null. Immutable receiver.
Sourcepub async fn complete(
&self,
name: &str,
ref_json: Value,
arg_name: &str,
arg_value: &str,
) -> BlockResult<Value>
pub async fn complete( &self, name: &str, ref_json: Value, arg_name: &str, arg_value: &str, ) -> BlockResult<Value>
Call completion/complete with the given reference and argument.
ref_json must be a JSON Object with a type field of either
"ref/prompt" (with a name field) or "ref/resource" (with a uri
field). Any other type value is rejected with BlockError::Mcp.
CompletionContext is not exposed (scope-out per issue.md:51); it is
always sent as None. Immutable receiver — usable under RwLock::read.
Sourcepub fn server_info(&self, name: &str) -> BlockResult<Value>
pub fn server_info(&self, name: &str) -> BlockResult<Value>
Return the server’s InitializeResult serialized as JSON.
peer_info() is sync (no I/O). It returns Some after a successful
MCP handshake and None before initialization completes.
Immutable receiver — usable under RwLock::read.
Sourcepub fn send_cancelled(&self, name: &str, request_id: Option<i64>)
pub fn send_cancelled(&self, name: &str, request_id: Option<i64>)
Send a notifications/cancelled to the named server.
This is a best-effort fire-and-forget: the notification is spawned in a
separate task so the caller is not blocked waiting for transport ack.
Errors from the peer send are logged at warn level and discarded —
the MCP spec does not require the server to ack cancellations (fire-and-forget
by design; warn-level logging is intentional).
request_id is Some(id) when the caller has captured the rmcp-internal
request ID, or None when the ID is not available (e.g. a timeout fired
before the ID was obtained). When None the notification is skipped
entirely to avoid accidentally matching request ID 0 on a server that
allocates IDs starting from zero.
Sourcepub fn notify_roots_list_changed(&self, name: &str)
pub fn notify_roots_list_changed(&self, name: &str)
Notify the named server that the client’s roots list has changed.
Sends a notifications/roots/list_changed notification to the server as a
fire-and-forget operation. The server may respond by issuing a new
roots/list request.
§Arguments
name— the name of the server connection to notify.
§Errors
None propagated. Unknown server is logged at warn level and silently ignored. Send failures inside the spawned task are also logged at warn level and discarded.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for McpManager
impl !UnwindSafe for McpManager
impl Freeze for McpManager
impl Send for McpManager
impl Sync for McpManager
impl Unpin for McpManager
impl UnsafeUnpin for McpManager
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more