github/copilot-sdk · warning

Received MCP OAuth request without a registered MCP auth…

Error message

Received MCP OAuth request without a registered MCP auth handler. SessionId=${this.sessionId}, RequestId=${data.requestId}

What it means

When the server emits an mcp.oauth_required event, CopilotSession needs a registered MCP auth handler to perform the OAuth flow and respond. If this.mcpAuthHandler is not set, the session logs this warning and drops the request, so the MCP tool that requires OAuth will remain unauthenticated and likely fail on subsequent calls.

Solutions

  1. Register an MCP auth handler on the session before starting it (the callback receives the McpAuthRequest and must complete the OAuth flow and respond).
  2. If no MCP OAuth usage is intended, ensure the connected MCP servers are configured with pre-provisioned credentials so no oauth_required event is emitted.
  3. Check that the handler registration happens before any events are processed - registering after the event is lost does not help; re-issue the MCP request.
  4. Inspect data.requestId in the logs to identify which MCP server triggered the flow.

Example fix

// before
const session = new CopilotSession({ /* no mcpAuthHandler */ });
// after
const session = new CopilotSession({
  mcpAuthHandler: async (request) => {
    const token = await myOAuthFlow(request);
    return { accessToken: token };
  }
});
Defensive patterns

Strategy: fallback

Validate before calling

if (typeof session.getMcpAuthHandler?.() !== 'function') {
  throw new Error('MCP auth handler must be registered before handling oauth_required events');
}

Type guard

function hasMcpAuthHandler(s: CopilotSession): boolean {
  return typeof (s as { mcpAuthHandler?: unknown }).mcpAuthHandler === 'function';
}

Try / catch

session.onMcpAuthRequest?.(async (data) => {
  if (!data?.requestId) return;
  try {
    const token = await performOAuth(data);
    await respondWithToken(data.requestId, token);
  } catch (err) {
    console.error('MCP OAuth flow failed', err);
  }
});

Prevention

When it happens

Trigger: A session event stream delivers an mcp.oauth_required event (with a requestId) while the application never registered a handler via the MCP auth handler registration API on CopilotSession.

Common situations: Using MCP servers that require OAuth without wiring an auth handler; upgrading the library where MCP OAuth support was added and not updating session setup; test harnesses that construct CopilotSession without full MCP configuration.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/2544ba6c87500866. Report an issue: GitHub.

Appendix: source

Thrown at nodejs/src/session.ts:1033

        } else if (event.type === "permission.requested") {
            const { requestId, permissionRequest, resolvedByHook } = event.data as {
                requestId: string;
                permissionRequest: PermissionRequest;
                resolvedByHook?: boolean;
            };
            if (resolvedByHook) {
                return; // Already resolved by a permissionRequest hook; no client action needed.
            }
            if (this.permissionHandler) {
                void this._executePermissionAndRespond(requestId, permissionRequest);
            }
        } else if (event.type === "mcp.oauth_required") {
            const data = event.data as McpAuthRequest | undefined;
            if (!data?.requestId) {
                return;
            }
            if (!this.mcpAuthHandler) {
                console.warn(
                    "Received MCP OAuth request without a registered MCP auth handler. " +
                        `SessionId=${this.sessionId}, RequestId=${data.requestId}`
                );
                return;
            }
            void this._executeMcpAuthAndRespond(data);
        } else if (event.type === "command.execute") {
            const { requestId, commandName, command, args } = event.data as {
                requestId: string;
                command: string;
                commandName: string;
                args: string;
            };
            void this._executeCommandAndRespond(requestId, commandName, command, args);
        } else if (event.type === "elicitation.requested") {
            if (this.elicitationHandler) {
                const { message, requestedSchema, mode, elicitationSource, url, requestId } =
                    event.data;

View on GitHub (pinned to cd8cf15dc3)