Merge branch 'wt/review-002-cov-deployment-knobs'
# Conflicts: # src/gateway/routes.rs
This commit is contained in:
@@ -581,3 +581,106 @@ async fn gateway_endpoints_exist_with_bearer_enforcement() {
|
||||
"unknown op is NOT_FOUND regardless of auth"
|
||||
);
|
||||
}
|
||||
|
||||
/// COV-11b: the rmcp-entered `ServerHandler::call_tool` routing shell is
|
||||
/// what production runs; the dispatch-level tests below it bypass it.
|
||||
/// One real rmcp-protocol `peer.call_tool` round-trip per gateway tool
|
||||
/// through the served `/mcp` mount.
|
||||
#[tokio::test]
|
||||
async fn to_mcp_call_tool_production_dispatch_round_trips_all_tools() {
|
||||
use rmcp::model::{CallToolRequestParams, ClientCapabilities, ClientInfo, Implementation};
|
||||
use rmcp::service::RoleClient;
|
||||
use rmcp::transport::streamable_http_client::{
|
||||
StreamableHttpClientTransport, StreamableHttpClientTransportConfig,
|
||||
};
|
||||
use rmcp::{Peer, ServiceExt};
|
||||
|
||||
let registry = local_registry();
|
||||
let provider = provider_with(vec![("tok-1", identity("alice", &["user"]))]);
|
||||
let base = spawn_full_server(registry, provider).await;
|
||||
|
||||
let mut default_headers = reqwest::header::HeaderMap::new();
|
||||
default_headers.insert(
|
||||
reqwest::header::AUTHORIZATION,
|
||||
reqwest::header::HeaderValue::from_static("Bearer tok-1"),
|
||||
);
|
||||
let http = reqwest::Client::builder()
|
||||
.default_headers(default_headers)
|
||||
.build()
|
||||
.unwrap();
|
||||
let url = format!("{base}/mcp");
|
||||
let transport = StreamableHttpClientTransport::with_client(
|
||||
http,
|
||||
StreamableHttpClientTransportConfig::with_uri(url),
|
||||
);
|
||||
let client_info = ClientInfo::new(
|
||||
ClientCapabilities::default(),
|
||||
Implementation::new("integration-test", "0.1.0"),
|
||||
);
|
||||
let running = client_info.serve(transport).await.expect("initialize");
|
||||
let peer: Peer<RoleClient> = running.peer().clone();
|
||||
|
||||
let schema_params = CallToolRequestParams::new("schema".to_string()).with_arguments(
|
||||
serde_json::json!({ "name": "echo/run" })
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.clone(),
|
||||
);
|
||||
let schema = peer.call_tool(schema_params).await.expect("schema call");
|
||||
assert_eq!(schema.is_error, Some(false));
|
||||
let structured = schema.structured_content.expect("structured present");
|
||||
assert_eq!(structured["name"], "echo/run");
|
||||
assert!(structured.get("input_schema").is_some());
|
||||
|
||||
let call_params = CallToolRequestParams::new("call".to_string()).with_arguments(
|
||||
serde_json::json!({ "operation": "echo/run", "input": { "v": 7 } })
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.clone(),
|
||||
);
|
||||
let call_result = peer.call_tool(call_params).await.expect("call call");
|
||||
assert_eq!(call_result.is_error, Some(false));
|
||||
assert_eq!(
|
||||
call_result.structured_content,
|
||||
Some(serde_json::json!({ "v": 7 }))
|
||||
);
|
||||
|
||||
let batch_params = CallToolRequestParams::new("batch".to_string()).with_arguments(
|
||||
serde_json::json!({ "calls": [
|
||||
{ "operation": "echo/run", "input": { "n": 1 } },
|
||||
{ "operation": "echo/run", "input": { "n": 2 } }
|
||||
] })
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.clone(),
|
||||
);
|
||||
let batch = peer.call_tool(batch_params).await.expect("batch call");
|
||||
assert_eq!(batch.is_error, Some(false));
|
||||
let results = batch
|
||||
.structured_content
|
||||
.and_then(|v| v.get("results").cloned())
|
||||
.expect("results array");
|
||||
assert_eq!(
|
||||
results,
|
||||
serde_json::json!([
|
||||
{ "isError": false, "output": { "n": 1 } },
|
||||
{ "isError": false, "output": { "n": 2 } }
|
||||
])
|
||||
);
|
||||
|
||||
let unknown = peer
|
||||
.call_tool(CallToolRequestParams::new("bogus".to_string()))
|
||||
.await
|
||||
.expect("unknown tool call resolves, not errors");
|
||||
assert_eq!(unknown.is_error, Some(true));
|
||||
let err = unknown
|
||||
.structured_content
|
||||
.expect("structured error present");
|
||||
assert_eq!(err["code"], "NOT_FOUND");
|
||||
assert!(err["message"]
|
||||
.as_str()
|
||||
.unwrap_or_default()
|
||||
.contains("unknown gateway tool"));
|
||||
|
||||
let _ = running.cancel().await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user