@lovable.dev/mcp-js 0.20.1-rc.0 → 0.20.1-rc.1

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,6 +1,8 @@
1
- type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "auth_config_error" | "auth_upstream_unreachable";
1
+ type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "auth_config_error";
2
2
  /** One recorded MCP call. Carries no arguments or response payloads — only the
3
- * tool name, the JSON-RPC method, the result class, timing, and byte sizes. */
3
+ * tool name, the JSON-RPC method, the result class, timing, and byte sizes.
4
+ * `errorText` is the sole exception: it is logged locally for debugging and
5
+ * deliberately never included in the OTLP payload (see `emit` / `buildLogsPayload`). */
4
6
  interface InvocationRecord {
5
7
  /** Tool name for `tools/call`; `null` for list/initialize, transport faults, and auth-config failures. */
6
8
  tool: string | null;
@@ -10,6 +12,9 @@ interface InvocationRecord {
10
12
  durationMs: number;
11
13
  reqBytes?: number;
12
14
  resBytes?: number;
15
+ /** The `tool_error` message (text content of an `isError` result). Local log
16
+ * only — never sent to the collector, so it stays on-box for the operator. */
17
+ errorText?: string;
13
18
  }
14
19
  /** A per-request telemetry recorder. `emit` logs the invocation and sends it as a
15
20
  * single OTLP POST, awaited so it lands before the request ends. */
@@ -0,0 +1,11 @@
1
+ // src/core/content.ts
2
+ function extractTextContent(content) {
3
+ if (!content)
4
+ return void 0;
5
+ const text = content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
6
+ return text.length > 0 ? text : void 0;
7
+ }
8
+
9
+ export {
10
+ extractTextContent
11
+ };
@@ -6,7 +6,7 @@ import {
6
6
  headResponse,
7
7
  methodNotAllowed,
8
8
  withCors
9
- } from "./chunk-E7CPOJN6.js";
9
+ } from "./chunk-XIGO7RW6.js";
10
10
 
11
11
  // src/protocols/rest/list-tools.ts
12
12
  import { objectFromShape } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -7,7 +7,7 @@ import {
7
7
  oauthConfigurationErrorResponse,
8
8
  resolveProtectedResource,
9
9
  withCors
10
- } from "./chunk-E7CPOJN6.js";
10
+ } from "./chunk-XIGO7RW6.js";
11
11
  import {
12
12
  describeError,
13
13
  log
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.20.1-rc.0";
2
+ var version = "0.20.1-rc.1";
3
3
 
4
4
  export {
5
5
  version
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-6DXGZZA4.js";
14
14
  import {
15
15
  version
16
- } from "./chunk-OMEL6F6I.js";
16
+ } from "./chunk-QWVSMQJF.js";
17
17
 
18
18
  // src/core/http.ts
19
19
  var JSON_HEADERS = { "Content-Type": "application/json" };
@@ -156,7 +156,8 @@ var BaseMetricRecorder = class {
156
156
  method: ev.method,
157
157
  outcome: ev.outcome,
158
158
  durationMs: ev.durationMs,
159
- stack: this.stack
159
+ stack: this.stack,
160
+ ...ev.errorText !== void 0 && { errorText: ev.errorText }
160
161
  });
161
162
  if (!this.config.enabled)
162
163
  return;
@@ -289,18 +290,6 @@ var OAuthConfigurationError = class extends Error {
289
290
  this.name = "OAuthConfigurationError";
290
291
  }
291
292
  };
292
- var OAuthUpstreamUnreachableError = class extends Error {
293
- constructor(message) {
294
- super(message);
295
- this.name = "OAuthUpstreamUnreachableError";
296
- }
297
- };
298
- var MetadataUnreachableError = class extends Error {
299
- constructor(message) {
300
- super(message);
301
- this.name = "MetadataUnreachableError";
302
- }
303
- };
304
293
  var METADATA_FETCH_TIMEOUT_MS = 5e3;
305
294
  function issuerPath(url) {
306
295
  const path = trimTrailingSlash(url.pathname);
@@ -325,37 +314,21 @@ function oauthMetadataUrlsForIssuer(issuer) {
325
314
  return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
326
315
  }
327
316
  async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
328
- const controller = new AbortController();
329
- const attempts = metadataUrls.map(
330
- (url) => fetchOAuthServerMetadata(url, expectedIssuer, controller.signal).catch((err) => {
317
+ const errors = [];
318
+ for (const url of metadataUrls) {
319
+ try {
320
+ return await fetchOAuthServerMetadata(url, expectedIssuer);
321
+ } catch (err) {
331
322
  log.debug("oauth.discovery.attempt_failed", { url, ...describeError(err) });
332
- throw err instanceof Error ? err : new Error(String(err));
333
- })
334
- );
335
- try {
336
- const metadata = await Promise.any(attempts);
337
- controller.abort();
338
- return metadata;
339
- } catch (aggregate) {
340
- const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
341
- const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
342
- const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
343
- log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
344
- const message = `failed to discover OAuth server metadata (${detail})`;
345
- throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
323
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
324
+ }
346
325
  }
326
+ log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors });
327
+ throw new Error(`failed to discover OAuth server metadata (${errors.join("; ")})`);
347
328
  }
348
- async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
329
+ async function fetchOAuthServerMetadata(url, expectedIssuer) {
349
330
  log.debug("oauth.discovery.fetch", { url });
350
- let response;
351
- try {
352
- response = await fetch(url, {
353
- signal: AbortSignal.any([signal, AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS)]),
354
- redirect: "manual"
355
- });
356
- } catch (err) {
357
- throw new MetadataUnreachableError(err instanceof Error ? err.message : String(err));
358
- }
331
+ const response = await fetch(url, { signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS), redirect: "manual" });
359
332
  if (!response.ok) {
360
333
  throw new Error(String(response.status));
361
334
  }
@@ -378,21 +351,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
378
351
  try {
379
352
  return await fetchFirstValidOAuthServerMetadata(oauthMetadataUrlsForIssuer(issuer), issuer);
380
353
  } catch (err) {
381
- const message = `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`;
382
- if (err instanceof MetadataUnreachableError) {
383
- log.error("oauth.discovery.unreachable", {
384
- issuer,
385
- ...describeError(err),
386
- outcome: "503 authorization server unreachable"
387
- });
388
- throw new OAuthUpstreamUnreachableError(message);
389
- }
390
354
  log.error("oauth.discovery.config_error", {
391
355
  issuer,
392
356
  ...describeError(err),
393
357
  outcome: "500 oauth configuration error"
394
358
  });
395
- throw new OAuthConfigurationError(message);
359
+ throw new OAuthConfigurationError(
360
+ `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`
361
+ );
396
362
  }
