feat(mcp): MCP OAuth sign-in in two halves, moved from coding-agent

pi-mcp now has startMcpSignIn and completeMcpSignIn, so a server app can
start a sign-in in one request and complete it in another (a callback
route, a pasted redirect URL, or a loopback server via
listenForLoopbackSignIn/waitForLoopbackSignIn), plus createMcpAuthProvider.
Application specifics (client name, Client ID Metadata Document base URL
and listed redirect URIs) are options. coding-agent's signInMcpServer is a
thin wrapper over them.

authorizeMcp gains refreshOnly: a failed refresh no longer registers a
client or replaces a pending sign-in's PKCE verifier and state. Sign-in
refreshes with the stored client before dropping it for another redirect
URI.
This commit is contained in:
Armin Ronacher 2026-11-03 01:35:52 +01:00
parent 032656b6c6
commit bb266bf359
16 changed files with 1638 additions and 420 deletions

View file

@ -2,13 +2,12 @@ import { createHash } from "node:crypto";
import { mkdtempSync, readdirSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { type OAuthChallenge, OAuthIssuerMismatchError } from "@earendil-works/pi-mcp/oauth";
import { type McpOAuthSettings, type OAuthChallenge, OAuthIssuerMismatchError } from "@earendil-works/pi-mcp/oauth";
import { afterEach, describe, expect, it } from "vitest";
import { InMemoryAuthStorageBackend } from "../src/core/auth-storage.ts";
import {
createMcpAuthProvider,
McpOAuthCredentialStore,
type McpOAuthSettings,
type McpSignInPrompt,
signInMcpServer,
} from "../src/extensions/mcp/oauth.ts";