Use thread connections for enterprise MCP status listings (#55394)

## Why

Enterprise-managed MCP authentication requires the thread's admitted connection. Bulk `mcpServerStatus/list` requests need to use that connection to report the enterprise server's catalog consistently with single-server requests.

## What changed

- Read enterprise server metadata from the thread runtime when listing all MCP servers, preserving ordinary server discovery.
- Check the expected server registration before discovery so edited or disabled registrations cannot reuse an old connection's catalog.

## Testing

Add coverage for bulk and single-server status consistency, catalog metadata, and registration changes. Extend enterprise authentication lifecycle tests to cover bearer renewal, grant replacement, and logout during a pending exchange. Add a scenario asserting that enterprise sign-in failure preserves ordinary MCP tool schemas, calls, and model history.

GitOrigin-RevId: 3bf3bd672511d0c753cd95ec777892f72bd6eb89
This commit is contained in:
jif
2026-10-19 22:02:44 +00:00
committed by copyberry
parent e645309723
commit 61fa059d49
8 changed files with 609 additions and 13 deletions
+8 -1
View File
@@ -7,6 +7,7 @@ use super::McpRuntimeContext;
use crate::McpConfig;
use crate::McpServerStatusSnapshot;
use crate::McpSnapshotDetail;
use crate::ResolvedMcpServer;
use crate::mcp::collect_mcp_server_status_snapshot_from_manager;
use crate::mcp::compute_auth_statuses;
use crate::mcp::effective_mcp_servers;
@@ -14,10 +15,12 @@ use crate::mcp::effective_mcp_servers;
impl McpRuntime {
/// Reuses the selected connection and catalog without starting unrelated servers.
/// Configuration and metadata belong to the same captured runtime publication.
/// An expected registration excludes mismatched connections before discovery.
pub async fn server_status_snapshot(
&self,
server: &str,
detail: McpSnapshotDetail,
expected_registration: Option<&ResolvedMcpServer>,
runtime_context: &McpRuntimeContext,
) -> anyhow::Result<(Arc<McpConfig>, McpServerStatusSnapshot)> {
let current = self.current.load_full();
@@ -32,7 +35,11 @@ impl McpRuntime {
.ok_or_else(|| anyhow::anyhow!("MCP runtime is not configured"))?,
);
let mut servers = effective_mcp_servers(&config, current.auth.as_ref());
servers.retain(|name, _| name == server);
servers.retain(|name, _| {
name == server
&& expected_registration
.is_none_or(|expected| config.mcp_server_catalog.server(name) == Some(expected))
});
let auth_statuses = compute_auth_statuses(
servers.iter(),
config.mcp_oauth_credentials_store_mode,