@frontmcp/adapters 1.8.2 → 1.8.4

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.
package/openapi/index.js CHANGED
@@ -46,7 +46,7 @@ module.exports = __toCommonJS(openapi_exports);
46
46
 
47
47
  // libs/adapters/src/openapi/openapi.adapter.ts
48
48
  var import_mcp_from_openapi3 = require("mcp-from-openapi");
49
- var import_sdk4 = require("@frontmcp/sdk");
49
+ var import_sdk5 = require("@frontmcp/sdk");
50
50
 
51
51
  // libs/adapters/src/openapi/openapi-spec-poller.ts
52
52
  var import_mcp_from_openapi = require("mcp-from-openapi");
@@ -219,12 +219,13 @@ var OpenApiSpecPoller = class {
219
219
 
220
220
  // libs/adapters/src/openapi/openapi.security.ts
221
221
  var import_mcp_from_openapi2 = require("mcp-from-openapi");
222
+ var import_sdk2 = require("@frontmcp/sdk");
222
223
  async function createSecurityContextFromAuth(tool2, ctx, options) {
223
224
  if (options.securityResolver) {
224
225
  return await options.securityResolver(tool2, ctx);
225
226
  }
226
227
  if (options.authProviderMapper) {
227
- const context = (0, import_mcp_from_openapi2.createSecurityContext)({});
228
+ const context = {};
228
229
  const securitySchemes = /* @__PURE__ */ new Set();
229
230
  for (const mapper of tool2.mapper) {
230
231
  if (mapper.security?.scheme) {
@@ -273,26 +274,42 @@ async function createSecurityContextFromAuth(tool2, ctx, options) {
273
274
  throw err;
274
275
  }
275
276
  const errorMessage = err instanceof Error ? err.message : String(err);
276
- throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`);
277
+ throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`, { cause: err });
277
278
  }
278
279
  }
279
280
  }
281
+ if (hasStaticAuth(options)) {
282
+ return (0, import_mcp_from_openapi2.createSecurityContext)({ ...options.staticAuth, ...context });
283
+ }
280
284
  const hasAnyAuth = context.jwt || context.apiKey || context.basic || context.oauth2Token;
281
- const authToken = ctx.authInfo?.token;
282
- if (!hasAnyAuth && authToken) {
283
- if (typeof authToken !== "string") {
284
- throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`);
285
+ if (!hasAnyAuth && options.passthroughCallerToken === true) {
286
+ const callerToken = getCallerToken(ctx);
287
+ if (callerToken) {
288
+ context.jwt = callerToken;
285
289
  }
286
- context.jwt = authToken;
287
290
  }
288
- return context;
291
+ return (0, import_mcp_from_openapi2.createSecurityContext)(context);
289
292
  }
290
- if (options.staticAuth) {
293
+ if (hasStaticAuth(options)) {
291
294
  return (0, import_mcp_from_openapi2.createSecurityContext)(options.staticAuth);
292
295
  }
293
- return (0, import_mcp_from_openapi2.createSecurityContext)({
294
- jwt: ctx.authInfo?.token
295
- });
296
+ if (options.passthroughCallerToken === true) {
297
+ return (0, import_mcp_from_openapi2.createSecurityContext)({ jwt: getCallerToken(ctx) });
298
+ }
299
+ return (0, import_mcp_from_openapi2.createSecurityContext)({});
300
+ }
301
+ function hasStaticAuth(options) {
302
+ return !!options.staticAuth && Object.keys(options.staticAuth).length > 0;
303
+ }
304
+ function getCallerToken(ctx) {
305
+ const authToken = ctx.authInfo?.token;
306
+ if (authToken === void 0 || authToken === null || authToken === "") {
307
+ return void 0;
308
+ }
309
+ if (typeof authToken !== "string") {
310
+ throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`);
311
+ }
312
+ return authToken;
296
313
  }
297
314
  function extractSecuritySchemes(tools) {
298
315
  const schemes = /* @__PURE__ */ new Set();
@@ -305,19 +322,158 @@ function extractSecuritySchemes(tools) {
305
322
  }
306
323
  return schemes;
307
324
  }
