Preserve MCP registration scope across client operations (#61257)

## Why

MCP servers registered under the same name in different environments need distinct inventory, routing, and status reporting.

## What changed

- Keep MCP inventory and runtime status keyed by registration scope so same-named servers remain separate.
- Add optional `environmentId` selectors for status lookup, tool calls, resource reads, and OAuth login. Omitting the selector preserves existing name-only routing.
- Carry environment identity through startup notifications, elicitation requests, and tool-call history, and display it in the TUI.
- Support `/mcp login <name> --environment <id>` and update generated protocol schemas and SDK types.

## Testing

Add integration coverage for two environments with identically named MCP servers, tools, and resource URIs. Verify separate inventory, explicit environment routing, legacy routing when the selector is omitted, and errors for unknown environments. Update protocol and TUI tests for environment identity.

GitOrigin-RevId: 074a3db10549438cb6aff33eb7bed10791adae4d
This commit is contained in:
sayan-oai
2026-11-13 04:51:06 +00:00
committed by copyberry
parent 7eaaee4270
commit 6fcfa75a9f
190 changed files with 1821 additions and 502 deletions
@@ -2749,6 +2749,13 @@ class McpServerOauthLoginParams(BaseModel):
description="Registration strategy for this login only; omission selects automatic discovery.",
),
] = None
environment_id: Annotated[
str | None,
Field(
alias="environmentId",
description="Exact registration scope; omission preserves legacy name-only selection.",
),
] = None
name: str
scopes: list[str] | None = None
thread_id: Annotated[str | None, Field(alias="threadId")] = None
@@ -2795,6 +2802,13 @@ class McpServerStatusUpdatedNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
environment_id: Annotated[
str | None,
Field(
alias="environmentId",
description="Registration scope, not necessarily the server's execution environment.",
),
] = None
error: str | None = None
failure_reason: Annotated[
McpServerStartupFailureReason | None, Field(alias="failureReason")
@@ -2810,6 +2824,13 @@ class McpServerToolCallParams(BaseModel):
)
field_meta: Annotated[Any | None, Field(alias="_meta")] = None
arguments: Any | None = None
environment_id: Annotated[
str | None,
Field(
alias="environmentId",
description="Exact registration scope; omission preserves legacy name-only selection.",
),
] = None
server: str
thread_id: Annotated[str, Field(alias="threadId")]
tool: str
@@ -5775,6 +5796,13 @@ class McpToolCallThreadItem(BaseModel):
int | None,
Field(alias="durationMs", description="The duration of the MCP tool call in milliseconds."),
] = None
environment_id: Annotated[
str | None,
Field(
alias="environmentId",
description="Registration scope, not necessarily the server's execution environment.",
),
] = None
error: McpToolCallError | None = None
id: str
mcp_app_resource_uri: Annotated[
@@ -9358,6 +9386,13 @@ class ListMcpServerStatusParams(BaseModel):
description="Controls how much MCP inventory data to fetch for each server. Defaults to `Full` when omitted."
),
] = None
environment_id: Annotated[
str | None,
Field(
alias="environmentId",
description="Select this environment's registration. Requires `serverName` and `threadId`. When omitted, a named request uses the same server as older clients.",
),
] = None
limit: Annotated[
int | None,
Field(description="Optional page size; defaults to a server-defined value.", ge=0),
@@ -9417,6 +9452,13 @@ class McpResourceReadParams(BaseModel):
),
] = None
connector_id: Annotated[str | None, Field(alias="connectorId")] = None
environment_id: Annotated[
str | None,
Field(
alias="environmentId",
description="Exact registration scope; omission preserves legacy name-only selection.",
),
] = None
origin_call_id: Annotated[
str | None,
Field(
@@ -9452,6 +9494,13 @@ class McpServerStatus(BaseModel):
populate_by_name=True,
)
auth_status: Annotated[McpAuthStatus, Field(alias="authStatus")]
environment_id: Annotated[
str | None,
Field(
alias="environmentId",
description="Environment that contributed this registration; null for a thread-wide server. Older servers omit this field.",
),
] = None
http_origin: Annotated[
str | None,
Field(