@frontmcp/adapters 1.8.3 → 1.8.5

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/esm/index.mjs CHANGED
@@ -183,7 +183,11 @@ var OpenApiSpecPoller = class {
183
183
  };
184
184
 
185
185
  // libs/adapters/src/openapi/openapi.security.ts
186
- import { createSecurityContext, SecurityResolver } from "mcp-from-openapi";
186
+ import {
187
+ createSecurityContext,
188
+ SecurityResolver
189
+ } from "mcp-from-openapi";
190
+ import { PublicMcpError } from "@frontmcp/sdk";
187
191
  async function createSecurityContextFromAuth(tool2, ctx, options) {
188
192
  if (options.securityResolver) {
189
193
  return await options.securityResolver(tool2, ctx);
@@ -238,7 +242,7 @@ async function createSecurityContextFromAuth(tool2, ctx, options) {
238
242
  throw err;
239
243
  }
240
244
  const errorMessage = err instanceof Error ? err.message : String(err);
241
- throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`);
245
+ throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`, { cause: err });
242
246
  }
243
247
  }
244
248
  }
@@ -286,19 +290,163 @@ function extractSecuritySchemes(tools) {
286
290
  }
287
291
  return schemes;
288
292
  }
293
+ function describeSecuritySchemes(tools) {
294
+ const schemes = /* @__PURE__ */ new Map();
295
+ for (const tool2 of tools) {
296
+ for (const mapper of tool2.mapper) {
297
+ if (mapper.security?.scheme && !schemes.has(mapper.security.scheme)) {
298
+ schemes.set(mapper.security.scheme, mapper.security);
299
+ }
300
+ }
301
+ }
302
+ return schemes;
303
+ }
304
+ function schemeParametersOf(tools) {
305
+ const parameters = /* @__PURE__ */ new Map();
306
+ for (const tool2 of tools) {
307
+ for (const mapper of tool2.mapper) {
308
+ const scheme = mapper.security?.scheme;
309
+ if (scheme && !parameters.has(scheme)) parameters.set(scheme, mapper);
310
+ }
311
+ }
312
+ return parameters;
313
+ }
314
+ function headerCredentialSource(parameter, options) {
315
+ if (!parameter) return void 0;
316
+ const staticHeaders = new Headers(options.additionalHeaders ?? {});
317
+ if (carriesSchemeParameter(parameter, new URL("http://startup.invalid/"), staticHeaders)) return "static";
318
+ if (options.headersMapper && (parameter.type === "header" || parameter.type === "cookie")) return "per-request";
319
+ return void 0;
320
+ }
321
+ function isBearerScheme(security) {
322
+ if (!security || security.type !== "http") return false;
323
+ return (security.httpScheme ?? "bearer").toLowerCase() === "bearer";
324
+ }
325
+ function credentialFieldOf(security) {
326
+ if (security?.type === "apiKey") return "apiKey";
327
+ if (security?.type === "oauth2" || security?.type === "openIdConnect") return "oauth2Token";
328
+ if (security?.type === "http" && security.httpScheme?.toLowerCase() === "basic") return "basic";
329
+ return "jwt";
330
+ }
331
+ function formatMissingSecurityMappingsError(adapterName, tools, missingMappings) {
332
+ const schemes = describeSecuritySchemes(tools);
333
+ const fieldOf = (scheme) => credentialFieldOf(schemes.get(scheme));
334
+ const firstField = fieldOf(missingMappings[0] ?? "");
335
+ const bearerSchemes = missingMappings.filter((scheme) => isBearerScheme(schemes.get(scheme)));
336
+ const lines = [
337
+ `[OpenAPI Adapter: ${adapterName}] Invalid security configuration.`,
338
+ `Missing auth provider mappings for security schemes: ${missingMappings.join(", ")}`,
339
+ "",
340
+ "Your OpenAPI spec requires these security schemes, but no credential option covers them.",
341
+ "",
342
+ "Add one of the following to your adapter configuration:",
343
+ "",
344
+ "1. authProviderMapper (recommended): a function per scheme that returns the credential issued for the API:",
345
+ " authProviderMapper: {",
346
+ ...missingMappings.map((scheme) => ` '${scheme}': (ctx) => getApiCredential(ctx), // the ${fieldOf(scheme)}`),
347
+ " }",
348
+ "",
349
+ "2. securityResolver:",
350
+ ` securityResolver: async (tool, ctx) => ({ ${firstField}: await getApiCredential(ctx) })`,
351
+ "",
352
+ "3. staticAuth (one credential for every caller):",
353
+ ` staticAuth: { ${firstField}: process.env.API_CREDENTIAL }`
354
+ ];
355
+ if (bearerSchemes.length > 0) {
356
+ lines.push(
357
+ "",
358
+ `4. passthroughCallerToken: true, for the HTTP bearer schemes (${bearerSchemes.join(", ")}) only, and only if the API`,
359
+ " accepts the MCP client's own token (same issuer and audience). It sends nothing for other schemes."
360
+ );
361
+ }
362
+ return lines.join("\n");
363
+ }
364
+ function authenticationRequiredError(tool2) {
365
+ const required = requiredSecurityOf(tool2);
366
+ const schemes = [...new Map(required.map((security) => [security.scheme, security])).values()];
367
+ const schemesStr = schemes.map((security) => `${security.scheme} (${security.type})`).join(", ") || "unknown";
368
+ const first = schemes[0];
369
+ const firstScheme = first?.scheme ?? "BearerAuth";
370
+ const field = credentialFieldOf(first);
371
+ const bearerSchemes = schemes.filter(isBearerScheme).map((security) => security.scheme);
372
+ const solutions = [
373
+ ` 1. Add authProviderMapper: { '${firstScheme}': (ctx) => getApiCredential(ctx) }, returning the ${field} issued for the API`,
374
+ ` 2. Add securityResolver: async (tool, ctx) => ({ ${field}: await getApiCredential(ctx) })`,
375
+ ` 3. Add staticAuth: { ${field}: process.env.API_CREDENTIAL }`
376
+ ];
377
+ if (bearerSchemes.length > 0) {
378
+ solutions.push(
379
+ ` 4. Set passthroughCallerToken: true, only if the API accepts the MCP client's own token (it fills ${bearerSchemes.join(", ")} only)`
380
+ );
381
+ }
382
+ return new Error(
383
+ `Authentication required for tool '${tool2.name}': no credential for its security schemes.
384
+ Required security schemes: ${schemesStr}
385
+ Solutions:
386
+ ` + solutions.join("\n")
387
+ );
388
+ }
389
+ function requiredSecurityOf(tool2) {
390
+ return tool2.mapper.flatMap((mapper) => mapper.security && mapper.required === true ? [mapper.security] : []);
391
+ }
392
+ function authorizationSchemeOf(security) {
393
+ if (security?.type === "http") return (security.httpScheme ?? "bearer").toLowerCase();
394
+ if (security?.type === "oauth2" || security?.type === "openIdConnect") return "bearer";
395
+ return void 0;
396
+ }
397
+ function carriesSchemeParameter(mapper, url, headers) {
398
+ if (mapper.type === "query") return !!url.searchParams.get(mapper.key);
399
+ if (mapper.type === "cookie") {
400
+ return (headers.get("cookie") ?? "").split(";").some((pair) => {
401
+ const [name, ...value2] = pair.trim().split("=");
402
+ return name === mapper.key && value2.join("=") !== "";
403
+ });
404
+ }
405
+ if (mapper.type !== "header") return false;
406
+ const value = headers.get(mapper.key)?.trim();
407
+ if (!value) return false;
408
+ const scheme = authorizationSchemeOf(mapper.security);
409
+ if (!scheme) return true;
410
+ const space = value.indexOf(" ");
411
+ return space > 0 && value.slice(0, space).toLowerCase() === scheme && value.slice(space + 1).trim() !== "";
412
+ }
413
+ function assertRequestHasCredential(tool2, url, headers) {
414
+ const securityMappers = tool2.mapper.filter((mapper) => mapper.security && mapper.required === true);
415
+ if (securityMappers.length === 0) return;
416
+ const parsedUrl = new URL(url);
417
+ if (!securityMappers.some((mapper) => carriesSchemeParameter(mapper, parsedUrl, headers))) {
418
+ throw authenticationRequiredError(tool2);
419
+ }
420
+ }
289
421
  function validateSecurityConfiguration(tools, options) {
422
+ const result = validateCredentialSources(tools, options);
423
+ const schemesInInput = inputSecuritySchemes(options);
424
+ if (schemesInInput !== "all" && schemesInInput.size > 0) {
425
+ const include = options.generateOptions?.includeSecurityInInput;
426
+ const sources = [
427
+ (options.securitySchemesInInput?.length ?? 0) > 0 ? "securitySchemesInInput" : void 0,
428
+ Array.isArray(include) && include.length > 0 ? "an includeSecurityInInput list" : void 0
429
+ ].filter((source) => source !== void 0);
430
+ result.securityRiskScore = "high";
431
+ result.warnings.push(
432
+ `SECURITY WARNING: ${sources.join(" and ")} ${sources.length > 1 ? "are" : "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.`
433
+ );
434
+ }
435
+ return result;
436
+ }
437
+ function validateCredentialSources(tools, options) {
290
438
  const result = {
291
439
  valid: true,
292
440
  missingMappings: [],
293
441
  warnings: [],
294
442
  securityRiskScore: "low"
295
443
  };
296
- const securitySchemes = extractSecuritySchemes(tools);
297
- const includeSecurityInInput = options.generateOptions?.includeSecurityInInput ?? false;
298
- if (includeSecurityInInput) {
444
+ const securitySchemes = describeSecuritySchemes(tools);
445
+ const inputSchemes = inputSecuritySchemes(options);
446
+ if (inputSchemes === "all") {
299
447
  result.securityRiskScore = "high";
300
448
  result.warnings.push(
301
- "SECURITY WARNING: includeSecurityInInput is enabled. Users will provide authentication directly in tool inputs. This increases security risk as credentials may be logged or exposed."
449
+ "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."
302
450
  );
303
451
  return result;
304
452
  }
@@ -316,21 +464,23 @@ function validateSecurityConfiguration(tools, options) {
316
464
  );
317
465
  return withPassthroughRisk(result, securitySchemes, options);
318
466
  }
319
- const schemesInInput = new Set(options.securitySchemesInInput || []);
467
+ const schemesInInput = inputSchemes;
320
468
  if (options.authProviderMapper || schemesInInput.size > 0) {
321
- result.securityRiskScore = schemesInInput.size > 0 ? "medium" : "low";
322
- if (schemesInInput.size > 0) {
323
- result.warnings.push(
324
- `INFO: Per-scheme security control enabled. Schemes in input: ${Array.from(schemesInInput).join(", ")}`
325
- );
326
- }
469
+ result.securityRiskScore = "low";
327
470
  const passthroughFallback = [];
328
- for (const scheme of securitySchemes) {
471
+ const perRequestHeaders = [];
472
+ const schemeParameters = schemeParametersOf(tools);
473
+ for (const [scheme, security] of securitySchemes) {
329
474
  if (schemesInInput.has(scheme)) {
330
475
  continue;
331
476
  }
332
477
  if (!options.authProviderMapper?.[scheme]) {
333
- if (options.passthroughCallerToken === true) {
478
+ const headerSource = headerCredentialSource(schemeParameters.get(scheme), options);
479
+ if (headerSource === "static") {
480
+ continue;
481
+ } else if (headerSource === "per-request") {
482
+ perRequestHeaders.push(scheme);
483
+ } else if (options.passthroughCallerToken === true && isBearerScheme(security)) {
334
484
  passthroughFallback.push(scheme);
335
485
  } else {
336
486
  result.valid = false;
@@ -343,6 +493,11 @@ function validateSecurityConfiguration(tools, options) {
343
493
  `ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(", ")}`
344
494
  );
345
495
  }
496
+ if (perRequestHeaders.length > 0) {
497
+ result.warnings.push(
498
+ `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.`
499
+ );
500
+ }
346
501
  withPassthroughRisk(result, securitySchemes, options);
347
502
  if (passthroughFallback.length > 0) {
348
503
  result.warnings.push(
@@ -352,10 +507,17 @@ function validateSecurityConfiguration(tools, options) {
352
507
  return result;
353
508
  }
354
509
  if (securitySchemes.size > 0 && options.passthroughCallerToken !== true) {
355
- const schemesStr = Array.from(securitySchemes).join(", ");
510
+ const schemesStr = Array.from(securitySchemes.keys()).join(", ");
356
511
  result.securityRiskScore = "medium";
357
512
  result.warnings.push(
358
- `SECURITY WARNING: No auth configuration provided, so the adapter has no credentials for the API (security schemes: ${schemesStr}). Operations that require authentication will fail. 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.`
513
+ `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.`
514
+ );
515
+ }
516
+ const unfilled = [...securitySchemes].filter(([, security]) => !isBearerScheme(security)).map(([scheme]) => scheme);
517
+ if (options.passthroughCallerToken === true && unfilled.length > 0) {
518
+ result.securityRiskScore = "medium";
519
+ result.warnings.push(
520
+ `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.`
359
521
  );
360
522
  }
361
523
  return withPassthroughRisk(result, securitySchemes, options);
@@ -364,10 +526,11 @@ function canPassThroughCallerToken(options) {
364
526
  return options.passthroughCallerToken === true && !options.securityResolver && !hasStaticAuth(options);
365
527
  }
366
528
  function withPassthroughRisk(result, securitySchemes, options) {
367
- if (securitySchemes.size === 0 || !canPassThroughCallerToken(options)) {
529
+ const bearerSchemes = [...securitySchemes].filter(([, security]) => isBearerScheme(security));
530
+ if (bearerSchemes.length === 0 || !canPassThroughCallerToken(options)) {
368
531
  return result;
369
532
  }
370
- const schemesStr = Array.from(securitySchemes).join(", ");
533
+ const schemesStr = bearerSchemes.map(([scheme]) => scheme).join(", ");
371
534
  const when = options.authProviderMapper ? " whenever no authProviderMapper function returns a credential" : "";
372
535
  result.securityRiskScore = "high";
373
536
  result.warnings.push(
@@ -375,28 +538,69 @@ function withPassthroughRisk(result, securitySchemes, options) {
375
538
  );
376
539
  return result;
377
540
  }
378
- async function resolveToolSecurity(tool2, ctx, options) {
541
+ async function resolveToolSecurity(tool2, ctx, options, request = {}) {
379
542
  const securityResolver = new SecurityResolver();
380
543
  const securityContext = await createSecurityContextFromAuth(tool2, ctx, options);
381
544
  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;
382
545
  const requiresSecurity = tool2.mapper.some((m) => m.security && m.required === true);
383
- if (requiresSecurity && !hasAuth) {
384
- const requiredSchemes = tool2.mapper.filter((m) => m.security && m.required === true).map((m) => m.security?.scheme ?? "unknown");
385
- const uniqueSchemes = [...new Set(requiredSchemes)];
386
- const schemesStr = uniqueSchemes.join(", ") || "unknown";
387
- const firstScheme = uniqueSchemes[0] || "BearerAuth";
388
- throw new Error(
389
- `Authentication required for tool '${tool2.name}' but no auth configuration found.
390
- Required security schemes: ${schemesStr}
391
- Solutions:
392
- 1. Add authProviderMapper: { '${firstScheme}': (ctx) => ctx.authInfo.user?.token }
393
- 2. Add securityResolver: async (tool, ctx) => ({ jwt: await getApiToken(ctx) })
394
- 3. Add staticAuth: { jwt: process.env.API_TOKEN }
395
- 4. Set passthroughCallerToken: true, only if the API accepts the MCP client's own token
396
- 5. Set generateOptions.includeSecurityInInput: true (not recommended for production)`
397
- );
546
+ const fromInput = request.input ? await resolveInputSecurity(tool2, request.input, options, securityResolver) : void 0;
547
+ const hasInputCredential = !!fromInput && Object.keys(fromInput.headers).length + Object.keys(fromInput.query).length + Object.keys(fromInput.cookies).length > 0;
548
+ if (requiresSecurity && !hasAuth && !hasInputCredential && !request.deferCredentialCheck) {
549
+ throw authenticationRequiredError(tool2);
398
550
  }
399
- return await securityResolver.resolve(tool2.mapper, securityContext);
551
+ const resolved = await securityResolver.resolve(tool2.mapper, securityContext);
552
+ if (!fromInput) return resolved;
553
+ return {
554
+ ...resolved,
555
+ headers: { ...fromInput.headers, ...resolved.headers },
556
+ query: { ...fromInput.query, ...resolved.query },
557
+ cookies: { ...fromInput.cookies, ...resolved.cookies }
558
+ };
559
+ }
560
+ function inputSecuritySchemes(options) {
561
+ const include = options.generateOptions?.includeSecurityInInput;
562
+ if (include === true) return "all";
563
+ return /* @__PURE__ */ new Set([...Array.isArray(include) ? include : [], ...options.securitySchemesInInput ?? []]);
564
+ }
565
+ function isInputScheme(scheme, options) {
566
+ const schemes = inputSecuritySchemes(options);
567
+ return schemes === "all" || schemes.has(scheme);
568
+ }
569
+ function inputCredentialContext(security, value) {
570
+ const bare = value.replace(/^(?:bearer|basic)\s+/i, "");
571
+ if (security.type === "apiKey") {
572
+ return security.apiKeyName ? { apiKeys: { [security.apiKeyName]: value } } : { apiKey: value };
573
+ }
574
+ if (security.type === "oauth2" || security.type === "openIdConnect") return { oauth2Token: bare };
575
+ if (security.type === "http") {
576
+ const httpScheme = (security.httpScheme ?? "bearer").toLowerCase();
577
+ if (httpScheme === "bearer") return { jwt: bare };
578
+ if (httpScheme === "basic") return { basic: bare };
579
+ }
580
+ return void 0;
581
+ }
582
+ async function resolveInputSecurity(tool2, input, options, securityResolver) {
583
+ const resolved = { headers: {}, query: {}, cookies: {} };
584
+ for (const mapper of tool2.mapper) {
585
+ const security = mapper.security;
586
+ if (!security || !isInputScheme(security.scheme, options)) continue;
587
+ const value = input[mapper.inputKey];
588
+ if (typeof value !== "string" || value === "") continue;
589
+ if (/[\r\n\x00\f\v]/.test(value)) {
590
+ throw new PublicMcpError(
591
+ `Invalid value for '${mapper.inputKey}': contains control characters (possible header injection attack)`,
592
+ "INVALID_HEADER_VALUE",
593
+ 400
594
+ );
595
+ }
596
+ const context = inputCredentialContext(security, value);
597
+ if (!context) continue;
598
+ const one = await securityResolver.resolve([mapper], createSecurityContext(context));
599
+ Object.assign(resolved.headers, one.headers);
600
+ Object.assign(resolved.query, one.query);
601
+ Object.assign(resolved.cookies, one.cookies);
602
+ }
603
+ return resolved;
400
604
  }
401
605
 
402
606
  // libs/adapters/src/openapi/openapi.tool.ts
@@ -645,7 +849,7 @@ function formatZodIssues(issues, prefix) {
645
849
  }
646
850
 
647
851
  // libs/adapters/src/openapi/openapi.utils.ts
648
- import { PublicMcpError } from "@frontmcp/sdk";
852
+ import { PublicMcpError as PublicMcpError2 } from "@frontmcp/sdk";
649
853
  import { trimTrailing, validateBaseUrl } from "@frontmcp/utils";
650
854
  function coerceToString(value, paramName, location) {
651
855
  if (value === null || value === void 0) {
@@ -703,7 +907,7 @@ function buildRequest(tool2, input, security, baseUrl) {
703
907
  case "header": {
704
908
  const headerValue = coerceToString(value, mapper.key, "header");
705
909
  if (/[\r\n\x00\f\v]/.test(headerValue)) {
706
- throw new PublicMcpError(
910
+ throw new PublicMcpError2(
707
911
  `Invalid header value for '${mapper.key}': contains control characters (possible header injection attack)`,
708
912
  "INVALID_HEADER_VALUE",
709
913
  400
@@ -880,7 +1084,10 @@ function createOpenApiTool(openapiTool, options, logger) {
880
1084
  inputTransforms,
881
1085
  transformContext
882
1086
  );
883
- const security = await resolveToolSecurity(openapiTool, ctx, options);
1087
+ const security = await resolveToolSecurity(openapiTool, ctx, options, {
1088
+ input: injectedInput,
1089
+ deferCredentialCheck: true
1090
+ });
884
1091
  const { url, headers, body: requestBody } = buildRequest(openapiTool, injectedInput, security, options.baseUrl);
885
1092
  applyAdditionalHeaders(headers, options.additionalHeaders);
886
1093
  if (options.headersMapper) {
@@ -896,6 +1103,7 @@ function createOpenApiTool(openapiTool, options, logger) {
896
1103
  throw new Error(`headersMapper failed for tool '${openapiTool.name}': ${errorMessage}`, { cause: err });
897
1104
  }
898
1105
  }
1106
+ assertRequestHasCredential(openapiTool, url, headers);
899
1107
  let finalBody = requestBody;
900
1108
  if (options.bodyMapper && requestBody) {
901
1109
  try {
@@ -1144,8 +1352,9 @@ var OpenapiAdapter = class extends DynamicAdapter {
1144
1352
  if (!this.generator) {
1145
1353
  this.generator = await this.initializeGenerator();
1146
1354
  }
1147
- const hasPerSchemeControl = this.options.securitySchemesInInput && this.options.securitySchemesInInput.length > 0;
1148
- const includeSecurityInInput = hasPerSchemeControl || (this.options.generateOptions?.includeSecurityInInput ?? false);
1355
+ const inputSchemes = inputSecuritySchemes(this.options);
1356
+ const hasPerSchemeControl = inputSchemes !== "all" && inputSchemes.size > 0;
1357
+ const includeSecurityInInput = inputSchemes === "all" || hasPerSchemeControl;
1149
1358
  let openapiTools = await this.generator.generateTools({
1150
1359
  includeOperations: this.options.generateOptions?.includeOperations,
1151
1360
  excludeOperations: this.options.generateOptions?.excludeOperations,
@@ -1161,7 +1370,7 @@ var OpenapiAdapter = class extends DynamicAdapter {
1161
1370
  formatResolvers: this.options.generateOptions?.formatResolvers
1162
1371
  });
1163
1372
  if (hasPerSchemeControl) {
1164
- openapiTools = openapiTools.map((tool2) => this.filterSecuritySchemes(tool2));
1373
+ openapiTools = openapiTools.map((tool2) => this.filterSecuritySchemes(tool2, inputSchemes));
1165
1374
  }
1166
1375
  const validation = validateSecurityConfiguration(openapiTools, this.options);
1167
1376
  this.logger.info("Security Analysis:");
@@ -1180,28 +1389,7 @@ var OpenapiAdapter = class extends DynamicAdapter {
1180
1389
  });
1181
1390
  }
1182
1391
  if (!validation.valid) {
1183
- throw new Error(
1184
- `[OpenAPI Adapter: ${this.options.name}] Invalid security configuration.
1185
- Missing auth provider mappings for security schemes: ${validation.missingMappings.join(", ")}
1186
-
1187
- Your OpenAPI spec requires these security schemes, but no auth configuration was provided.
1188
-
1189
- Add one of the following to your adapter configuration:
1190
-
1191
- 1. authProviderMapper (recommended):
1192
- authProviderMapper: {
1193
- ` + validation.missingMappings.map((s) => ` '${s}': (authInfo) => authInfo.user?.${s.toLowerCase()}Token,`).join("\n") + `
1194
- }
1195
-
1196
- 2. securityResolver:
1197
- securityResolver: async (tool, ctx) => ({ jwt: await getApiToken(ctx) })
1198
-
1199
- 3. staticAuth:
1200
- staticAuth: { jwt: process.env.API_TOKEN }
1201
-
1202
- 4. Include security in input (NOT recommended for production):
1203
- generateOptions: { includeSecurityInInput: true }`
1204
- );
1392
+ throw new Error(formatMissingSecurityMappingsError(this.options.name, openapiTools, validation.missingMappings));
1205
1393
  }
1206
1394
  let transformedTools = openapiTools;
1207
1395
  if (this.options.descriptionMode && this.options.descriptionMode !== "summaryOnly") {
@@ -1493,12 +1681,12 @@ ${opDescription}`;
1493
1681
  };
1494
1682
  }
1495
1683
  /**
1496
- * Filter security schemes in tool input based on securitySchemesInInput option.
1497
- * Removes security inputs that should be resolved from context instead of user input.
1684
+ * Filter security schemes in tool input to the ones named for it (`securitySchemesInInput`, or an
1685
+ * `includeSecurityInInput` list). Removes security inputs that should be resolved from context
1686
+ * instead of user input.
1498
1687
  * @private
1499
1688
  */
1500
- filterSecuritySchemes(tool2) {
1501
- const allowedSchemes = new Set(this.options.securitySchemesInInput || []);
1689
+ filterSecuritySchemes(tool2, allowedSchemes) {
1502
1690
  if (allowedSchemes.size === 0) return tool2;
1503
1691
  const schemesToRemove = /* @__PURE__ */ new Set();
1504
1692
  const inputKeysToRemove = /* @__PURE__ */ new Set();