Repository navigation
auth: target MCP tokens by session and customization - #535
Merged
Connor Peet (connor4312) merged 2 commits intoOct 20, 2026
Merged
Conversation
Add an optional MCP server identity to authenticate requests and regenerate every client/schema mirror so hosts can route same-resource credentials independently. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace `AuthenticateParams.serverName` with an optional, extensible `target` discriminated union. The `mcpServer` variant identifies the consumer by session URI and `McpServerCustomization.id`, which clients echo from host-published state. A bare server name is not unique across sessions or manifests, and `authenticate` is a root-channel command. With a target, hosts MUST apply the token only to that MCP server in that session. Without one, resource/scope matching is unchanged. `kind` is @nonexhaustive so host-owned authentication (#404) can add variants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
roblourens
approved these changes
Oct 20, 2026
Connor Peet (connor4312)
deleted the
connor4312/mcp-authenticate-target
branch
October 20, 2026 19:07
Connor Peet (connor4312)
added a commit
to microsoft/vscode
that referenced
this pull request
Oct 20, 2026
* agentHost: send each MCP OAuth token only to its target server MCP servers that share an OAuth protected resource and scopes received the same token. The host gave the first token to all pending authentication requests for that resource, so a server could use the credential of a different account. This change uses the new optional AHP `authenticate.target` (microsoft/agent-host-protocol#535) to identify the server for each token. - Backport `AuthenticateTarget` and `AuthenticateParams.target` into the generated protocol copy. - Workbench: send `target` (host session URI and MCP customization ID) for each MCP token. Keep provider-level tokens untargeted. Send untargeted tokens when an older host gives no target. - Agent host: reject a target that does not identify an MCP server in an existing session. Keep targeted tokens in their own slots. Do not give them to agent-level resources or `getAuthToken`. Keep the target when tokens are replayed. - Copilot: give a targeted token only to the pending request of the target server in the owning session. - Codex: keep targeted tokens per session and server, and reconnect only that session. - Mission Control relay: do not use a targeted MCP token as the relay identity. - Copilot: show a server as ready after OAuth when its new connection loads tools. The runtime does not send a `connected` status change after an OAuth reconnect, so the server stayed in "starting". Fixes #342147 (Commit message generated by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: keep MCP OAuth sign-ins separate for each static client The workbench used one dynamic authentication provider for each authorization server and resource, and ignored the OAuth client ID. MCP servers with different static clients for the same resource used one provider. A sign-in with a different client removed the provider and its stored tokens, so a sign-in to one server signed out the other. After a reload, silent authentication did not find a token for that server. - Agent host MCP authentication: give each static OAuth client its own provider ID (`<legacy ID> client:<client ID>`). Use the legacy provider when its stored registration already has the same client, so existing sign-ins continue to work. - Do not remove a provider registration when a request uses a different client. Replace a registration only for the same client, for example when its secret changes. - Add an optional provider ID to `createDynamicAuthenticationProvider`, the provider host delegate, and `$registerDynamicAuthProvider`. The extension host provider then keeps its registration and tokens under that ID. Providers without a static client keep their IDs. Fixes #342147 Fixes #293533 (Commit message generated by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * agentHost: keep targeted MCP credentials separate for reconnect replay The protocol client keeps each accepted `authenticate` request to replay it after a reconnect. The replay cache used only the resource and scopes as its key. Targeted MCP tokens for servers that share these values replaced each other and the provider credential, and a revocation for one server removed the cached credential of another server. - Add the authentication target (kind, session, and customization ID) to the cache key. Keep the key for untargeted credentials unchanged. - Add a test that keeps the provider credential and a targeted credential when a different target is revoked. Fixes #342147 (Commit message generated by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #439.
Summary
Adds an optional, extensible
targettoAuthenticateParamsso a client can say which consumer a pushed token is for:When
targetis present, the host MUST apply the token only to that MCP server in that session, never to sibling servers, other sessions, or agent-level resources, even when they shareresourceand scopes. If the session or customization is unknown, or the customization is not an MCP server, the host rejects withInvalidParams. An empty token revokes only for that target. Withouttarget, resource/scope matching is unchanged, and older hosts ignore the field, so no capability or version bump is needed.Why
Two MCP servers can share one protected resource while using different OAuth clients or accounts (microsoft/vscode#342147: two Slack workspaces behind
https://mcp.slack.com). Todayauthenticatecarries only resource, scopes, and token, so the host applies the first token to every pending challenge for that resource, and one workspace's server ends up with the other's credential.#439 proposed a bare
serverName. That isn't unique across sessions or manifests, andauthenticateis a root-channel command. The session URI plus customization ID identifies the server exactly, and the client only echoes host-published values:McpServerAuthRequiredStatelives on the customization, andToolCallAuthRequiredState.contributor.customizationIdnames it.kindis@nonexhaustive, so host-owned authentication (#404) can add variants rather than new fields.Validation
npm run generate: passed.npm test: 567/568 passed. The one failure isscripts/no-redaction-marker.test.ts, which only flags files under the git-ignored localdocs/.vitepress/cache, no tracked files.cargo test -p ahp-types: passed.go build ./... && go test ./ahptypes/...: passed.swift build: passed../gradlew testineclipse-temurin:17-jdkvia podman: passed.