397
363
  }
398
364
  function createOAuthDiscoveryResolver(auth) {
@@ -458,14 +424,8 @@ function tokenHeaderFields(token) {
458
424
  }
459
425
  }
460
426
  async function fetchVerificationKeySet(jwksUri) {
461
- let response;
462
- try {
463
- response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
464
- } catch (err) {
465
- log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
466
- throw new OAuthUpstreamUnreachableError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
467
- }
468
427
  try {
428
+ const response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
469
429
  if (!response.ok)
470
430
  throw new Error(`JWKS endpoint returned ${response.status}`);
471
431
  const json = await response.json();
@@ -606,12 +566,6 @@ function oauthConfigurationErrorResponse() {
606
566
  headers: { ...JSON_HEADERS, "Cache-Control": "no-store" }
607
567
  });
608
568
  }
609
- function oauthUpstreamUnreachableResponse() {
610
- return new Response(JSON.stringify({ error: "authorization server unreachable" }), {
611
- status: 503,
612
- headers: { ...JSON_HEADERS, "Cache-Control": "no-store", "Retry-After": "30" }
613
- });
614
- }
615
569
  function parseBearerToken(request) {
616
570
  const header = request.headers.get("Authorization");
617
571
  if (!header)
@@ -684,16 +638,6 @@ function createRequestAuthorizer(mcp, options = {}) {
684
638
  assertRequiredScopes(runtime.auth, auth);
685
639
  return { ok: true, auth };
686
640
  } catch (err) {
687
- if (err instanceof OAuthUpstreamUnreachableError) {
688
- log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
689
- await recorder?.emit({
690
- tool: null,
691
- method: "authorize",
692
- outcome: "auth_upstream_unreachable",
693
- durationMs: nowMs() - startedAt
694
- });
695
- return { ok: false, response: oauthUpstreamUnreachableResponse() };
696
- }
697
641
  if (err instanceof OAuthConfigurationError) {
698
642
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
699
643
  await recorder?.emit({
@@ -1,3 +1,6 @@
1
+ import {
2
+ extractTextContent
3
+ } from "./chunk-6QFZYYUV.js";
1
4
  import {
2
5
  ToolContext
3
6
  } from "./chunk-MA5H6PSF.js";
@@ -7,7 +10,7 @@ import {
7
10
  createRequestAuthorizer,
8
11
  nowMs,
9
12
  withCors
10
- } from "./chunk-E7CPOJN6.js";
13
+ } from "./chunk-XIGO7RW6.js";
11
14
  import {
12
15
  describeError,
13
16
  log
@@ -45,7 +48,8 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
45
48
  tool: tool.name,
46
49
  method: "tools/call",
47
50
  outcome: result.isError ? "tool_error" : "ok",
48
- durationMs: nowMs() - start
51
+ durationMs: nowMs() - start,
52
+ errorText: result.isError ? extractTextContent(result.content) : void 0
49
53
  });
50
54
  return { content: result.content ?? [], structuredContent: result.structuredContent, isError: result.isError };
51
55
  };
@@ -1,3 +1,6 @@
1
+ import {
2
+ extractTextContent
3
+ } from "./chunk-6QFZYYUV.js";
1
4
  import {
2
5
  ToolContext
3
6
  } from "./chunk-MA5H6PSF.js";
@@ -10,7 +13,7 @@ import {
10
13
  methodNotAllowed,
11
14
  nowMs,
12
15
  withCors
13
- } from "./chunk-E7CPOJN6.js";
16
+ } from "./chunk-XIGO7RW6.js";
14
17
 
15
18
  // src/protocols/rest/invoke-tool.ts
16
19
  import { getParseErrorMessage, objectFromShape, safeParseAsync } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -113,7 +116,8 @@ function createInvokeToolHandler(mcp, options = {}) {
113
116
  tool: tool.name,
114
117
  method: "tools/call",
115
118
  outcome: result.isError ? "tool_error" : "ok",
116
- durationMs: nowMs() - start
119
+ durationMs: nowMs() - start,
120
+ errorText: result.isError ? extractTextContent(result.content) : void 0
117
121
  });
118
122
  return Response.json({
119
123
  content: result.content ?? [],
@@ -13,7 +13,7 @@ function isFileMissing(err) {
13
13
  }
14
14
 
15
15
  // package.json
16
- var version = "0.20.1-rc.0";
16
+ var version = "0.20.1-rc.1";
17
17
 
18
18
  // src/protocols/rest/list-tools.ts
19
19
  var import_zod_compat = require("@modelcontextprotocol/sdk/server/zod-compat.js");
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildMcpListing
4
- } from "../chunk-YAXKWTJK.js";
5
- import "../chunk-E7CPOJN6.js";
4
+ } from "../chunk-ICCGSB2E.js";
5
+ import "../chunk-XIGO7RW6.js";
6
6
  import "../chunk-H37EB22A.js";
7
7
  import "../chunk-6DXGZZA4.js";
8
8
  import {
@@ -10,7 +10,7 @@ import {
10
10
  } from "../chunk-Y3ZFPEQH.js";
11
11
  import {
12
12
  version
13
- } from "../chunk-OMEL6F6I.js";
13
+ } from "../chunk-QWVSMQJF.js";
14
14
 
15
15
  // src/manifest/io.ts
16
16
  import { randomUUID } from "crypto";
@@ -153,18 +153,6 @@ var OAuthConfigurationError = class extends Error {
153
153
  this.name = "OAuthConfigurationError";
154
154
  }
155
155
  };
156
- var OAuthUpstreamUnreachableError = class extends Error {
157
- constructor(message) {
158
- super(message);
159
- this.name = "OAuthUpstreamUnreachableError";
160
- }
161
- };
162
- var MetadataUnreachableError = class extends Error {
163
- constructor(message) {
164
- super(message);
165
- this.name = "MetadataUnreachableError";
166
- }
167
- };
168
156
  var METADATA_FETCH_TIMEOUT_MS = 5e3;
