feat(mcp): carry an absolute expiresAt on the OAuth authorization-url update - #2609
Conversation
… update The authenticate flow waits for the OAuth callback with a fixed budget, but the authorization-url tool update surfaced to embedding hosts did not say when that window ends — hosts had to hardcode a mirror of the 15-minute constant to render countdowns. Include the absolute deadline (now + effective wait timeout) in the update payload for v1 and v2. Resolve MoonshotAI#2607
|
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bf4ec99d3d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| export interface McpOAuthAuthorizationUrlUpdateData { | ||
| readonly serverName: string; | ||
| readonly authorizationUrl: string; | ||
| /** | ||
| * Epoch-ms instant when the engine stops waiting for the OAuth callback. | ||
| * Hosts derive countdowns and expiry states from this value instead of | ||
| * mirroring the engine-side timeout constant. | ||
| */ | ||
| readonly expiresAt?: number; |
There was a problem hiding this comment.
Update the OAuth update schema to carry
expiresAt
Adding expiresAt to the TypeScript interface is not enough here: the exported mcpOAuthAuthorizationUrlUpdateDataSchema in this file, and the mirrored copy in packages/kap-server/src/protocol/events-zod.ts, still only accept serverName and authorizationUrl. Any consumer that validates the custom update through the official schema will silently strip the new deadline, so hosts never receive the data needed to render the countdown/expired state promised by this change.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch — the interface change alone would have been stripped at the validation boundary. Fixed in a46bc76: both schema copies (protocol/src/events.ts and the kap-server mirror) now accept expiresAt: z.number().optional().
…-url update schemas The zod validators mirrored the pre-expiresAt payload shape and would strip the new field at the kap-server boundary.
… update (MoonshotAI#2609) * feat(mcp): carry an absolute expiresAt on the OAuth authorization-url update The authenticate flow waits for the OAuth callback with a fixed budget, but the authorization-url tool update surfaced to embedding hosts did not say when that window ends — hosts had to hardcode a mirror of the 15-minute constant to render countdowns. Include the absolute deadline (now + effective wait timeout) in the update payload for v1 and v2. Resolve MoonshotAI#2607 * fix(protocol,kap-server): accept expiresAt in the OAuth authorization-url update schemas The zod validators mirrored the pre-expiresAt payload shape and would strip the new field at the kap-server boundary. --------- Co-authored-by: zouying <zouying@moonshot.cn>
… update (MoonshotAI#2609) * feat(mcp): carry an absolute expiresAt on the OAuth authorization-url update The authenticate flow waits for the OAuth callback with a fixed budget, but the authorization-url tool update surfaced to embedding hosts did not say when that window ends — hosts had to hardcode a mirror of the 15-minute constant to render countdowns. Include the absolute deadline (now + effective wait timeout) in the update payload for v1 and v2. Resolve MoonshotAI#2607 * fix(protocol,kap-server): accept expiresAt in the OAuth authorization-url update schemas The zod validators mirrored the pre-expiresAt payload shape and would strip the new field at the kap-server boundary. --------- Co-authored-by: zouying <zouying@moonshot.cn>
Related Issue
Resolve #2607
Problem
See linked issue: the
authenticateflow waits for the OAuth callback with a fixed budget (DEFAULT_AUTH_TIMEOUT_MS = 15 min), but themcp.oauth.authorization_urltool update surfaced to embedding hosts carries only{serverName, authorizationUrl}. A host that wants to render a countdown or an expired state has to hardcode its own mirror of the 15-minute constant and count from event receipt — a mirror that drifts with transport latency and silently breaks if the engine-side default ever changes.What changed
packages/protocol/src/events.ts:McpOAuthAuthorizationUrlUpdateDatagains an optionalexpiresAt?: number(epoch ms) — the instant the engine stops waiting for the callback. Optional and additive, so existing consumers are unaffected.packages/agent-core/src/mcp/auth-tool.tsand v2packages/agent-core-v2/src/agent/mcp/tools/auth.ts: the update payload includesexpiresAt = now + effective wait timeout, computed from the same value later passed toflow.complete(so an overriddentimeoutMsstays consistent with the advertised deadline).No changeset: an additive optional field on an internal event payload; no user-visible CLI behavior changes.
Verification
Updated the v1/v2 auth-tool tests: the update still matches on
serverName/authorizationUrl, andexpiresAtis asserted to lie between now and now + 15 min.tsc --noEmitpasses forprotocol,agent-core, andagent-core-v2;oxlintclean; both auth-tool suites pass (5 tests each).