From d797bf249f883b55623f36a76da6d35c4f317b73 Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Wed, 14 Oct 2026 21:11:48 +0000 Subject: [PATCH] fix(mcp): preserve confirmation compatibility across clients Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- apps/mcp/src/server/index.ts | 1 - apps/mcp/src/server/oauth-metadata.ts | 8 +------- apps/mcp/src/server/tools/add-memory.ts | 1 - apps/mcp/src/server/tools/forget-memory.ts | 12 +++++++----- apps/mcp/src/server/tools/output-schemas.ts | 2 +- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/apps/mcp/src/server/index.ts b/apps/mcp/src/server/index.ts index be520df9..c4cbeb3a 100644 --- a/apps/mcp/src/server/index.ts +++ b/apps/mcp/src/server/index.ts @@ -70,7 +70,6 @@ function resourceMetadata(c: Context<{ Bindings: Bindings }>) { const canonicalMetadataUrl = new URL( protectedResourceMetadataUrl(mcpResource), ) - // MCP clients also try the root well-known location as a compatibility fallback. const isMcpRootFallback = requestUrl.pathname === PROTECTED_RESOURCE_METADATA_PATH && requestUrl.search === "" diff --git a/apps/mcp/src/server/oauth-metadata.ts b/apps/mcp/src/server/oauth-metadata.ts index 73d8a01a..01ca5846 100644 --- a/apps/mcp/src/server/oauth-metadata.ts +++ b/apps/mcp/src/server/oauth-metadata.ts @@ -1,13 +1,7 @@ export const PROTECTED_RESOURCE_METADATA_PATH = "/.well-known/oauth-protected-resource" -/** - * Builds the protected-resource metadata URL advertised to OAuth clients. - * - * The canonical resource is the single source of truth so the advertised URL - * and the metadata document cannot disagree. Forwarded headers are intentionally - * excluded because they are request-controlled in some proxy deployments. - */ +// Discovery must use the configured resource, never request-controlled forwarding headers. export function protectedResourceMetadataUrl(resource: string): string { const resourceUrl = new URL(resource) const resourcePath = resourceUrl.pathname === "/" ? "" : resourceUrl.pathname diff --git a/apps/mcp/src/server/tools/add-memory.ts b/apps/mcp/src/server/tools/add-memory.ts index ff3f7f00..92e6b24f 100644 --- a/apps/mcp/src/server/tools/add-memory.ts +++ b/apps/mcp/src/server/tools/add-memory.ts @@ -10,7 +10,6 @@ import { forgetMemory } from "./forget-memory" import { addMemoryOutputSchema, type AddMemoryOutput } from "./output-schemas" import { textContent, type ToolDeps } from "./types" -// v5 metadata values are flat: string, number, boolean or string list. export const memoryMetadataSchema = z .record( z.string(), diff --git a/apps/mcp/src/server/tools/forget-memory.ts b/apps/mcp/src/server/tools/forget-memory.ts index 668e1021..feacef4a 100644 --- a/apps/mcp/src/server/tools/forget-memory.ts +++ b/apps/mcp/src/server/tools/forget-memory.ts @@ -28,15 +28,18 @@ export interface ForgetMemoryArgs { containerTag?: string } -// Only 2026-era requests carry capabilities per request; stateless legacy requests never saw initialize, so they use the confirm flag instead. +// Stateless legacy requests cannot receive elicitation, so they use explicit two-call confirmation. function canElicit(context: ServerContext | undefined): boolean { const envelope = context?.mcpReq?.envelope if (!envelope) return false const capabilities = Reflect.get(envelope, CLIENT_CAPABILITIES_META_KEY) + if (!capabilities || typeof capabilities !== "object") return false + const elicitation = Reflect.get(capabilities, "elicitation") return Boolean( - capabilities && - typeof capabilities === "object" && - Reflect.get(capabilities, "elicitation"), + elicitation && + typeof elicitation === "object" && + (Reflect.get(elicitation, "form") !== undefined || + Reflect.get(elicitation, "url") === undefined), ) } @@ -60,7 +63,6 @@ function askToConfirm( }, }), }, - // Only compared against the server-resolved ID, so a tampered value can just trigger a re-ask. requestState: candidate.id, }) } diff --git a/apps/mcp/src/server/tools/output-schemas.ts b/apps/mcp/src/server/tools/output-schemas.ts index 321fb9f4..f8074881 100644 --- a/apps/mcp/src/server/tools/output-schemas.ts +++ b/apps/mcp/src/server/tools/output-schemas.ts @@ -25,13 +25,13 @@ export const addMemoryOutputSchema = z.object({ message: z.string(), id: z.string().optional(), status: z.string().optional(), + memory: z.string().optional(), }) export type AddMemoryOutput = z.infer export const forgetMemoryOutputSchema = addMemoryOutputSchema.extend({ action: z.literal("forget"), - memory: z.string().optional(), }) export const getDocumentOutputSchema = z.object({