169
157
  function issuerPath(url) {
170
158
  const path = trimTrailingSlash(url.pathname);
@@ -189,37 +177,21 @@ function oauthMetadataUrlsForIssuer(issuer) {
189
177
  return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
190
178
  }
191
179
  async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
192
- const controller = new AbortController();
193
- const attempts = metadataUrls.map(
194
- (url) => fetchOAuthServerMetadata(url, expectedIssuer, controller.signal).catch((err) => {
180
+ const errors = [];
181
+ for (const url of metadataUrls) {
182
+ try {
183
+ return await fetchOAuthServerMetadata(url, expectedIssuer);
184
+ } catch (err) {
195
185
  log.debug("oauth.discovery.attempt_failed", { url, ...describeError(err) });
196
- throw err instanceof Error ? err : new Error(String(err));
197
- })
198
- );
199
- try {
200
- const metadata = await Promise.any(attempts);
201
- controller.abort();
202
- return metadata;
203
- } catch (aggregate) {
204
- const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
205
- const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
206
- const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
207
- log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
208
- const message = `failed to discover OAuth server metadata (${detail})`;
209
- throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
210
- }
211
- }
212
- async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
213
- log.debug("oauth.discovery.fetch", { url });
214
- let response;
215
- try {
216
- response = await fetch(url, {
217
- signal: AbortSignal.any([signal, AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS)]),
218
- redirect: "manual"
219
- });
220
- } catch (err) {
221
- throw new MetadataUnreachableError(err instanceof Error ? err.message : String(err));
186
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
187
+ }
222
188
  }
189
+ log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors });
190
+ throw new Error(`failed to discover OAuth server metadata (${errors.join("; ")})`);
191
+ }
192
+ async function fetchOAuthServerMetadata(url, expectedIssuer) {
193
+ log.debug("oauth.discovery.fetch", { url });
194
+ const response = await fetch(url, { signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS), redirect: "manual" });
223
195
  if (!response.ok) {
224
196
  throw new Error(String(response.status));
225
197
  }
@@ -242,21 +214,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
242
214
  try {
243
215
  return await fetchFirstValidOAuthServerMetadata(oauthMetadataUrlsForIssuer(issuer), issuer);
244
216
  } catch (err) {
245
- const message = `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`;
246
- if (err instanceof MetadataUnreachableError) {
247
- log.error("oauth.discovery.unreachable", {
248
- issuer,
249
- ...describeError(err),
250
- outcome: "503 authorization server unreachable"
251
- });
252
- throw new OAuthUpstreamUnreachableError(message);
253
- }
254
217
  log.error("oauth.discovery.config_error", {
255
218
  issuer,
256
219
  ...describeError(err),
257
220
  outcome: "500 oauth configuration error"
258
221
  });
259
- throw new OAuthConfigurationError(message);
222
+ throw new OAuthConfigurationError(
223
+ `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`
224
+ );
260
225
  }
261
226
  }
262
227
  function createOAuthDiscoveryResolver(auth) {
@@ -349,14 +314,8 @@ function tokenHeaderFields(token) {
349
314
  }
350
315
  }
351
316
  async function fetchVerificationKeySet(jwksUri) {
352
- let response;
353
- try {
354
- response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
355
- } catch (err) {
356
- log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
357
- throw new OAuthUpstreamUnreachableError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
358
- }
359
317
  try {
318
+ const response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
360
319
  if (!response.ok)
361
320
  throw new Error(`JWKS endpoint returned ${response.status}`);
362
321
  const json = await response.json();
@@ -497,12 +456,6 @@ function oauthConfigurationErrorResponse() {
497
456
  headers: { ...JSON_HEADERS, "Cache-Control": "no-store" }
498
457
  });
499
458
  }
500
- function oauthUpstreamUnreachableResponse() {
501
- return new Response(JSON.stringify({ error: "authorization server unreachable" }), {
502
- status: 503,
503
- headers: { ...JSON_HEADERS, "Cache-Control": "no-store", "Retry-After": "30" }
504
- });
505
- }
506
459
  function parseBearerToken(request) {
507
460
  const header = request.headers.get("Authorization");
508
461
  if (!header)
@@ -567,16 +520,6 @@ function createRequestAuthorizer(mcp, options = {}) {
567
520
  assertRequiredScopes(runtime.auth, auth);
568
521
  return { ok: true, auth };
569
522
  } catch (err) {
570
- if (err instanceof OAuthUpstreamUnreachableError) {
571
- log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
572
- await recorder?.emit({
573
- tool: null,
574
- method: "authorize",
575
- outcome: "auth_upstream_unreachable",
576
- durationMs: nowMs() - startedAt
577
- });
578
- return { ok: false, response: oauthUpstreamUnreachableResponse() };
579
- }
580
523
  if (err instanceof OAuthConfigurationError) {
581
524
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
582
525
  await recorder?.emit({
@@ -661,6 +604,14 @@ var ToolContext = class {
661
604
  }
662
605
  };
663
606
 
607
+ // src/core/content.ts
608
+ function extractTextContent(content) {
609
+ if (!content)
610
+ return void 0;
611
+ const text = content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
612
+ return text.length > 0 ? text : void 0;
613
+ }
614
+
664
615
  // src/core/cors.ts
665
616
  var EXPOSE_HEADERS = "WWW-Authenticate, Mcp-Session-Id, Mcp-Protocol-Version";
666
617
  var ALLOW_HEADERS = "Authorization, Content-Type, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID";
@@ -711,7 +662,8 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
711
662
  tool: tool.name,
712
663
  method: "tools/call",
713
664
  outcome: result.isError ? "tool_error" : "ok",
714
- durationMs: nowMs() - start
665
+ durationMs: nowMs() - start,
666
+ errorText: result.isError ? extractTextContent(result.content) : void 0
715
667
  });
716
668
  return { content: result.content ?? [], structuredContent: result.structuredContent, isError: result.isError };
717
669
  };
@@ -1,6 +1,6 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
2
2
  import { d as McpDefinition } from '../../types-CPkhCRxc.js';
3
- import { M as MetricsRecorder } from '../../base-RSqYamjy.js';
3
+ import { M as MetricsRecorder } from '../../base-CFy5vZ5Z.js';
4
4
  import 'zod';
5
5
 
6
6
  type McpProtocolHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
@@ -1,6 +1,6 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
2
2
  import { d as McpDefinition } from '../../types-CPkhCRxc.js';
3
- import { M as MetricsRecorder } from '../../base-RSqYamjy.js';
3
+ import { M as MetricsRecorder } from '../../base-CFy5vZ5Z.js';
4
4
  import 'zod';
5
5
 
6
6
  type McpProtocolHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  createMcpProtocolHandler
3
- } from "../../chunk-ID3YWZBR.js";
3
+ } from "../../chunk-YQFF4OCL.js";
4
+ import "../../chunk-6QFZYYUV.js";
4
5
  import "../../chunk-MA5H6PSF.js";
