@stigmer/runner 3.1.6 → 3.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"hash":"1a646fa123b0f5ef","builtAt":"2026-07-07T14:07:11.073Z","fileCount":243}
1
+ {"hash":"4c57edff0c688075","builtAt":"2026-07-07T15:43:06.051Z","fileCount":244}
@@ -23,6 +23,7 @@ import { activityStarted, activityFinished } from "../idle-watchdog.js";
23
23
  import { StigmerClient } from "../client/stigmer-client.js";
24
24
  import { mcpServerToResolved } from "../shared/mcp-resolver.js";
25
25
  import { toMcpClientConfig } from "../shared/mcp-manager.js";
26
+ import { detectOAuthChallenge } from "../shared/mcp-oauth-detect.js";
26
27
  const SESSION_INIT_TIMEOUT_MS = 270_000;
27
28
  const PLATFORM_INJECTABLE_MAP = {
28
29
  STIGMER_SERVER_ADDRESS: "STIGMER_MCP_PUBLIC_ENDPOINT",
@@ -228,6 +229,16 @@ async function connectAndDiscover(slug, connectionConfig) {
228
229
  }
229
230
  });
230
231
  }
232
+ catch (err) {
233
+ // The MCP client surfaces a 401 OAuth challenge as an opaque aggregate
234
+ // ("unhandled errors in a TaskGroup"). For HTTP servers, re-probe once to
235
+ // see if the endpoint is actually asking for OAuth and, if so, replace the
236
+ // useless error with an actionable one. Non-OAuth failures rethrow as-is.
237
+ const oauthError = await classifyHttpOAuthFailure(slug, connectionConfig);
238
+ if (oauthError)
239
+ throw oauthError;
240
+ throw err;
241
+ }
231
242
  finally {
232
243
  await client.close().catch((err) => {
233
244
  console.warn(`[DiscoverMcpServer] Error closing MCP client for '${slug}': ` +
@@ -236,6 +247,18 @@ async function connectAndDiscover(slug, connectionConfig) {
236
247
  }
237
248
  return { tools, resourceTemplates };
238
249
  }
250
+ /**
251
+ * If the server uses HTTP transport, probe its endpoint to classify a discovery
252
+ * failure as an OAuth challenge. Returns the actionable error to throw, or
253
+ * `null` for stdio servers and non-OAuth failures (caller rethrows original).
254
+ */
255
+ async function classifyHttpOAuthFailure(slug, connectionConfig) {
256
+ const connection = connectionConfig[slug];
257
+ if (!connection || connection.transport !== "http" || !connection.url) {
258
+ return null;
259
+ }
260
+ return detectOAuthChallenge(connection.url, connection.headers, slug);
261
+ }
239
262
  async function withTimeout(ms, serverSlug, fn) {
240
263
  return new Promise((resolve, reject) => {
241
264
  const timer = setTimeout(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"discover-mcp-server.js","sourceRoot":"","sources":["../../src/activities/discover-mcp-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"discover-mcp-server.js","sourceRoot":"","sources":["../../src/activities/discover-mcp-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * OAuth-challenge classification for HTTP MCP endpoints.
3
+ *
4
+ * When an HTTP MCP endpoint requires OAuth (per the MCP Authorization spec /
5
+ * RFC 9728), an unauthenticated or statically-tokened request is answered with
6
+ * `401` and a `WWW-Authenticate: Bearer ...` header pointing at OAuth protected
7
+ * resource metadata. The MCP client SDK surfaces this only as an opaque
8
+ * aggregate error ("unhandled errors in a TaskGroup"), which tells the user
9
+ * nothing.
10
+ *
11
+ * This module turns that opaque failure into a precise, actionable signal: it
12
+ * re-probes the endpoint once (only on the failure path, so the happy path pays
13
+ * nothing) and, if it sees an OAuth challenge, returns an {@link
14
+ * OAuthRequiredError} whose message tells the user to connect via OAuth instead
15
+ * of a manual token.
16
+ *
17
+ * Kept transport-library-agnostic (uses global `fetch`) so it is reusable by
18
+ * connect-time discovery, execution-time error enrichment, and any other caller
19
+ * that holds an MCP endpoint URL + headers.
20
+ */
21
+ /**
22
+ * Raised when an HTTP MCP endpoint answers with an OAuth authentication
23
+ * challenge. The message is self-contained and user-facing: it survives the
24
+ * Temporal boundary and is shown by the connect error wrappers verbatim.
25
+ *
26
+ * The literal phrase "requires OAuth" is a stable marker the Go/Java connect
27
+ * wrappers match to avoid appending a generic "check your credentials" suffix.
28
+ */
29
+ export declare class OAuthRequiredError extends Error {
30
+ readonly serverSlug: string;
31
+ readonly resourceMetadataUrl?: string | undefined;
32
+ constructor(serverSlug: string, resourceMetadataUrl?: string | undefined);
33
+ }
34
+ /**
35
+ * Whether a `WWW-Authenticate` header value is an OAuth challenge.
36
+ *
37
+ * The MCP auth spec emits `Bearer realm="OAuth", resource_metadata="..."`. We
38
+ * require the `Bearer` scheme plus either an OAuth realm or a resource-metadata
39
+ * pointer, so a plain `Bearer` 401 from a static-token API (an invalid key, not
40
+ * an OAuth requirement) is not misclassified.
41
+ */
42
+ export declare function isOAuthChallenge(wwwAuthenticate: string): boolean;
43
+ /** Extract the `resource_metadata` URL from a `WWW-Authenticate` value, if present. */
44
+ export declare function parseResourceMetadataUrl(wwwAuthenticate: string): string | undefined;
45
+ /**
46
+ * Probe an HTTP MCP endpoint once to decide whether its failure is an OAuth
47
+ * challenge. Returns an {@link OAuthRequiredError} to throw, or `null` when the
48
+ * endpoint is not asking for OAuth (so the caller rethrows the original error).
49
+ *
50
+ * Never throws: any probe/network failure returns `null` so this classification
51
+ * step can never mask or replace the original discovery error.
52
+ */
53
+ export declare function detectOAuthChallenge(url: string, headers: Record<string, string> | undefined, slug: string): Promise<OAuthRequiredError | null>;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * OAuth-challenge classification for HTTP MCP endpoints.
3
+ *
4
+ * When an HTTP MCP endpoint requires OAuth (per the MCP Authorization spec /
5
+ * RFC 9728), an unauthenticated or statically-tokened request is answered with
6
+ * `401` and a `WWW-Authenticate: Bearer ...` header pointing at OAuth protected
7
+ * resource metadata. The MCP client SDK surfaces this only as an opaque
8
+ * aggregate error ("unhandled errors in a TaskGroup"), which tells the user
9
+ * nothing.
10
+ *
11
+ * This module turns that opaque failure into a precise, actionable signal: it
12
+ * re-probes the endpoint once (only on the failure path, so the happy path pays
13
+ * nothing) and, if it sees an OAuth challenge, returns an {@link
14
+ * OAuthRequiredError} whose message tells the user to connect via OAuth instead
15
+ * of a manual token.
16
+ *
17
+ * Kept transport-library-agnostic (uses global `fetch`) so it is reusable by
18
+ * connect-time discovery, execution-time error enrichment, and any other caller
19
+ * that holds an MCP endpoint URL + headers.
20
+ */
21
+ const OAUTH_PROBE_TIMEOUT_MS = 10_000;
22
+ /**
23
+ * Raised when an HTTP MCP endpoint answers with an OAuth authentication
24
+ * challenge. The message is self-contained and user-facing: it survives the
25
+ * Temporal boundary and is shown by the connect error wrappers verbatim.
26
+ *
27
+ * The literal phrase "requires OAuth" is a stable marker the Go/Java connect
28
+ * wrappers match to avoid appending a generic "check your credentials" suffix.
29
+ */
30
+ export class OAuthRequiredError extends Error {
31
+ serverSlug;
32
+ resourceMetadataUrl;
33
+ constructor(serverSlug, resourceMetadataUrl) {
34
+ super(`MCP server '${serverSlug}' requires OAuth: its endpoint returned an ` +
35
+ `authentication challenge (HTTP 401). A manually-entered API token will ` +
36
+ `not work here — connect it with the OAuth "Sign in" flow instead.`);
37
+ this.serverSlug = serverSlug;
38
+ this.resourceMetadataUrl = resourceMetadataUrl;
39
+ this.name = "OAuthRequiredError";
40
+ }
41
+ }
42
+ /**
43
+ * Whether a `WWW-Authenticate` header value is an OAuth challenge.
44
+ *
45
+ * The MCP auth spec emits `Bearer realm="OAuth", resource_metadata="..."`. We
46
+ * require the `Bearer` scheme plus either an OAuth realm or a resource-metadata
47
+ * pointer, so a plain `Bearer` 401 from a static-token API (an invalid key, not
48
+ * an OAuth requirement) is not misclassified.
49
+ */
50
+ export function isOAuthChallenge(wwwAuthenticate) {
51
+ const value = wwwAuthenticate.toLowerCase();
52
+ if (!value.includes("bearer"))
53
+ return false;
54
+ return value.includes("oauth") || value.includes("resource_metadata");
55
+ }
56
+ /** Extract the `resource_metadata` URL from a `WWW-Authenticate` value, if present. */
57
+ export function parseResourceMetadataUrl(wwwAuthenticate) {
58
+ const match = /resource_metadata="([^"]+)"/i.exec(wwwAuthenticate);
59
+ return match?.[1];
60
+ }
61
+ /**
62
+ * Probe an HTTP MCP endpoint once to decide whether its failure is an OAuth
63
+ * challenge. Returns an {@link OAuthRequiredError} to throw, or `null` when the
64
+ * endpoint is not asking for OAuth (so the caller rethrows the original error).
65
+ *
66
+ * Never throws: any probe/network failure returns `null` so this classification
67
+ * step can never mask or replace the original discovery error.
68
+ */
69
+ export async function detectOAuthChallenge(url, headers, slug) {
70
+ try {
71
+ const response = await fetch(url, {
72
+ method: "POST",
73
+ headers: {
74
+ "Content-Type": "application/json",
75
+ Accept: "application/json, text/event-stream",
76
+ ...(headers ?? {}),
77
+ },
78
+ // A minimal MCP initialize request — enough to trigger the endpoint's
79
+ // auth check without establishing a session.
80
+ body: JSON.stringify({
81
+ jsonrpc: "2.0",
82
+ id: 1,
83
+ method: "initialize",
84
+ params: {},
85
+ }),
86
+ signal: AbortSignal.timeout(OAUTH_PROBE_TIMEOUT_MS),
87
+ });
88
+ if (response.status !== 401)
89
+ return null;
90
+ const wwwAuthenticate = response.headers.get("www-authenticate") ?? "";
91
+ if (!isOAuthChallenge(wwwAuthenticate))
92
+ return null;
93
+ return new OAuthRequiredError(slug, parseResourceMetadataUrl(wwwAuthenticate));
94
+ }
95
+ catch {
96
+ return null;
97
+ }
98
+ }
99
+ //# sourceMappingURL=mcp-oauth-detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-oauth-detect.js","sourceRoot":"","sources":["../../src/shared/mcp-oauth-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAEtC;;;;;;;GAOG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAEzB;IACA;IAFlB,YACkB,UAAkB,EAClB,mBAA4B;QAE5C,KAAK,CACH,eAAe,UAAU,6CAA6C;YACpE,yEAAyE;YACzE,mEAAmE,CACtE,CAAC;QAPc,eAAU,GAAV,UAAU,CAAQ;QAClB,wBAAmB,GAAnB,mBAAmB,CAAS;QAO5C,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,eAAuB;IACtD,MAAM,KAAK,GAAG,eAAe,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;AACxE,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,wBAAwB,CACtC,eAAuB;IAEvB,MAAM,KAAK,GAAG,8BAA8B,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACnE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,GAAW,EACX,OAA2C,EAC3C,IAAY;IAEZ,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,qCAAqC;gBAC7C,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;aACnB;YACD,sEAAsE;YACtE,6CAA6C;YAC7C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,EAAE,EAAE,CAAC;gBACL,MAAM,EAAE,YAAY;gBACpB,MAAM,EAAE,EAAE;aACX,CAAC;YACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,sBAAsB,CAAC;SACpD,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAEzC,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC;QACvE,IAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC;YAAE,OAAO,IAAI,CAAC;QAEpD,OAAO,IAAI,kBAAkB,CAC3B,IAAI,EACJ,wBAAwB,CAAC,eAAe,CAAC,CAC1C,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/runner",
3
- "version": "3.1.6",
3
+ "version": "3.1.7",
4
4
  "description": "Embeddable Temporal worker for the Stigmer AI agent platform — handles agent execution, workflow orchestration, and MCP server management",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -85,7 +85,7 @@
85
85
  "@opentelemetry/sdk-metrics": "^2.0.0",
86
86
  "@opentelemetry/sdk-trace-base": "^2.0.0",
87
87
  "@opentelemetry/sdk-trace-node": "^2.0.0",
88
- "@stigmer/protos": "3.1.6",
88
+ "@stigmer/protos": "3.1.7",
89
89
  "@temporalio/activity": "^1.11.0",
90
90
  "@temporalio/client": "^1.11.0",
91
91
  "@temporalio/common": "^1.11.0",
@@ -24,6 +24,7 @@ import { activityStarted, activityFinished } from "../idle-watchdog.js";
24
24
  import { StigmerClient } from "../client/stigmer-client.js";
25
25
  import { mcpServerToResolved } from "../shared/mcp-resolver.js";
26
26
  import { toMcpClientConfig } from "../shared/mcp-manager.js";
27
+ import { detectOAuthChallenge } from "../shared/mcp-oauth-detect.js";
27
28
  import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
28
29
  import type { Config } from "../config.js";
29
30
 
@@ -374,6 +375,14 @@ async function connectAndDiscover(
374
375
  );
375
376
  }
376
377
  });
378
+ } catch (err) {
379
+ // The MCP client surfaces a 401 OAuth challenge as an opaque aggregate
380
+ // ("unhandled errors in a TaskGroup"). For HTTP servers, re-probe once to
381
+ // see if the endpoint is actually asking for OAuth and, if so, replace the
382
+ // useless error with an actionable one. Non-OAuth failures rethrow as-is.
383
+ const oauthError = await classifyHttpOAuthFailure(slug, connectionConfig);
384
+ if (oauthError) throw oauthError;
385
+ throw err;
377
386
  } finally {
378
387
  await client.close().catch((err: unknown) => {
379
388
  console.warn(
@@ -386,6 +395,22 @@ async function connectAndDiscover(
386
395
  return { tools, resourceTemplates };
387
396
  }
388
397
 
398
+ /**
399
+ * If the server uses HTTP transport, probe its endpoint to classify a discovery
400
+ * failure as an OAuth challenge. Returns the actionable error to throw, or
401
+ * `null` for stdio servers and non-OAuth failures (caller rethrows original).
402
+ */
403
+ async function classifyHttpOAuthFailure(
404
+ slug: string,
405
+ connectionConfig: ReturnType<typeof toMcpClientConfig>,
406
+ ): Promise<Error | null> {
407
+ const connection = connectionConfig[slug];
408
+ if (!connection || connection.transport !== "http" || !connection.url) {
409
+ return null;
410
+ }
411
+ return detectOAuthChallenge(connection.url, connection.headers, slug);
412
+ }
413
+
389
414
  async function withTimeout<T>(
390
415
  ms: number,
391
416
  serverSlug: string,
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Unit tests for the HTTP MCP OAuth-challenge classifier.
3
+ *
4
+ * Verifies that `detectOAuthChallenge` recognizes a real MCP OAuth challenge
5
+ * (401 + `WWW-Authenticate: Bearer ...` per RFC 9728), and does NOT misfire on
6
+ * a plain invalid-token 401, a success, a non-OAuth error, or a network fault —
7
+ * so it can only ever turn an opaque failure into a clearer one, never mask a
8
+ * different cause.
9
+ */
10
+
11
+ import { afterEach, describe, it, expect, vi } from "vitest";
12
+ import {
13
+ OAuthRequiredError,
14
+ detectOAuthChallenge,
15
+ isOAuthChallenge,
16
+ parseResourceMetadataUrl,
17
+ } from "../mcp-oauth-detect.js";
18
+
19
+ function mockFetchOnce(response: {
20
+ status: number;
21
+ wwwAuthenticate?: string;
22
+ }): void {
23
+ const headers = new Headers();
24
+ if (response.wwwAuthenticate !== undefined) {
25
+ headers.set("www-authenticate", response.wwwAuthenticate);
26
+ }
27
+ vi.stubGlobal(
28
+ "fetch",
29
+ vi.fn(async () =>
30
+ new Response(null, { status: response.status, headers }),
31
+ ),
32
+ );
33
+ }
34
+
35
+ afterEach(() => {
36
+ vi.unstubAllGlobals();
37
+ vi.restoreAllMocks();
38
+ });
39
+
40
+ describe("isOAuthChallenge", () => {
41
+ it("matches the MCP auth spec Bearer + OAuth realm challenge", () => {
42
+ expect(
43
+ isOAuthChallenge('Bearer realm="OAuth", resource_metadata="https://x/.well-known/oauth-protected-resource"'),
44
+ ).toBe(true);
45
+ });
46
+
47
+ it("matches a Bearer challenge that only advertises resource_metadata", () => {
48
+ expect(
49
+ isOAuthChallenge('Bearer resource_metadata="https://x/.well-known/oauth-protected-resource"'),
50
+ ).toBe(true);
51
+ });
52
+
53
+ it("does not match a plain Bearer 401 (invalid API key, not an OAuth requirement)", () => {
54
+ expect(isOAuthChallenge('Bearer error="invalid_token"')).toBe(false);
55
+ });
56
+
57
+ it("does not match a non-Bearer scheme", () => {
58
+ expect(isOAuthChallenge('Basic realm="oauth"')).toBe(false);
59
+ });
60
+
61
+ it("is empty-safe", () => {
62
+ expect(isOAuthChallenge("")).toBe(false);
63
+ });
64
+ });
65
+
66
+ describe("parseResourceMetadataUrl", () => {
67
+ it("extracts the resource_metadata URL", () => {
68
+ expect(
69
+ parseResourceMetadataUrl(
70
+ 'Bearer realm="OAuth", resource_metadata="https://mcp.notion.com/.well-known/oauth-protected-resource/mcp"',
71
+ ),
72
+ ).toBe("https://mcp.notion.com/.well-known/oauth-protected-resource/mcp");
73
+ });
74
+
75
+ it("returns undefined when absent", () => {
76
+ expect(parseResourceMetadataUrl('Bearer realm="OAuth"')).toBeUndefined();
77
+ });
78
+ });
79
+
80
+ describe("detectOAuthChallenge", () => {
81
+ it("returns an OAuthRequiredError for a 401 OAuth challenge", async () => {
82
+ mockFetchOnce({
83
+ status: 401,
84
+ wwwAuthenticate:
85
+ 'Bearer realm="OAuth", resource_metadata="https://mcp.notion.com/.well-known/oauth-protected-resource/mcp"',
86
+ });
87
+
88
+ const result = await detectOAuthChallenge("https://mcp.notion.com/mcp", {}, "notion");
89
+
90
+ expect(result).toBeInstanceOf(OAuthRequiredError);
91
+ expect(result?.serverSlug).toBe("notion");
92
+ expect(result?.resourceMetadataUrl).toBe(
93
+ "https://mcp.notion.com/.well-known/oauth-protected-resource/mcp",
94
+ );
95
+ // The message is self-contained and carries the "requires OAuth" marker the
96
+ // connect wrappers key on.
97
+ expect(result?.message).toContain("requires OAuth");
98
+ expect(result?.message).toContain("notion");
99
+ });
100
+
101
+ it("returns null for a 401 that is NOT an OAuth challenge (invalid static token)", async () => {
102
+ mockFetchOnce({ status: 401, wwwAuthenticate: 'Bearer error="invalid_token"' });
103
+ expect(
104
+ await detectOAuthChallenge("https://api.example.com/mcp", {}, "example"),
105
+ ).toBeNull();
106
+ });
107
+
108
+ it("returns null on a non-401 response", async () => {
109
+ mockFetchOnce({ status: 200 });
110
+ expect(
111
+ await detectOAuthChallenge("https://api.example.com/mcp", {}, "example"),
112
+ ).toBeNull();
113
+ });
114
+
115
+ it("returns null (never throws) when the probe itself fails", async () => {
116
+ vi.stubGlobal(
117
+ "fetch",
118
+ vi.fn(async () => {
119
+ throw new Error("network down");
120
+ }),
121
+ );
122
+ expect(
123
+ await detectOAuthChallenge("https://api.example.com/mcp", {}, "example"),
124
+ ).toBeNull();
125
+ });
126
+
127
+ it("forwards the resolved headers to the probe request", async () => {
128
+ const fetchMock = vi.fn(
129
+ async (_url: string | URL, _init?: RequestInit) =>
130
+ new Response(null, { status: 200 }),
131
+ );
132
+ vi.stubGlobal("fetch", fetchMock);
133
+
134
+ await detectOAuthChallenge(
135
+ "https://api.example.com/mcp",
136
+ { Authorization: "Bearer stale-token" },
137
+ "example",
138
+ );
139
+
140
+ expect(fetchMock).toHaveBeenCalledOnce();
141
+ const init = fetchMock.mock.calls[0]?.[1];
142
+ expect((init?.headers as Record<string, string>).Authorization).toBe(
143
+ "Bearer stale-token",
144
+ );
145
+ expect(init?.method).toBe("POST");
146
+ });
147
+ });
@@ -0,0 +1,112 @@
1
+ /**
2
+ * OAuth-challenge classification for HTTP MCP endpoints.
3
+ *
4
+ * When an HTTP MCP endpoint requires OAuth (per the MCP Authorization spec /
5
+ * RFC 9728), an unauthenticated or statically-tokened request is answered with
6
+ * `401` and a `WWW-Authenticate: Bearer ...` header pointing at OAuth protected
7
+ * resource metadata. The MCP client SDK surfaces this only as an opaque
8
+ * aggregate error ("unhandled errors in a TaskGroup"), which tells the user
9
+ * nothing.
10
+ *
11
+ * This module turns that opaque failure into a precise, actionable signal: it
12
+ * re-probes the endpoint once (only on the failure path, so the happy path pays
13
+ * nothing) and, if it sees an OAuth challenge, returns an {@link
14
+ * OAuthRequiredError} whose message tells the user to connect via OAuth instead
15
+ * of a manual token.
16
+ *
17
+ * Kept transport-library-agnostic (uses global `fetch`) so it is reusable by
18
+ * connect-time discovery, execution-time error enrichment, and any other caller
19
+ * that holds an MCP endpoint URL + headers.
20
+ */
21
+
22
+ const OAUTH_PROBE_TIMEOUT_MS = 10_000;
23
+
24
+ /**
25
+ * Raised when an HTTP MCP endpoint answers with an OAuth authentication
26
+ * challenge. The message is self-contained and user-facing: it survives the
27
+ * Temporal boundary and is shown by the connect error wrappers verbatim.
28
+ *
29
+ * The literal phrase "requires OAuth" is a stable marker the Go/Java connect
30
+ * wrappers match to avoid appending a generic "check your credentials" suffix.
31
+ */
32
+ export class OAuthRequiredError extends Error {
33
+ constructor(
34
+ public readonly serverSlug: string,
35
+ public readonly resourceMetadataUrl?: string,
36
+ ) {
37
+ super(
38
+ `MCP server '${serverSlug}' requires OAuth: its endpoint returned an ` +
39
+ `authentication challenge (HTTP 401). A manually-entered API token will ` +
40
+ `not work here — connect it with the OAuth "Sign in" flow instead.`,
41
+ );
42
+ this.name = "OAuthRequiredError";
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Whether a `WWW-Authenticate` header value is an OAuth challenge.
48
+ *
49
+ * The MCP auth spec emits `Bearer realm="OAuth", resource_metadata="..."`. We
50
+ * require the `Bearer` scheme plus either an OAuth realm or a resource-metadata
51
+ * pointer, so a plain `Bearer` 401 from a static-token API (an invalid key, not
52
+ * an OAuth requirement) is not misclassified.
53
+ */
54
+ export function isOAuthChallenge(wwwAuthenticate: string): boolean {
55
+ const value = wwwAuthenticate.toLowerCase();
56
+ if (!value.includes("bearer")) return false;
57
+ return value.includes("oauth") || value.includes("resource_metadata");
58
+ }
59
+
60
+ /** Extract the `resource_metadata` URL from a `WWW-Authenticate` value, if present. */
61
+ export function parseResourceMetadataUrl(
62
+ wwwAuthenticate: string,
63
+ ): string | undefined {
64
+ const match = /resource_metadata="([^"]+)"/i.exec(wwwAuthenticate);
65
+ return match?.[1];
66
+ }
67
+
68
+ /**
69
+ * Probe an HTTP MCP endpoint once to decide whether its failure is an OAuth
70
+ * challenge. Returns an {@link OAuthRequiredError} to throw, or `null` when the
71
+ * endpoint is not asking for OAuth (so the caller rethrows the original error).
72
+ *
73
+ * Never throws: any probe/network failure returns `null` so this classification
74
+ * step can never mask or replace the original discovery error.
75
+ */
76
+ export async function detectOAuthChallenge(
77
+ url: string,
78
+ headers: Record<string, string> | undefined,
79
+ slug: string,
80
+ ): Promise<OAuthRequiredError | null> {
81
+ try {
82
+ const response = await fetch(url, {
83
+ method: "POST",
84
+ headers: {
85
+ "Content-Type": "application/json",
86
+ Accept: "application/json, text/event-stream",
87
+ ...(headers ?? {}),
88
+ },
89
+ // A minimal MCP initialize request — enough to trigger the endpoint's
90
+ // auth check without establishing a session.
91
+ body: JSON.stringify({
92
+ jsonrpc: "2.0",
93
+ id: 1,
94
+ method: "initialize",
95
+ params: {},
96
+ }),
97
+ signal: AbortSignal.timeout(OAUTH_PROBE_TIMEOUT_MS),
98
+ });
99
+
100
+ if (response.status !== 401) return null;
101
+
102
+ const wwwAuthenticate = response.headers.get("www-authenticate") ?? "";
103
+ if (!isOAuthChallenge(wwwAuthenticate)) return null;
104
+
105
+ return new OAuthRequiredError(
106
+ slug,
107
+ parseResourceMetadataUrl(wwwAuthenticate),
108
+ );
109
+ } catch {
110
+ return null;
111
+ }
112
+ }