mirror of
https://github.com/openai/codex.git
synced 2026-11-10 21:00:47 +00:00
Expose deferred MCP servers in resource listings (#60423)
## Why Aggregate resource listings omitted dormant MCP servers, leaving callers without their names for explicit queries. ## What changed Include a sorted `deferredServers` list in aggregate `list_mcp_resources` and `list_mcp_resource_templates` results alongside resources from ready servers. Apply the listing filters to deferred servers and omit the field when empty. Discovery leaves dormant servers unstarted; callers can query them by passing `server` explicitly. ## Testing Extend the resource discovery scenario for direct calls and Code Mode to verify deferred server names, confirm discovery leaves the server unstarted, and then list and read resources by server name. GitOrigin-RevId: f95b8beb64bb1329f4ae3245e8c375614fcb3360
This commit is contained in:
@@ -5,6 +5,7 @@ use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use codex_mcp::McpResourceListing;
|
||||
use codex_protocol::items::McpToolCallError;
|
||||
use codex_protocol::items::McpToolCallItem;
|
||||
use codex_protocol::items::McpToolCallStatus;
|
||||
@@ -197,6 +198,8 @@ struct ListResourcesPayload {
|
||||
resources: Vec<ResourceWithServer<Resource>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
next_cursor: Option<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
deferred_servers: Vec<String>,
|
||||
}
|
||||
|
||||
impl ListResourcesPayload {
|
||||
@@ -205,14 +208,16 @@ impl ListResourcesPayload {
|
||||
resources: ResourceWithServer::from_server(&server, result.resources),
|
||||
server: Some(server),
|
||||
next_cursor: result.next_cursor,
|
||||
deferred_servers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_all_servers(resources_by_server: HashMap<String, Vec<Resource>>) -> Self {
|
||||
fn from_all_servers(listing: McpResourceListing<Resource>) -> Self {
|
||||
Self {
|
||||
server: None,
|
||||
resources: ResourceWithServer::from_all_servers(resources_by_server),
|
||||
resources: ResourceWithServer::from_all_servers(listing.by_server),
|
||||
next_cursor: None,
|
||||
deferred_servers: listing.deferred_servers,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,6 +230,8 @@ struct ListResourceTemplatesPayload {
|
||||
resource_templates: Vec<ResourceWithServer<ResourceTemplate>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
next_cursor: Option<String>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
deferred_servers: Vec<String>,
|
||||
}
|
||||
|
||||
impl ListResourceTemplatesPayload {
|
||||
@@ -233,14 +240,16 @@ impl ListResourceTemplatesPayload {
|
||||
resource_templates: ResourceWithServer::from_server(&server, result.resource_templates),
|
||||
server: Some(server),
|
||||
next_cursor: result.next_cursor,
|
||||
deferred_servers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_all_servers(templates_by_server: HashMap<String, Vec<ResourceTemplate>>) -> Self {
|
||||
fn from_all_servers(listing: McpResourceListing<ResourceTemplate>) -> Self {
|
||||
Self {
|
||||
server: None,
|
||||
resource_templates: ResourceWithServer::from_all_servers(templates_by_server),
|
||||
resource_templates: ResourceWithServer::from_all_servers(listing.by_server),
|
||||
next_cursor: None,
|
||||
deferred_servers: listing.deferred_servers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,10 @@ fn list_resources_payload_from_all_servers_is_sorted() {
|
||||
vec![resource("memo://a-1", "a-1"), resource("memo://a-2", "a-2")],
|
||||
);
|
||||
|
||||
let payload = ListResourcesPayload::from_all_servers(map);
|
||||
let payload = ListResourcesPayload::from_all_servers(McpResourceListing {
|
||||
by_server: map,
|
||||
deferred_servers: Vec::new(),
|
||||
});
|
||||
let value = serde_json::to_value(&payload).expect("serialize payload");
|
||||
let uris: Vec<String> = value["resources"]
|
||||
.as_array()
|
||||
@@ -132,7 +135,10 @@ fn list_resource_templates_payload_from_all_servers_is_sorted() {
|
||||
vec![template("memo://alpha/{id}", "alpha")],
|
||||
);
|
||||
|
||||
let payload = ListResourceTemplatesPayload::from_all_servers(templates_by_server);
|
||||
let payload = ListResourceTemplatesPayload::from_all_servers(McpResourceListing {
|
||||
by_server: templates_by_server,
|
||||
deferred_servers: Vec::new(),
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(payload).expect("serialize resource templates"),
|
||||
|
||||
Reference in New Issue
Block a user