5
- import "../../chunk-E7CPOJN6.js";
6
+ import "../../chunk-XIGO7RW6.js";
6
7
  import "../../chunk-H37EB22A.js";
7
8
  import "../../chunk-6DXGZZA4.js";
8
- import "../../chunk-OMEL6F6I.js";
9
+ import "../../chunk-QWVSMQJF.js";
9
10
  export {
10
11
  createMcpProtocolHandler
11
12
  };
@@ -148,18 +148,6 @@ var OAuthConfigurationError = class extends Error {
148
148
  this.name = "OAuthConfigurationError";
149
149
  }
150
150
  };
151
- var OAuthUpstreamUnreachableError = class extends Error {
152
- constructor(message) {
153
- super(message);
154
- this.name = "OAuthUpstreamUnreachableError";
155
- }
156
- };
157
- var MetadataUnreachableError = class extends Error {
158
- constructor(message) {
159
- super(message);
160
- this.name = "MetadataUnreachableError";
161
- }
162
- };
163
151
  var METADATA_FETCH_TIMEOUT_MS = 5e3;
164
152
  function issuerPath(url) {
165
153
  const path = trimTrailingSlash(url.pathname);
@@ -184,37 +172,21 @@ function oauthMetadataUrlsForIssuer(issuer) {
184
172
  return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
185
173
  }
186
174
  async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
187
- const controller = new AbortController();
188
- const attempts = metadataUrls.map(
189
- (url) => fetchOAuthServerMetadata(url, expectedIssuer, controller.signal).catch((err) => {
175
+ const errors = [];
176
+ for (const url of metadataUrls) {
177
+ try {
178
+ return await fetchOAuthServerMetadata(url, expectedIssuer);
179
+ } catch (err) {
190
180
  log.debug("oauth.discovery.attempt_failed", { url, ...describeError(err) });
191
- throw err instanceof Error ? err : new Error(String(err));
192
- })
193
- );
194
- try {
195
- const metadata = await Promise.any(attempts);
196
- controller.abort();
197
- return metadata;
198
- } catch (aggregate) {
199
- const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
200
- const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
201
- const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
202
- log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
203
- const message = `failed to discover OAuth server metadata (${detail})`;
204
- throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
181
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
182
+ }
205
183
  }
184
+ log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors });
185
+ throw new Error(`failed to discover OAuth server metadata (${errors.join("; ")})`);
206
186
  }
207
- async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
187
+ async function fetchOAuthServerMetadata(url, expectedIssuer) {
208
188
  log.debug("oauth.discovery.fetch", { url });
209
- let response;
210
- try {
211
- response = await fetch(url, {
212
- signal: AbortSignal.any([signal, AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS)]),
213
- redirect: "manual"
214
- });
215
- } catch (err) {
216
- throw new MetadataUnreachableError(err instanceof Error ? err.message : String(err));
217
- }
189
+ const response = await fetch(url, { signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS), redirect: "manual" });
218
190
  if (!response.ok) {
219
191
  throw new Error(String(response.status));
220
192
  }
@@ -237,21 +209,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
237
209
  try {
238
210
  return await fetchFirstValidOAuthServerMetadata(oauthMetadataUrlsForIssuer(issuer), issuer);
239
211
  } catch (err) {
240
- const message = `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`;
241
- if (err instanceof MetadataUnreachableError) {
242
- log.error("oauth.discovery.unreachable", {
243
- issuer,
244
- ...describeError(err),
245
- outcome: "503 authorization server unreachable"
246
- });
247
- throw new OAuthUpstreamUnreachableError(message);
248
- }
249
212
  log.error("oauth.discovery.config_error", {
250
213
  issuer,
251
214
  ...describeError(err),
252
215
  outcome: "500 oauth configuration error"
253
216
  });
254
- throw new OAuthConfigurationError(message);
217
+ throw new OAuthConfigurationError(
218
+ `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`
219
+ );
255
220
  }
256
221
  }
257
222
  function createOAuthDiscoveryResolver(auth) {
@@ -341,14 +306,8 @@ function tokenHeaderFields(token) {
341
306
  }
342
307
  }
343
308
  async function fetchVerificationKeySet(jwksUri) {
344
- let response;
345
- try {
346
- response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
347
- } catch (err) {
348
- log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
349
- throw new OAuthUpstreamUnreachableError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
350
- }
351
309
  try {
310
+ const response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
352
311
  if (!response.ok)
353
312
  throw new Error(`JWKS endpoint returned ${response.status}`);
354
313
  const json = await response.json();
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createOAuthProtectedResourceMetadataHandler
3
- } from "../chunk-A2GUTEAK.js";
4
- import "../chunk-E7CPOJN6.js";
3
+ } from "../chunk-PKYNTB7X.js";
4
+ import "../chunk-XIGO7RW6.js";
5
5
  import "../chunk-H37EB22A.js";
6
6
  import "../chunk-6DXGZZA4.js";
7
- import "../chunk-OMEL6F6I.js";
7
+ import "../chunk-QWVSMQJF.js";
8
8
  export {
9
9
  createOAuthProtectedResourceMetadataHandler
10
10
  };
@@ -163,18 +163,6 @@ var OAuthConfigurationError = class extends Error {
163
163
  this.name = "OAuthConfigurationError";
164
164
  }
165
165
  };
166
- var OAuthUpstreamUnreachableError = class extends Error {
167
- constructor(message) {
168
- super(message);
169
- this.name = "OAuthUpstreamUnreachableError";
170
- }
171
- };
172
- var MetadataUnreachableError = class extends Error {
173
- constructor(message) {
174
- super(message);
175
- this.name = "MetadataUnreachableError";
176
- }
177
- };
178
166
  var METADATA_FETCH_TIMEOUT_MS = 5e3;
