mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Expose plugin ownership in MCP server status (#37850)
## What changed - Add `pluginId` to each `mcpServerStatus/list` result. - Populate it for MCP servers contributed by installed or selected plugins, and return `null` for servers from other sources. - Update the generated protocol schemas, TypeScript bindings, and app-server documentation. ## Testing - Cover plugin-owned servers in plugin installation and executor flows. - Verify non-plugin servers and protocol serialization return a null `pluginId`. GitOrigin-RevId: 0e4b912252cf51be56dcb63e0c1c7365a5e870ee
This commit is contained in:
1 parent
97729885d4
commit
78d3665d15
16 files changed
+107
-33
No files matched your search
+6
@@ -13227,6 +13227,12 @@
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"pluginId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
"resourceTemplates": {
|
"resourceTemplates": {
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/v2/ResourceTemplate"
|
"$ref": "#/definitions/v2/ResourceTemplate"
|
||||||
|
|||||||
+6
@@ -9564,6 +9564,12 @@
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"pluginId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
"resourceTemplates": {
|
"resourceTemplates": {
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/ResourceTemplate"
|
"$ref": "#/definitions/ResourceTemplate"
|
||||||
|
|||||||
@@ -60,6 +60,12 @@
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"pluginId": {
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
},
|
||||||
"resourceTemplates": {
|
"resourceTemplates": {
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/ResourceTemplate"
|
"$ref": "#/definitions/ResourceTemplate"
|
||||||
|
|||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -7,4 +7,4 @@ import type { ResourceTemplate } from "../ResourceTemplate";
|
|||||||
import type { Tool } from "../Tool";
|
import type { Tool } from "../Tool";
|
||||||
import type { McpAuthStatus } from "./McpAuthStatus";
|
import type { McpAuthStatus } from "./McpAuthStatus";
|
||||||
|
|
||||||
export type McpServerStatus = { name: string, serverInfo: McpServerInfo | null, tools: { [key in string]?: Tool }, resources: Array<Resource>, resourceTemplates: Array<ResourceTemplate>, authStatus: McpAuthStatus, };
|
export type McpServerStatus = { name: string, pluginId: string | null, serverInfo: McpServerInfo | null, tools: { [key in string]?: Tool }, resources: Array<Resource>, resourceTemplates: Array<ResourceTemplate>, authStatus: McpAuthStatus, };
|
||||||
@@ -61,6 +61,7 @@ pub enum McpServerStatusDetail {
|
|||||||
#[ts(export_to = "v2/")]
|
#[ts(export_to = "v2/")]
|
||||||
pub struct McpServerStatus {
|
pub struct McpServerStatus {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub plugin_id: Option<String>,
|
||||||
pub server_info: Option<McpServerInfo>,
|
pub server_info: Option<McpServerInfo>,
|
||||||
pub tools: std::collections::HashMap<String, McpTool>,
|
pub tools: std::collections::HashMap<String, McpTool>,
|
||||||
pub resources: Vec<McpResource>,
|
pub resources: Vec<McpResource>,
|
||||||
|
|||||||
@@ -2422,6 +2422,7 @@ fn mcp_server_status_serializes_absent_server_info_as_null() {
|
|||||||
let response = ListMcpServerStatusResponse {
|
let response = ListMcpServerStatusResponse {
|
||||||
data: vec![McpServerStatus {
|
data: vec![McpServerStatus {
|
||||||
name: "not-ready".to_string(),
|
name: "not-ready".to_string(),
|
||||||
|
plugin_id: None,
|
||||||
server_info: None,
|
server_info: None,
|
||||||
tools: HashMap::new(),
|
tools: HashMap::new(),
|
||||||
resources: Vec::new(),
|
resources: Vec::new(),
|
||||||
@@ -2436,6 +2437,7 @@ fn mcp_server_status_serializes_absent_server_info_as_null() {
|
|||||||
json!({
|
json!({
|
||||||
"data": [{
|
"data": [{
|
||||||
"name": "not-ready",
|
"name": "not-ready",
|
||||||
|
"pluginId": null,
|
||||||
"serverInfo": null,
|
"serverInfo": null,
|
||||||
"tools": {},
|
"tools": {},
|
||||||
"resources": [],
|
"resources": [],
|
||||||
@@ -2507,6 +2509,7 @@ fn mcp_server_status_serializes_absent_server_info_metadata_as_null() {
|
|||||||
let response = ListMcpServerStatusResponse {
|
let response = ListMcpServerStatusResponse {
|
||||||
data: vec![McpServerStatus {
|
data: vec![McpServerStatus {
|
||||||
name: "initialized".to_string(),
|
name: "initialized".to_string(),
|
||||||
|
plugin_id: Some("lookup@test".to_string()),
|
||||||
server_info: Some(McpServerInfo {
|
server_info: Some(McpServerInfo {
|
||||||
name: "lookup-server".to_string(),
|
name: "lookup-server".to_string(),
|
||||||
title: None,
|
title: None,
|
||||||
@@ -2528,6 +2531,7 @@ fn mcp_server_status_serializes_absent_server_info_metadata_as_null() {
|
|||||||
json!({
|
json!({
|
||||||
"data": [{
|
"data": [{
|
||||||
"name": "initialized",
|
"name": "initialized",
|
||||||
|
"pluginId": "lookup@test",
|
||||||
"serverInfo": {
|
"serverInfo": {
|
||||||
"name": "lookup-server",
|
"name": "lookup-server",
|
||||||
"title": null,
|
"title": null,
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ Example with notification opt-out:
|
|||||||
- `mcpServer/oauth/login` — start an OAuth login for a configured MCP server; pass `threadId` to resolve servers from that thread's selected plugins and executor, and receive an `authorization_url` followed by `mcpServer/oauthLogin/completed` once the browser flow finishes.
|
- `mcpServer/oauth/login` — start an OAuth login for a configured MCP server; pass `threadId` to resolve servers from that thread's selected plugins and executor, and receive an `authorization_url` followed by `mcpServer/oauthLogin/completed` once the browser flow finishes.
|
||||||
- `tool/requestUserInput` — prompt the user with 1–3 short questions for a tool call and return their answers (experimental).
|
- `tool/requestUserInput` — prompt the user with 1–3 short questions for a tool call and return their answers (experimental).
|
||||||
- `config/mcpServer/reload` — reload MCP server config from disk and queue a refresh for loaded threads (applied on each thread's next active turn); returns `{}`. Use this after editing `config.toml` without restarting the server.
|
- `config/mcpServer/reload` — reload MCP server config from disk and queue a refresh for loaded threads (applied on each thread's next active turn); returns `{}`. Use this after editing `config.toml` without restarting the server.
|
||||||
- `mcpServerStatus/list` — enumerate configured MCP servers with their tools, auth status, server info, plus resources/resource templates for `full` detail; supports optional `threadId` and cursor+limit pagination. If `threadId` is omitted, the server reads from the latest global config directly. If `detail` is omitted, the server defaults to `full`. An `unknown` auth status means OAuth support could not be determined; `unsupported` means OAuth is known not to be supported.
|
- `mcpServerStatus/list` — enumerate configured MCP servers with their tools, auth status, server info, owning `pluginId` (`null` for servers not contributed by a plugin), plus resources/resource templates for `full` detail; supports optional `threadId` and cursor+limit pagination. If `threadId` is omitted, the server reads from the latest global config directly. If `detail` is omitted, the server defaults to `full`. An `unknown` auth status means OAuth support could not be determined; `unsupported` means OAuth is known not to be supported.
|
||||||
- `mcpServer/resource/read` — read a resource from a configured MCP server by optional `threadId`, `server`, and `uri`, returning text/blob resource `contents`. If `threadId` is omitted, the server reads from the latest MCP config directly.
|
- `mcpServer/resource/read` — read a resource from a configured MCP server by optional `threadId`, `server`, and `uri`, returning text/blob resource `contents`. If `threadId` is omitted, the server reads from the latest MCP config directly.
|
||||||
- `mcpServer/tool/call` — call a tool on a thread's configured MCP server by `threadId`, `server`, `tool`, optional `arguments`, and optional `_meta`, returning the MCP tool result.
|
- `mcpServer/tool/call` — call a tool on a thread's configured MCP server by `threadId`, `server`, `tool`, optional `arguments`, and optional `_meta`, returning the MCP tool result.
|
||||||
- `windowsSandbox/setupStart` — start Windows sandbox setup for the selected mode (`elevated` or `unelevated`); accepts an optional absolute `cwd` to target setup for a specific workspace, returns `{ started: true }` immediately, and later emits `windowsSandbox/setupCompleted`.
|
- `windowsSandbox/setupStart` — start Windows sandbox setup for the selected mode (`elevated` or `unelevated`); accepts an optional absolute `cwd` to target setup for a specific workspace, returns `{ started: true }` immediately, and later emits `windowsSandbox/setupCompleted`.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use codex_core::McpManager;
|
use codex_core::McpManager;
|
||||||
|
use codex_mcp::McpServerSource;
|
||||||
|
|
||||||
const MCP_TOOL_THREAD_ID_META_KEY: &str = "threadId";
|
const MCP_TOOL_THREAD_ID_META_KEY: &str = "threadId";
|
||||||
|
|
||||||
@@ -374,6 +375,17 @@ impl McpRequestProcessor {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|name| McpServerStatus {
|
.map(|name| McpServerStatus {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
|
plugin_id: mcp_config.mcp_server_catalog.server(name).and_then(
|
||||||
|
|server| match server.source() {
|
||||||
|
McpServerSource::Plugin(plugin)
|
||||||
|
| McpServerSource::SelectedPlugin(plugin) => {
|
||||||
|
Some(plugin.plugin_id().to_owned())
|
||||||
|
}
|
||||||
|
McpServerSource::Config
|
||||||
|
| McpServerSource::Compatibility { .. }
|
||||||
|
| McpServerSource::Extension { .. } => None,
|
||||||
|
},
|
||||||
|
),
|
||||||
server_info: server_infos.get(name).cloned(),
|
server_info: server_infos.get(name).cloned(),
|
||||||
tools: tools_by_server.get(name).cloned().unwrap_or_default(),
|
tools: tools_by_server.get(name).cloned().unwrap_or_default(),
|
||||||
resources: resources.get(name).cloned().unwrap_or_default(),
|
resources: resources.get(name).cloned().unwrap_or_default(),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use codex_app_server_protocol::ListMcpServerStatusParams;
|
|||||||
use codex_app_server_protocol::ListMcpServerStatusResponse;
|
use codex_app_server_protocol::ListMcpServerStatusResponse;
|
||||||
use codex_app_server_protocol::McpServerOauthLoginCompletedNotification;
|
use codex_app_server_protocol::McpServerOauthLoginCompletedNotification;
|
||||||
use codex_app_server_protocol::McpServerOauthLoginResponse;
|
use codex_app_server_protocol::McpServerOauthLoginResponse;
|
||||||
|
use codex_app_server_protocol::McpServerStatus;
|
||||||
use codex_app_server_protocol::McpServerToolCallParams;
|
use codex_app_server_protocol::McpServerToolCallParams;
|
||||||
use codex_app_server_protocol::McpServerToolCallResponse;
|
use codex_app_server_protocol::McpServerToolCallResponse;
|
||||||
use codex_app_server_protocol::RequestId;
|
use codex_app_server_protocol::RequestId;
|
||||||
@@ -40,6 +41,7 @@ use rmcp::transport::StreamableHttpService;
|
|||||||
use rmcp::transport::streamable_http_server::session::local::LocalSessionManager;
|
use rmcp::transport::streamable_http_server::session::local::LocalSessionManager;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
@@ -447,26 +449,37 @@ startup_timeout_sec = 10
|
|||||||
Some(json!("ECHOING: refresh applied"))
|
Some(json!("ECHOING: refresh applied"))
|
||||||
);
|
);
|
||||||
|
|
||||||
let selected_server_names = mcp_server_names(&mut app_server, selected_thread).await?;
|
let selected_server_owners = mcp_server_statuses(&mut app_server, selected_thread)
|
||||||
assert!(
|
.await?
|
||||||
selected_server_names
|
.into_iter()
|
||||||
.iter()
|
.map(|server| (server.name, server.plugin_id))
|
||||||
.any(|name| name == MCP_SERVER_NAME)
|
.collect::<BTreeMap<_, _>>();
|
||||||
);
|
assert_eq!(
|
||||||
assert!(
|
selected_server_owners,
|
||||||
selected_server_names
|
BTreeMap::from([
|
||||||
.iter()
|
(
|
||||||
.any(|name| name == HTTP_MCP_SERVER_NAME)
|
HTTP_MCP_SERVER_NAME.to_string(),
|
||||||
);
|
Some("executor-demo@1".to_string()),
|
||||||
assert!(
|
),
|
||||||
selected_server_names
|
(
|
||||||
.iter()
|
MCP_SERVER_NAME.to_string(),
|
||||||
.any(|name| name == OAUTH_MCP_SERVER_NAME)
|
Some("executor-demo@1".to_string()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
OAUTH_MCP_SERVER_NAME.to_string(),
|
||||||
|
Some("executor-demo@1".to_string()),
|
||||||
|
),
|
||||||
|
(REFRESH_PROBE_SERVER_NAME.to_string(), None),
|
||||||
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
let unselected_thread =
|
let unselected_thread =
|
||||||
start_thread(&mut app_server, /*selected_capability_roots*/ None).await?;
|
start_thread(&mut app_server, /*selected_capability_roots*/ None).await?;
|
||||||
let unselected_server_names = mcp_server_names(&mut app_server, unselected_thread).await?;
|
let unselected_server_names = mcp_server_statuses(&mut app_server, unselected_thread)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|server| server.name)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
assert!(unselected_server_names.iter().all(|name| {
|
assert!(unselected_server_names.iter().all(|name| {
|
||||||
name != MCP_SERVER_NAME && name != HTTP_MCP_SERVER_NAME && name != OAUTH_MCP_SERVER_NAME
|
name != MCP_SERVER_NAME && name != HTTP_MCP_SERVER_NAME && name != OAUTH_MCP_SERVER_NAME
|
||||||
}));
|
}));
|
||||||
@@ -525,10 +538,10 @@ impl ServerHandler for ExecutorHttpMcpServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn mcp_server_names(
|
async fn mcp_server_statuses(
|
||||||
app_server: &mut TestAppServer,
|
app_server: &mut TestAppServer,
|
||||||
thread_id: String,
|
thread_id: String,
|
||||||
) -> Result<Vec<String>> {
|
) -> Result<Vec<McpServerStatus>> {
|
||||||
let request_id = app_server
|
let request_id = app_server
|
||||||
.send_list_mcp_server_status_request(ListMcpServerStatusParams {
|
.send_list_mcp_server_status_request(ListMcpServerStatusParams {
|
||||||
cursor: None,
|
cursor: None,
|
||||||
@@ -539,11 +552,7 @@ async fn mcp_server_names(
|
|||||||
.await?;
|
.await?;
|
||||||
let response: ListMcpServerStatusResponse =
|
let response: ListMcpServerStatusResponse =
|
||||||
timeout(DEFAULT_READ_TIMEOUT, app_server.read_response(request_id)).await??;
|
timeout(DEFAULT_READ_TIMEOUT, app_server.read_response(request_id)).await??;
|
||||||
Ok(response
|
Ok(response.data)
|
||||||
.data
|
|
||||||
.into_iter()
|
|
||||||
.map(|server| server.name)
|
|
||||||
.collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_thread(
|
async fn start_thread(
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ async fn mcp_server_status_list_returns_raw_server_and_tool_names() -> Result<()
|
|||||||
assert_eq!(response.data.len(), 1);
|
assert_eq!(response.data.len(), 1);
|
||||||
let status = &response.data[0];
|
let status = &response.data[0];
|
||||||
assert_eq!(status.name, "some-server");
|
assert_eq!(status.name, "some-server");
|
||||||
|
assert_eq!(status.plugin_id, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
status.tools.keys().cloned().collect::<BTreeSet<_>>(),
|
status.tools.keys().cloned().collect::<BTreeSet<_>>(),
|
||||||
BTreeSet::from(["look-up.raw".to_string()])
|
BTreeSet::from(["look-up.raw".to_string()])
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ use codex_app_server_protocol::AppInfo;
|
|||||||
use codex_app_server_protocol::AppSummary;
|
use codex_app_server_protocol::AppSummary;
|
||||||
use codex_app_server_protocol::AppsListParams;
|
use codex_app_server_protocol::AppsListParams;
|
||||||
use codex_app_server_protocol::AppsListResponse;
|
use codex_app_server_protocol::AppsListResponse;
|
||||||
|
use codex_app_server_protocol::ListMcpServerStatusParams;
|
||||||
|
use codex_app_server_protocol::ListMcpServerStatusResponse;
|
||||||
use codex_app_server_protocol::PluginAuthPolicy;
|
use codex_app_server_protocol::PluginAuthPolicy;
|
||||||
use codex_app_server_protocol::PluginAvailability;
|
use codex_app_server_protocol::PluginAvailability;
|
||||||
use codex_app_server_protocol::PluginInstallParams;
|
use codex_app_server_protocol::PluginInstallParams;
|
||||||
@@ -32,6 +34,7 @@ use codex_app_server_protocol::PluginInstallResponse;
|
|||||||
use codex_app_server_protocol::RequestId;
|
use codex_app_server_protocol::RequestId;
|
||||||
use codex_config::types::AuthCredentialsStoreMode;
|
use codex_config::types::AuthCredentialsStoreMode;
|
||||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||||
|
use core_test_support::stdio_server_bin;
|
||||||
use flate2::Compression;
|
use flate2::Compression;
|
||||||
use flate2::write::GzEncoder;
|
use flate2::write::GzEncoder;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
@@ -2264,13 +2267,13 @@ async fn plugin_install_makes_bundled_mcp_servers_available_to_followup_requests
|
|||||||
write_plugin_source(repo_root.path(), "sample-plugin", &[])?;
|
write_plugin_source(repo_root.path(), "sample-plugin", &[])?;
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
repo_root.path().join("sample-plugin/.mcp.json"),
|
repo_root.path().join("sample-plugin/.mcp.json"),
|
||||||
r#"{
|
serde_json::to_vec(&json!({
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"sample-mcp": {
|
"sample-mcp": {
|
||||||
"command": "echo"
|
"command": stdio_server_bin()?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}"#,
|
}))?,
|
||||||
)?;
|
)?;
|
||||||
let marketplace_path =
|
let marketplace_path =
|
||||||
AbsolutePathBuf::try_from(repo_root.path().join(".agents/plugins/marketplace.json"))?;
|
AbsolutePathBuf::try_from(repo_root.path().join(".agents/plugins/marketplace.json"))?;
|
||||||
@@ -2294,7 +2297,28 @@ async fn plugin_install_makes_bundled_mcp_servers_available_to_followup_requests
|
|||||||
assert_eq!(response.apps_needing_auth, Vec::<AppSummary>::new());
|
assert_eq!(response.apps_needing_auth, Vec::<AppSummary>::new());
|
||||||
let config = std::fs::read_to_string(codex_home.path().join("config.toml"))?;
|
let config = std::fs::read_to_string(codex_home.path().join("config.toml"))?;
|
||||||
assert!(!config.contains("[mcp_servers.sample-mcp]"));
|
assert!(!config.contains("[mcp_servers.sample-mcp]"));
|
||||||
assert!(!config.contains("command = \"echo\""));
|
|
||||||
|
let request_id = mcp
|
||||||
|
.send_list_mcp_server_status_request(ListMcpServerStatusParams {
|
||||||
|
cursor: None,
|
||||||
|
limit: None,
|
||||||
|
detail: None,
|
||||||
|
thread_id: None,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
let response: ListMcpServerStatusResponse =
|
||||||
|
timeout(DEFAULT_TIMEOUT, mcp.read_response(request_id)).await??;
|
||||||
|
assert_eq!(
|
||||||
|
response
|
||||||
|
.data
|
||||||
|
.into_iter()
|
||||||
|
.map(|server| (server.name, server.plugin_id))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
vec![(
|
||||||
|
"sample-mcp".to_string(),
|
||||||
|
Some("sample-plugin@debug".to_string()),
|
||||||
|
)]
|
||||||
|
);
|
||||||
|
|
||||||
let request_id = mcp
|
let request_id = mcp
|
||||||
.send_raw_request(
|
.send_raw_request(
|
||||||
|
|||||||
@@ -1443,6 +1443,7 @@ mod tests {
|
|||||||
let statuses = vec![
|
let statuses = vec![
|
||||||
McpServerStatus {
|
McpServerStatus {
|
||||||
name: "docs".to_string(),
|
name: "docs".to_string(),
|
||||||
|
plugin_id: None,
|
||||||
server_info: None,
|
server_info: None,
|
||||||
tools: HashMap::from([(
|
tools: HashMap::from([(
|
||||||
"list".to_string(),
|
"list".to_string(),
|
||||||
@@ -1463,6 +1464,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
McpServerStatus {
|
McpServerStatus {
|
||||||
name: "disabled".to_string(),
|
name: "disabled".to_string(),
|
||||||
|
plugin_id: None,
|
||||||
server_info: None,
|
server_info: None,
|
||||||
tools: HashMap::new(),
|
tools: HashMap::new(),
|
||||||
resources: Vec::new(),
|
resources: Vec::new(),
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ async fn handle_mcp_inventory_result_respects_origin_thread() {
|
|||||||
app.handle_mcp_inventory_result(
|
app.handle_mcp_inventory_result(
|
||||||
Ok(vec![McpServerStatus {
|
Ok(vec![McpServerStatus {
|
||||||
name: "docs".to_string(),
|
name: "docs".to_string(),
|
||||||
|
plugin_id: None,
|
||||||
server_info: None,
|
server_info: None,
|
||||||
tools: HashMap::new(),
|
tools: HashMap::new(),
|
||||||
resources: Vec::new(),
|
resources: Vec::new(),
|
||||||
|
|||||||
@@ -964,6 +964,7 @@ async fn mcp_tools_output_lists_tools_for_hyphenated_server_names() {
|
|||||||
fn mcp_tools_output_from_statuses_renders_status_only_servers() {
|
fn mcp_tools_output_from_statuses_renders_status_only_servers() {
|
||||||
let statuses = vec![McpServerStatus {
|
let statuses = vec![McpServerStatus {
|
||||||
name: "plugin_docs".to_string(),
|
name: "plugin_docs".to_string(),
|
||||||
|
plugin_id: None,
|
||||||
server_info: None,
|
server_info: None,
|
||||||
tools: HashMap::from([(
|
tools: HashMap::from([(
|
||||||
"lookup".to_string(),
|
"lookup".to_string(),
|
||||||
@@ -994,6 +995,7 @@ fn mcp_tools_output_from_statuses_renders_status_only_servers() {
|
|||||||
fn mcp_tools_output_from_statuses_renders_verbose_inventory() {
|
fn mcp_tools_output_from_statuses_renders_verbose_inventory() {
|
||||||
let statuses = vec![McpServerStatus {
|
let statuses = vec![McpServerStatus {
|
||||||
name: "plugin_docs".to_string(),
|
name: "plugin_docs".to_string(),
|
||||||
|
plugin_id: None,
|
||||||
server_info: None,
|
server_info: None,
|
||||||
tools: HashMap::from([(
|
tools: HashMap::from([(
|
||||||
"lookup".to_string(),
|
"lookup".to_string(),
|
||||||
|
|||||||
Reference in new issue
Block a user