325
+ function describeSecuritySchemes(tools) {
326
+ const schemes = /* @__PURE__ */ new Map();
327
+ for (const tool2 of tools) {
328
+ for (const mapper of tool2.mapper) {
329
+ if (mapper.security?.scheme && !schemes.has(mapper.security.scheme)) {
330
+ schemes.set(mapper.security.scheme, mapper.security);
331
+ }
332
+ }
333
+ }
334
+ return schemes;
335
+ }
336
+ function schemeParametersOf(tools) {
337
+ const parameters = /* @__PURE__ */ new Map();
338
+ for (const tool2 of tools) {
339
+ for (const mapper of tool2.mapper) {
340
+ const scheme = mapper.security?.scheme;
341
+ if (scheme && !parameters.has(scheme)) parameters.set(scheme, mapper);
342
+ }
343
+ }
344
+ return parameters;
345
+ }
346
+ function headerCredentialSource(parameter, options) {
347
+ if (!parameter) return void 0;
348
+ const staticHeaders = new Headers(options.additionalHeaders ?? {});
349
+ if (carriesSchemeParameter(parameter, new URL("http://startup.invalid/"), staticHeaders)) return "static";
350
+ if (options.headersMapper && (parameter.type === "header" || parameter.type === "cookie")) return "per-request";
351
+ return void 0;
352
+ }
353
+ function isBearerScheme(security) {
354
+ if (!security || security.type !== "http") return false;
355
+ return (security.httpScheme ?? "bearer").toLowerCase() === "bearer";
356
+ }
357
+ function credentialFieldOf(security) {
358
+ if (security?.type === "apiKey") return "apiKey";
359
+ if (security?.type === "oauth2" || security?.type === "openIdConnect") return "oauth2Token";
360
+ if (security?.type === "http" && security.httpScheme?.toLowerCase() === "basic") return "basic";
361
+ return "jwt";
362
+ }
363
+ function formatMissingSecurityMappingsError(adapterName, tools, missingMappings) {
364
+ const schemes = describeSecuritySchemes(tools);
365
+ const fieldOf = (scheme) => credentialFieldOf(schemes.get(scheme));
366
+ const firstField = fieldOf(missingMappings[0] ?? "");
367
+ const bearerSchemes = missingMappings.filter((scheme) => isBearerScheme(schemes.get(scheme)));
368
+ const lines = [
369
+ `[OpenAPI Adapter: ${adapterName}] Invalid security configuration.`,
370
+ `Missing auth provider mappings for security schemes: ${missingMappings.join(", ")}`,
371
+ "",
372
+ "Your OpenAPI spec requires these security schemes, but no credential option covers them.",
373
+ "",
374
+ "Add one of the following to your adapter configuration:",
375
+ "",
376
+ "1. authProviderMapper (recommended): a function per scheme that returns the credential issued for the API:",
377
+ " authProviderMapper: {",
378
+ ...missingMappings.map((scheme) => ` '${scheme}': (ctx) => getApiCredential(ctx), // the ${fieldOf(scheme)}`),
379
+ " }",
380
+ "",
381
+ "2. securityResolver:",
382
+ ` securityResolver: async (tool, ctx) => ({ ${firstField}: await getApiCredential(ctx) })`,
383
+ "",
384
+ "3. staticAuth (one credential for every caller):",
385
+ ` staticAuth: { ${firstField}: process.env.API_CREDENTIAL }`
386
+ ];
387
+ if (bearerSchemes.length > 0) {
388
+ lines.push(
389
+ "",
390
+ `4. passthroughCallerToken: true, for the HTTP bearer schemes (${bearerSchemes.join(", ")}) only, and only if the API`,
391
+ " accepts the MCP client's own token (same issuer and audience). It sends nothing for other schemes."
392
+ );
393
+ }
394
+ return lines.join("\n");
395
+ }
396
+ function authenticationRequiredError(tool2) {
397
+ const required = requiredSecurityOf(tool2);
398
+ const schemes = [...new Map(required.map((security) => [security.scheme, security])).values()];
399
+ const schemesStr = schemes.map((security) => `${security.scheme} (${security.type})`).join(", ") || "unknown";
400
+ const first = schemes[0];
401
+ const firstScheme = first?.scheme ?? "BearerAuth";
402
+ const field = credentialFieldOf(first);
403
+ const bearerSchemes = schemes.filter(isBearerScheme).map((security) => security.scheme);
404
+ const solutions = [
405
+ ` 1. Add authProviderMapper: { '${firstScheme}': (ctx) => getApiCredential(ctx) }, returning the ${field} issued for the API`,
406
+ ` 2. Add securityResolver: async (tool, ctx) => ({ ${field}: await getApiCredential(ctx) })`,
407
+ ` 3. Add staticAuth: { ${field}: process.env.API_CREDENTIAL }`
408
+ ];
409
+ if (bearerSchemes.length > 0) {
410
+ solutions.push(
411
+ ` 4. Set passthroughCallerToken: true, only if the API accepts the MCP client's own token (it fills ${bearerSchemes.join(", ")} only)`
412
+ );
413
+ }
414
+ return new Error(
415
+ `Authentication required for tool '${tool2.name}': no credential for its security schemes.
416
+ Required security schemes: ${schemesStr}
417
+ Solutions:
418
+ ` + solutions.join("\n")
419
+ );
420
+ }
421
+ function requiredSecurityOf(tool2) {
422
+ return tool2.mapper.flatMap((mapper) => mapper.security && mapper.required === true ? [mapper.security] : []);
423
+ }
424
+ function authorizationSchemeOf(security) {
425
+ if (security?.type === "http") return (security.httpScheme ?? "bearer").toLowerCase();
426
+ if (security?.type === "oauth2" || security?.type === "openIdConnect") return "bearer";
427
+ return void 0;
428
+ }
429
+ function carriesSchemeParameter(mapper, url, headers) {
430
+ if (mapper.type === "query") return !!url.searchParams.get(mapper.key);
431
+ if (mapper.type === "cookie") {
432
+ return (headers.get("cookie") ?? "").split(";").some((pair) => {
433
+ const [name, ...value2] = pair.trim().split("=");
434
+ return name === mapper.key && value2.join("=") !== "";
435
+ });
436
+ }
437
+ if (mapper.type !== "header") return false;
438
+ const value = headers.get(mapper.key)?.trim();
439
+ if (!value) return false;
440
+ const scheme = authorizationSchemeOf(mapper.security);
441
+ if (!scheme) return true;
442
+ const space = value.indexOf(" ");
443
+ return space > 0 && value.slice(0, space).toLowerCase() === scheme && value.slice(space + 1).trim() !== "";
444
+ }
445
+ function assertRequestHasCredential(tool2, url, headers) {
446
+ const securityMappers = tool2.mapper.filter((mapper) => mapper.security && mapper.required === true);
447
+ if (securityMappers.length === 0) return;
448
+ const parsedUrl = new URL(url);
449
+ if (!securityMappers.some((mapper) => carriesSchemeParameter(mapper, parsedUrl, headers))) {
450
+ throw authenticationRequiredError(tool2);
451
+ }
452
+ }
308
453
  function validateSecurityConfiguration(tools, options) {
454
+ const result = validateCredentialSources(tools, options);
455
+ const schemesInInput = options.securitySchemesInInput ?? [];
456
+ if (options.generateOptions?.includeSecurityInInput !== true && schemesInInput.length > 0) {
457
+ result.securityRiskScore = "high";
458
+ result.warnings.push(
459
+ `SECURITY WARNING: securitySchemesInInput is enabled. The model provides the credential for security schemes ${schemesInInput.join(", ")} in tool inputs, used when the server supplies none. Credentials may be logged or exposed, and the model chooses whose account a call uses.`
460
+ );
461
+ }
462
+ return result;
463
+ }
464
+ function validateCredentialSources(tools, options) {
309
465
  const result = {
310
466
  valid: true,
311
467
  missingMappings: [],
312
468
  warnings: [],
313
469
  securityRiskScore: "low"
314
470
  };
315
- const securitySchemes = extractSecuritySchemes(tools);
471
+ const securitySchemes = describeSecuritySchemes(tools);
316
472
  const includeSecurityInInput = options.generateOptions?.includeSecurityInInput ?? false;
317
473
  if (includeSecurityInInput) {
318
474
  result.securityRiskScore = "high";
319
475
  result.warnings.push(
320
- "SECURITY WARNING: includeSecurityInInput is enabled. Users will provide authentication directly in tool inputs. This increases security risk as credentials may be logged or exposed."
476
+ "SECURITY WARNING: includeSecurityInInput is enabled. Users will provide authentication directly in tool inputs (used for a scheme when the server supplies none). This increases security risk as credentials may be logged or exposed."
321
477
  );
322
478
  return result;
323
479
  }
@@ -328,28 +484,35 @@ function validateSecurityConfiguration(tools, options) {
328
484
  );
329
485
  return result;
330
486
  }