179
167
  function issuerPath(url) {
180
168
  const path = trimTrailingSlash(url.pathname);
@@ -199,37 +187,21 @@ function oauthMetadataUrlsForIssuer(issuer) {
199
187
  return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
200
188
  }
201
189
  async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
202
- const controller = new AbortController();
203
- const attempts = metadataUrls.map(
204
- (url) => fetchOAuthServerMetadata(url, expectedIssuer, controller.signal).catch((err) => {
190
+ const errors = [];
191
+ for (const url of metadataUrls) {
192
+ try {
193
+ return await fetchOAuthServerMetadata(url, expectedIssuer);
194
+ } catch (err) {
205
195
  log.debug("oauth.discovery.attempt_failed", { url, ...describeError(err) });
206
- throw err instanceof Error ? err : new Error(String(err));
207
- })
208
- );
209
- try {
210
- const metadata = await Promise.any(attempts);
211
- controller.abort();
212
- return metadata;
213
- } catch (aggregate) {
214
- const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
215
- const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
216
- const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
217
- log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
218
- const message = `failed to discover OAuth server metadata (${detail})`;
219
- throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
220
- }
221
- }
222
- async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
223
- log.debug("oauth.discovery.fetch", { url });
224
- let response;
225
- try {
226
- response = await fetch(url, {
227
- signal: AbortSignal.any([signal, AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS)]),
228
- redirect: "manual"
229
- });
230
- } catch (err) {
231
- throw new MetadataUnreachableError(err instanceof Error ? err.message : String(err));
196
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
197
+ }
232
198
  }
199
+ log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors });
200
+ throw new Error(`failed to discover OAuth server metadata (${errors.join("; ")})`);
201
+ }
202
+ async function fetchOAuthServerMetadata(url, expectedIssuer) {
203
+ log.debug("oauth.discovery.fetch", { url });
204
+ const response = await fetch(url, { signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS), redirect: "manual" });
233
205
  if (!response.ok) {
234
206
  throw new Error(String(response.status));
235
207
  }
@@ -252,21 +224,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
252
224
  try {
253
225
  return await fetchFirstValidOAuthServerMetadata(oauthMetadataUrlsForIssuer(issuer), issuer);
254
226
  } catch (err) {
255
- const message = `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`;
256
- if (err instanceof MetadataUnreachableError) {
257
- log.error("oauth.discovery.unreachable", {
258
- issuer,
259
- ...describeError(err),
260
- outcome: "503 authorization server unreachable"
261
- });
262
- throw new OAuthUpstreamUnreachableError(message);
263
- }
264
227
  log.error("oauth.discovery.config_error", {
265
228
  issuer,
266
229
  ...describeError(err),
267
230
  outcome: "500 oauth configuration error"
268
231
  });
269
- throw new OAuthConfigurationError(message);
232
+ throw new OAuthConfigurationError(
233
+ `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`
234
+ );
270
235
  }
271
236
  }
272
237
  function createOAuthDiscoveryResolver(auth) {
@@ -359,14 +324,8 @@ function tokenHeaderFields(token) {
359
324
  }
360
325
  }
361
326
  async function fetchVerificationKeySet(jwksUri) {
362
- let response;
363
- try {
364
- response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
365
- } catch (err) {
366
- log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
367
- throw new OAuthUpstreamUnreachableError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
368
- }
369
327
  try {
328
+ const response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
370
329
  if (!response.ok)
371
330
  throw new Error(`JWKS endpoint returned ${response.status}`);
372
331
  const json = await response.json();
@@ -507,12 +466,6 @@ function oauthConfigurationErrorResponse() {
507
466
  headers: { ...JSON_HEADERS, "Cache-Control": "no-store" }
508
467
  });
509
468
  }
