Route hook MCP calls through current connections (#39331)

## What changed

- Execute hook-triggered MCP calls through the runtime's latest connection set instead of preparing a separate catalog-bound call.
- Keep hook calls from waiting for server startup or reconnecting, and reject disconnected servers immediately.
- Apply the shorter of the hook-requested timeout and the server's configured tool timeout.

## Testing

- Update connection manager tests to cover non-waiting calls and disabled tool filters.

GitOrigin-RevId: 3166b2d1e26d9ae2b8b3a648b4d0897cc260eb93
This commit is contained in:
Abhinav
2026-08-19 01:15:10 +00:00
committed by copyberry
parent 67ed4e717a
commit d35e5495f9
8 changed files with 84 additions and 269 deletions
+10 -20
View File
@@ -45,7 +45,6 @@ use tokio_util::sync::CancellationToken;
use crate::McpConfig;
use crate::binding::McpBinding;
use crate::binding::PreparedMcpCall;
use crate::connection_manager::McpConnectionSet;
use crate::elicitation::ElicitationLifecycle;
use crate::elicitation::ElicitationRequestRouter;
@@ -409,24 +408,6 @@ impl McpRuntime {
Self::binding_from_published_runtime(current, /*required_servers*/ &[]).await
}
/// Prepares an exact MCP tool call only when its server is already connected.
///
/// Missing, disconnected, filtered, or uncataloged tools return `None` immediately rather
/// than starting a server, waiting for startup, initiating OAuth, or reconnecting. Successful
/// calls capture the live client, effective tool policy, and current catalog revision together.
pub async fn prepare_call_if_connected(
&self,
server: &str,
tool: &str,
) -> Option<PreparedMcpCall> {
let current = self.current.load_full();
let config = Arc::clone(current.config.as_ref()?);
current
.connections
.prepare_connected_call(config, server, tool)
.await
}
/// Returns the latest published configuration without waiting for clients.
pub fn current_config(&self) -> Option<Arc<McpConfig>> {
self.current.load().config.clone()
@@ -481,9 +462,18 @@ impl McpRuntime {
tool: &str,
arguments: Option<serde_json::Value>,
meta: Option<serde_json::Value>,
requested_timeout: Option<Duration>,
wait_for_server: bool,
) -> anyhow::Result<CallToolResult> {
self.latest_connections()
.call_tool(server, tool, arguments, meta)
.call_tool(
server,
tool,
arguments,
meta,
requested_timeout,
wait_for_server,
)
.await
}