331
- if (options.staticAuth && Object.keys(options.staticAuth).length > 0) {
487
+ if (hasStaticAuth(options)) {
332
488
  result.securityRiskScore = "medium";
333
489
  result.warnings.push(
334
490
  "SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager)."
335
491
  );
336
- return result;
492
+ return withPassthroughRisk(result, securitySchemes, options);
337
493
  }
338
494
  const schemesInInput = new Set(options.securitySchemesInInput || []);
339
495
  if (options.authProviderMapper || schemesInInput.size > 0) {
340
- result.securityRiskScore = schemesInInput.size > 0 ? "medium" : "low";
341
- if (schemesInInput.size > 0) {
342
- result.warnings.push(
343
- `INFO: Per-scheme security control enabled. Schemes in input: ${Array.from(schemesInInput).join(", ")}`
344
- );
345
- }
346
- for (const scheme of securitySchemes) {
496
+ result.securityRiskScore = "low";
497
+ const passthroughFallback = [];
498
+ const perRequestHeaders = [];
499
+ const schemeParameters = schemeParametersOf(tools);
500
+ for (const [scheme, security] of securitySchemes) {
347
501
  if (schemesInInput.has(scheme)) {
348
502
  continue;
349
503
  }
350
504
  if (!options.authProviderMapper?.[scheme]) {
351
- result.valid = false;
352
- result.missingMappings.push(scheme);
505
+ const headerSource = headerCredentialSource(schemeParameters.get(scheme), options);
506
+ if (headerSource === "static") {
507
+ continue;
508
+ } else if (headerSource === "per-request") {
509
+ perRequestHeaders.push(scheme);
510
+ } else if (options.passthroughCallerToken === true && isBearerScheme(security)) {
511
+ passthroughFallback.push(scheme);
512
+ } else {
513
+ result.valid = false;
514
+ result.missingMappings.push(scheme);
515
+ }
353
516
  }
354
517
  }
355
518
  if (!result.valid) {
@@ -357,47 +520,113 @@ function validateSecurityConfiguration(tools, options) {
357
520
  `ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(", ")}`
358
521
  );
359
522
  }
523
+ if (perRequestHeaders.length > 0) {
524
+ result.warnings.push(
525
+ `INFO: Security schemes with no authProviderMapper entry (${perRequestHeaders.join(", ")}) take their credential from headersMapper. An operation that requires only them is refused when headersMapper sets none.`
526
+ );
527
+ }
528
+ withPassthroughRisk(result, securitySchemes, options);
529
+ if (passthroughFallback.length > 0) {
530
+ result.warnings.push(
531
+ `SECURITY WARNING: Security schemes with no authProviderMapper entry (${passthroughFallback.join(", ")}) get the MCP client's own token, because passthroughCallerToken is enabled.`
532
+ );
533
+ }
360
534
  return result;
361
535
  }
362
- if (securitySchemes.size > 0) {
536
+ if (securitySchemes.size > 0 && options.passthroughCallerToken !== true) {
537
+ const schemesStr = Array.from(securitySchemes.keys()).join(", ");
363
538
  result.securityRiskScore = "medium";
364
539
  result.warnings.push(
365
- `INFO: No auth configuration provided. Using default ctx.authInfo.token for all security schemes: ${Array.from(
366
- securitySchemes
367
- ).join(", ")}`
540
+ `SECURITY WARNING: No auth configuration provided, so the adapter has no credentials for the API (security schemes: ${schemesStr}). Operations that require authentication fail unless additionalHeaders or headersMapper sets their credential. The MCP client's own token is not forwarded: configure authProviderMapper, securityResolver or staticAuth, or set passthroughCallerToken: true if the API is meant to receive the caller's MCP token.`
368
541
  );
542
+ }
543
+ const unfilled = [...securitySchemes].filter(([, security]) => !isBearerScheme(security)).map(([scheme]) => scheme);
544
+ if (options.passthroughCallerToken === true && unfilled.length > 0) {
545
+ result.securityRiskScore = "medium";
369
546
  result.warnings.push(
370
- "RECOMMENDATION: For multiple auth providers, use authProviderMapper or securityResolver to map each security scheme to the correct auth provider."
547
+ `SECURITY WARNING: The adapter has no credentials for the API for security schemes: ${unfilled.join(", ")}. passthroughCallerToken sends only a bearer token, which these schemes don't use, so operations that require only them fail unless additionalHeaders or headersMapper sets their credential. Configure authProviderMapper, securityResolver or staticAuth for them.`
371
548
  );
372
549
  }
550
+ return withPassthroughRisk(result, securitySchemes, options);
551
+ }
552
+ function canPassThroughCallerToken(options) {
553
+ return options.passthroughCallerToken === true && !options.securityResolver && !hasStaticAuth(options);
554
+ }
555
+ function withPassthroughRisk(result, securitySchemes, options) {
556
+ const bearerSchemes = [...securitySchemes].filter(([, security]) => isBearerScheme(security));
557
+ if (bearerSchemes.length === 0 || !canPassThroughCallerToken(options)) {
558
+ return result;
559
+ }
560
+ const schemesStr = bearerSchemes.map(([scheme]) => scheme).join(", ");
561
+ const when = options.authProviderMapper ? " whenever no authProviderMapper function returns a credential" : "";
562
+ result.securityRiskScore = "high";
563
+ result.warnings.push(
564
+ `SECURITY WARNING: passthroughCallerToken is enabled. The MCP client's own token (ctx.authInfo.token) is sent to the API${when} for security schemes: ${schemesStr}. Only use this when the API accepts tokens issued for this MCP server.`
565
+ );
373
566
  return result;
374
567
  }
375
- async function resolveToolSecurity(tool2, ctx, options) {
568
+ async function resolveToolSecurity(tool2, ctx, options, request = {}) {
376
569
  const securityResolver = new import_mcp_from_openapi2.SecurityResolver();
377
570
  const securityContext = await createSecurityContextFromAuth(tool2, ctx, options);
378
571
  const hasAuth = securityContext.jwt || securityContext.apiKey || securityContext.basic || securityContext.oauth2Token || securityContext.apiKeys && Object.keys(securityContext.apiKeys).length > 0 || securityContext.customHeaders && Object.keys(securityContext.customHeaders).length > 0;
379
572
  const requiresSecurity = tool2.mapper.some((m) => m.security && m.required === true);
380
- if (requiresSecurity && !hasAuth) {
381
- const requiredSchemes = tool2.mapper.filter((m) => m.security && m.required === true).map((m) => m.security?.scheme ?? "unknown");
382
- const uniqueSchemes = [...new Set(requiredSchemes)];
383
- const schemesStr = uniqueSchemes.join(", ") || "unknown";
384
- const firstScheme = uniqueSchemes[0] || "BearerAuth";
385
- throw new Error(
386
- `Authentication required for tool '${tool2.name}' but no auth configuration found.
387
- Required security schemes: ${schemesStr}
388
- Solutions:
389
- 1. Add authProviderMapper: { '${firstScheme}': (ctx) => ctx.authInfo.user?.token }
390
- 2. Add securityResolver: (tool, ctx) => ({ jwt: ctx.authInfo.token })
391
- 3. Add staticAuth: { jwt: process.env.API_TOKEN }
392
- 4. Set generateOptions.includeSecurityInInput: true (not recommended for production)`
393
- );
573
+ const fromInput = request.input ? await resolveInputSecurity(tool2, request.input, options, securityResolver) : void 0;
574
+ const hasInputCredential = !!fromInput && Object.keys(fromInput.headers).length + Object.keys(fromInput.query).length + Object.keys(fromInput.cookies).length > 0;
575
+ if (requiresSecurity && !hasAuth && !hasInputCredential && !request.deferCredentialCheck) {
576
+ throw authenticationRequiredError(tool2);
394
577
  }
395
- return await securityResolver.resolve(tool2.mapper, securityContext);
578
+ const resolved = await securityResolver.resolve(tool2.mapper, securityContext);
579
+ if (!fromInput) return resolved;
580
+ return {
581
+ ...resolved,
582
+ headers: { ...fromInput.headers, ...resolved.headers },
583
+ query: { ...fromInput.query, ...resolved.query },
584
+ cookies: { ...fromInput.cookies, ...resolved.cookies }
585
+ };
586
+ }
587
+ function isInputScheme(scheme, options) {
588
+ return options.generateOptions?.includeSecurityInInput === true || (options.securitySchemesInInput ?? []).includes(scheme);
589
+ }
590
+ function inputCredentialContext(security, value) {
591
+ const bare = value.replace(/^(?:bearer|basic)\s+/i, "");
592
+ if (security.type === "apiKey") {
593
+ return security.apiKeyName ? { apiKeys: { [security.apiKeyName]: value } } : { apiKey: value };
594
+ }
595
+ if (security.type === "oauth2" || security.type === "openIdConnect") return { oauth2Token: bare };
596
+ if (security.type === "http") {
597
+ const httpScheme = (security.httpScheme ?? "bearer").toLowerCase();
598
+ if (httpScheme === "bearer") return { jwt: bare };
599
+ if (httpScheme === "basic") return { basic: bare };
600
+ }
601
+ return void 0;
602
+ }
603
+ async function resolveInputSecurity(tool2, input, options, securityResolver) {
604
+ const resolved = { headers: {}, query: {}, cookies: {} };
605
+ for (const mapper of tool2.mapper) {
606
+ const security = mapper.security;
607
+ if (!security || !isInputScheme(security.scheme, options)) continue;
608
+ const value = input[mapper.inputKey];
609
+ if (typeof value !== "string" || value === "") continue;
610
+ if (/[\r\n\x00\f\v]/.test(value)) {
611
+ throw new import_sdk2.PublicMcpError(
612
+ `Invalid value for '${mapper.inputKey}': contains control characters (possible header injection attack)`,
613
+ "INVALID_HEADER_VALUE",
614
+ 400
615
+ );
616
+ }
617
+ const context = inputCredentialContext(security, value);
618
+ if (!context) continue;
619
+ const one = await securityResolver.resolve([mapper], (0, import_mcp_from_openapi2.createSecurityContext)(context));
620
+ Object.assign(resolved.headers, one.headers);
621
+ Object.assign(resolved.query, one.query);
622
+ Object.assign(resolved.cookies, one.cookies);
623
+ }
624
+ return resolved;
396
625
  }
397
626
 
398
627
  // libs/adapters/src/openapi/openapi.tool.ts
399
628
  var import_lazy_zod2 = require("@frontmcp/lazy-zod");
400
- var import_sdk3 = require("@frontmcp/sdk");
629
+ var import_sdk4 = require("@frontmcp/sdk");
401
630
  var import_utils3 = require("@frontmcp/utils");
402
631
 
403
632
  // libs/adapters/src/openapi/openapi.frontmcp-schema.ts
@@ -641,7 +870,7 @@ function formatZodIssues(issues, prefix) {
641
870
  }
642
871
 
643
872
  // libs/adapters/src/openapi/openapi.utils.ts
644
- var import_sdk2 = require("@frontmcp/sdk");
873
+ var import_sdk3 = require("@frontmcp/sdk");
645
874
  var import_utils2 = require("@frontmcp/utils");
646
875
  function coerceToString(value, paramName, location) {
647
876
  if (value === null || value === void 0) {
@@ -699,7 +928,7 @@ function buildRequest(tool2, input, security, baseUrl) {
699
928
  case "header": {
700
929
  const headerValue = coerceToString(value, mapper.key, "header");
701
930
  if (/[\r\n\x00\f\v]/.test(headerValue)) {
702
- throw new import_sdk2.PublicMcpError(
931
+ throw new import_sdk3.PublicMcpError(
703
932
  `Invalid header value for '${mapper.key}': contains control characters (possible header injection attack)`,
704
933
  "INVALID_HEADER_VALUE",
705
934
  400
@@ -864,7 +1093,7 @@ function createOpenApiTool(openapiTool, options, logger) {
864
1093
  if (toolTransform.ui) {
865
1094
  toolMetadata["ui"] = toolTransform.ui;
866
1095
  }
867
- return (0, import_sdk3.tool)(toolMetadata)(async (input, toolCtx) => {
1096
+ return (0, import_sdk4.tool)(toolMetadata)(async (input, toolCtx) => {
868
1097
  const ctx = toolCtx.context;
869
1098
  const transformContext = {
870
1099
  ctx,
@@ -876,7 +1105,10 @@ function createOpenApiTool(openapiTool, options, logger) {
876
1105
  inputTransforms,
877
1106
  transformContext
878
1107
  );
879
- const security = await resolveToolSecurity(openapiTool, ctx, options);
1108
+ const security = await resolveToolSecurity(openapiTool, ctx, options, {
1109
+ input: injectedInput,
1110
+ deferCredentialCheck: true
1111
+ });
880
1112
  const { url, headers, body: requestBody } = buildRequest(openapiTool, injectedInput, security, options.baseUrl);
881
1113
  applyAdditionalHeaders(headers, options.additionalHeaders);
882
1114
  if (options.headersMapper) {
@@ -892,6 +1124,7 @@ function createOpenApiTool(openapiTool, options, logger) {
892
1124
  throw new Error(`headersMapper failed for tool '${openapiTool.name}': ${errorMessage}`, { cause: err });
893
1125
  }
894
1126
  }
1127
+ assertRequestHasCredential(openapiTool, url, headers);
895
1128
  let finalBody = requestBody;
896
1129
  if (options.bodyMapper && requestBody) {
897
1130
  try {
@@ -1113,7 +1346,7 @@ function createConsoleLogger(prefix) {
1113
1346
  child: (childPrefix) => createConsoleLogger(`${prefix}:${childPrefix}`)
1114
1347
  };
1115
1348
  }
1116
- var OpenapiAdapter = class extends import_sdk4.DynamicAdapter {
1349
+ var OpenapiAdapter = class extends import_sdk5.DynamicAdapter {
1117
1350
  generator;
1118
1351
  logger;
1119
1352
  options;
@@ -1176,28 +1409,7 @@ var OpenapiAdapter = class extends import_sdk4.DynamicAdapter {
1176
1409
  });
1177
1410
  }
1178
1411
  if (!validation.valid) {
1179
- throw new Error(
1180
- `[OpenAPI Adapter: ${this.options.name}] Invalid security configuration.
1181
- Missing auth provider mappings for security schemes: ${validation.missingMappings.join(", ")}
1182
-
1183
- Your OpenAPI spec requires these security schemes, but no auth configuration was provided.
1184
-
1185
- Add one of the following to your adapter configuration:
1186
-
1187
- 1. authProviderMapper (recommended):
1188
- authProviderMapper: {
1189
- ` + validation.missingMappings.map((s) => ` '${s}': (authInfo) => authInfo.user?.${s.toLowerCase()}Token,`).join("\n") + `
1190
- }
1191
-
1192
- 2. securityResolver:
1193
- securityResolver: (tool, authInfo) => ({ jwt: authInfo.token })
1194
-
1195
- 3. staticAuth:
1196
- staticAuth: { jwt: process.env.API_TOKEN }
1197
-
1198
- 4. Include security in input (NOT recommended for production):
1199
- generateOptions: { includeSecurityInInput: true }`
1200
- );
1412
+ throw new Error(formatMissingSecurityMappingsError(this.options.name, openapiTools, validation.missingMappings));
1201
1413
  }
1202
1414
  let transformedTools = openapiTools;
1203
1415
  if (this.options.descriptionMode && this.options.descriptionMode !== "summaryOnly") {
@@ -1851,7 +2063,7 @@ ${this.formatSchemaAsSummary(schema)}`;
1851
2063
  }
1852
2064
  };
1853
2065
  OpenapiAdapter = __decorateClass([
1854
- (0, import_sdk4.Adapter)({
2066
+ (0, import_sdk5.Adapter)({
1855
2067
  name: "openapi",
1856
2068
  description: "OpenAPI adapter for FrontMCP - Automatically generates MCP tools from OpenAPI specifications"
1857
2069
  })
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.adapter.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,cAAc,EAAE,KAAK,uBAAuB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAK3G,OAAO,EAIL,KAAK,qBAAqB,EAQ3B,MAAM,iBAAiB,CAAC;AAwBzB,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,cAAc,CAAC,qBAAqB,CAAC;IAC/E,OAAO,CAAC,SAAS,CAAC,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAiB;IACxB,OAAO,EAAE,qBAAqB,CAAC;IACtC,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,eAAe,CAA0D;IACjF,OAAO,CAAC,YAAY,CAAoC;gBAE5C,OAAO,EAAE,qBAAqB;IAc1C;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIjC,KAAK,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAuI/C;;;OAGG;IACH;;;;;;;;;;OAUG;IACH,OAAO,CAAC,oBAAoB;YAId,mBAAmB;IA4BjC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA0C5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAMtB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA6D7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAsC3B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAwBhC;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA2D7B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA0C7B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAkBnC;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAoBpC;;;;OAIG;YACW,wBAAwB;IAiFtC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;;OAGG;IACH,OAAO,CAAC,0CAA0C;IA+BlD;;;OAGG;IACH,OAAO,CAAC,2CAA2C;IAyCnD;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAuB7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,IAAI,GAAG,MAAM,IAAI;IAO3E;;;;OAIG;IACH,YAAY,IAAI,IAAI;IA6CpB;;OAEG;IACH,WAAW,IAAI,IAAI;CAOpB"}
1
+ {"version":3,"file":"openapi.adapter.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,cAAc,EAAE,KAAK,uBAAuB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAK3G,OAAO,EAIL,KAAK,qBAAqB,EAQ3B,MAAM,iBAAiB,CAAC;AAwBzB,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,cAAc,CAAC,qBAAqB,CAAC;IAC/E,OAAO,CAAC,SAAS,CAAC,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAiB;IACxB,OAAO,EAAE,qBAAqB,CAAC;IACtC,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,eAAe,CAA0D;IACjF,OAAO,CAAC,YAAY,CAAoC;gBAE5C,OAAO,EAAE,qBAAqB;IAc1C;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIjC,KAAK,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAsH/C;;;OAGG;IACH;;;;;;;;;;OAUG;IACH,OAAO,CAAC,oBAAoB;YAId,mBAAmB;IA4BjC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA0C5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAMtB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IA6D7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAsC3B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAwBhC;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA2D7B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA0C7B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAkBnC;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAoBpC;;;;OAIG;YACW,wBAAwB;IAiFtC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;;OAGG;IACH,OAAO,CAAC,0CAA0C;IA+BlD;;;OAGG;IACH,OAAO,CAAC,2CAA2C;IAyCnD;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAuB7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,IAAI,GAAG,MAAM,IAAI;IAO3E;;;;OAIG;IACH,YAAY,IAAI,IAAI;IA6CpB;;OAEG;IACH,WAAW,IAAI,IAAI;CAOpB"}
@@ -1,5 +1,5 @@
1
- import { type McpOpenAPITool, type SecurityContext } from 'mcp-from-openapi';
2
- import type { FrontMcpContext } from '@frontmcp/sdk';
1
+ import { type McpOpenAPITool, type ResolvedSecurity, type SecurityContext } from 'mcp-from-openapi';
2
+ import { type FrontMcpContext } from '@frontmcp/sdk';
3
3
  import type { OpenApiAdapterOptions } from './openapi.types';
4
4
  /**
5
5
  * Security scheme information extracted from OpenAPI spec
@@ -28,7 +28,7 @@ export interface SecurityValidationResult {
28
28
  * @param options - Adapter options with auth configuration
29
29
  * @returns Security context for resolver
30
30
  */
31
- export declare function createSecurityContextFromAuth(tool: McpOpenAPITool, ctx: FrontMcpContext, options: Pick<OpenApiAdapterOptions, 'securityResolver' | 'authProviderMapper' | 'staticAuth'>): Promise<SecurityContext>;
31
+ export declare function createSecurityContextFromAuth(tool: McpOpenAPITool, ctx: FrontMcpContext, options: Pick<OpenApiAdapterOptions, 'securityResolver' | 'authProviderMapper' | 'staticAuth' | 'passthroughCallerToken'>): Promise<SecurityContext>;
32
32
  /**
33
33
  * Extract all security schemes used by a set of tools
34
34
  *
@@ -36,6 +36,26 @@ export declare function createSecurityContextFromAuth(tool: McpOpenAPITool, ctx:
36
36
  * @returns Set of security scheme names
37
37
  */
38
38
  export declare function extractSecuritySchemes(tools: McpOpenAPITool[]): Set<string>;
39
+ /**
40
+ * The startup error for security schemes that no credential option covers, with a suggestion for
41
+ * each: an `authProviderMapper` function (it receives the request context), `securityResolver`,
42
+ * `staticAuth`, and `passthroughCallerToken` only for the HTTP bearer schemes it can fill.
43
+ */
44
+ export declare function formatMissingSecurityMappingsError(adapterName: string, tools: McpOpenAPITool[], missingMappings: string[]): string;
45
+ /**
46
+ * Refuse a request, before it is sent, when its operation requires authentication and the request
47
+ * carries no credential for any of the operation's security schemes.
48
+ *
49
+ * `resolveToolSecurity` only checks that some credential source answered. That answer may not fit
50
+ * the operation: `passthroughCallerToken` and a `staticAuth` holding only `jwt` fill the bearer
51
+ * token, which an API key, basic, OAuth2 or OpenID Connect scheme never reads, so the request
52
+ * would go out with no credential at all. The request is checked as built, after `additionalHeaders`
53
+ * and `headersMapper`, so a key those set counts. An OpenAPI spec may accept any one of an
54
+ * operation's schemes, so one is enough.
55
+ *
56
+ * @throws Error `Authentication required for tool '…'`
57
+ */
58
+ export declare function assertRequestHasCredential(tool: McpOpenAPITool, url: string, headers: Headers): void;
39
59
  /**
40
60
  * Validate security configuration against OpenAPI security requirements
41
61
  *
@@ -43,15 +63,34 @@ export declare function extractSecuritySchemes(tools: McpOpenAPITool[]): Set<str
43
63
  * @param options - Adapter options
44
64
  * @returns Validation result with errors and warnings
45
65
  */
46
- export declare function validateSecurityConfiguration(tools: McpOpenAPITool[], options: Pick<OpenApiAdapterOptions, 'securityResolver' | 'authProviderMapper' | 'staticAuth' | 'generateOptions' | 'securitySchemesInInput'>): SecurityValidationResult;
66
+ export declare function validateSecurityConfiguration(tools: McpOpenAPITool[], options: Pick<OpenApiAdapterOptions, 'securityResolver' | 'authProviderMapper' | 'staticAuth' | 'generateOptions' | 'securitySchemesInInput' | 'passthroughCallerToken' | 'additionalHeaders' | 'headersMapper'>): SecurityValidationResult;
67
+ /**
68
+ * How `resolveToolSecurity` is used for one call.
69
+ */
70
+ export interface ResolveToolSecurityRequest {
71
+ /**
72
+ * The tool's input: the credentials it carries for the schemes `generateOptions.includeSecurityInInput`
73
+ * or `securitySchemesInInput` put there are resolved too, and used for a scheme only when the
74
+ * server supplies none for it (a credential option here, `additionalHeaders` or `headersMapper`
75
+ * after): the model chooses them, so a prompt injection could otherwise swap in another account.
76
+ */
77
+ input?: Record<string, unknown>;
78
+ /**
79
+ * The caller checks the request it builds with `assertRequestHasCredential` (after
80
+ * `additionalHeaders` and `headersMapper`), so an operation is not refused here for a context with
81
+ * no credential: a header those set, or an input credential, may still supply it.
82
+ */
83
+ deferCredentialCheck?: boolean;
84
+ }
47
85
  /**
48
86
  * Resolve security for an OpenAPI tool with validation
49
87
  *
50
88
  * @param tool - OpenAPI tool with mapper
51
89
  * @param ctx - FrontMCP request context with authInfo, sessionId, traceId, etc.
52
90
  * @param options - Adapter options with auth configuration
91
+ * @param request - The call's input, and whether the caller checks the built request itself
53
92
  * @returns Resolved security (headers, query params, etc.)
54
93
  * @throws Error if security cannot be resolved
55
94
  */
56
- export declare function resolveToolSecurity(tool: McpOpenAPITool, ctx: FrontMcpContext, options: Pick<OpenApiAdapterOptions, 'securityResolver' | 'authProviderMapper' | 'staticAuth'>): Promise<import("mcp-from-openapi").ResolvedSecurity>;
95
+ export declare function resolveToolSecurity(tool: McpOpenAPITool, ctx: FrontMcpContext, options: Pick<OpenApiAdapterOptions, 'securityResolver' | 'authProviderMapper' | 'staticAuth' | 'passthroughCallerToken' | 'generateOptions' | 'securitySchemesInInput'>, request?: ResolveToolSecurityRequest): Promise<ResolvedSecurity>;
57
96
  //# sourceMappingURL=openapi.security.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.security.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.security.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACtH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iBAAiB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC9C;AAED;;;;;;;GAOG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,kBAAkB,GAAG,oBAAoB,GAAG,YAAY,CAAC,GAC7F,OAAO,CAAC,eAAe,CAAC,CA0G1B;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAY3E;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,IAAI,CACX,qBAAqB,EACrB,kBAAkB,GAAG,oBAAoB,GAAG,YAAY,GAAG,iBAAiB,GAAG,wBAAwB,CACxG,GACA,wBAAwB,CA6F1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,kBAAkB,GAAG,oBAAoB,GAAG,YAAY,CAAC,wDAwC/F"}
1
+ {"version":3,"file":"openapi.security.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.security.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,cAAc,EAEnB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EAErB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iBAAiB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC9C;AAED;;;;;;;GAOG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,IAAI,CACX,qBAAqB,EACrB,kBAAkB,GAAG,oBAAoB,GAAG,YAAY,GAAG,wBAAwB,CACpF,GACA,OAAO,CAAC,eAAe,CAAC,CA+G1B;AAwBD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAY3E;AA8DD;;;;GAIG;AACH,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,cAAc,EAAE,EACvB,eAAe,EAAE,MAAM,EAAE,GACxB,MAAM,CAgCR;AAqED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAOpG;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,IAAI,CACX,qBAAqB,EACnB,kBAAkB,GAClB,oBAAoB,GACpB,YAAY,GACZ,iBAAiB,GACjB,wBAAwB,GACxB,wBAAwB,GACxB,mBAAmB,GACnB,eAAe,CAClB,GACA,wBAAwB,CAY1B;AAkLD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,IAAI,CACX,qBAAqB,EACnB,kBAAkB,GAClB,oBAAoB,GACpB,YAAY,GACZ,wBAAwB,GACxB,iBAAiB,GACjB,wBAAwB,CAC3B,EACD,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,gBAAgB,CAAC,CA8C3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.tool.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAK1D,OAAO,KAAK,EAIV,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AAMzB;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,cAAc,cA8SpH"}
1
+ {"version":3,"file":"openapi.tool.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAK1D,OAAO,KAAK,EAIV,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AAMzB;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,cAAc,cAwTpH"}
@@ -638,6 +638,9 @@ interface BaseOptions {
638
638
  * Static authentication configuration when not using dynamic auth from context.
639
639
  * Useful for server-to-server APIs with static credentials.
640
640
  *
641
+ * With an `authProviderMapper`, it fills every credential no mapper function returned (a mapped
642
+ * value wins), so the caller's token (`passthroughCallerToken`) is never used alongside it.
643
+ *
641
644
  * @example
642
645
  * ```typescript
643
646
  * staticAuth: {
@@ -647,6 +650,22 @@ interface BaseOptions {
647
650
  * ```
648
651
  */
649
652
  staticAuth?: Partial<SecurityContext>;
653
+ /**
654
+ * Forward the MCP client's own bearer token (`ctx.authInfo.token`) to the API when no other
655
+ * credential source (`authProviderMapper`, `staticAuth`) supplied a credential.
656
+ *
657
+ * Off by default: the caller's token was issued for this MCP server, and sending it to another
658
+ * service is token passthrough, which the MCP specification forbids. Without this option an
659
+ * operation that requires authentication fails when the adapter has no credential for it.
660
+ * Enable it only when the API is meant to accept the same token (same issuer and audience).
661
+ * The token is sent as the bearer token (`jwt`), so it fills only HTTP bearer schemes: it also
662
+ * covers such a scheme when it has no `authProviderMapper` entry (otherwise refused at startup),
663
+ * and an operation whose schemes are all of other types (API key, basic, OAuth2, OpenID
664
+ * Connect) still fails with `Authentication required for tool '…'`.
665
+ *
666
+ * @default false
667
+ */
668
+ passthroughCallerToken?: boolean;
650
669
  /**
651
670
  * Options for loading the OpenAPI specification.
652
671
  *