510
- function oauthUpstreamUnreachableResponse() {
511
- return new Response(JSON.stringify({ error: "authorization server unreachable" }), {
512
- status: 503,
513
- headers: { ...JSON_HEADERS, "Cache-Control": "no-store", "Retry-After": "30" }
514
- });
515
- }
516
469
  function parseBearerToken(request) {
517
470
  const header = request.headers.get("Authorization");
518
471
  if (!header)
@@ -585,16 +538,6 @@ function createRequestAuthorizer(mcp, options = {}) {
585
538
  assertRequiredScopes(runtime.auth, auth);
586
539
  return { ok: true, auth };
587
540
  } catch (err) {
588
- if (err instanceof OAuthUpstreamUnreachableError) {
589
- log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
590
- await recorder?.emit({
591
- tool: null,
592
- method: "authorize",
593
- outcome: "auth_upstream_unreachable",
594
- durationMs: nowMs() - startedAt
595
- });
596
- return { ok: false, response: oauthUpstreamUnreachableResponse() };
597
- }
598
541
  if (err instanceof OAuthConfigurationError) {
599
542
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
600
543
  await recorder?.emit({
@@ -744,6 +687,14 @@ var ToolContext = class {
744
687
  }
745
688
  };
746
689
 
690
+ // src/core/content.ts
691
+ function extractTextContent(content) {
692
+ if (!content)
693
+ return void 0;
694
+ const text = content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
695
+ return text.length > 0 ? text : void 0;
696
+ }
697
+
747
698
  // src/protocols/rest/invoke-tool.ts
748
699
  var MAX_REFLECTED_TOOL_NAME = 256;
749
700
  function safeReflectName(name) {
@@ -844,7 +795,8 @@ function createInvokeToolHandler(mcp, options = {}) {
844
795
  tool: tool.name,
845
796
  method: "tools/call",
846
797
  outcome: result.isError ? "tool_error" : "ok",
847
- durationMs: nowMs() - start
798
+ durationMs: nowMs() - start,
799
+ errorText: result.isError ? extractTextContent(result.content) : void 0
848
800
  });
849
801
  return Response.json({
850
802
  content: result.content ?? [],
@@ -1,6 +1,6 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
2
2
  import { d as McpDefinition } from '../../types-CPkhCRxc.js';
3
- import { M as MetricsRecorder } from '../../base-RSqYamjy.js';
3
+ import { M as MetricsRecorder } from '../../base-CFy5vZ5Z.js';
4
4
  import 'zod';
5
5
 
6
6
  type RestListToolsHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
@@ -1,6 +1,6 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
2
2
  import { d as McpDefinition } from '../../types-CPkhCRxc.js';
3
- import { M as MetricsRecorder } from '../../base-RSqYamjy.js';
3
+ import { M as MetricsRecorder } from '../../base-CFy5vZ5Z.js';
4
4
  import 'zod';
5
5
 
6
6
  type RestListToolsHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
@@ -1,14 +1,15 @@
1
1
  import {
2
2
  createInvokeToolHandler
3
- } from "../../chunk-RT2I26ZN.js";
3
+ } from "../../chunk-YQMS7A7Z.js";
4
4
  import {
5
5
  createListToolsHandler
6
- } from "../../chunk-YAXKWTJK.js";
6
+ } from "../../chunk-ICCGSB2E.js";
7
+ import "../../chunk-6QFZYYUV.js";
7
8
  import "../../chunk-MA5H6PSF.js";
8
- import "../../chunk-E7CPOJN6.js";
9
+ import "../../chunk-XIGO7RW6.js";
9
10
  import "../../chunk-H37EB22A.js";
10
11
  import "../../chunk-6DXGZZA4.js";
11
- import "../../chunk-OMEL6F6I.js";
12
+ import "../../chunk-QWVSMQJF.js";
12
13
  export {
13
14
  createInvokeToolHandler,
14
15
  createListToolsHandler
@@ -174,7 +174,7 @@ function describeError(err) {
174
174
  }
175
175
 
176
176
  // package.json
177
- var version = "0.20.1-rc.0";
177
+ var version = "0.20.1-rc.1";
178
178
 
179
179
  // src/metrics/otlp.ts
180
180
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -281,7 +281,8 @@ var BaseMetricRecorder = class {
281
281
  method: ev.method,
282
282
  outcome: ev.outcome,
283
283
  durationMs: ev.durationMs,
284
- stack: this.stack
284
+ stack: this.stack,
285
+ ...ev.errorText !== void 0 && { errorText: ev.errorText }
285
286
  });
286
287
  if (!this.config.enabled)
287
288
  return;
@@ -445,18 +446,6 @@ var OAuthConfigurationError = class extends Error {
445
446
  this.name = "OAuthConfigurationError";
446
447
  }
447
448
  };
448
- var OAuthUpstreamUnreachableError = class extends Error {
449
- constructor(message) {
450
- super(message);
451
- this.name = "OAuthUpstreamUnreachableError";
452
- }
453
- };
454
- var MetadataUnreachableError = class extends Error {
455
- constructor(message) {
456
- super(message);
457
- this.name = "MetadataUnreachableError";
458
- }
459
- };
460
449
  var METADATA_FETCH_TIMEOUT_MS = 5e3;
461
450
  function issuerPath(url) {
462
451
  const path = trimTrailingSlash(url.pathname);
@@ -481,37 +470,21 @@ function oauthMetadataUrlsForIssuer(issuer) {
481
470
  return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
482
471
  }
483
472
  async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
484
- const controller = new AbortController();
485
- const attempts = metadataUrls.map(
486
- (url) => fetchOAuthServerMetadata(url, expectedIssuer, controller.signal).catch((err) => {
473
+ const errors = [];
474
+ for (const url of metadataUrls) {
475
+ try {
476
+ return await fetchOAuthServerMetadata(url, expectedIssuer);
477
+ } catch (err) {
487
478
  log.debug("oauth.discovery.attempt_failed", { url, ...describeError(err) });
488
- throw err instanceof Error ? err : new Error(String(err));
489
- })
490
- );
491
- try {
492
- const metadata = await Promise.any(attempts);
493
- controller.abort();
494
- return metadata;
495
- } catch (aggregate) {
496
- const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
497
- const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
498
- const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
499
- log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
500
- const message = `failed to discover OAuth server metadata (${detail})`;
501
- throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
479
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
480
+ }
502
481
  }
482
+ log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors });
483
+ throw new Error(`failed to discover OAuth server metadata (${errors.join("; ")})`);
503
484
  }
504
- async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
485
+ async function fetchOAuthServerMetadata(url, expectedIssuer) {
505
486
  log.debug("oauth.discovery.fetch", { url });
506
- let response;
507
- try {
508
- response = await fetch(url, {
509
- signal: AbortSignal.any([signal, AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS)]),
510
- redirect: "manual"
511
- });
512
- } catch (err) {
513
- throw new MetadataUnreachableError(err instanceof Error ? err.message : String(err));
514
- }
487
+ const response = await fetch(url, { signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS), redirect: "manual" });
515
488
  if (!response.ok) {
516
489
  throw new Error(String(response.status));
517
490
  }
@@ -534,21 +507,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
534
507
  try {
535
508
  return await fetchFirstValidOAuthServerMetadata(oauthMetadataUrlsForIssuer(issuer), issuer);
536
509
  } catch (err) {
537
- const message = `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`;
538
- if (err instanceof MetadataUnreachableError) {
539
- log.error("oauth.discovery.unreachable", {
540
- issuer,
541
- ...describeError(err),
542
- outcome: "503 authorization server unreachable"
543
- });
544
- throw new OAuthUpstreamUnreachableError(message);
545
- }
546
510
  log.error("oauth.discovery.config_error", {
547
511
  issuer,
548
512
  ...describeError(err),
549
513
  outcome: "500 oauth configuration error"
550
514
  });
551
- throw new OAuthConfigurationError(message);
515
+ throw new OAuthConfigurationError(
516
+ `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`
517
+ );
552
518
  }
553
519
  }
554
520
  function createOAuthDiscoveryResolver(auth) {
@@ -614,14 +580,8 @@ function tokenHeaderFields(token) {
614
580
  }
615
581
  }
616
582
  async function fetchVerificationKeySet(jwksUri) {
617
- let response;
618
- try {
619
- response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
620
- } catch (err) {
621
- log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
622
- throw new OAuthUpstreamUnreachableError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
623
- }
624
583
  try {
584
+ const response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
625
585
  if (!response.ok)
626
586
  throw new Error(`JWKS endpoint returned ${response.status}`);
627
587
  const json = await response.json();
@@ -762,12 +722,6 @@ function oauthConfigurationErrorResponse() {
762
722
  headers: { ...JSON_HEADERS, "Cache-Control": "no-store" }
763
723
  });
764
724
  }
765
- function oauthUpstreamUnreachableResponse() {
766
- return new Response(JSON.stringify({ error: "authorization server unreachable" }), {
767
- status: 503,
768
- headers: { ...JSON_HEADERS, "Cache-Control": "no-store", "Retry-After": "30" }
769
- });
770
- }
771
725
  function parseBearerToken(request) {
772
726
  const header = request.headers.get("Authorization");
773
727
  if (!header)
@@ -840,16 +794,6 @@ function createRequestAuthorizer(mcp, options = {}) {
840
794
  assertRequiredScopes(runtime.auth, auth);
841
795
  return { ok: true, auth };
842
796
  } catch (err) {
843
- if (err instanceof OAuthUpstreamUnreachableError) {
844
- log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
845
- await recorder?.emit({
846
- tool: null,
847
- method: "authorize",
848
- outcome: "auth_upstream_unreachable",
849
- durationMs: nowMs() - startedAt
850
- });
851
- return { ok: false, response: oauthUpstreamUnreachableResponse() };
852
- }
853
797
  if (err instanceof OAuthConfigurationError) {
854
798
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
855
799
  await recorder?.emit({
@@ -934,6 +878,14 @@ var ToolContext = class {
934
878
  }
935
879
  };
936
880
 
881
+ // src/core/content.ts
882
+ function extractTextContent(content) {
883
+ if (!content)
884
+ return void 0;
885
+ const text = content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
886
+ return text.length > 0 ? text : void 0;
887
+ }
888
+
937
889
  // src/core/cors.ts
938
890
  var EXPOSE_HEADERS = "WWW-Authenticate, Mcp-Session-Id, Mcp-Protocol-Version";
939
891
  var ALLOW_HEADERS = "Authorization, Content-Type, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID";
@@ -984,7 +936,8 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
984
936
  tool: tool.name,
985
937
  method: "tools/call",
986
938
  outcome: result.isError ? "tool_error" : "ok",
987
- durationMs: nowMs() - start
939
+ durationMs: nowMs() - start,
940
+ errorText: result.isError ? extractTextContent(result.content) : void 0
988
941
  });
989
942
  return { content: result.content ?? [], structuredContent: result.structuredContent, isError: result.isError };
990
943
  };
@@ -1240,7 +1193,8 @@ function createInvokeToolHandler(mcp, options = {}) {
1240
1193
  tool: tool.name,
1241
1194
  method: "tools/call",
1242
1195
  outcome: result.isError ? "tool_error" : "ok",
1243
- durationMs: nowMs() - start
1196
+ durationMs: nowMs() - start,
1197
+ errorText: result.isError ? extractTextContent(result.content) : void 0
1244
1198
  });
1245
1199
  return Response.json({
1246
1200
  content: result.content ?? [],
@@ -3,21 +3,22 @@ import {
3
3
  } from "../../chunk-UQK5UO6C.js";
4
4
  import {
5
5
  createMcpProtocolHandler
6
- } from "../../chunk-ID3YWZBR.js";
6
+ } from "../../chunk-YQFF4OCL.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-A2GUTEAK.js";
9
+ } from "../../chunk-PKYNTB7X.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-RT2I26ZN.js";
12
+ } from "../../chunk-YQMS7A7Z.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-YAXKWTJK.js";
15
+ } from "../../chunk-ICCGSB2E.js";
16
+ import "../../chunk-6QFZYYUV.js";
16
17
  import "../../chunk-MA5H6PSF.js";
17
18
  import {
18
19
  assertResourcePathShape,
19
20
  createRecorderForRuntime
20
- } from "../../chunk-E7CPOJN6.js";
21
+ } from "../../chunk-XIGO7RW6.js";
21
22
  import {
22
23
  trimTrailingSlash
23
24
  } from "../../chunk-H37EB22A.js";
@@ -28,7 +29,7 @@ import {
28
29
  FUNCTIONS_MOUNT_PREFIX,
29
30
  assertFunctionName
30
31
  } from "../../chunk-XQWJN6DC.js";
31
- import "../../chunk-OMEL6F6I.js";
32
+ import "../../chunk-QWVSMQJF.js";
32
33
 
33
34
  // src/stacks/supabase/handler.ts
34
35
  function deriveResourcePath(options) {
@@ -33,7 +33,7 @@ var import_node_fs = require("fs");
33
33
  var import_node_path = require("path");
34
34
 
35
35
  // package.json
36
- var version = "0.20.1-rc.0";
36
+ var version = "0.20.1-rc.1";
37
37
 
38
38
  // src/core/fs-errors.ts
39
39
  function isFileMissing(err) {
@@ -7,7 +7,7 @@ import {
7
7
  } from "../../chunk-XQWJN6DC.js";
8
8
  import {
9
9
  version
10
- } from "../../chunk-OMEL6F6I.js";
10
+ } from "../../chunk-QWVSMQJF.js";
11
11
 
12
12
  // src/stacks/supabase/vite.ts
13
13
  import { resolve as resolve2, sep as sep2 } from "path";
@@ -129,7 +129,7 @@ function describeError(err) {
129
129
  }
130
130
 
131
131
  // package.json
132
- var version = "0.20.1-rc.0";
132
+ var version = "0.20.1-rc.1";
133
133
 
134
134
  // src/metrics/otlp.ts
135
135
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -236,7 +236,8 @@ var BaseMetricRecorder = class {
236
236
  method: ev.method,
237
237
  outcome: ev.outcome,
238
238
  durationMs: ev.durationMs,
239
- stack: this.stack
239
+ stack: this.stack,
240
+ ...ev.errorText !== void 0 && { errorText: ev.errorText }
240
241
  });
241
242
  if (!this.config.enabled)
242
243
  return;
@@ -421,18 +422,6 @@ var OAuthConfigurationError = class extends Error {
421
422
  this.name = "OAuthConfigurationError";
422
423
  }
423
424
  };
424
- var OAuthUpstreamUnreachableError = class extends Error {
425
- constructor(message) {
426
- super(message);
427
- this.name = "OAuthUpstreamUnreachableError";
428
- }
429
- };
430
- var MetadataUnreachableError = class extends Error {
431
- constructor(message) {
432
- super(message);
433
- this.name = "MetadataUnreachableError";
434
- }
435
- };
436
425
  var METADATA_FETCH_TIMEOUT_MS = 5e3;
437
426
  function issuerPath(url) {
438
427
  const path = trimTrailingSlash(url.pathname);
@@ -457,37 +446,21 @@ function oauthMetadataUrlsForIssuer(issuer) {
457
446
  return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
458
447
  }
459
448
  async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
460
- const controller = new AbortController();
461
- const attempts = metadataUrls.map(
462
- (url) => fetchOAuthServerMetadata(url, expectedIssuer, controller.signal).catch((err) => {
449
+ const errors = [];
450
+ for (const url of metadataUrls) {
451
+ try {
452
+ return await fetchOAuthServerMetadata(url, expectedIssuer);
453
+ } catch (err) {
463
454
  log.debug("oauth.discovery.attempt_failed", { url, ...describeError(err) });
464
- throw err instanceof Error ? err : new Error(String(err));
465
- })
466
- );
467
- try {
468
- const metadata = await Promise.any(attempts);
469
- controller.abort();
470
- return metadata;
471
- } catch (aggregate) {
472
- const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
473
- const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
474
- const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
475
- log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
476
- const message = `failed to discover OAuth server metadata (${detail})`;
477
- throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
455
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
456
+ }
478
457
  }
458
+ log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors });
459
+ throw new Error(`failed to discover OAuth server metadata (${errors.join("; ")})`);
479
460
  }
480
- async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
461
+ async function fetchOAuthServerMetadata(url, expectedIssuer) {
481
462
  log.debug("oauth.discovery.fetch", { url });
482
- let response;
483
- try {
484
- response = await fetch(url, {
485
- signal: AbortSignal.any([signal, AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS)]),
486
- redirect: "manual"
487
- });
488
- } catch (err) {
489
- throw new MetadataUnreachableError(err instanceof Error ? err.message : String(err));
490
- }
463
+ const response = await fetch(url, { signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS), redirect: "manual" });
491
464
  if (!response.ok) {
492
465
  throw new Error(String(response.status));
493
466
  }
@@ -510,21 +483,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
510
483
  try {
511
484
  return await fetchFirstValidOAuthServerMetadata(oauthMetadataUrlsForIssuer(issuer), issuer);
512
485
  } catch (err) {
513
- const message = `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`;
514
- if (err instanceof MetadataUnreachableError) {
515
- log.error("oauth.discovery.unreachable", {
516
- issuer,
517
- ...describeError(err),
518
- outcome: "503 authorization server unreachable"
519
- });
520
- throw new OAuthUpstreamUnreachableError(message);
521
- }
522
486
  log.error("oauth.discovery.config_error", {
523
487
  issuer,
524
488
  ...describeError(err),
525
489
  outcome: "500 oauth configuration error"
526
490
  });
527
- throw new OAuthConfigurationError(message);
491
+ throw new OAuthConfigurationError(
492
+ `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`
493
+ );
528
494
  }
529
495
  }
530
496
  function createOAuthDiscoveryResolver(auth) {
@@ -617,14 +583,8 @@ function tokenHeaderFields(token) {
617
583
  }
618
584
  }
619
585
  async function fetchVerificationKeySet(jwksUri) {
620
- let response;
621
- try {
622
- response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
623
- } catch (err) {
624
- log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
625
- throw new OAuthUpstreamUnreachableError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
626
- }
627
586
  try {
587
+ const response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
628
588
  if (!response.ok)
629
589
  throw new Error(`JWKS endpoint returned ${response.status}`);
630
590
  const json = await response.json();
@@ -765,12 +725,6 @@ function oauthConfigurationErrorResponse() {
765
725
  headers: { ...JSON_HEADERS, "Cache-Control": "no-store" }
766
726
  });
767
727
  }
768
- function oauthUpstreamUnreachableResponse() {
769
- return new Response(JSON.stringify({ error: "authorization server unreachable" }), {
770
- status: 503,
771
- headers: { ...JSON_HEADERS, "Cache-Control": "no-store", "Retry-After": "30" }
772
- });
773
- }
774
728
  function parseBearerToken(request) {
775
729
  const header = request.headers.get("Authorization");
776
730
  if (!header)
@@ -843,16 +797,6 @@ function createRequestAuthorizer(mcp, options = {}) {
843
797
  assertRequiredScopes(runtime.auth, auth);
844
798
  return { ok: true, auth };
845
799
  } catch (err) {
846
- if (err instanceof OAuthUpstreamUnreachableError) {
847
- log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
848
- await recorder?.emit({
849
- tool: null,
850
- method: "authorize",
851
- outcome: "auth_upstream_unreachable",
852
- durationMs: nowMs() - startedAt
853
- });
854
- return { ok: false, response: oauthUpstreamUnreachableResponse() };
855
- }
856
800
  if (err instanceof OAuthConfigurationError) {
857
801
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
858
802
  await recorder?.emit({
@@ -937,6 +881,14 @@ var ToolContext = class {
937
881
  }
938
882
  };
939
883
 
884
+ // src/core/content.ts
885
+ function extractTextContent(content) {
886
+ if (!content)
887
+ return void 0;
888
+ const text = content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
889
+ return text.length > 0 ? text : void 0;
890
+ }
891
+
940
892
  // src/core/cors.ts
941
893
  var EXPOSE_HEADERS = "WWW-Authenticate, Mcp-Session-Id, Mcp-Protocol-Version";
942
894
  var ALLOW_HEADERS = "Authorization, Content-Type, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID";
@@ -987,7 +939,8 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
987
939
  tool: tool.name,
988
940
  method: "tools/call",
989
941
  outcome: result.isError ? "tool_error" : "ok",
990
- durationMs: nowMs() - start
942
+ durationMs: nowMs() - start,
943
+ errorText: result.isError ? extractTextContent(result.content) : void 0
991
944
  });
992
945
  return { content: result.content ?? [], structuredContent: result.structuredContent, isError: result.isError };
993
946
  };
@@ -1243,7 +1196,8 @@ function createInvokeToolHandler(mcp, options = {}) {
1243
1196
  tool: tool.name,
1244
1197
  method: "tools/call",
1245
1198
  outcome: result.isError ? "tool_error" : "ok",
1246
- durationMs: nowMs() - start
1199
+ durationMs: nowMs() - start,
1200
+ errorText: result.isError ? extractTextContent(result.content) : void 0
1247
1201
  });
1248
1202
  return Response.json({
1249
1203
  content: result.content ?? [],
@@ -3,23 +3,24 @@ import {
3
3
  } from "../../chunk-UQK5UO6C.js";
4
4
  import {
5
5
  createMcpProtocolHandler
6
- } from "../../chunk-ID3YWZBR.js";
6
+ } from "../../chunk-YQFF4OCL.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-A2GUTEAK.js";
9
+ } from "../../chunk-PKYNTB7X.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-RT2I26ZN.js";
12
+ } from "../../chunk-YQMS7A7Z.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-YAXKWTJK.js";
15
+ } from "../../chunk-ICCGSB2E.js";
16
+ import "../../chunk-6QFZYYUV.js";
16
17
  import "../../chunk-MA5H6PSF.js";
17
18
  import {
18
19
  createRecorderForRuntime
19
- } from "../../chunk-E7CPOJN6.js";
20
+ } from "../../chunk-XIGO7RW6.js";
20
21
  import "../../chunk-H37EB22A.js";
21
22
  import "../../chunk-6DXGZZA4.js";
22
- import "../../chunk-OMEL6F6I.js";
23
+ import "../../chunk-QWVSMQJF.js";
23
24
 
24
25
  // src/stacks/tanstack/handlers.ts
25
26
  var STACK = "tanstack";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovable.dev/mcp-js",
3
- "version": "0.20.1-rc.0",
3
+ "version": "0.20.1-rc.1",
4
4
  "description": "Author MCP servers for Lovable apps. Declare tools with defineTool, register them in defineMcp, and a framework adapter (TanStack or Supabase Edge Functions) emits the route(s) at build time.",
5
5
  "type": "module",
6
6
  "repository": {