@frontmcp/adapters 1.12.0-rc.1 → 1.12.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.
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var __decorateClass=(decorators,target,key,kind)=>{var result=kind>1?void 0:kind?__getOwnPropDesc(target,key):target;for(var i=decorators.length-1,decorator;i>=0;i--)if(decorator=decorators[i])result=(kind?decorator(target,key,result):decorator(result))||result;if(kind&&result)__defProp(target,key,result);return result};var index_exports={};__export(index_exports,{FRONTMCP_EXTENSION_KEY:()=>FRONTMCP_EXTENSION_KEY,OpenAPIFetchError:()=>OpenAPIFetchError,OpenApiSpecPoller:()=>OpenApiSpecPoller,OpenapiAdapter:()=>OpenapiAdapter,applyAdditionalHeaders:()=>applyAdditionalHeaders,buildRequest:()=>buildRequest,createSecurityContextFromAuth:()=>createSecurityContextFromAuth,extractSecuritySchemes:()=>extractSecuritySchemes,forceJwtSecurity:()=>forceJwtSecurity,parseResponse:()=>parseResponse,removeSecurityFromOperations:()=>removeSecurityFromOperations,resolveToolSecurity:()=>resolveToolSecurity,validateSecurityConfiguration:()=>validateSecurityConfiguration});module.exports=__toCommonJS(index_exports);var import_mcp_from_openapi3=require("mcp-from-openapi");var import_sdk5=require("@frontmcp/sdk");var import_mcp_from_openapi=require("mcp-from-openapi");var import_utils=require("@frontmcp/utils");var import_sdk=require("@frontmcp/sdk");var OpenAPIFetchError=class extends import_sdk.InternalMcpError{constructor(url,status,statusText){super(`OpenAPI spec fetch failed from "${url}": ${status} ${statusText}`,"OPENAPI_FETCH_FAILED")}};var DEFAULT_RETRY={maxRetries:3,initialDelayMs:1e3,maxDelayMs:1e4,backoffMultiplier:2};var OpenApiSpecPoller=class{url;intervalMs;fetchTimeoutMs;changeDetection;retry;unhealthyThreshold;headers;ssrf;followRedirects;callbacks;intervalTimer=null;lastHash=null;lastEtag=null;lastModified=null;consecutiveFailures=0;isPolling=false;wasUnhealthy=false;health="unknown";constructor(url,options={},callbacks={}){this.url=url;this.intervalMs=options.intervalMs??6e4;this.fetchTimeoutMs=options.fetchTimeoutMs??1e4;this.changeDetection=options.changeDetection??"auto";this.retry={...DEFAULT_RETRY,...options.retry};this.unhealthyThreshold=options.unhealthyThreshold??3;this.headers=options.headers??{};this.ssrf=options.ssrf??(0,import_mcp_from_openapi.normalizeSsrfOptions)(void 0);this.followRedirects=options.followRedirects??false;this.callbacks=callbacks}start(){if(this.intervalTimer)return;this.poll().catch(()=>{});this.intervalTimer=setInterval(()=>{this.poll().catch(()=>{})},this.intervalMs)}stop(){if(this.intervalTimer){clearInterval(this.intervalTimer);this.intervalTimer=null}}getStats(){return{hash:this.lastHash,consecutiveFailures:this.consecutiveFailures,health:this.health,isRunning:this.intervalTimer!==null}}async poll(){if(this.isPolling)return;this.isPolling=true;try{await this.fetchWithRetry()}finally{this.isPolling=false}}async fetchWithRetry(){const{maxRetries,initialDelayMs,maxDelayMs,backoffMultiplier}=this.retry;for(let attempt=0;attempt<=maxRetries;attempt++){try{await this.doFetch();if(this.consecutiveFailures>0){this.consecutiveFailures=0;if(this.wasUnhealthy){this.wasUnhealthy=false;this.health="healthy";this.callbacks.onRecovered?.()}}this.health="healthy";return}catch(error){if(attempt===maxRetries){this.consecutiveFailures++;this.callbacks.onError?.(error instanceof Error?error:new Error(String(error)));if(this.consecutiveFailures>=this.unhealthyThreshold&&!this.wasUnhealthy){this.wasUnhealthy=true;this.health="unhealthy";this.callbacks.onUnhealthy?.(this.consecutiveFailures)}return}const delay=Math.min(initialDelayMs*Math.pow(backoffMultiplier,attempt),maxDelayMs);await new Promise(r=>setTimeout(r,delay))}}}async doFetch(){const headers={...this.headers};if(this.changeDetection!=="content-hash"){if(this.lastEtag){headers["If-None-Match"]=this.lastEtag}if(this.lastModified){headers["If-Modified-Since"]=this.lastModified}}const response=await(0,import_mcp_from_openapi.safeFetch)(this.url,{headers,timeoutMs:this.fetchTimeoutMs,followRedirects:this.followRedirects,ssrf:this.ssrf});if(response.status===304){this.callbacks.onUnchanged?.();return}if(!response.ok){throw new OpenAPIFetchError(this.url,response.status,response.statusText)}const etag=response.headers.get("etag");const lastModified=response.headers.get("last-modified");if(etag)this.lastEtag=etag;if(lastModified)this.lastModified=lastModified;const body=await response.text();const hash=(0,import_utils.sha256Hex)(body);if(this.lastHash&&this.lastHash===hash){this.callbacks.onUnchanged?.();return}this.lastHash=hash;this.callbacks.onChanged?.(body,hash)}dispose(){this.stop()}};var BODYLESS_STATUS_CODES=new Set([204,205]);var DEFAULT_RESPONSE_STATUS=0;var SUCCESS_RANGE_STATUS=2;function isSuccessWithBody(statusCode){if(statusCode===DEFAULT_RESPONSE_STATUS||statusCode===SUCCESS_RANGE_STATUS)return true;return typeof statusCode==="number"&&statusCode>=200&&statusCode<300&&!BODYLESS_STATUS_CODES.has(statusCode)}function acceptAnyUndeclaredBody(schema){const undeclared=schema.type==="null"&&schema["x-content-type"]===void 0&&isSuccessWithBody(schema["x-status-code"]);if(!undeclared)return schema;const{type:_null,...annotations}=schema;return annotations}function outputSchemaOf(tool2){const outputSchema=tool2.outputSchema;if(!outputSchema||tool2.metadata.method==="head")return outputSchema;const statusBranches=outputSchema.oneOf;if(statusBranches&&outputSchema["x-status-code"]===void 0){const{oneOf:_exclusive,...union}=outputSchema;return{...union,anyOf:statusBranches.map(acceptAnyUndeclaredBody)}}return acceptAnyUndeclaredBody(outputSchema)}var import_mcp_from_openapi2=require("mcp-from-openapi");var import_sdk2=require("@frontmcp/sdk");async function createSecurityContextFromAuth(tool2,ctx,options){if(options.securityResolver){return await options.securityResolver(tool2,ctx)}if(options.authProviderMapper){const context={};const securitySchemes=new Set;for(const mapper of tool2.mapper){if(mapper.security?.scheme){securitySchemes.add(mapper.security.scheme)}}for(const scheme of securitySchemes){const authExtractor=options.authProviderMapper[scheme];if(authExtractor){try{const token=authExtractor(ctx);if(token!==void 0&&token!==null&&typeof token!=="string"){throw new Error(`authProviderMapper['${scheme}'] must return a string or undefined, but returned: ${typeof token}`)}if(token===""){throw new Error(`authProviderMapper['${scheme}'] returned empty string. Return undefined/null if no token is available, or provide a valid token.`)}if(token){const schemeMapper=tool2.mapper.find(m=>m.security?.scheme===scheme);const schemeType=schemeMapper?.security?.type?.toLowerCase();const httpScheme=schemeMapper?.security?.httpScheme?.toLowerCase();if(schemeType==="apikey"){if(!context.apiKey){context.apiKey=token}}else if(schemeType==="http"&&httpScheme==="basic"){if(!context.basic){context.basic=token}}else if(schemeType==="oauth2"){if(!context.oauth2Token){context.oauth2Token=token}}else{if(!context.jwt){context.jwt=token}}}}catch(err){if(err instanceof Error&&err.message.includes("authProviderMapper")){throw err}const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`,{cause:err})}}}if(hasStaticAuth(options)){return(0,import_mcp_from_openapi2.createSecurityContext)({...options.staticAuth,...context})}const hasAnyAuth=context.jwt||context.apiKey||context.basic||context.oauth2Token;if(!hasAnyAuth&&options.passthroughCallerToken===true){const callerToken=getCallerToken(ctx);if(callerToken){context.jwt=callerToken}}return(0,import_mcp_from_openapi2.createSecurityContext)(context)}if(hasStaticAuth(options)){return(0,import_mcp_from_openapi2.createSecurityContext)(options.staticAuth)}if(options.passthroughCallerToken===true){return(0,import_mcp_from_openapi2.createSecurityContext)({jwt:getCallerToken(ctx)})}return(0,import_mcp_from_openapi2.createSecurityContext)({})}function hasStaticAuth(options){return!!options.staticAuth&&Object.keys(options.staticAuth).length>0}function getCallerToken(ctx){const authToken=ctx.authInfo?.token;if(authToken===void 0||authToken===null||authToken===""){return void 0}if(typeof authToken!=="string"){throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`)}return authToken}function extractSecuritySchemes(tools){const schemes=new Set;for(const tool2 of tools){for(const mapper of tool2.mapper){if(mapper.security?.scheme){schemes.add(mapper.security.scheme)}}}return schemes}function describeSecuritySchemes(tools){const schemes=new Map;for(const tool2 of tools){for(const mapper of tool2.mapper){if(mapper.security?.scheme&&!schemes.has(mapper.security.scheme)){schemes.set(mapper.security.scheme,mapper.security)}}}return schemes}function schemeParametersOf(tools){const parameters=new Map;for(const tool2 of tools){for(const mapper of tool2.mapper){const scheme=mapper.security?.scheme;if(scheme&&!parameters.has(scheme))parameters.set(scheme,mapper)}}return parameters}function headerCredentialSource(parameter,options){if(!parameter)return void 0;const staticHeaders=new Headers(options.additionalHeaders??{});if(carriesSchemeParameter(parameter,new URL("http://startup.invalid/"),staticHeaders))return"static";if(options.headersMapper&&(parameter.type==="header"||parameter.type==="cookie"))return"per-request";return void 0}function isBearerScheme(security){if(!security||security.type!=="http")return false;return(security.httpScheme??"bearer").toLowerCase()==="bearer"}function credentialFieldOf(security){if(security?.type==="apiKey")return"apiKey";if(security?.type==="oauth2"||security?.type==="openIdConnect")return"oauth2Token";if(security?.type==="http"&&security.httpScheme?.toLowerCase()==="basic")return"basic";return"jwt"}function formatMissingSecurityMappingsError(adapterName,tools,missingMappings){const schemes=describeSecuritySchemes(tools);const fieldOf=scheme=>credentialFieldOf(schemes.get(scheme));const firstField=fieldOf(missingMappings[0]??"");const bearerSchemes=missingMappings.filter(scheme=>isBearerScheme(schemes.get(scheme)));const lines=[`[OpenAPI Adapter: ${adapterName}] Invalid security configuration.`,`Missing auth provider mappings for security schemes: ${missingMappings.join(", ")}`,"","Your OpenAPI spec requires these security schemes, but no credential option covers them.","","Add one of the following to your adapter configuration:","","1. authProviderMapper (recommended): a function per scheme that returns the credential issued for the API:"," authProviderMapper: {",...missingMappings.map(scheme=>` '${scheme}': (ctx) => getApiCredential(ctx), // the ${fieldOf(scheme)}`)," }","","2. securityResolver:",` securityResolver: async (tool, ctx) => ({ ${firstField}: await getApiCredential(ctx) })`,"","3. staticAuth (one credential for every caller):",` staticAuth: { ${firstField}: process.env.API_CREDENTIAL }`];if(bearerSchemes.length>0){lines.push("",`4. passthroughCallerToken: true, for the HTTP bearer schemes (${bearerSchemes.join(", ")}) only, and only if the API`," accepts the MCP client's own token (same issuer and audience). It sends nothing for other schemes.")}return lines.join("\n")}function authenticationRequiredError(tool2){const required=requiredSecurityOf(tool2);const schemes=[...new Map(required.map(security=>[security.scheme,security])).values()];const schemesStr=schemes.map(security=>`${security.scheme} (${security.type})`).join(", ")||"unknown";const first=schemes[0];const firstScheme=first?.scheme??"BearerAuth";const field=credentialFieldOf(first);const bearerSchemes=schemes.filter(isBearerScheme).map(security=>security.scheme);const solutions=[` 1. Add authProviderMapper: { '${firstScheme}': (ctx) => getApiCredential(ctx) }, returning the ${field} issued for the API`,` 2. Add securityResolver: async (tool, ctx) => ({ ${field}: await getApiCredential(ctx) })`,` 3. Add staticAuth: { ${field}: process.env.API_CREDENTIAL }`];if(bearerSchemes.length>0){solutions.push(` 4. Set passthroughCallerToken: true, only if the API accepts the MCP client's own token (it fills ${bearerSchemes.join(", ")} only)`)}return new Error(`Authentication required for tool '${tool2.name}': no credential for its security schemes.
2
2
  Required security schemes: ${schemesStr}
3
3
  Solutions:
4
- `+solutions.join("\n"))}function requiredSecurityOf(tool2){return tool2.mapper.flatMap(mapper=>mapper.security&&mapper.required===true?[mapper.security]:[])}function authorizationSchemeOf(security){if(security?.type==="http")return(security.httpScheme??"bearer").toLowerCase();if(security?.type==="oauth2"||security?.type==="openIdConnect")return"bearer";return void 0}function carriesSchemeParameter(mapper,url,headers){if(mapper.type==="query")return!!url.searchParams.get(mapper.key);if(mapper.type==="cookie"){return(headers.get("cookie")??"").split(";").some(pair=>{const[name,...value2]=pair.trim().split("=");return name===mapper.key&&value2.join("=")!==""})}if(mapper.type!=="header")return false;const value=headers.get(mapper.key)?.trim();if(!value)return false;const scheme=authorizationSchemeOf(mapper.security);if(!scheme)return true;const space=value.indexOf(" ");return space>0&&value.slice(0,space).toLowerCase()===scheme&&value.slice(space+1).trim()!==""}function assertRequestHasCredential(tool2,url,headers){const securityMappers=tool2.mapper.filter(mapper=>mapper.security&&mapper.required===true);if(securityMappers.length===0)return;const parsedUrl=new URL(url);if(!securityMappers.some(mapper=>carriesSchemeParameter(mapper,parsedUrl,headers))){throw authenticationRequiredError(tool2)}}function validateSecurityConfiguration(tools,options){const result=validateCredentialSources(tools,options);const schemesInInput=inputSecuritySchemes(options);if(schemesInInput!=="all"&&schemesInInput.size>0){const include=options.generateOptions?.includeSecurityInInput;const sources=[(options.securitySchemesInInput?.length??0)>0?"securitySchemesInInput":void 0,Array.isArray(include)&&include.length>0?"an includeSecurityInInput list":void 0].filter(source=>source!==void 0);result.securityRiskScore="high";result.warnings.push(`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.`)}return result}function validateCredentialSources(tools,options){const result={valid:true,missingMappings:[],warnings:[],securityRiskScore:"low"};const securitySchemes=describeSecuritySchemes(tools);const inputSchemes=inputSecuritySchemes(options);if(inputSchemes==="all"){result.securityRiskScore="high";result.warnings.push("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.");return result}if(options.securityResolver){result.securityRiskScore="low";result.warnings.push("INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context.");return result}if(hasStaticAuth(options)){result.securityRiskScore="medium";result.warnings.push("SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager).");return withPassthroughRisk(result,securitySchemes,options)}const schemesInInput=inputSchemes;if(options.authProviderMapper||schemesInInput.size>0){result.securityRiskScore="low";const passthroughFallback=[];const perRequestHeaders=[];const schemeParameters=schemeParametersOf(tools);for(const[scheme,security]of securitySchemes){if(schemesInInput.has(scheme)){continue}if(!options.authProviderMapper?.[scheme]){const headerSource=headerCredentialSource(schemeParameters.get(scheme),options);if(headerSource==="static"){continue}else if(headerSource==="per-request"){perRequestHeaders.push(scheme)}else if(options.passthroughCallerToken===true&&isBearerScheme(security)){passthroughFallback.push(scheme)}else{result.valid=false;result.missingMappings.push(scheme)}}}if(!result.valid){result.warnings.push(`ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(", ")}`)}if(perRequestHeaders.length>0){result.warnings.push(`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.`)}withPassthroughRisk(result,securitySchemes,options);if(passthroughFallback.length>0){result.warnings.push(`SECURITY WARNING: Security schemes with no authProviderMapper entry (${passthroughFallback.join(", ")}) get the MCP client's own token, because passthroughCallerToken is enabled.`)}return result}if(securitySchemes.size>0&&options.passthroughCallerToken!==true){const schemesStr=Array.from(securitySchemes.keys()).join(", ");result.securityRiskScore="medium";result.warnings.push(`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.`)}const unfilled=[...securitySchemes].filter(([,security])=>!isBearerScheme(security)).map(([scheme])=>scheme);if(options.passthroughCallerToken===true&&unfilled.length>0){result.securityRiskScore="medium";result.warnings.push(`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.`)}return withPassthroughRisk(result,securitySchemes,options)}function canPassThroughCallerToken(options){return options.passthroughCallerToken===true&&!options.securityResolver&&!hasStaticAuth(options)}function withPassthroughRisk(result,securitySchemes,options){const bearerSchemes=[...securitySchemes].filter(([,security])=>isBearerScheme(security));if(bearerSchemes.length===0||!canPassThroughCallerToken(options)){return result}const schemesStr=bearerSchemes.map(([scheme])=>scheme).join(", ");const when=options.authProviderMapper?" whenever no authProviderMapper function returns a credential":"";result.securityRiskScore="high";result.warnings.push(`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.`);return result}async function resolveToolSecurity(tool2,ctx,options,request={}){const securityResolver=new import_mcp_from_openapi2.SecurityResolver;const securityContext=await createSecurityContextFromAuth(tool2,ctx,options);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;const requiresSecurity=tool2.mapper.some(m=>m.security&&m.required===true);const fromInput=request.input?await resolveInputSecurity(tool2,request.input,options,securityResolver):void 0;const hasInputCredential=!!fromInput&&Object.keys(fromInput.headers).length+Object.keys(fromInput.query).length+Object.keys(fromInput.cookies).length>0;if(requiresSecurity&&!hasAuth&&!hasInputCredential&&!request.deferCredentialCheck){throw authenticationRequiredError(tool2)}const resolved=await securityResolver.resolve(tool2.mapper,securityContext);if(!fromInput)return resolved;return{...resolved,headers:{...fromInput.headers,...resolved.headers},query:{...fromInput.query,...resolved.query},cookies:{...fromInput.cookies,...resolved.cookies}}}function inputSecuritySchemes(options){const include=options.generateOptions?.includeSecurityInInput;if(include===true)return"all";return new Set([...Array.isArray(include)?include:[],...options.securitySchemesInInput??[]])}function isInputScheme(scheme,options){const schemes=inputSecuritySchemes(options);return schemes==="all"||schemes.has(scheme)}function inputCredentialContext(security,value){const bare=value.replace(/^(?:bearer|basic)\s+/i,"");if(security.type==="apiKey"){return security.apiKeyName?{apiKeys:{[security.apiKeyName]:value}}:{apiKey:value}}if(security.type==="oauth2"||security.type==="openIdConnect")return{oauth2Token:bare};if(security.type==="http"){const httpScheme=(security.httpScheme??"bearer").toLowerCase();if(httpScheme==="bearer")return{jwt:bare};if(httpScheme==="basic")return{basic:bare}}return void 0}async function resolveInputSecurity(tool2,input,options,securityResolver){const resolved={headers:{},query:{},cookies:{}};for(const mapper of tool2.mapper){const security=mapper.security;if(!security||!isInputScheme(security.scheme,options))continue;const value=input[mapper.inputKey];if(typeof value!=="string"||value==="")continue;if(/[\r\n\x00\f\v]/.test(value)){throw new import_sdk2.PublicMcpError(`Invalid value for '${mapper.inputKey}': contains control characters (possible header injection attack)`,"INVALID_HEADER_VALUE",400)}const context=inputCredentialContext(security,value);if(!context)continue;const one=await securityResolver.resolve([mapper],(0,import_mcp_from_openapi2.createSecurityContext)(context));Object.assign(resolved.headers,one.headers);Object.assign(resolved.query,one.query);Object.assign(resolved.cookies,one.cookies)}return resolved}var import_lazy_zod2=require("@frontmcp/lazy-zod");var import_sdk4=require("@frontmcp/sdk");var import_utils3=require("@frontmcp/utils");var import_lazy_zod=require("@frontmcp/lazy-zod");var FRONTMCP_SCHEMA_VERSION="1.0";var SUPPORTED_VERSIONS=["1.0"];var FrontMcpAnnotationsSchema=import_lazy_zod.z.object({title:import_lazy_zod.z.string().optional(),readOnlyHint:import_lazy_zod.z.boolean().optional(),destructiveHint:import_lazy_zod.z.boolean().optional(),idempotentHint:import_lazy_zod.z.boolean().optional(),openWorldHint:import_lazy_zod.z.boolean().optional()});var FrontMcpCacheSchema=import_lazy_zod.z.object({ttl:import_lazy_zod.z.number().int().positive().optional(),slideWindow:import_lazy_zod.z.boolean().optional()});var FrontMcpCodeCallSchema=import_lazy_zod.z.object({enabledInCodeCall:import_lazy_zod.z.boolean().optional(),visibleInListTools:import_lazy_zod.z.boolean().optional()});var FrontMcpExampleSchema=import_lazy_zod.z.object({description:import_lazy_zod.z.string(),input:import_lazy_zod.z.record(import_lazy_zod.z.string(),import_lazy_zod.z.any()),output:import_lazy_zod.z.any().optional()});var KNOWN_EXTENSION_FIELDS=new Set(["version","annotations","cache","codecall","tags","hideFromDiscovery","examples","meta","icons"]);var KNOWN_ANNOTATION_FIELDS=new Set(["title","readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);var KNOWN_CACHE_FIELDS=new Set(["ttl","slideWindow"]);var KNOWN_CODECALL_FIELDS=new Set(["enabledInCodeCall","visibleInListTools"]);function validateFrontMcpExtension(rawData,toolName,logger){const warnings=[];if(rawData===null||rawData===void 0){return{success:true,data:null,warnings:[]}}if(typeof rawData!=="object"||Array.isArray(rawData)){warnings.push(`x-frontmcp must be an object, got ${Array.isArray(rawData)?"array":typeof rawData}`);logger.warn(`[${toolName}] Invalid x-frontmcp extension: ${warnings[0]}`);return{success:false,data:null,warnings}}const data=rawData;const version=typeof data["version"]==="string"?data["version"]:FRONTMCP_SCHEMA_VERSION;if(!SUPPORTED_VERSIONS.includes(version)){warnings.push(`Unsupported x-frontmcp version '${version}'. Supported versions: ${SUPPORTED_VERSIONS.join(", ")}`);logger.warn(`[${toolName}] ${warnings[0]}`);return{success:false,data:null,warnings}}const validData=extractValidFields(data,version,warnings);if(warnings.length>0){logger.warn(`[${toolName}] x-frontmcp extension has invalid fields that were ignored:`);warnings.forEach(w=>logger.warn(` - ${w}`))}return{success:true,data:validData,warnings}}function extractValidFields(data,version,warnings){const result={version};for(const key of Object.keys(data)){if(!KNOWN_EXTENSION_FIELDS.has(key)){warnings.push(`Unknown field '${key}' in x-frontmcp (will be ignored)`)}}if(data["annotations"]!==void 0){const annotationsResult=FrontMcpAnnotationsSchema.safeParse(data["annotations"]);if(annotationsResult.success){result.annotations=annotationsResult.data}else{const issues=formatZodIssues(annotationsResult.error.issues,"annotations");warnings.push(...issues);result.annotations=extractValidAnnotations(data["annotations"],warnings)}}if(data["cache"]!==void 0){const cacheResult=FrontMcpCacheSchema.safeParse(data["cache"]);if(cacheResult.success){result.cache=cacheResult.data}else{const issues=formatZodIssues(cacheResult.error.issues,"cache");warnings.push(...issues);result.cache=extractValidCache(data["cache"],warnings)}}if(data["codecall"]!==void 0){const codecallResult=FrontMcpCodeCallSchema.safeParse(data["codecall"]);if(codecallResult.success){result.codecall=codecallResult.data}else{const issues=formatZodIssues(codecallResult.error.issues,"codecall");warnings.push(...issues);result.codecall=extractValidCodeCall(data["codecall"],warnings)}}if(data["tags"]!==void 0){const tagsSchema=import_lazy_zod.z.array(import_lazy_zod.z.string());const tagsResult=tagsSchema.safeParse(data["tags"]);if(tagsResult.success){result.tags=tagsResult.data}else{warnings.push(`Invalid 'tags': expected array of strings`);result.tags=extractValidTags(data["tags"])}}if(data["hideFromDiscovery"]!==void 0){if(typeof data["hideFromDiscovery"]==="boolean"){result.hideFromDiscovery=data["hideFromDiscovery"]}else{warnings.push(`Invalid 'hideFromDiscovery': expected boolean, got ${typeof data["hideFromDiscovery"]}`)}}if(data["examples"]!==void 0){const examplesSchema=import_lazy_zod.z.array(FrontMcpExampleSchema);const examplesResult=examplesSchema.safeParse(data["examples"]);if(examplesResult.success){result.examples=examplesResult.data}else{warnings.push(`Invalid 'examples': some examples have invalid format`);result.examples=extractValidExamples(data["examples"],warnings)}}return result}function extractValidAnnotations(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};for(const field of KNOWN_ANNOTATION_FIELDS){if(obj[field]!==void 0){if(field==="title"&&typeof obj[field]==="string"){result.title=obj[field]}else if(field!=="title"&&typeof obj[field]==="boolean"){result[field]=obj[field]}}}for(const key of Object.keys(obj)){if(!KNOWN_ANNOTATION_FIELDS.has(key)){warnings.push(`Unknown field 'annotations.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidCache(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};if(typeof obj["ttl"]==="number"&&Number.isInteger(obj["ttl"])&&obj["ttl"]>0){result.ttl=obj["ttl"]}else if(obj["ttl"]!==void 0){warnings.push(`Invalid 'cache.ttl': expected positive integer`)}if(typeof obj["slideWindow"]==="boolean"){result.slideWindow=obj["slideWindow"]}else if(obj["slideWindow"]!==void 0){warnings.push(`Invalid 'cache.slideWindow': expected boolean`)}for(const key of Object.keys(obj)){if(!KNOWN_CACHE_FIELDS.has(key)){warnings.push(`Unknown field 'cache.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidCodeCall(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};if(typeof obj["enabledInCodeCall"]==="boolean"){result.enabledInCodeCall=obj["enabledInCodeCall"]}else if(obj["enabledInCodeCall"]!==void 0){warnings.push(`Invalid 'codecall.enabledInCodeCall': expected boolean`)}if(typeof obj["visibleInListTools"]==="boolean"){result.visibleInListTools=obj["visibleInListTools"]}else if(obj["visibleInListTools"]!==void 0){warnings.push(`Invalid 'codecall.visibleInListTools': expected boolean`)}for(const key of Object.keys(obj)){if(!KNOWN_CODECALL_FIELDS.has(key)){warnings.push(`Unknown field 'codecall.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidTags(data){if(!Array.isArray(data))return void 0;const validTags=data.filter(item=>typeof item==="string");return validTags.length>0?validTags:void 0}function extractValidExamples(data,warnings){if(!Array.isArray(data))return void 0;const validExamples=[];for(let i=0;i<data.length;i++){const item=data[i];const result=FrontMcpExampleSchema.safeParse(item);if(result.success){validExamples.push(result.data)}else{warnings.push(`Invalid example at index ${i}: ${formatZodIssues(result.error.issues,`examples[${i}]`).join(", ")}`)}}return validExamples.length>0?validExamples:void 0}function formatZodIssues(issues,prefix){return issues.map(issue=>{const path=issue.path.length>0?`${prefix}.${issue.path.join(".")}`:prefix;return`Invalid '${path}': ${issue.message}`})}var import_sdk3=require("@frontmcp/sdk");var import_utils2=require("@frontmcp/utils");function coerceToString(value,paramName,location){if(value===null||value===void 0){return""}if(typeof value==="object"){if(Array.isArray(value)){throw new Error(`${location} parameter '${paramName}' cannot be an array. Received: ${JSON.stringify(value)}`)}throw new Error(`${location} parameter '${paramName}' cannot be an object. Received: ${JSON.stringify(value)}`)}return String(value)}var QUERY_DELIMITERS={form:",",spaceDelimited:" ",pipeDelimited:"|"};function serializeQueryParameter(mapper,value){const style=mapper.style??"form";const explode=mapper.explode??style==="form";const name=mapper.key;const delimiter=QUERY_DELIMITERS[style]??",";if(Array.isArray(value)){const items=value.map(item=>coerceToString(item,name,"query"));return explode?items.map(item=>[name,item]):[[name,items.join(delimiter)]]}if(typeof value==="object"&&value!==null){const properties=Object.entries(value).filter(([,propertyValue])=>propertyValue!==void 0).map(([property,propertyValue])=>[property,coerceToString(propertyValue,name,"query")]);if(style==="deepObject"){return properties.map(([property,propertyValue])=>[`${name}[${property}]`,propertyValue])}return explode?properties:[[name,properties.flat().join(delimiter)]]}return[[name,coerceToString(value,name,"query")]]}function appendCookie(headers,name,value){if(!/^[\w!#$%&'*+\-.^`|~]+$/.test(name)){throw new Error(`Invalid cookie name: '${name}'. Cookie names must be valid tokens.`)}const existing=headers.get("Cookie")||"";const cookiePair=`${name}=${encodeURIComponent(coerceToString(value,name,"cookie"))}`;const combined=existing?`${existing}; ${cookiePair}`:cookiePair;headers.set("Cookie",combined)}var DOT_SEGMENTS=new Set([".",".."]);function assertPathStaysOnOperation(tool2,apiBaseUrl,resolvedPath,url){const templatePath=tool2.metadata.path;const templateSegments=templatePath.split("/");const addsDotSegment=resolvedPath.split("/").some((segment,index)=>DOT_SEGMENTS.has(segment)&&segment!==templateSegments[index]);const literalPrefix=templatePath.split("{")[0]??"";const expectedPathPrefix=new URL(`${apiBaseUrl}${literalPrefix}`).pathname;if(addsDotSegment||!new URL(url).pathname.startsWith(expectedPathPrefix)){throw new import_sdk3.PublicMcpError(`The path parameters of operation '${tool2.name}' do not resolve to its path`,"INVALID_PATH_PARAMETER",400)}}function specDefault(tool2,inputKey){const property=tool2.inputSchema.properties?.[inputKey];return typeof property==="object"?property.default:void 0}function buildRequest(tool2,input,security,baseUrl){const rawBaseUrl=tool2.metadata.servers?.[0]?.url||baseUrl;(0,import_utils2.validateBaseUrl)(rawBaseUrl);const apiBaseUrl=(0,import_utils2.trimTrailing)(rawBaseUrl,"/");let path=tool2.metadata.path;const queryParams=new URLSearchParams;const headers=new Headers({accept:"application/json",...security.headers});let body;for(const mapper of tool2.mapper){if(mapper.security)continue;const value=input[mapper.inputKey]??(mapper.required?specDefault(tool2,mapper.inputKey):void 0);if(value===void 0||value===null){if(mapper.required){throw new Error(`Required ${mapper.type} parameter '${mapper.key}' (input: '${mapper.inputKey}') is missing for operation '${tool2.name}'`)}continue}switch(mapper.type){case"path":{const pathValue=coerceToString(value,mapper.key,"path");if(DOT_SEGMENTS.has(pathValue)){throw new import_sdk3.PublicMcpError(`Path parameter '${mapper.key}' of operation '${tool2.name}' cannot be '.' or '..'`,"INVALID_PATH_PARAMETER",400)}path=path.replaceAll(`{${mapper.key}}`,encodeURIComponent(pathValue));break}case"query":for(const[queryName,queryValue]of serializeQueryParameter(mapper,value)){queryParams.append(queryName,queryValue)}break;case"header":{const headerValue=coerceToString(value,mapper.key,"header");if(/[\r\n\x00\f\v]/.test(headerValue)){throw new import_sdk3.PublicMcpError(`Invalid header value for '${mapper.key}': contains control characters (possible header injection attack)`,"INVALID_HEADER_VALUE",400)}headers.set(mapper.key,headerValue);break}case"cookie":appendCookie(headers,mapper.key,value);break;case"body":if(!body)body={};body[mapper.key]=value;break;default:throw new Error(`Unknown mapper type '${mapper.type}' for parameter '${mapper.key}' in operation '${tool2.name}'`)}}Object.entries(security.query).forEach(([key,value])=>{if(queryParams.has(key)){throw new Error(`Query parameter collision: '${key}' is provided both as user input and security parameter. This could indicate a security misconfiguration in operation '${tool2.name}'.`)}queryParams.set(key,coerceToString(value,key,"security query"))});if(security.cookies&&Object.keys(security.cookies).length>0){Object.entries(security.cookies).forEach(([key,value])=>{appendCookie(headers,key,value)})}if(path.includes("{")){throw new Error(`Failed to resolve all path parameters in ${path} for operation ${tool2.name}`)}const queryString=queryParams.toString();const url=`${apiBaseUrl}${path}${queryString?`?${queryString}`:""}`;assertPathStaysOnOperation(tool2,apiBaseUrl,path,url);return{url,headers,body}}function applyAdditionalHeaders(headers,additionalHeaders){if(!additionalHeaders)return;Object.entries(additionalHeaders).forEach(([key,value])=>{headers.set(key,value)})}var DEFAULT_MAX_RESPONSE_SIZE=10*1024*1024;async function parseResponse(response,options){const maxSize=options?.maxResponseSize??DEFAULT_MAX_RESPONSE_SIZE;const contentLength=response.headers.get("content-length");if(contentLength){const length=parseInt(contentLength,10);if(!isNaN(length)&&isFinite(length)&&length>maxSize){throw new Error(`Response size (${length} bytes) exceeds maximum allowed (${maxSize} bytes)`)}}const text=await response.text();const byteSize=new TextEncoder().encode(text).length;if(byteSize>maxSize){throw new Error(`Response size (${byteSize} bytes) exceeds maximum allowed (${maxSize} bytes)`)}const contentType=response.headers.get("content-type");let data;if(contentType?.toLowerCase().includes("application/json")){try{data=JSON.parse(text)}catch{data=text}}else{data=text}if(!response.ok){return{status:response.status,ok:false,data,error:typeof data==="object"&&data!==null&&"message"in data?String(data.message):typeof data==="string"?data:`HTTP ${response.status} error`}}return{status:response.status,ok:true,data}}function createOpenApiTool(openapiTool,options,logger){const metadata=openapiTool.metadata;const inputTransforms=metadata.adapter?.inputTransforms??[];const toolTransform=metadata.adapter?.toolTransform??{};const postToolTransform=metadata.adapter?.postToolTransform;const serverFilledKeys=new Set(inputTransforms.map(transform=>transform.inputKey));const frontmcpValidation=validateFrontMcpExtension(metadata.frontmcp,openapiTool.name,logger);const frontmcpExt=frontmcpValidation.data;const schemaResult=getZodSchemaFromJsonSchema(openapiTool.inputSchema,openapiTool.name,logger);const argumentCheck=schemaResult.conversionFailed?void 0:getZodSchemaFromJsonSchema(toArgumentJsonSchema(openapiTool),openapiTool.name,logger);let wrappedOutputSchema;if(openapiTool.outputSchema!==void 0){const baseOutputSchema=openapiTool.outputSchema??{type:"string"};wrappedOutputSchema={type:"object",properties:{status:{type:"number",description:"HTTP status code"},ok:{type:"boolean",description:"Whether the response was successful"},data:baseOutputSchema,error:{type:"string",description:"Error message for non-ok responses"}},required:["status","ok"]}}const toolMetadata={id:openapiTool.name,name:openapiTool.name,...openapiTool.title&&{title:openapiTool.title},description:openapiTool.description,inputSchema:schemaResult.schema.shape||{},rawInputSchema:openapiTool.inputSchema,...wrappedOutputSchema&&{rawOutputSchema:wrappedOutputSchema},...openapiTool.annotations&&{annotations:{...openapiTool.annotations}},...openapiTool.icons?.length&&{icons:openapiTool.icons.map(icon=>({...icon}))},...openapiTool._meta&&{_meta:{...openapiTool._meta}}};if(schemaResult.conversionFailed){toolMetadata["_schemaConversionFailed"]=true;toolMetadata["_schemaConversionError"]=schemaResult.error}if(frontmcpExt){if(frontmcpExt.annotations){toolMetadata["annotations"]={...toolMetadata["annotations"]||{},...frontmcpExt.annotations}}if(frontmcpExt.tags){toolMetadata["tags"]=[...frontmcpExt.tags]}if(frontmcpExt.hideFromDiscovery!==void 0){toolMetadata["hideFromDiscovery"]=frontmcpExt.hideFromDiscovery}if(frontmcpExt.examples){toolMetadata["examples"]=[...frontmcpExt.examples]}if(frontmcpExt.cache){toolMetadata["cache"]={...frontmcpExt.cache}}if(frontmcpExt.codecall){toolMetadata["codecall"]={...frontmcpExt.codecall}}}if(toolTransform.annotations){toolMetadata["annotations"]={...toolMetadata["annotations"]||{},...toolTransform.annotations}}if(toolTransform.tags){const existingTags=toolMetadata["tags"]||[];toolMetadata["tags"]=[...existingTags,...toolTransform.tags]}if(toolTransform.hideFromDiscovery!==void 0){toolMetadata["hideFromDiscovery"]=toolTransform.hideFromDiscovery}if(toolTransform.examples){const existingExamples=toolMetadata["examples"]||[];toolMetadata["examples"]=[...existingExamples,...toolTransform.examples]}if(toolTransform.ui){toolMetadata["ui"]=toolTransform.ui}return(0,import_sdk4.tool)(toolMetadata)(async(input,toolCtx)=>{const ctx=toolCtx.context;const modelInput=omitKeys(input,serverFilledKeys);if(argumentCheck&&!argumentCheck.conversionFailed){const validation=argumentCheck.schema.safeParse(modelInput);if(!validation.success){const problems=validation.error.issues.map(issue=>`${issue.path.join(".")||"input"}: ${issue.message}`);throw new import_sdk4.InvalidInputError(`Invalid arguments for tool '${openapiTool.name}': ${problems.join("; ")}`)}}const transformContext={ctx,env:process.env,tool:openapiTool};const injectedInput=await injectTransformedValues(modelInput,inputTransforms,transformContext);const security=await resolveToolSecurity(openapiTool,ctx,options,{input:injectedInput,deferCredentialCheck:true});const{url,headers,body:requestBody}=buildRequest(openapiTool,injectedInput,security,options.baseUrl);applyAdditionalHeaders(headers,options.additionalHeaders);if(options.headersMapper){try{const mappedHeaders=options.headersMapper(ctx,headers);if(mappedHeaders&&typeof mappedHeaders.forEach==="function"){mappedHeaders.forEach((value,key)=>{headers.set(key,value)})}}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`headersMapper failed for tool '${openapiTool.name}': ${errorMessage}`,{cause:err})}}assertRequestHasCredential(openapiTool,url,headers);let finalBody=requestBody;if(options.bodyMapper&&requestBody){try{finalBody=options.bodyMapper(ctx,requestBody)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`bodyMapper failed for tool '${openapiTool.name}': ${errorMessage}`,{cause:err})}}if(finalBody&&!headers.has("content-type")){headers.set("content-type","application/json")}let serializedBody;if(finalBody){try{serializedBody=JSON.stringify(finalBody)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`Failed to serialize request body for tool '${openapiTool.name}': ${errorMessage}. Body may contain circular references, BigInt, or non-serializable values.`,{cause:err})}const maxRequestSize=options.maxRequestSize??DEFAULT_MAX_REQUEST_SIZE;if(serializedBody.length>maxRequestSize){throw new Error(`Request body size (${serializedBody.length} bytes) exceeds maximum allowed (${maxRequestSize} bytes)`)}}const requestTimeout=options.requestTimeoutMs??DEFAULT_REQUEST_TIMEOUT_MS;const controller=new AbortController;const timeoutId=setTimeout(()=>controller.abort(),requestTimeout);try{const response=await fetch(url,{method:openapiTool.metadata.method.toUpperCase(),headers,body:serializedBody,signal:controller.signal,redirect:"manual"});if((0,import_utils3.isRedirectResponse)(response)){logger.warn(`[${openapiTool.name}] upstream returned a redirect; not followed`,{status:response.status});return{content:[{type:"text",text:JSON.stringify({status:response.status,error:`Upstream returned a redirect (${response.status}); not followed to protect injected credentials.`})}],isError:true,_meta:{status:response.status,errorCode:"OPENAPI_REDIRECT_NOT_FOLLOWED"}}}const apiResponse=await parseResponse(response,{maxResponseSize:options.maxResponseSize});let transformedData=apiResponse.data;if(postToolTransform){const transformCtx={ctx,tool:openapiTool,status:apiResponse.status,ok:apiResponse.ok,adapterOptions:options};const shouldTransform=postToolTransform.filter?postToolTransform.filter(transformCtx):true;if(shouldTransform){try{transformedData=await postToolTransform.transform(apiResponse.data,transformCtx)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);const errorStack=err instanceof Error?err.stack:void 0;logger.error(`[${openapiTool.name}] Post-tool output transform failed`,{error:errorMessage,stack:errorStack,status:apiResponse.status,ok:apiResponse.ok})}}}if(!apiResponse.ok){return{content:[{type:"text",text:JSON.stringify({status:apiResponse.status,error:apiResponse.error,data:transformedData})}],isError:true,_meta:{status:apiResponse.status,errorCode:"OPENAPI_ERROR"}}}return{status:apiResponse.status,ok:true,data:transformedData}}catch(err){if(err instanceof Error&&err.name==="AbortError"){const timeoutError=new Error(`Request timeout after ${requestTimeout}ms for tool '${openapiTool.name}'`);logger.error(`[${openapiTool.name}] API request timeout`,{timeout:requestTimeout,url,method:openapiTool.metadata.method.toUpperCase()});throw timeoutError}logger.error(`[${openapiTool.name}] API request failed`,{url,method:openapiTool.metadata.method.toUpperCase(),error:err instanceof Error?{name:err.name,message:err.message,stack:err.stack}:err});throw err}finally{clearTimeout(timeoutId)}})}var DEFAULT_TRANSFORM_TIMEOUT_MS=5e3;var DEFAULT_REQUEST_TIMEOUT_MS=3e4;var DEFAULT_MAX_REQUEST_SIZE=10*1024*1024;var RESERVED_KEYS=["__proto__","constructor","prototype"];async function safeInject(transform,ctx,timeoutMs=DEFAULT_TRANSFORM_TIMEOUT_MS){let timeoutId;try{const result=await Promise.race([Promise.resolve(transform.inject(ctx)),new Promise((_,reject)=>{timeoutId=setTimeout(()=>reject(new Error(`Transform timeout after ${timeoutMs}ms`)),timeoutMs)})]);return result}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`Input transform for '${transform.inputKey}' failed: ${errorMessage}`,{cause:err})}finally{if(timeoutId!==void 0){clearTimeout(timeoutId)}}}function isPlainObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function omitKeys(input,keys){if(keys.size===0||!isPlainObject(input))return input;return Object.fromEntries(Object.entries(input).filter(([key])=>!keys.has(key)))}async function injectTransformedValues(input,transforms,ctx){if(!isPlainObject(input)){throw new Error(`Invalid input type: expected object, got ${input===null?"null":typeof input}`)}if(transforms.length===0)return input;const result={...input};for(const transform of transforms){if(RESERVED_KEYS.includes(transform.inputKey)){throw new Error(`Invalid inputKey '${transform.inputKey}': reserved keys (${RESERVED_KEYS.join(", ")}) cannot be used`)}const value=await safeInject(transform,ctx);if(value!==void 0){result[transform.inputKey]=value}}return result}var SUBSCHEMA_KEYWORDS=["items","additionalProperties","not","if","then","else","contains","propertyNames","unevaluatedItems","unevaluatedProperties"];var SUBSCHEMA_LIST_KEYWORDS=["allOf","anyOf","prefixItems"];var SUBSCHEMA_MAP_KEYWORDS=["properties","patternProperties","dependentSchemas","$defs","definitions"];function toArgumentJsonSchema(openapiTool){const argumentSchema=relaxSchema(openapiTool.inputSchema);const credentialKeys=new Set(openapiTool.mapper.filter(mapper=>mapper.security).map(mapper=>mapper.inputKey));const required=argumentSchema["required"];if(Array.isArray(required)){argumentSchema["required"]=required.filter(key=>!credentialKeys.has(key))}return argumentSchema}function relaxSchema(schema){if(Array.isArray(schema))return schema.map(relaxSchema);if(typeof schema!=="object"||schema===null)return schema;const relaxed={...schema};delete relaxed["format"];for(const keyword of SUBSCHEMA_KEYWORDS){if(keyword in relaxed)relaxed[keyword]=relaxSchema(relaxed[keyword])}for(const keyword of SUBSCHEMA_LIST_KEYWORDS){const subschemas=relaxed[keyword];if(Array.isArray(subschemas))relaxed[keyword]=subschemas.map(relaxSchema)}for(const keyword of SUBSCHEMA_MAP_KEYWORDS){const subschemasByName=relaxed[keyword];if(typeof subschemasByName==="object"&&subschemasByName!==null){relaxed[keyword]=Object.fromEntries(Object.entries(subschemasByName).map(([name,subschema])=>[name,relaxSchema(subschema)]))}}const exclusiveBranches=relaxed["oneOf"];if(Array.isArray(exclusiveBranches)){delete relaxed["oneOf"];const branches=exclusiveBranches.map(relaxSchema);if(Array.isArray(relaxed["anyOf"])){const allOf=Array.isArray(relaxed["allOf"])?relaxed["allOf"]:[];relaxed["allOf"]=[...allOf,{anyOf:branches}]}else{relaxed["anyOf"]=branches}}return relaxed}function getZodSchemaFromJsonSchema(jsonSchema,toolName,logger){if(typeof jsonSchema!=="object"||jsonSchema===null){logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);return{schema:import_lazy_zod2.z.looseObject({}),conversionFailed:true,error:"No valid JSON schema"}}try{const zodSchema=import_lazy_zod2.z.fromJSONSchema(jsonSchema,{defaultTarget:"draft-2020-12"});if(typeof zodSchema?.parse!=="function"){throw new Error("Conversion did not produce a valid Zod schema.")}return{schema:zodSchema,conversionFailed:false}}catch(err){const errorMessage=err instanceof Error?err.message:String(err);logger.warn(`[${toolName}] Failed to generate Zod schema, using permissive schema. Tool will accept any input but may fail at API level. Error: ${errorMessage}`);return{schema:import_lazy_zod2.z.looseObject({}),conversionFailed:true,error:errorMessage}}}var RESERVED_KEYS2=["__proto__","constructor","prototype"];var HTTP_METHODS=["get","post","put","patch","delete","head","options","trace"];function normalizeMethods(adapterName,optionName,methods){return methods?.map(method=>{const lowerMethod=method.toLowerCase();if(!HTTP_METHODS.includes(lowerMethod)){throw new Error(`[OpenAPI Adapter: ${adapterName}] generateOptions.${optionName} lists "${method}", which is not an HTTP method; use one of ${HTTP_METHODS.join(", ")}.`)}return lowerMethod})}function createConsoleLogger(prefix){const formatMessage=(level,msg)=>`[${prefix}] ${level}: ${msg}`;return{verbose:(msg,...args)=>console.debug(formatMessage("VERBOSE",msg),...args),debug:(msg,...args)=>console.debug(formatMessage("DEBUG",msg),...args),info:(msg,...args)=>console.info(formatMessage("INFO",msg),...args),warn:(msg,...args)=>console.warn(formatMessage("WARN",msg),...args),error:(msg,...args)=>console.error(formatMessage("ERROR",msg),...args),child:childPrefix=>createConsoleLogger(`${prefix}:${childPrefix}`)}}var OpenapiAdapter=class extends import_sdk5.DynamicAdapter{generator;logger;options;poller=null;updateCallbacks=new Set;rebuildChain=Promise.resolve();methodFilters;constructor(options){super();this.options=options;this.methodFilters={includeMethods:normalizeMethods(options.name,"includeMethods",options.generateOptions?.includeMethods),excludeMethods:normalizeMethods(options.name,"excludeMethods",options.generateOptions?.excludeMethods)};this.logger=options.logger??createConsoleLogger(`openapi:${options.name}`);if(options.polling?.enabled&&!("url"in options)){throw new Error(`[OpenAPI Adapter: ${options.name}] Polling requires URL-based options (use 'url' instead of 'spec').`)}}setLogger(logger){this.logger=logger}async fetch(){if(!this.generator){this.generator=await this.initializeGenerator()}const inputSchemes=inputSecuritySchemes(this.options);const hasPerSchemeControl=inputSchemes!=="all"&&inputSchemes.size>0;const includeSecurityInInput=inputSchemes==="all"||hasPerSchemeControl;const generateOptions=this.options.generateOptions;let openapiTools=await this.generator.generateTools({...generateOptions,...this.methodFilters,filterFn:this.operationFilter(),preferredStatusCodes:generateOptions?.preferredStatusCodes??[200,201,202,204],includeDeprecated:generateOptions?.includeDeprecated??false,includeAllResponses:generateOptions?.includeAllResponses??true,includeSecurityInInput});openapiTools=openapiTools.map(tool2=>({...tool2,outputSchema:outputSchemaOf(tool2)}));if(hasPerSchemeControl){openapiTools=openapiTools.map(tool2=>this.filterSecuritySchemes(tool2,inputSchemes))}const validation=validateSecurityConfiguration(openapiTools,this.options);this.logger.info("Security Analysis:");this.logger.info(` Security Risk Score: ${validation.securityRiskScore.toUpperCase()}`);this.logger.info(` Valid Configuration: ${validation.valid?"YES":"NO"}`);if(validation.warnings.length>0){this.logger.info("Messages:");validation.warnings.forEach(warning=>{if(warning.startsWith("ERROR:")){this.logger.error(` - ${warning}`)}else if(warning.startsWith("SECURITY WARNING:")){this.logger.warn(` - ${warning}`)}else{this.logger.info(` - ${warning}`)}})}if(!validation.valid){throw new Error(formatMissingSecurityMappingsError(this.options.name,openapiTools,validation.missingMappings))}let transformedTools=openapiTools;if(this.options.descriptionMode&&this.options.descriptionMode!=="summaryOnly"){transformedTools=transformedTools.map(tool2=>this.applyDescriptionMode(tool2))}if(this.options.toolTransforms){transformedTools=transformedTools.map(tool2=>this.applyToolTransforms(tool2))}const nameMap=new Map;for(const tool2 of transformedTools){const meta=tool2.metadata;const source=`${meta["method"]?.toUpperCase()??"?"} ${meta["path"]??"?"}`;const existing=nameMap.get(tool2.name);if(existing){existing.push(source)}else{nameMap.set(tool2.name,[source])}}for(const[name,sources]of nameMap){if(sources.length>1){throw new Error(`Tool name collision: "${name}" produced by ${sources.length} operations: ${sources.join(", ")}. Rename conflicting operations in your OpenAPI spec or use toolTransforms.perTool to assign unique names.`)}}if(this.options.inputTransforms){transformedTools=transformedTools.map(tool2=>this.applyInputTransforms(tool2))}if(this.options.schemaTransforms){transformedTools=transformedTools.map(tool2=>this.applySchemaTransforms(tool2))}const dataTransforms=this.options.dataTransforms;if(this.options.outputSchema||dataTransforms){transformedTools=await Promise.all(transformedTools.map(tool2=>this.applyOutputSchemaOptions(tool2,dataTransforms)))}const tools=transformedTools.map(openapiTool=>createOpenApiTool(openapiTool,this.options,this.logger));return{tools}}resolveRefResolution(){return this.options.loadOptions?.refResolution??{allowedProtocols:[]}}operationFilter(){const{includeOperations,filterFn}=this.options.generateOptions??{};if(!includeOperations)return filterFn;return operation=>operation.operationId!==void 0&&includeOperations.includes(operation.operationId)&&(filterFn?.(operation)??true)}async initializeGenerator(){const loadOptions={...this.options.loadOptions,baseUrl:this.options.baseUrl,validate:this.options.loadOptions?.validate??true,dereference:this.options.loadOptions?.dereference??true,followRedirects:this.options.loadOptions?.followRedirects??false,refResolution:this.resolveRefResolution()};if("url"in this.options){return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromURL(this.options.url,loadOptions)}else if("spec"in this.options){return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromJSON(this.options.spec,loadOptions)}else{throw new Error("Either url or spec must be provided in OpenApiAdapterOptions")}}applyDescriptionMode(tool2){const mode=this.options.descriptionMode||"summaryOnly";const metadata=tool2.metadata;const summary=metadata["operationSummary"];const opDescription=metadata["operationDescription"];const operationId=metadata["operationId"];const method=metadata["method"];const path=metadata["path"];let description;switch(mode){case"descriptionOnly":description=opDescription||summary||`${method.toUpperCase()} ${path}`;break;case"combined":if(summary&&opDescription){description=`${summary}
4
+ `+solutions.join("\n"))}function requiredSecurityOf(tool2){return tool2.mapper.flatMap(mapper=>mapper.security&&mapper.required===true?[mapper.security]:[])}function authorizationSchemeOf(security){if(security?.type==="http")return(security.httpScheme??"bearer").toLowerCase();if(security?.type==="oauth2"||security?.type==="openIdConnect")return"bearer";return void 0}function carriesSchemeParameter(mapper,url,headers){if(mapper.type==="query")return!!url.searchParams.get(mapper.key);if(mapper.type==="cookie"){return(headers.get("cookie")??"").split(";").some(pair=>{const[name,...value2]=pair.trim().split("=");return name===mapper.key&&value2.join("=")!==""})}if(mapper.type!=="header")return false;const value=headers.get(mapper.key)?.trim();if(!value)return false;const scheme=authorizationSchemeOf(mapper.security);if(!scheme)return true;const space=value.indexOf(" ");return space>0&&value.slice(0,space).toLowerCase()===scheme&&value.slice(space+1).trim()!==""}function assertRequestHasCredential(tool2,url,headers){const securityMappers=tool2.mapper.filter(mapper=>mapper.security&&mapper.required===true);if(securityMappers.length===0)return;const parsedUrl=new URL(url);if(!securityMappers.some(mapper=>carriesSchemeParameter(mapper,parsedUrl,headers))){throw authenticationRequiredError(tool2)}}function validateSecurityConfiguration(tools,options){const result=validateCredentialSources(tools,options);const schemesInInput=inputSecuritySchemes(options);if(schemesInInput!=="all"&&schemesInInput.size>0){const include=options.generateOptions?.includeSecurityInInput;const sources=[(options.securitySchemesInInput?.length??0)>0?"securitySchemesInInput":void 0,Array.isArray(include)&&include.length>0?"an includeSecurityInInput list":void 0].filter(source=>source!==void 0);result.securityRiskScore="high";result.warnings.push(`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.`)}return result}function validateCredentialSources(tools,options){const result={valid:true,missingMappings:[],warnings:[],securityRiskScore:"low"};const securitySchemes=describeSecuritySchemes(tools);const inputSchemes=inputSecuritySchemes(options);if(inputSchemes==="all"){result.securityRiskScore="high";result.warnings.push("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.");return result}if(options.securityResolver){result.securityRiskScore="low";result.warnings.push("INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context.");return result}if(hasStaticAuth(options)){result.securityRiskScore="medium";result.warnings.push("SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager).");return withPassthroughRisk(result,securitySchemes,options)}const schemesInInput=inputSchemes;if(options.authProviderMapper||schemesInInput.size>0){result.securityRiskScore="low";const passthroughFallback=[];const perRequestHeaders=[];const schemeParameters=schemeParametersOf(tools);for(const[scheme,security]of securitySchemes){if(schemesInInput.has(scheme)){continue}if(!options.authProviderMapper?.[scheme]){const headerSource=headerCredentialSource(schemeParameters.get(scheme),options);if(headerSource==="static"){continue}else if(headerSource==="per-request"){perRequestHeaders.push(scheme)}else if(options.passthroughCallerToken===true&&isBearerScheme(security)){passthroughFallback.push(scheme)}else{result.valid=false;result.missingMappings.push(scheme)}}}if(!result.valid){result.warnings.push(`ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(", ")}`)}if(perRequestHeaders.length>0){result.warnings.push(`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.`)}withPassthroughRisk(result,securitySchemes,options);if(passthroughFallback.length>0){result.warnings.push(`SECURITY WARNING: Security schemes with no authProviderMapper entry (${passthroughFallback.join(", ")}) get the MCP client's own token, because passthroughCallerToken is enabled.`)}return result}if(securitySchemes.size>0&&options.passthroughCallerToken!==true){const schemesStr=Array.from(securitySchemes.keys()).join(", ");result.securityRiskScore="medium";result.warnings.push(`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.`)}const unfilled=[...securitySchemes].filter(([,security])=>!isBearerScheme(security)).map(([scheme])=>scheme);if(options.passthroughCallerToken===true&&unfilled.length>0){result.securityRiskScore="medium";result.warnings.push(`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.`)}return withPassthroughRisk(result,securitySchemes,options)}function canPassThroughCallerToken(options){return options.passthroughCallerToken===true&&!options.securityResolver&&!hasStaticAuth(options)}function withPassthroughRisk(result,securitySchemes,options){const bearerSchemes=[...securitySchemes].filter(([,security])=>isBearerScheme(security));if(bearerSchemes.length===0||!canPassThroughCallerToken(options)){return result}const schemesStr=bearerSchemes.map(([scheme])=>scheme).join(", ");const when=options.authProviderMapper?" whenever no authProviderMapper function returns a credential":"";result.securityRiskScore="high";result.warnings.push(`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.`);return result}async function resolveToolSecurity(tool2,ctx,options,request={}){const securityResolver=new import_mcp_from_openapi2.SecurityResolver;const securityContext=await createSecurityContextFromAuth(tool2,ctx,options);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;const requiresSecurity=tool2.mapper.some(m=>m.security&&m.required===true);const fromInput=request.input?await resolveInputSecurity(tool2,request.input,options,securityResolver):void 0;const hasInputCredential=!!fromInput&&Object.keys(fromInput.headers).length+Object.keys(fromInput.query).length+Object.keys(fromInput.cookies).length>0;if(requiresSecurity&&!hasAuth&&!hasInputCredential&&!request.deferCredentialCheck){throw authenticationRequiredError(tool2)}const resolved=await securityResolver.resolve(tool2.mapper,securityContext);if(!fromInput)return resolved;return{...resolved,headers:{...fromInput.headers,...resolved.headers},query:{...fromInput.query,...resolved.query},cookies:{...fromInput.cookies,...resolved.cookies}}}function inputSecuritySchemes(options){const include=options.generateOptions?.includeSecurityInInput;if(include===true)return"all";return new Set([...Array.isArray(include)?include:[],...options.securitySchemesInInput??[]])}function isInputScheme(scheme,options){const schemes=inputSecuritySchemes(options);return schemes==="all"||schemes.has(scheme)}function inputCredentialContext(security,value){const bare=value.replace(/^(?:bearer|basic)\s+/i,"");if(security.type==="apiKey"){return security.apiKeyName?{apiKeys:{[security.apiKeyName]:value}}:{apiKey:value}}if(security.type==="oauth2"||security.type==="openIdConnect")return{oauth2Token:bare};if(security.type==="http"){const httpScheme=(security.httpScheme??"bearer").toLowerCase();if(httpScheme==="bearer")return{jwt:bare};if(httpScheme==="basic")return{basic:bare}}return void 0}async function resolveInputSecurity(tool2,input,options,securityResolver){const resolved={headers:{},query:{},cookies:{}};for(const mapper of tool2.mapper){const security=mapper.security;if(!security||!isInputScheme(security.scheme,options))continue;const value=input[mapper.inputKey];if(typeof value!=="string"||value==="")continue;if(/[\r\n\x00\f\v]/.test(value)){throw new import_sdk2.PublicMcpError(`Invalid value for '${mapper.inputKey}': contains control characters (possible header injection attack)`,"INVALID_HEADER_VALUE",400)}const context=inputCredentialContext(security,value);if(!context)continue;const one=await securityResolver.resolve([mapper],(0,import_mcp_from_openapi2.createSecurityContext)(context));Object.assign(resolved.headers,one.headers);Object.assign(resolved.query,one.query);Object.assign(resolved.cookies,one.cookies)}return resolved}var import_lazy_zod2=require("@frontmcp/lazy-zod");var import_sdk4=require("@frontmcp/sdk");var import_utils3=require("@frontmcp/utils");var import_lazy_zod=require("@frontmcp/lazy-zod");var FRONTMCP_SCHEMA_VERSION="1.0";var SUPPORTED_VERSIONS=["1.0"];var FrontMcpAnnotationsSchema=import_lazy_zod.z.object({title:import_lazy_zod.z.string().optional(),readOnlyHint:import_lazy_zod.z.boolean().optional(),destructiveHint:import_lazy_zod.z.boolean().optional(),idempotentHint:import_lazy_zod.z.boolean().optional(),openWorldHint:import_lazy_zod.z.boolean().optional()});var FrontMcpCacheSchema=import_lazy_zod.z.object({ttl:import_lazy_zod.z.number().int().positive().optional(),slideWindow:import_lazy_zod.z.boolean().optional()});var FrontMcpCodeCallSchema=import_lazy_zod.z.object({enabledInCodeCall:import_lazy_zod.z.boolean().optional(),visibleInListTools:import_lazy_zod.z.boolean().optional()});var FrontMcpExampleSchema=import_lazy_zod.z.object({description:import_lazy_zod.z.string(),input:import_lazy_zod.z.record(import_lazy_zod.z.string(),import_lazy_zod.z.any()),output:import_lazy_zod.z.any().optional()});var KNOWN_EXTENSION_FIELDS=new Set(["version","annotations","cache","codecall","tags","hideFromDiscovery","examples","meta","icons"]);var KNOWN_ANNOTATION_FIELDS=new Set(["title","readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);var KNOWN_CACHE_FIELDS=new Set(["ttl","slideWindow"]);var KNOWN_CODECALL_FIELDS=new Set(["enabledInCodeCall","visibleInListTools"]);function validateFrontMcpExtension(rawData,toolName,logger){const warnings=[];if(rawData===null||rawData===void 0){return{success:true,data:null,warnings:[]}}if(typeof rawData!=="object"||Array.isArray(rawData)){warnings.push(`x-frontmcp must be an object, got ${Array.isArray(rawData)?"array":typeof rawData}`);logger.warn(`[${toolName}] Invalid x-frontmcp extension: ${warnings[0]}`);return{success:false,data:null,warnings}}const data=rawData;const version=typeof data["version"]==="string"?data["version"]:FRONTMCP_SCHEMA_VERSION;if(!SUPPORTED_VERSIONS.includes(version)){warnings.push(`Unsupported x-frontmcp version '${version}'. Supported versions: ${SUPPORTED_VERSIONS.join(", ")}`);logger.warn(`[${toolName}] ${warnings[0]}`);return{success:false,data:null,warnings}}const validData=extractValidFields(data,version,warnings);if(warnings.length>0){logger.warn(`[${toolName}] x-frontmcp extension has invalid fields that were ignored:`);warnings.forEach(w=>logger.warn(` - ${w}`))}return{success:true,data:validData,warnings}}function extractValidFields(data,version,warnings){const result={version};for(const key of Object.keys(data)){if(!KNOWN_EXTENSION_FIELDS.has(key)){warnings.push(`Unknown field '${key}' in x-frontmcp (will be ignored)`)}}if(data["annotations"]!==void 0){const annotationsResult=FrontMcpAnnotationsSchema.safeParse(data["annotations"]);if(annotationsResult.success){result.annotations=annotationsResult.data}else{const issues=formatZodIssues(annotationsResult.error.issues,"annotations");warnings.push(...issues);result.annotations=extractValidAnnotations(data["annotations"],warnings)}}if(data["cache"]!==void 0){const cacheResult=FrontMcpCacheSchema.safeParse(data["cache"]);if(cacheResult.success){result.cache=cacheResult.data}else{const issues=formatZodIssues(cacheResult.error.issues,"cache");warnings.push(...issues);result.cache=extractValidCache(data["cache"],warnings)}}if(data["codecall"]!==void 0){const codecallResult=FrontMcpCodeCallSchema.safeParse(data["codecall"]);if(codecallResult.success){result.codecall=codecallResult.data}else{const issues=formatZodIssues(codecallResult.error.issues,"codecall");warnings.push(...issues);result.codecall=extractValidCodeCall(data["codecall"],warnings)}}if(data["tags"]!==void 0){const tagsSchema=import_lazy_zod.z.array(import_lazy_zod.z.string());const tagsResult=tagsSchema.safeParse(data["tags"]);if(tagsResult.success){result.tags=tagsResult.data}else{warnings.push(`Invalid 'tags': expected array of strings`);result.tags=extractValidTags(data["tags"])}}if(data["hideFromDiscovery"]!==void 0){if(typeof data["hideFromDiscovery"]==="boolean"){result.hideFromDiscovery=data["hideFromDiscovery"]}else{warnings.push(`Invalid 'hideFromDiscovery': expected boolean, got ${typeof data["hideFromDiscovery"]}`)}}if(data["examples"]!==void 0){const examplesSchema=import_lazy_zod.z.array(FrontMcpExampleSchema);const examplesResult=examplesSchema.safeParse(data["examples"]);if(examplesResult.success){result.examples=examplesResult.data}else{warnings.push(`Invalid 'examples': some examples have invalid format`);result.examples=extractValidExamples(data["examples"],warnings)}}return result}function extractValidAnnotations(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};for(const field of KNOWN_ANNOTATION_FIELDS){if(obj[field]!==void 0){if(field==="title"&&typeof obj[field]==="string"){result.title=obj[field]}else if(field!=="title"&&typeof obj[field]==="boolean"){result[field]=obj[field]}}}for(const key of Object.keys(obj)){if(!KNOWN_ANNOTATION_FIELDS.has(key)){warnings.push(`Unknown field 'annotations.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidCache(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};if(typeof obj["ttl"]==="number"&&Number.isInteger(obj["ttl"])&&obj["ttl"]>0){result.ttl=obj["ttl"]}else if(obj["ttl"]!==void 0){warnings.push(`Invalid 'cache.ttl': expected positive integer`)}if(typeof obj["slideWindow"]==="boolean"){result.slideWindow=obj["slideWindow"]}else if(obj["slideWindow"]!==void 0){warnings.push(`Invalid 'cache.slideWindow': expected boolean`)}for(const key of Object.keys(obj)){if(!KNOWN_CACHE_FIELDS.has(key)){warnings.push(`Unknown field 'cache.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidCodeCall(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};if(typeof obj["enabledInCodeCall"]==="boolean"){result.enabledInCodeCall=obj["enabledInCodeCall"]}else if(obj["enabledInCodeCall"]!==void 0){warnings.push(`Invalid 'codecall.enabledInCodeCall': expected boolean`)}if(typeof obj["visibleInListTools"]==="boolean"){result.visibleInListTools=obj["visibleInListTools"]}else if(obj["visibleInListTools"]!==void 0){warnings.push(`Invalid 'codecall.visibleInListTools': expected boolean`)}for(const key of Object.keys(obj)){if(!KNOWN_CODECALL_FIELDS.has(key)){warnings.push(`Unknown field 'codecall.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidTags(data){if(!Array.isArray(data))return void 0;const validTags=data.filter(item=>typeof item==="string");return validTags.length>0?validTags:void 0}function extractValidExamples(data,warnings){if(!Array.isArray(data))return void 0;const validExamples=[];for(let i=0;i<data.length;i++){const item=data[i];const result=FrontMcpExampleSchema.safeParse(item);if(result.success){validExamples.push(result.data)}else{warnings.push(`Invalid example at index ${i}: ${formatZodIssues(result.error.issues,`examples[${i}]`).join(", ")}`)}}return validExamples.length>0?validExamples:void 0}function formatZodIssues(issues,prefix){return issues.map(issue=>{const path=issue.path.length>0?`${prefix}.${issue.path.join(".")}`:prefix;return`Invalid '${path}': ${issue.message}`})}var import_sdk3=require("@frontmcp/sdk");var import_utils2=require("@frontmcp/utils");function coerceToString(value,paramName,location){if(value===null||value===void 0){return""}if(typeof value==="object"){if(Array.isArray(value)){throw new Error(`${location} parameter '${paramName}' cannot be an array. Received: ${JSON.stringify(value)}`)}throw new Error(`${location} parameter '${paramName}' cannot be an object. Received: ${JSON.stringify(value)}`)}return String(value)}var QUERY_DELIMITERS={form:",",spaceDelimited:" ",pipeDelimited:"|"};function serializeQueryParameter(mapper,value){const style=mapper.style??"form";const explode=mapper.explode??style==="form";const name=mapper.key;const delimiter=QUERY_DELIMITERS[style]??",";if(Array.isArray(value)){const items=value.map(item=>coerceToString(item,name,"query"));return explode?items.map(item=>[name,item]):[[name,items.join(delimiter)]]}if(typeof value==="object"&&value!==null){const properties=Object.entries(value).filter(([,propertyValue])=>propertyValue!==void 0).map(([property,propertyValue])=>[property,coerceToString(propertyValue,name,"query")]);if(style==="deepObject"){return properties.map(([property,propertyValue])=>[`${name}[${property}]`,propertyValue])}return explode?properties:[[name,properties.flat().join(delimiter)]]}return[[name,coerceToString(value,name,"query")]]}function appendCookie(headers,name,value){if(!/^[\w!#$%&'*+\-.^`|~]+$/.test(name)){throw new Error(`Invalid cookie name: '${name}'. Cookie names must be valid tokens.`)}const existing=headers.get("Cookie")||"";const cookiePair=`${name}=${encodeURIComponent(coerceToString(value,name,"cookie"))}`;const combined=existing?`${existing}; ${cookiePair}`:cookiePair;headers.set("Cookie",combined)}var DOT_SEGMENTS=new Set([".",".."]);function assertPathStaysOnOperation(tool2,apiBaseUrl,resolvedPath,url){const templatePath=tool2.metadata.path;const templateSegments=templatePath.split("/");const addsDotSegment=resolvedPath.split("/").some((segment,index)=>DOT_SEGMENTS.has(segment)&&segment!==templateSegments[index]);const literalPrefix=templatePath.split("{")[0]??"";const expectedPathPrefix=new URL(`${apiBaseUrl}${literalPrefix}`).pathname;if(addsDotSegment||!new URL(url).pathname.startsWith(expectedPathPrefix)){throw new import_sdk3.PublicMcpError(`The path parameters of operation '${tool2.name}' do not resolve to its path`,"INVALID_PATH_PARAMETER",400)}}function specDefault(tool2,inputKey){const property=tool2.inputSchema.properties?.[inputKey];return typeof property==="object"?property.default:void 0}function buildRequest(tool2,input,security,baseUrl){const rawBaseUrl=tool2.metadata.servers?.[0]?.url||baseUrl;(0,import_utils2.validateBaseUrl)(rawBaseUrl);const apiBaseUrl=(0,import_utils2.trimTrailing)(rawBaseUrl,"/");let path=tool2.metadata.path;const queryParams=new URLSearchParams;const headers=new Headers({accept:"application/json",...security.headers});let body;for(const mapper of tool2.mapper){if(mapper.security)continue;const value=input[mapper.inputKey]??(mapper.required?specDefault(tool2,mapper.inputKey):void 0);if(value===void 0||value===null){if(mapper.required){throw new Error(`Required ${mapper.type} parameter '${mapper.key}' (input: '${mapper.inputKey}') is missing for operation '${tool2.name}'`)}continue}switch(mapper.type){case"path":{const pathValue=coerceToString(value,mapper.key,"path");if(DOT_SEGMENTS.has(pathValue)){throw new import_sdk3.PublicMcpError(`Path parameter '${mapper.key}' of operation '${tool2.name}' cannot be '.' or '..'`,"INVALID_PATH_PARAMETER",400)}path=path.replaceAll(`{${mapper.key}}`,encodeURIComponent(pathValue));break}case"query":for(const[queryName,queryValue]of serializeQueryParameter(mapper,value)){queryParams.append(queryName,queryValue)}break;case"header":{const headerValue=coerceToString(value,mapper.key,"header");if(/[\r\n\x00\f\v]/.test(headerValue)){throw new import_sdk3.PublicMcpError(`Invalid header value for '${mapper.key}': contains control characters (possible header injection attack)`,"INVALID_HEADER_VALUE",400)}headers.set(mapper.key,headerValue);break}case"cookie":appendCookie(headers,mapper.key,value);break;case"body":if(!body)body={};body[mapper.key]=value;break;default:throw new Error(`Unknown mapper type '${mapper.type}' for parameter '${mapper.key}' in operation '${tool2.name}'`)}}Object.entries(security.query).forEach(([key,value])=>{if(queryParams.has(key)){throw new Error(`Query parameter collision: '${key}' is provided both as user input and security parameter. This could indicate a security misconfiguration in operation '${tool2.name}'.`)}queryParams.set(key,coerceToString(value,key,"security query"))});if(security.cookies&&Object.keys(security.cookies).length>0){Object.entries(security.cookies).forEach(([key,value])=>{appendCookie(headers,key,value)})}if(path.includes("{")){throw new Error(`Failed to resolve all path parameters in ${path} for operation ${tool2.name}`)}const queryString=queryParams.toString();const url=`${apiBaseUrl}${path}${queryString?`?${queryString}`:""}`;assertPathStaysOnOperation(tool2,apiBaseUrl,path,url);return{url,headers,body}}function applyAdditionalHeaders(headers,additionalHeaders){if(!additionalHeaders)return;Object.entries(additionalHeaders).forEach(([key,value])=>{headers.set(key,value)})}var DEFAULT_MAX_RESPONSE_SIZE=10*1024*1024;async function parseResponse(response,options){const maxSize=options?.maxResponseSize??DEFAULT_MAX_RESPONSE_SIZE;const contentLength=response.headers.get("content-length");if(contentLength){const length=parseInt(contentLength,10);if(!isNaN(length)&&isFinite(length)&&length>maxSize){throw new Error(`Response size (${length} bytes) exceeds maximum allowed (${maxSize} bytes)`)}}let text;try{text=await(0,import_utils2.readTextWithLimit)(response,maxSize)}catch(error){if(error instanceof import_utils2.ResponseTooLargeError){throw new Error(`Response size exceeds maximum allowed (${maxSize} bytes)`,{cause:error})}throw error}const contentType=response.headers.get("content-type");let data;if(contentType?.toLowerCase().includes("application/json")){try{data=JSON.parse(text)}catch{data=text}}else{data=text}if(!response.ok){return{status:response.status,ok:false,data,error:typeof data==="object"&&data!==null&&"message"in data?String(data.message):typeof data==="string"?data:`HTTP ${response.status} error`}}return{status:response.status,ok:true,data}}function createOpenApiTool(openapiTool,options,logger){const metadata=openapiTool.metadata;const inputTransforms=metadata.adapter?.inputTransforms??[];const toolTransform=metadata.adapter?.toolTransform??{};const postToolTransform=metadata.adapter?.postToolTransform;const serverFilledKeys=new Set(inputTransforms.map(transform=>transform.inputKey));const frontmcpValidation=validateFrontMcpExtension(metadata.frontmcp,openapiTool.name,logger);const frontmcpExt=frontmcpValidation.data;const schemaResult=getZodSchemaFromJsonSchema(openapiTool.inputSchema,openapiTool.name,logger);const argumentCheck=schemaResult.conversionFailed?void 0:getZodSchemaFromJsonSchema(toArgumentJsonSchema(openapiTool),openapiTool.name,logger);let wrappedOutputSchema;if(openapiTool.outputSchema!==void 0){const baseOutputSchema=openapiTool.outputSchema??{type:"string"};wrappedOutputSchema={type:"object",properties:{status:{type:"number",description:"HTTP status code"},ok:{type:"boolean",description:"Whether the response was successful"},data:baseOutputSchema,error:{type:"string",description:"Error message for non-ok responses"}},required:["status","ok"]}}const toolMetadata={id:openapiTool.name,name:openapiTool.name,...openapiTool.title&&{title:openapiTool.title},description:openapiTool.description,inputSchema:schemaResult.schema.shape||{},rawInputSchema:openapiTool.inputSchema,...wrappedOutputSchema&&{rawOutputSchema:wrappedOutputSchema},...openapiTool.annotations&&{annotations:{...openapiTool.annotations}},...openapiTool.icons?.length&&{icons:openapiTool.icons.map(icon=>({...icon}))},...openapiTool._meta&&{_meta:{...openapiTool._meta}}};if(schemaResult.conversionFailed){toolMetadata["_schemaConversionFailed"]=true;toolMetadata["_schemaConversionError"]=schemaResult.error}if(frontmcpExt){if(frontmcpExt.annotations){toolMetadata["annotations"]={...toolMetadata["annotations"]||{},...frontmcpExt.annotations}}if(frontmcpExt.tags){toolMetadata["tags"]=[...frontmcpExt.tags]}if(frontmcpExt.hideFromDiscovery!==void 0){toolMetadata["hideFromDiscovery"]=frontmcpExt.hideFromDiscovery}if(frontmcpExt.examples){toolMetadata["examples"]=[...frontmcpExt.examples]}if(frontmcpExt.cache){toolMetadata["cache"]={...frontmcpExt.cache}}if(frontmcpExt.codecall){toolMetadata["codecall"]={...frontmcpExt.codecall}}}if(toolTransform.annotations){toolMetadata["annotations"]={...toolMetadata["annotations"]||{},...toolTransform.annotations}}if(toolTransform.tags){const existingTags=toolMetadata["tags"]||[];toolMetadata["tags"]=[...existingTags,...toolTransform.tags]}if(toolTransform.hideFromDiscovery!==void 0){toolMetadata["hideFromDiscovery"]=toolTransform.hideFromDiscovery}if(toolTransform.examples){const existingExamples=toolMetadata["examples"]||[];toolMetadata["examples"]=[...existingExamples,...toolTransform.examples]}if(toolTransform.ui){toolMetadata["ui"]=toolTransform.ui}return(0,import_sdk4.tool)(toolMetadata)(async(input,toolCtx)=>{const ctx=toolCtx.context;const modelInput=omitKeys(input,serverFilledKeys);if(argumentCheck&&!argumentCheck.conversionFailed){const validation=argumentCheck.schema.safeParse(modelInput);if(!validation.success){const problems=validation.error.issues.map(issue=>`${issue.path.join(".")||"input"}: ${issue.message}`);throw new import_sdk4.InvalidInputError(`Invalid arguments for tool '${openapiTool.name}': ${problems.join("; ")}`)}}const transformContext={ctx,env:process.env,tool:openapiTool};const injectedInput=await injectTransformedValues(modelInput,inputTransforms,transformContext);const security=await resolveToolSecurity(openapiTool,ctx,options,{input:injectedInput,deferCredentialCheck:true});const{url,headers,body:requestBody}=buildRequest(openapiTool,injectedInput,security,options.baseUrl);applyAdditionalHeaders(headers,options.additionalHeaders);if(options.headersMapper){try{const mappedHeaders=options.headersMapper(ctx,headers);if(mappedHeaders&&typeof mappedHeaders.forEach==="function"){mappedHeaders.forEach((value,key)=>{headers.set(key,value)})}}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`headersMapper failed for tool '${openapiTool.name}': ${errorMessage}`,{cause:err})}}assertRequestHasCredential(openapiTool,url,headers);let finalBody=requestBody;if(options.bodyMapper&&requestBody){try{finalBody=options.bodyMapper(ctx,requestBody)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`bodyMapper failed for tool '${openapiTool.name}': ${errorMessage}`,{cause:err})}}if(finalBody&&!headers.has("content-type")){headers.set("content-type","application/json")}let serializedBody;if(finalBody){try{serializedBody=JSON.stringify(finalBody)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`Failed to serialize request body for tool '${openapiTool.name}': ${errorMessage}. Body may contain circular references, BigInt, or non-serializable values.`,{cause:err})}const maxRequestSize=options.maxRequestSize??DEFAULT_MAX_REQUEST_SIZE;if(serializedBody.length>maxRequestSize){throw new Error(`Request body size (${serializedBody.length} bytes) exceeds maximum allowed (${maxRequestSize} bytes)`)}}const requestTimeout=options.requestTimeoutMs??DEFAULT_REQUEST_TIMEOUT_MS;const controller=new AbortController;const timeoutId=setTimeout(()=>controller.abort(),requestTimeout);try{const response=await fetch(url,{method:openapiTool.metadata.method.toUpperCase(),headers,body:serializedBody,signal:controller.signal,redirect:"manual"});if((0,import_utils3.isRedirectResponse)(response)){logger.warn(`[${openapiTool.name}] upstream returned a redirect; not followed`,{status:response.status});return{content:[{type:"text",text:JSON.stringify({status:response.status,error:`Upstream returned a redirect (${response.status}); not followed to protect injected credentials.`})}],isError:true,_meta:{status:response.status,errorCode:"OPENAPI_REDIRECT_NOT_FOLLOWED"}}}const apiResponse=await parseResponse(response,{maxResponseSize:options.maxResponseSize});let transformedData=apiResponse.data;if(postToolTransform){const transformCtx={ctx,tool:openapiTool,status:apiResponse.status,ok:apiResponse.ok,adapterOptions:options};const shouldTransform=postToolTransform.filter?postToolTransform.filter(transformCtx):true;if(shouldTransform){try{transformedData=await postToolTransform.transform(apiResponse.data,transformCtx)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);const errorStack=err instanceof Error?err.stack:void 0;logger.error(`[${openapiTool.name}] Post-tool output transform failed`,{error:errorMessage,stack:errorStack,status:apiResponse.status,ok:apiResponse.ok})}}}if(!apiResponse.ok){return{content:[{type:"text",text:JSON.stringify({status:apiResponse.status,error:apiResponse.error,data:transformedData})}],isError:true,_meta:{status:apiResponse.status,errorCode:"OPENAPI_ERROR"}}}return{status:apiResponse.status,ok:true,data:transformedData}}catch(err){if(err instanceof Error&&err.name==="AbortError"){const timeoutError=new Error(`Request timeout after ${requestTimeout}ms for tool '${openapiTool.name}'`);logger.error(`[${openapiTool.name}] API request timeout`,{timeout:requestTimeout,url:urlWithoutQuery(url),method:openapiTool.metadata.method.toUpperCase()});throw timeoutError}logger.error(`[${openapiTool.name}] API request failed`,{url:urlWithoutQuery(url),method:openapiTool.metadata.method.toUpperCase(),error:err instanceof Error?{name:err.name,message:err.message,stack:err.stack}:err});throw err}finally{clearTimeout(timeoutId)}})}function urlWithoutQuery(url){const queryStart=url.indexOf("?");const fragmentStart=url.indexOf("#");const cutPoints=[queryStart,fragmentStart].filter(index=>index!==-1);return cutPoints.length===0?url:url.slice(0,Math.min(...cutPoints))}var DEFAULT_TRANSFORM_TIMEOUT_MS=5e3;var DEFAULT_REQUEST_TIMEOUT_MS=3e4;var DEFAULT_MAX_REQUEST_SIZE=10*1024*1024;var RESERVED_KEYS=["__proto__","constructor","prototype"];async function safeInject(transform,ctx,timeoutMs=DEFAULT_TRANSFORM_TIMEOUT_MS){let timeoutId;try{const result=await Promise.race([Promise.resolve(transform.inject(ctx)),new Promise((_,reject)=>{timeoutId=setTimeout(()=>reject(new Error(`Transform timeout after ${timeoutMs}ms`)),timeoutMs)})]);return result}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`Input transform for '${transform.inputKey}' failed: ${errorMessage}`,{cause:err})}finally{if(timeoutId!==void 0){clearTimeout(timeoutId)}}}function isPlainObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function omitKeys(input,keys){if(keys.size===0||!isPlainObject(input))return input;return Object.fromEntries(Object.entries(input).filter(([key])=>!keys.has(key)))}async function injectTransformedValues(input,transforms,ctx){if(!isPlainObject(input)){throw new Error(`Invalid input type: expected object, got ${input===null?"null":typeof input}`)}if(transforms.length===0)return input;const result={...input};for(const transform of transforms){if(RESERVED_KEYS.includes(transform.inputKey)){throw new Error(`Invalid inputKey '${transform.inputKey}': reserved keys (${RESERVED_KEYS.join(", ")}) cannot be used`)}const value=await safeInject(transform,ctx);if(value!==void 0){result[transform.inputKey]=value}}return result}var SUBSCHEMA_KEYWORDS=["items","additionalProperties","not","if","then","else","contains","propertyNames","unevaluatedItems","unevaluatedProperties"];var SUBSCHEMA_LIST_KEYWORDS=["allOf","anyOf","prefixItems"];var SUBSCHEMA_MAP_KEYWORDS=["properties","patternProperties","dependentSchemas","$defs","definitions"];function toArgumentJsonSchema(openapiTool){const argumentSchema=relaxSchema(openapiTool.inputSchema);const credentialKeys=new Set(openapiTool.mapper.filter(mapper=>mapper.security).map(mapper=>mapper.inputKey));const required=argumentSchema["required"];if(Array.isArray(required)){argumentSchema["required"]=required.filter(key=>!credentialKeys.has(key))}return argumentSchema}function relaxSchema(schema){if(Array.isArray(schema))return schema.map(relaxSchema);if(typeof schema!=="object"||schema===null)return schema;const relaxed={...schema};delete relaxed["format"];if(typeof relaxed["pattern"]==="string"&&!(0,import_utils3.isPatternSafe)(relaxed["pattern"]))delete relaxed["pattern"];const propertyPatterns=relaxed["patternProperties"];if(typeof propertyPatterns==="object"&&propertyPatterns!==null){if(Object.keys(propertyPatterns).some(propertyPattern=>!(0,import_utils3.isPatternSafe)(propertyPattern))){delete relaxed["patternProperties"];delete relaxed["additionalProperties"]}}for(const keyword of SUBSCHEMA_KEYWORDS){if(keyword in relaxed)relaxed[keyword]=relaxSchema(relaxed[keyword])}for(const keyword of SUBSCHEMA_LIST_KEYWORDS){const subschemas=relaxed[keyword];if(Array.isArray(subschemas))relaxed[keyword]=subschemas.map(relaxSchema)}for(const keyword of SUBSCHEMA_MAP_KEYWORDS){const subschemasByName=relaxed[keyword];if(typeof subschemasByName==="object"&&subschemasByName!==null){relaxed[keyword]=Object.fromEntries(Object.entries(subschemasByName).map(([name,subschema])=>[name,relaxSchema(subschema)]))}}const exclusiveBranches=relaxed["oneOf"];if(Array.isArray(exclusiveBranches)){delete relaxed["oneOf"];const branches=exclusiveBranches.map(relaxSchema);if(Array.isArray(relaxed["anyOf"])){const allOf=Array.isArray(relaxed["allOf"])?relaxed["allOf"]:[];relaxed["allOf"]=[...allOf,{anyOf:branches}]}else{relaxed["anyOf"]=branches}}return relaxed}function getZodSchemaFromJsonSchema(jsonSchema,toolName,logger){if(typeof jsonSchema!=="object"||jsonSchema===null){logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);return{schema:import_lazy_zod2.z.looseObject({}),conversionFailed:true,error:"No valid JSON schema"}}try{const zodSchema=import_lazy_zod2.z.fromJSONSchema(jsonSchema,{defaultTarget:"draft-2020-12"});if(typeof zodSchema?.parse!=="function"){throw new Error("Conversion did not produce a valid Zod schema.")}return{schema:zodSchema,conversionFailed:false}}catch(err){const errorMessage=err instanceof Error?err.message:String(err);logger.warn(`[${toolName}] Failed to generate Zod schema, using permissive schema. Tool will accept any input but may fail at API level. Error: ${errorMessage}`);return{schema:import_lazy_zod2.z.looseObject({}),conversionFailed:true,error:errorMessage}}}var RESERVED_KEYS2=["__proto__","constructor","prototype"];var HTTP_METHODS=["get","post","put","patch","delete","head","options","trace"];function normalizeMethods(adapterName,optionName,methods){return methods?.map(method=>{const lowerMethod=method.toLowerCase();if(!HTTP_METHODS.includes(lowerMethod)){throw new Error(`[OpenAPI Adapter: ${adapterName}] generateOptions.${optionName} lists "${method}", which is not an HTTP method; use one of ${HTTP_METHODS.join(", ")}.`)}return lowerMethod})}function createConsoleLogger(prefix){const formatMessage=(level,msg)=>`[${prefix}] ${level}: ${msg}`;return{verbose:(msg,...args)=>console.debug(formatMessage("VERBOSE",msg),...args),debug:(msg,...args)=>console.debug(formatMessage("DEBUG",msg),...args),info:(msg,...args)=>console.info(formatMessage("INFO",msg),...args),warn:(msg,...args)=>console.warn(formatMessage("WARN",msg),...args),error:(msg,...args)=>console.error(formatMessage("ERROR",msg),...args),child:childPrefix=>createConsoleLogger(`${prefix}:${childPrefix}`)}}var OpenapiAdapter=class extends import_sdk5.DynamicAdapter{generator;logger;options;poller=null;updateCallbacks=new Set;rebuildChain=Promise.resolve();methodFilters;constructor(options){super();this.options=options;this.methodFilters={includeMethods:normalizeMethods(options.name,"includeMethods",options.generateOptions?.includeMethods),excludeMethods:normalizeMethods(options.name,"excludeMethods",options.generateOptions?.excludeMethods)};this.logger=options.logger??createConsoleLogger(`openapi:${options.name}`);if(options.polling?.enabled&&!("url"in options)){throw new Error(`[OpenAPI Adapter: ${options.name}] Polling requires URL-based options (use 'url' instead of 'spec').`)}}setLogger(logger){this.logger=logger}async fetch(){if(!this.generator){this.generator=await this.initializeGenerator()}const inputSchemes=inputSecuritySchemes(this.options);const hasPerSchemeControl=inputSchemes!=="all"&&inputSchemes.size>0;const includeSecurityInInput=inputSchemes==="all"||hasPerSchemeControl;const generateOptions=this.options.generateOptions;let openapiTools=await this.generator.generateTools({...generateOptions,...this.methodFilters,filterFn:this.operationFilter(),preferredStatusCodes:generateOptions?.preferredStatusCodes??[200,201,202,204],includeDeprecated:generateOptions?.includeDeprecated??false,includeAllResponses:generateOptions?.includeAllResponses??true,includeSecurityInInput});openapiTools=openapiTools.map(tool2=>({...tool2,outputSchema:outputSchemaOf(tool2)}));if(hasPerSchemeControl){openapiTools=openapiTools.map(tool2=>this.filterSecuritySchemes(tool2,inputSchemes))}const validation=validateSecurityConfiguration(openapiTools,this.options);this.logger.info("Security Analysis:");this.logger.info(` Security Risk Score: ${validation.securityRiskScore.toUpperCase()}`);this.logger.info(` Valid Configuration: ${validation.valid?"YES":"NO"}`);if(validation.warnings.length>0){this.logger.info("Messages:");validation.warnings.forEach(warning=>{if(warning.startsWith("ERROR:")){this.logger.error(` - ${warning}`)}else if(warning.startsWith("SECURITY WARNING:")){this.logger.warn(` - ${warning}`)}else{this.logger.info(` - ${warning}`)}})}if(!validation.valid){throw new Error(formatMissingSecurityMappingsError(this.options.name,openapiTools,validation.missingMappings))}let transformedTools=openapiTools;if(this.options.descriptionMode&&this.options.descriptionMode!=="summaryOnly"){transformedTools=transformedTools.map(tool2=>this.applyDescriptionMode(tool2))}if(this.options.toolTransforms){transformedTools=transformedTools.map(tool2=>this.applyToolTransforms(tool2))}const nameMap=new Map;for(const tool2 of transformedTools){const meta=tool2.metadata;const source=`${meta["method"]?.toUpperCase()??"?"} ${meta["path"]??"?"}`;const existing=nameMap.get(tool2.name);if(existing){existing.push(source)}else{nameMap.set(tool2.name,[source])}}for(const[name,sources]of nameMap){if(sources.length>1){throw new Error(`Tool name collision: "${name}" produced by ${sources.length} operations: ${sources.join(", ")}. Rename conflicting operations in your OpenAPI spec or use toolTransforms.perTool to assign unique names.`)}}if(this.options.inputTransforms){transformedTools=transformedTools.map(tool2=>this.applyInputTransforms(tool2))}if(this.options.schemaTransforms){transformedTools=transformedTools.map(tool2=>this.applySchemaTransforms(tool2))}const dataTransforms=this.options.dataTransforms;if(this.options.outputSchema||dataTransforms){transformedTools=await Promise.all(transformedTools.map(tool2=>this.applyOutputSchemaOptions(tool2,dataTransforms)))}const tools=transformedTools.map(openapiTool=>createOpenApiTool(openapiTool,this.options,this.logger));return{tools}}resolveRefResolution(){return this.options.loadOptions?.refResolution??{allowedProtocols:[]}}operationFilter(){const{includeOperations,filterFn}=this.options.generateOptions??{};if(!includeOperations)return filterFn;return operation=>operation.operationId!==void 0&&includeOperations.includes(operation.operationId)&&(filterFn?.(operation)??true)}async initializeGenerator(){const loadOptions={...this.options.loadOptions,baseUrl:this.options.baseUrl,validate:this.options.loadOptions?.validate??true,dereference:this.options.loadOptions?.dereference??true,followRedirects:this.options.loadOptions?.followRedirects??false,refResolution:this.resolveRefResolution()};if("url"in this.options){return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromURL(this.options.url,loadOptions)}else if("spec"in this.options){return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromJSON(this.options.spec,loadOptions)}else{throw new Error("Either url or spec must be provided in OpenApiAdapterOptions")}}applyDescriptionMode(tool2){const mode=this.options.descriptionMode||"summaryOnly";const metadata=tool2.metadata;const summary=metadata["operationSummary"];const opDescription=metadata["operationDescription"];const operationId=metadata["operationId"];const method=metadata["method"];const path=metadata["path"];let description;switch(mode){case"descriptionOnly":description=opDescription||summary||`${method.toUpperCase()} ${path}`;break;case"combined":if(summary&&opDescription){description=`${summary}
5
5
 
6
6
  ${opDescription}`}else{description=summary||opDescription||`${method.toUpperCase()} ${path}`}break;case"full":{const parts=[];if(summary)parts.push(summary);if(opDescription&&opDescription!==summary)parts.push(opDescription);if(operationId)parts.push(`Operation: ${operationId}`);parts.push(`${method.toUpperCase()} ${path}`);description=parts.join("\n\n");break}default:return tool2}return{...tool2,description}}resolvePerTool(perTool,tool2){if(!perTool)return void 0;if(Object.prototype.hasOwnProperty.call(perTool,tool2.name))return perTool[tool2.name];return void 0}collectToolTransforms(tool2){const result={};const opts=this.options.toolTransforms;if(!opts)return result;if(opts.global){Object.assign(result,opts.global);if(opts.global.annotations){result.annotations={...opts.global.annotations}}if(opts.global.tags){result.tags=[...opts.global.tags]}if(opts.global.examples){result.examples=[...opts.global.examples]}}const perToolMatch=this.resolvePerTool(opts.perTool,tool2);if(perToolMatch){const perTool=perToolMatch;if(perTool.name)result.name=perTool.name;if(perTool.description)result.description=perTool.description;if(perTool.hideFromDiscovery!==void 0)result.hideFromDiscovery=perTool.hideFromDiscovery;if(perTool.ui)result.ui=perTool.ui;if(perTool.annotations){result.annotations={...result.annotations,...perTool.annotations}}if(perTool.tags){result.tags=[...result.tags||[],...perTool.tags]}if(perTool.examples){result.examples=[...result.examples||[],...perTool.examples]}}if(opts.generator){const generated=opts.generator(tool2);if(generated){if(generated.name)result.name=generated.name;if(generated.description)result.description=generated.description;if(generated.hideFromDiscovery!==void 0)result.hideFromDiscovery=generated.hideFromDiscovery;if(generated.ui)result.ui=generated.ui;if(generated.annotations){result.annotations={...result.annotations,...generated.annotations}}if(generated.tags){result.tags=[...result.tags||[],...generated.tags]}if(generated.examples){result.examples=[...result.examples||[],...generated.examples]}}}return result}applyToolTransforms(tool2){const transforms=this.collectToolTransforms(tool2);if(Object.keys(transforms).length===0)return tool2;let newName=tool2.name;let newDescription=tool2.description;if(transforms.name){newName=typeof transforms.name==="function"?transforms.name(tool2.name,tool2):transforms.name}if(transforms.description){newDescription=typeof transforms.description==="function"?transforms.description(tool2.description,tool2):transforms.description}this.logger.debug(`Applied tool transforms to '${tool2.name}'`);const metadataRecord=tool2.metadata;const existingAdapter=metadataRecord["adapter"];return{...tool2,name:newName,description:newDescription,metadata:{...tool2.metadata,adapter:{...existingAdapter||{},toolTransform:transforms}}}}collectTransformsForTool(tool2){const transforms=[];const opts=this.options.inputTransforms;if(!opts)return transforms;if(opts.global){transforms.push(...opts.global)}const perToolInputTransforms=this.resolvePerTool(opts.perTool,tool2);if(perToolInputTransforms){transforms.push(...perToolInputTransforms)}if(opts.generator){transforms.push(...opts.generator(tool2))}return transforms}applyInputTransforms(tool2){const transforms=this.collectTransformsForTool(tool2);if(transforms.length===0)return tool2;for(const transform of transforms){if(RESERVED_KEYS2.includes(transform.inputKey)){throw new Error(`Invalid inputKey '${transform.inputKey}' in tool '${tool2.name}': reserved keys (${RESERVED_KEYS2.join(", ")}) cannot be used`)}}const transformedInputKeys=new Set(transforms.map(t=>t.inputKey));const inputSchema=tool2.inputSchema;const properties=inputSchema?.["properties"]||{};const required=inputSchema?.["required"]||[];const newProperties={...properties};for(const key of transformedInputKeys){delete newProperties[key]}const newRequired=required.filter(key=>!transformedInputKeys.has(key));this.logger.debug(`Applied ${transforms.length} input transforms to tool '${tool2.name}'`);const metadataRecord=tool2.metadata;const existingAdapter=metadataRecord["adapter"];return{...tool2,inputSchema:{...inputSchema,properties:newProperties,...newRequired.length>0?{required:newRequired}:{}},metadata:{...tool2.metadata,adapter:{...existingAdapter||{},inputTransforms:transforms}}}}filterSecuritySchemes(tool2,allowedSchemes){if(allowedSchemes.size===0)return tool2;const schemesToRemove=new Set;const inputKeysToRemove=new Set;for(const mapper of tool2.mapper){if(mapper.security?.scheme&&!allowedSchemes.has(mapper.security.scheme)){schemesToRemove.add(mapper.security.scheme);inputKeysToRemove.add(mapper.inputKey)}}if(inputKeysToRemove.size===0)return tool2;const inputSchema=tool2.inputSchema;const properties=inputSchema?.["properties"]||{};const required=inputSchema?.["required"]||[];const newProperties={...properties};for(const key of inputKeysToRemove){delete newProperties[key]}const newRequired=required.filter(key=>!inputKeysToRemove.has(key));this.logger.debug(`[${tool2.name}] Filtered security schemes from input: ${Array.from(schemesToRemove).join(", ")}. Kept in input: ${Array.from(allowedSchemes).filter(s=>!schemesToRemove.has(s)).join(", ")||"none"}`);const metadataRecord=tool2.metadata;const existingAdapter=metadataRecord["adapter"];return{...tool2,inputSchema:{...inputSchema,properties:newProperties,...newRequired.length>0?{required:newRequired}:{}},metadata:{...tool2.metadata,adapter:{...existingAdapter||{},securitySchemesInInput:Array.from(allowedSchemes),securitySchemesFromContext:Array.from(schemesToRemove)}}}}applySchemaTransforms(tool2){const opts=this.options.schemaTransforms;if(!opts)return tool2;const ctx={tool:tool2,adapterOptions:this.options};let newInputSchema=tool2.inputSchema;let newOutputSchema=tool2.outputSchema;if(opts.input){const inputTransform=this.collectInputSchemaTransform(tool2);if(inputTransform){newInputSchema=inputTransform(newInputSchema,ctx)}}if(opts.output){const outputTransform=this.collectOutputSchemaTransform(tool2);if(outputTransform){newOutputSchema=outputTransform(newOutputSchema,ctx)}}if(newInputSchema===tool2.inputSchema&&newOutputSchema===tool2.outputSchema){return tool2}this.logger.debug(`Applied schema transforms to '${tool2.name}'`);return{...tool2,inputSchema:newInputSchema,outputSchema:newOutputSchema}}collectInputSchemaTransform(tool2){const opts=this.options.schemaTransforms?.input;if(!opts)return void 0;if(opts.generator){const generated=opts.generator(tool2);if(generated)return generated}const perToolInputSchema=this.resolvePerTool(opts.perTool,tool2);if(perToolInputSchema){return perToolInputSchema}return opts.global}collectOutputSchemaTransform(tool2){const opts=this.options.schemaTransforms?.output;if(!opts)return void 0;if(opts.generator){const generated=opts.generator(tool2);if(generated)return generated}const perToolOutputSchema=this.resolvePerTool(opts.perTool,tool2);if(perToolOutputSchema){return perToolOutputSchema}return opts.global}async applyOutputSchemaOptions(tool2,dataTransforms){const outputSchemaOpts=this.options.outputSchema;let newDescription=tool2.description;let newOutputSchema=tool2.outputSchema;const mode=outputSchemaOpts?.mode??"definition";if(newOutputSchema&&(mode==="description"||mode==="both")){const descriptionFormat=outputSchemaOpts?.descriptionFormat??"summary";const formatter=outputSchemaOpts?.descriptionFormatter;const formatterCtx={tool:tool2,adapterOptions:this.options,originalDescription:tool2.description};let schemaText;if(formatter){schemaText=await Promise.resolve(formatter(newOutputSchema,formatterCtx))}else{schemaText=this.formatSchemaForDescription(newOutputSchema,descriptionFormat)}newDescription=tool2.description+schemaText}if(mode==="description"){newOutputSchema=void 0}const preTransform=this.collectPreToolTransformsFromDataTransforms(tool2,dataTransforms);if(preTransform){const ctx={tool:tool2,adapterOptions:this.options};if(preTransform.transformSchema){newOutputSchema=preTransform.transformSchema(newOutputSchema,ctx)}if(preTransform.transformDescription){newDescription=preTransform.transformDescription(newDescription,newOutputSchema,ctx)}}const postTransform=this.collectPostToolTransformsFromDataTransforms(tool2,dataTransforms);if(newDescription===tool2.description&&newOutputSchema===tool2.outputSchema&&!postTransform){return tool2}this.logger.debug(`Applied output schema options to '${tool2.name}' (mode: ${mode})`);const metadataRecord=tool2.metadata;const existingAdapter=metadataRecord["adapter"];return{...tool2,description:newDescription,outputSchema:newOutputSchema,metadata:{...tool2.metadata,adapter:{...existingAdapter||{},...postTransform&&{postToolTransform:postTransform}}}}}formatSchemaForDescription(schema,mode){switch(mode){case"jsonSchema":return`
7
7
 
package/openapi/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var __decorateClass=(decorators,target,key,kind)=>{var result=kind>1?void 0:kind?__getOwnPropDesc(target,key):target;for(var i=decorators.length-1,decorator;i>=0;i--)if(decorator=decorators[i])result=(kind?decorator(target,key,result):decorator(result))||result;if(kind&&result)__defProp(target,key,result);return result};var openapi_exports={};__export(openapi_exports,{FRONTMCP_EXTENSION_KEY:()=>FRONTMCP_EXTENSION_KEY,OpenAPIFetchError:()=>OpenAPIFetchError,OpenApiSpecPoller:()=>OpenApiSpecPoller,applyAdditionalHeaders:()=>applyAdditionalHeaders,buildRequest:()=>buildRequest,createSecurityContextFromAuth:()=>createSecurityContextFromAuth,default:()=>OpenapiAdapter,extractSecuritySchemes:()=>extractSecuritySchemes,forceJwtSecurity:()=>forceJwtSecurity,parseResponse:()=>parseResponse,removeSecurityFromOperations:()=>removeSecurityFromOperations,resolveToolSecurity:()=>resolveToolSecurity,validateSecurityConfiguration:()=>validateSecurityConfiguration});module.exports=__toCommonJS(openapi_exports);var import_mcp_from_openapi3=require("mcp-from-openapi");var import_sdk5=require("@frontmcp/sdk");var import_mcp_from_openapi=require("mcp-from-openapi");var import_utils=require("@frontmcp/utils");var import_sdk=require("@frontmcp/sdk");var OpenAPIFetchError=class extends import_sdk.InternalMcpError{constructor(url,status,statusText){super(`OpenAPI spec fetch failed from "${url}": ${status} ${statusText}`,"OPENAPI_FETCH_FAILED")}};var DEFAULT_RETRY={maxRetries:3,initialDelayMs:1e3,maxDelayMs:1e4,backoffMultiplier:2};var OpenApiSpecPoller=class{url;intervalMs;fetchTimeoutMs;changeDetection;retry;unhealthyThreshold;headers;ssrf;followRedirects;callbacks;intervalTimer=null;lastHash=null;lastEtag=null;lastModified=null;consecutiveFailures=0;isPolling=false;wasUnhealthy=false;health="unknown";constructor(url,options={},callbacks={}){this.url=url;this.intervalMs=options.intervalMs??6e4;this.fetchTimeoutMs=options.fetchTimeoutMs??1e4;this.changeDetection=options.changeDetection??"auto";this.retry={...DEFAULT_RETRY,...options.retry};this.unhealthyThreshold=options.unhealthyThreshold??3;this.headers=options.headers??{};this.ssrf=options.ssrf??(0,import_mcp_from_openapi.normalizeSsrfOptions)(void 0);this.followRedirects=options.followRedirects??false;this.callbacks=callbacks}start(){if(this.intervalTimer)return;this.poll().catch(()=>{});this.intervalTimer=setInterval(()=>{this.poll().catch(()=>{})},this.intervalMs)}stop(){if(this.intervalTimer){clearInterval(this.intervalTimer);this.intervalTimer=null}}getStats(){return{hash:this.lastHash,consecutiveFailures:this.consecutiveFailures,health:this.health,isRunning:this.intervalTimer!==null}}async poll(){if(this.isPolling)return;this.isPolling=true;try{await this.fetchWithRetry()}finally{this.isPolling=false}}async fetchWithRetry(){const{maxRetries,initialDelayMs,maxDelayMs,backoffMultiplier}=this.retry;for(let attempt=0;attempt<=maxRetries;attempt++){try{await this.doFetch();if(this.consecutiveFailures>0){this.consecutiveFailures=0;if(this.wasUnhealthy){this.wasUnhealthy=false;this.health="healthy";this.callbacks.onRecovered?.()}}this.health="healthy";return}catch(error){if(attempt===maxRetries){this.consecutiveFailures++;this.callbacks.onError?.(error instanceof Error?error:new Error(String(error)));if(this.consecutiveFailures>=this.unhealthyThreshold&&!this.wasUnhealthy){this.wasUnhealthy=true;this.health="unhealthy";this.callbacks.onUnhealthy?.(this.consecutiveFailures)}return}const delay=Math.min(initialDelayMs*Math.pow(backoffMultiplier,attempt),maxDelayMs);await new Promise(r=>setTimeout(r,delay))}}}async doFetch(){const headers={...this.headers};if(this.changeDetection!=="content-hash"){if(this.lastEtag){headers["If-None-Match"]=this.lastEtag}if(this.lastModified){headers["If-Modified-Since"]=this.lastModified}}const response=await(0,import_mcp_from_openapi.safeFetch)(this.url,{headers,timeoutMs:this.fetchTimeoutMs,followRedirects:this.followRedirects,ssrf:this.ssrf});if(response.status===304){this.callbacks.onUnchanged?.();return}if(!response.ok){throw new OpenAPIFetchError(this.url,response.status,response.statusText)}const etag=response.headers.get("etag");const lastModified=response.headers.get("last-modified");if(etag)this.lastEtag=etag;if(lastModified)this.lastModified=lastModified;const body=await response.text();const hash=(0,import_utils.sha256Hex)(body);if(this.lastHash&&this.lastHash===hash){this.callbacks.onUnchanged?.();return}this.lastHash=hash;this.callbacks.onChanged?.(body,hash)}dispose(){this.stop()}};var BODYLESS_STATUS_CODES=new Set([204,205]);var DEFAULT_RESPONSE_STATUS=0;var SUCCESS_RANGE_STATUS=2;function isSuccessWithBody(statusCode){if(statusCode===DEFAULT_RESPONSE_STATUS||statusCode===SUCCESS_RANGE_STATUS)return true;return typeof statusCode==="number"&&statusCode>=200&&statusCode<300&&!BODYLESS_STATUS_CODES.has(statusCode)}function acceptAnyUndeclaredBody(schema){const undeclared=schema.type==="null"&&schema["x-content-type"]===void 0&&isSuccessWithBody(schema["x-status-code"]);if(!undeclared)return schema;const{type:_null,...annotations}=schema;return annotations}function outputSchemaOf(tool2){const outputSchema=tool2.outputSchema;if(!outputSchema||tool2.metadata.method==="head")return outputSchema;const statusBranches=outputSchema.oneOf;if(statusBranches&&outputSchema["x-status-code"]===void 0){const{oneOf:_exclusive,...union}=outputSchema;return{...union,anyOf:statusBranches.map(acceptAnyUndeclaredBody)}}return acceptAnyUndeclaredBody(outputSchema)}var import_mcp_from_openapi2=require("mcp-from-openapi");var import_sdk2=require("@frontmcp/sdk");async function createSecurityContextFromAuth(tool2,ctx,options){if(options.securityResolver){return await options.securityResolver(tool2,ctx)}if(options.authProviderMapper){const context={};const securitySchemes=new Set;for(const mapper of tool2.mapper){if(mapper.security?.scheme){securitySchemes.add(mapper.security.scheme)}}for(const scheme of securitySchemes){const authExtractor=options.authProviderMapper[scheme];if(authExtractor){try{const token=authExtractor(ctx);if(token!==void 0&&token!==null&&typeof token!=="string"){throw new Error(`authProviderMapper['${scheme}'] must return a string or undefined, but returned: ${typeof token}`)}if(token===""){throw new Error(`authProviderMapper['${scheme}'] returned empty string. Return undefined/null if no token is available, or provide a valid token.`)}if(token){const schemeMapper=tool2.mapper.find(m=>m.security?.scheme===scheme);const schemeType=schemeMapper?.security?.type?.toLowerCase();const httpScheme=schemeMapper?.security?.httpScheme?.toLowerCase();if(schemeType==="apikey"){if(!context.apiKey){context.apiKey=token}}else if(schemeType==="http"&&httpScheme==="basic"){if(!context.basic){context.basic=token}}else if(schemeType==="oauth2"){if(!context.oauth2Token){context.oauth2Token=token}}else{if(!context.jwt){context.jwt=token}}}}catch(err){if(err instanceof Error&&err.message.includes("authProviderMapper")){throw err}const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`,{cause:err})}}}if(hasStaticAuth(options)){return(0,import_mcp_from_openapi2.createSecurityContext)({...options.staticAuth,...context})}const hasAnyAuth=context.jwt||context.apiKey||context.basic||context.oauth2Token;if(!hasAnyAuth&&options.passthroughCallerToken===true){const callerToken=getCallerToken(ctx);if(callerToken){context.jwt=callerToken}}return(0,import_mcp_from_openapi2.createSecurityContext)(context)}if(hasStaticAuth(options)){return(0,import_mcp_from_openapi2.createSecurityContext)(options.staticAuth)}if(options.passthroughCallerToken===true){return(0,import_mcp_from_openapi2.createSecurityContext)({jwt:getCallerToken(ctx)})}return(0,import_mcp_from_openapi2.createSecurityContext)({})}function hasStaticAuth(options){return!!options.staticAuth&&Object.keys(options.staticAuth).length>0}function getCallerToken(ctx){const authToken=ctx.authInfo?.token;if(authToken===void 0||authToken===null||authToken===""){return void 0}if(typeof authToken!=="string"){throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`)}return authToken}function extractSecuritySchemes(tools){const schemes=new Set;for(const tool2 of tools){for(const mapper of tool2.mapper){if(mapper.security?.scheme){schemes.add(mapper.security.scheme)}}}return schemes}function describeSecuritySchemes(tools){const schemes=new Map;for(const tool2 of tools){for(const mapper of tool2.mapper){if(mapper.security?.scheme&&!schemes.has(mapper.security.scheme)){schemes.set(mapper.security.scheme,mapper.security)}}}return schemes}function schemeParametersOf(tools){const parameters=new Map;for(const tool2 of tools){for(const mapper of tool2.mapper){const scheme=mapper.security?.scheme;if(scheme&&!parameters.has(scheme))parameters.set(scheme,mapper)}}return parameters}function headerCredentialSource(parameter,options){if(!parameter)return void 0;const staticHeaders=new Headers(options.additionalHeaders??{});if(carriesSchemeParameter(parameter,new URL("http://startup.invalid/"),staticHeaders))return"static";if(options.headersMapper&&(parameter.type==="header"||parameter.type==="cookie"))return"per-request";return void 0}function isBearerScheme(security){if(!security||security.type!=="http")return false;return(security.httpScheme??"bearer").toLowerCase()==="bearer"}function credentialFieldOf(security){if(security?.type==="apiKey")return"apiKey";if(security?.type==="oauth2"||security?.type==="openIdConnect")return"oauth2Token";if(security?.type==="http"&&security.httpScheme?.toLowerCase()==="basic")return"basic";return"jwt"}function formatMissingSecurityMappingsError(adapterName,tools,missingMappings){const schemes=describeSecuritySchemes(tools);const fieldOf=scheme=>credentialFieldOf(schemes.get(scheme));const firstField=fieldOf(missingMappings[0]??"");const bearerSchemes=missingMappings.filter(scheme=>isBearerScheme(schemes.get(scheme)));const lines=[`[OpenAPI Adapter: ${adapterName}] Invalid security configuration.`,`Missing auth provider mappings for security schemes: ${missingMappings.join(", ")}`,"","Your OpenAPI spec requires these security schemes, but no credential option covers them.","","Add one of the following to your adapter configuration:","","1. authProviderMapper (recommended): a function per scheme that returns the credential issued for the API:"," authProviderMapper: {",...missingMappings.map(scheme=>` '${scheme}': (ctx) => getApiCredential(ctx), // the ${fieldOf(scheme)}`)," }","","2. securityResolver:",` securityResolver: async (tool, ctx) => ({ ${firstField}: await getApiCredential(ctx) })`,"","3. staticAuth (one credential for every caller):",` staticAuth: { ${firstField}: process.env.API_CREDENTIAL }`];if(bearerSchemes.length>0){lines.push("",`4. passthroughCallerToken: true, for the HTTP bearer schemes (${bearerSchemes.join(", ")}) only, and only if the API`," accepts the MCP client's own token (same issuer and audience). It sends nothing for other schemes.")}return lines.join("\n")}function authenticationRequiredError(tool2){const required=requiredSecurityOf(tool2);const schemes=[...new Map(required.map(security=>[security.scheme,security])).values()];const schemesStr=schemes.map(security=>`${security.scheme} (${security.type})`).join(", ")||"unknown";const first=schemes[0];const firstScheme=first?.scheme??"BearerAuth";const field=credentialFieldOf(first);const bearerSchemes=schemes.filter(isBearerScheme).map(security=>security.scheme);const solutions=[` 1. Add authProviderMapper: { '${firstScheme}': (ctx) => getApiCredential(ctx) }, returning the ${field} issued for the API`,` 2. Add securityResolver: async (tool, ctx) => ({ ${field}: await getApiCredential(ctx) })`,` 3. Add staticAuth: { ${field}: process.env.API_CREDENTIAL }`];if(bearerSchemes.length>0){solutions.push(` 4. Set passthroughCallerToken: true, only if the API accepts the MCP client's own token (it fills ${bearerSchemes.join(", ")} only)`)}return new Error(`Authentication required for tool '${tool2.name}': no credential for its security schemes.
2
2
  Required security schemes: ${schemesStr}
3
3
  Solutions:
4
- `+solutions.join("\n"))}function requiredSecurityOf(tool2){return tool2.mapper.flatMap(mapper=>mapper.security&&mapper.required===true?[mapper.security]:[])}function authorizationSchemeOf(security){if(security?.type==="http")return(security.httpScheme??"bearer").toLowerCase();if(security?.type==="oauth2"||security?.type==="openIdConnect")return"bearer";return void 0}function carriesSchemeParameter(mapper,url,headers){if(mapper.type==="query")return!!url.searchParams.get(mapper.key);if(mapper.type==="cookie"){return(headers.get("cookie")??"").split(";").some(pair=>{const[name,...value2]=pair.trim().split("=");return name===mapper.key&&value2.join("=")!==""})}if(mapper.type!=="header")return false;const value=headers.get(mapper.key)?.trim();if(!value)return false;const scheme=authorizationSchemeOf(mapper.security);if(!scheme)return true;const space=value.indexOf(" ");return space>0&&value.slice(0,space).toLowerCase()===scheme&&value.slice(space+1).trim()!==""}function assertRequestHasCredential(tool2,url,headers){const securityMappers=tool2.mapper.filter(mapper=>mapper.security&&mapper.required===true);if(securityMappers.length===0)return;const parsedUrl=new URL(url);if(!securityMappers.some(mapper=>carriesSchemeParameter(mapper,parsedUrl,headers))){throw authenticationRequiredError(tool2)}}function validateSecurityConfiguration(tools,options){const result=validateCredentialSources(tools,options);const schemesInInput=inputSecuritySchemes(options);if(schemesInInput!=="all"&&schemesInInput.size>0){const include=options.generateOptions?.includeSecurityInInput;const sources=[(options.securitySchemesInInput?.length??0)>0?"securitySchemesInInput":void 0,Array.isArray(include)&&include.length>0?"an includeSecurityInInput list":void 0].filter(source=>source!==void 0);result.securityRiskScore="high";result.warnings.push(`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.`)}return result}function validateCredentialSources(tools,options){const result={valid:true,missingMappings:[],warnings:[],securityRiskScore:"low"};const securitySchemes=describeSecuritySchemes(tools);const inputSchemes=inputSecuritySchemes(options);if(inputSchemes==="all"){result.securityRiskScore="high";result.warnings.push("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.");return result}if(options.securityResolver){result.securityRiskScore="low";result.warnings.push("INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context.");return result}if(hasStaticAuth(options)){result.securityRiskScore="medium";result.warnings.push("SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager).");return withPassthroughRisk(result,securitySchemes,options)}const schemesInInput=inputSchemes;if(options.authProviderMapper||schemesInInput.size>0){result.securityRiskScore="low";const passthroughFallback=[];const perRequestHeaders=[];const schemeParameters=schemeParametersOf(tools);for(const[scheme,security]of securitySchemes){if(schemesInInput.has(scheme)){continue}if(!options.authProviderMapper?.[scheme]){const headerSource=headerCredentialSource(schemeParameters.get(scheme),options);if(headerSource==="static"){continue}else if(headerSource==="per-request"){perRequestHeaders.push(scheme)}else if(options.passthroughCallerToken===true&&isBearerScheme(security)){passthroughFallback.push(scheme)}else{result.valid=false;result.missingMappings.push(scheme)}}}if(!result.valid){result.warnings.push(`ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(", ")}`)}if(perRequestHeaders.length>0){result.warnings.push(`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.`)}withPassthroughRisk(result,securitySchemes,options);if(passthroughFallback.length>0){result.warnings.push(`SECURITY WARNING: Security schemes with no authProviderMapper entry (${passthroughFallback.join(", ")}) get the MCP client's own token, because passthroughCallerToken is enabled.`)}return result}if(securitySchemes.size>0&&options.passthroughCallerToken!==true){const schemesStr=Array.from(securitySchemes.keys()).join(", ");result.securityRiskScore="medium";result.warnings.push(`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.`)}const unfilled=[...securitySchemes].filter(([,security])=>!isBearerScheme(security)).map(([scheme])=>scheme);if(options.passthroughCallerToken===true&&unfilled.length>0){result.securityRiskScore="medium";result.warnings.push(`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.`)}return withPassthroughRisk(result,securitySchemes,options)}function canPassThroughCallerToken(options){return options.passthroughCallerToken===true&&!options.securityResolver&&!hasStaticAuth(options)}function withPassthroughRisk(result,securitySchemes,options){const bearerSchemes=[...securitySchemes].filter(([,security])=>isBearerScheme(security));if(bearerSchemes.length===0||!canPassThroughCallerToken(options)){return result}const schemesStr=bearerSchemes.map(([scheme])=>scheme).join(", ");const when=options.authProviderMapper?" whenever no authProviderMapper function returns a credential":"";result.securityRiskScore="high";result.warnings.push(`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.`);return result}async function resolveToolSecurity(tool2,ctx,options,request={}){const securityResolver=new import_mcp_from_openapi2.SecurityResolver;const securityContext=await createSecurityContextFromAuth(tool2,ctx,options);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;const requiresSecurity=tool2.mapper.some(m=>m.security&&m.required===true);const fromInput=request.input?await resolveInputSecurity(tool2,request.input,options,securityResolver):void 0;const hasInputCredential=!!fromInput&&Object.keys(fromInput.headers).length+Object.keys(fromInput.query).length+Object.keys(fromInput.cookies).length>0;if(requiresSecurity&&!hasAuth&&!hasInputCredential&&!request.deferCredentialCheck){throw authenticationRequiredError(tool2)}const resolved=await securityResolver.resolve(tool2.mapper,securityContext);if(!fromInput)return resolved;return{...resolved,headers:{...fromInput.headers,...resolved.headers},query:{...fromInput.query,...resolved.query},cookies:{...fromInput.cookies,...resolved.cookies}}}function inputSecuritySchemes(options){const include=options.generateOptions?.includeSecurityInInput;if(include===true)return"all";return new Set([...Array.isArray(include)?include:[],...options.securitySchemesInInput??[]])}function isInputScheme(scheme,options){const schemes=inputSecuritySchemes(options);return schemes==="all"||schemes.has(scheme)}function inputCredentialContext(security,value){const bare=value.replace(/^(?:bearer|basic)\s+/i,"");if(security.type==="apiKey"){return security.apiKeyName?{apiKeys:{[security.apiKeyName]:value}}:{apiKey:value}}if(security.type==="oauth2"||security.type==="openIdConnect")return{oauth2Token:bare};if(security.type==="http"){const httpScheme=(security.httpScheme??"bearer").toLowerCase();if(httpScheme==="bearer")return{jwt:bare};if(httpScheme==="basic")return{basic:bare}}return void 0}async function resolveInputSecurity(tool2,input,options,securityResolver){const resolved={headers:{},query:{},cookies:{}};for(const mapper of tool2.mapper){const security=mapper.security;if(!security||!isInputScheme(security.scheme,options))continue;const value=input[mapper.inputKey];if(typeof value!=="string"||value==="")continue;if(/[\r\n\x00\f\v]/.test(value)){throw new import_sdk2.PublicMcpError(`Invalid value for '${mapper.inputKey}': contains control characters (possible header injection attack)`,"INVALID_HEADER_VALUE",400)}const context=inputCredentialContext(security,value);if(!context)continue;const one=await securityResolver.resolve([mapper],(0,import_mcp_from_openapi2.createSecurityContext)(context));Object.assign(resolved.headers,one.headers);Object.assign(resolved.query,one.query);Object.assign(resolved.cookies,one.cookies)}return resolved}var import_lazy_zod2=require("@frontmcp/lazy-zod");var import_sdk4=require("@frontmcp/sdk");var import_utils3=require("@frontmcp/utils");var import_lazy_zod=require("@frontmcp/lazy-zod");var FRONTMCP_SCHEMA_VERSION="1.0";var SUPPORTED_VERSIONS=["1.0"];var FrontMcpAnnotationsSchema=import_lazy_zod.z.object({title:import_lazy_zod.z.string().optional(),readOnlyHint:import_lazy_zod.z.boolean().optional(),destructiveHint:import_lazy_zod.z.boolean().optional(),idempotentHint:import_lazy_zod.z.boolean().optional(),openWorldHint:import_lazy_zod.z.boolean().optional()});var FrontMcpCacheSchema=import_lazy_zod.z.object({ttl:import_lazy_zod.z.number().int().positive().optional(),slideWindow:import_lazy_zod.z.boolean().optional()});var FrontMcpCodeCallSchema=import_lazy_zod.z.object({enabledInCodeCall:import_lazy_zod.z.boolean().optional(),visibleInListTools:import_lazy_zod.z.boolean().optional()});var FrontMcpExampleSchema=import_lazy_zod.z.object({description:import_lazy_zod.z.string(),input:import_lazy_zod.z.record(import_lazy_zod.z.string(),import_lazy_zod.z.any()),output:import_lazy_zod.z.any().optional()});var KNOWN_EXTENSION_FIELDS=new Set(["version","annotations","cache","codecall","tags","hideFromDiscovery","examples","meta","icons"]);var KNOWN_ANNOTATION_FIELDS=new Set(["title","readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);var KNOWN_CACHE_FIELDS=new Set(["ttl","slideWindow"]);var KNOWN_CODECALL_FIELDS=new Set(["enabledInCodeCall","visibleInListTools"]);function validateFrontMcpExtension(rawData,toolName,logger){const warnings=[];if(rawData===null||rawData===void 0){return{success:true,data:null,warnings:[]}}if(typeof rawData!=="object"||Array.isArray(rawData)){warnings.push(`x-frontmcp must be an object, got ${Array.isArray(rawData)?"array":typeof rawData}`);logger.warn(`[${toolName}] Invalid x-frontmcp extension: ${warnings[0]}`);return{success:false,data:null,warnings}}const data=rawData;const version=typeof data["version"]==="string"?data["version"]:FRONTMCP_SCHEMA_VERSION;if(!SUPPORTED_VERSIONS.includes(version)){warnings.push(`Unsupported x-frontmcp version '${version}'. Supported versions: ${SUPPORTED_VERSIONS.join(", ")}`);logger.warn(`[${toolName}] ${warnings[0]}`);return{success:false,data:null,warnings}}const validData=extractValidFields(data,version,warnings);if(warnings.length>0){logger.warn(`[${toolName}] x-frontmcp extension has invalid fields that were ignored:`);warnings.forEach(w=>logger.warn(` - ${w}`))}return{success:true,data:validData,warnings}}function extractValidFields(data,version,warnings){const result={version};for(const key of Object.keys(data)){if(!KNOWN_EXTENSION_FIELDS.has(key)){warnings.push(`Unknown field '${key}' in x-frontmcp (will be ignored)`)}}if(data["annotations"]!==void 0){const annotationsResult=FrontMcpAnnotationsSchema.safeParse(data["annotations"]);if(annotationsResult.success){result.annotations=annotationsResult.data}else{const issues=formatZodIssues(annotationsResult.error.issues,"annotations");warnings.push(...issues);result.annotations=extractValidAnnotations(data["annotations"],warnings)}}if(data["cache"]!==void 0){const cacheResult=FrontMcpCacheSchema.safeParse(data["cache"]);if(cacheResult.success){result.cache=cacheResult.data}else{const issues=formatZodIssues(cacheResult.error.issues,"cache");warnings.push(...issues);result.cache=extractValidCache(data["cache"],warnings)}}if(data["codecall"]!==void 0){const codecallResult=FrontMcpCodeCallSchema.safeParse(data["codecall"]);if(codecallResult.success){result.codecall=codecallResult.data}else{const issues=formatZodIssues(codecallResult.error.issues,"codecall");warnings.push(...issues);result.codecall=extractValidCodeCall(data["codecall"],warnings)}}if(data["tags"]!==void 0){const tagsSchema=import_lazy_zod.z.array(import_lazy_zod.z.string());const tagsResult=tagsSchema.safeParse(data["tags"]);if(tagsResult.success){result.tags=tagsResult.data}else{warnings.push(`Invalid 'tags': expected array of strings`);result.tags=extractValidTags(data["tags"])}}if(data["hideFromDiscovery"]!==void 0){if(typeof data["hideFromDiscovery"]==="boolean"){result.hideFromDiscovery=data["hideFromDiscovery"]}else{warnings.push(`Invalid 'hideFromDiscovery': expected boolean, got ${typeof data["hideFromDiscovery"]}`)}}if(data["examples"]!==void 0){const examplesSchema=import_lazy_zod.z.array(FrontMcpExampleSchema);const examplesResult=examplesSchema.safeParse(data["examples"]);if(examplesResult.success){result.examples=examplesResult.data}else{warnings.push(`Invalid 'examples': some examples have invalid format`);result.examples=extractValidExamples(data["examples"],warnings)}}return result}function extractValidAnnotations(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};for(const field of KNOWN_ANNOTATION_FIELDS){if(obj[field]!==void 0){if(field==="title"&&typeof obj[field]==="string"){result.title=obj[field]}else if(field!=="title"&&typeof obj[field]==="boolean"){result[field]=obj[field]}}}for(const key of Object.keys(obj)){if(!KNOWN_ANNOTATION_FIELDS.has(key)){warnings.push(`Unknown field 'annotations.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidCache(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};if(typeof obj["ttl"]==="number"&&Number.isInteger(obj["ttl"])&&obj["ttl"]>0){result.ttl=obj["ttl"]}else if(obj["ttl"]!==void 0){warnings.push(`Invalid 'cache.ttl': expected positive integer`)}if(typeof obj["slideWindow"]==="boolean"){result.slideWindow=obj["slideWindow"]}else if(obj["slideWindow"]!==void 0){warnings.push(`Invalid 'cache.slideWindow': expected boolean`)}for(const key of Object.keys(obj)){if(!KNOWN_CACHE_FIELDS.has(key)){warnings.push(`Unknown field 'cache.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidCodeCall(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};if(typeof obj["enabledInCodeCall"]==="boolean"){result.enabledInCodeCall=obj["enabledInCodeCall"]}else if(obj["enabledInCodeCall"]!==void 0){warnings.push(`Invalid 'codecall.enabledInCodeCall': expected boolean`)}if(typeof obj["visibleInListTools"]==="boolean"){result.visibleInListTools=obj["visibleInListTools"]}else if(obj["visibleInListTools"]!==void 0){warnings.push(`Invalid 'codecall.visibleInListTools': expected boolean`)}for(const key of Object.keys(obj)){if(!KNOWN_CODECALL_FIELDS.has(key)){warnings.push(`Unknown field 'codecall.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidTags(data){if(!Array.isArray(data))return void 0;const validTags=data.filter(item=>typeof item==="string");return validTags.length>0?validTags:void 0}function extractValidExamples(data,warnings){if(!Array.isArray(data))return void 0;const validExamples=[];for(let i=0;i<data.length;i++){const item=data[i];const result=FrontMcpExampleSchema.safeParse(item);if(result.success){validExamples.push(result.data)}else{warnings.push(`Invalid example at index ${i}: ${formatZodIssues(result.error.issues,`examples[${i}]`).join(", ")}`)}}return validExamples.length>0?validExamples:void 0}function formatZodIssues(issues,prefix){return issues.map(issue=>{const path=issue.path.length>0?`${prefix}.${issue.path.join(".")}`:prefix;return`Invalid '${path}': ${issue.message}`})}var import_sdk3=require("@frontmcp/sdk");var import_utils2=require("@frontmcp/utils");function coerceToString(value,paramName,location){if(value===null||value===void 0){return""}if(typeof value==="object"){if(Array.isArray(value)){throw new Error(`${location} parameter '${paramName}' cannot be an array. Received: ${JSON.stringify(value)}`)}throw new Error(`${location} parameter '${paramName}' cannot be an object. Received: ${JSON.stringify(value)}`)}return String(value)}var QUERY_DELIMITERS={form:",",spaceDelimited:" ",pipeDelimited:"|"};function serializeQueryParameter(mapper,value){const style=mapper.style??"form";const explode=mapper.explode??style==="form";const name=mapper.key;const delimiter=QUERY_DELIMITERS[style]??",";if(Array.isArray(value)){const items=value.map(item=>coerceToString(item,name,"query"));return explode?items.map(item=>[name,item]):[[name,items.join(delimiter)]]}if(typeof value==="object"&&value!==null){const properties=Object.entries(value).filter(([,propertyValue])=>propertyValue!==void 0).map(([property,propertyValue])=>[property,coerceToString(propertyValue,name,"query")]);if(style==="deepObject"){return properties.map(([property,propertyValue])=>[`${name}[${property}]`,propertyValue])}return explode?properties:[[name,properties.flat().join(delimiter)]]}return[[name,coerceToString(value,name,"query")]]}function appendCookie(headers,name,value){if(!/^[\w!#$%&'*+\-.^`|~]+$/.test(name)){throw new Error(`Invalid cookie name: '${name}'. Cookie names must be valid tokens.`)}const existing=headers.get("Cookie")||"";const cookiePair=`${name}=${encodeURIComponent(coerceToString(value,name,"cookie"))}`;const combined=existing?`${existing}; ${cookiePair}`:cookiePair;headers.set("Cookie",combined)}var DOT_SEGMENTS=new Set([".",".."]);function assertPathStaysOnOperation(tool2,apiBaseUrl,resolvedPath,url){const templatePath=tool2.metadata.path;const templateSegments=templatePath.split("/");const addsDotSegment=resolvedPath.split("/").some((segment,index)=>DOT_SEGMENTS.has(segment)&&segment!==templateSegments[index]);const literalPrefix=templatePath.split("{")[0]??"";const expectedPathPrefix=new URL(`${apiBaseUrl}${literalPrefix}`).pathname;if(addsDotSegment||!new URL(url).pathname.startsWith(expectedPathPrefix)){throw new import_sdk3.PublicMcpError(`The path parameters of operation '${tool2.name}' do not resolve to its path`,"INVALID_PATH_PARAMETER",400)}}function specDefault(tool2,inputKey){const property=tool2.inputSchema.properties?.[inputKey];return typeof property==="object"?property.default:void 0}function buildRequest(tool2,input,security,baseUrl){const rawBaseUrl=tool2.metadata.servers?.[0]?.url||baseUrl;(0,import_utils2.validateBaseUrl)(rawBaseUrl);const apiBaseUrl=(0,import_utils2.trimTrailing)(rawBaseUrl,"/");let path=tool2.metadata.path;const queryParams=new URLSearchParams;const headers=new Headers({accept:"application/json",...security.headers});let body;for(const mapper of tool2.mapper){if(mapper.security)continue;const value=input[mapper.inputKey]??(mapper.required?specDefault(tool2,mapper.inputKey):void 0);if(value===void 0||value===null){if(mapper.required){throw new Error(`Required ${mapper.type} parameter '${mapper.key}' (input: '${mapper.inputKey}') is missing for operation '${tool2.name}'`)}continue}switch(mapper.type){case"path":{const pathValue=coerceToString(value,mapper.key,"path");if(DOT_SEGMENTS.has(pathValue)){throw new import_sdk3.PublicMcpError(`Path parameter '${mapper.key}' of operation '${tool2.name}' cannot be '.' or '..'`,"INVALID_PATH_PARAMETER",400)}path=path.replaceAll(`{${mapper.key}}`,encodeURIComponent(pathValue));break}case"query":for(const[queryName,queryValue]of serializeQueryParameter(mapper,value)){queryParams.append(queryName,queryValue)}break;case"header":{const headerValue=coerceToString(value,mapper.key,"header");if(/[\r\n\x00\f\v]/.test(headerValue)){throw new import_sdk3.PublicMcpError(`Invalid header value for '${mapper.key}': contains control characters (possible header injection attack)`,"INVALID_HEADER_VALUE",400)}headers.set(mapper.key,headerValue);break}case"cookie":appendCookie(headers,mapper.key,value);break;case"body":if(!body)body={};body[mapper.key]=value;break;default:throw new Error(`Unknown mapper type '${mapper.type}' for parameter '${mapper.key}' in operation '${tool2.name}'`)}}Object.entries(security.query).forEach(([key,value])=>{if(queryParams.has(key)){throw new Error(`Query parameter collision: '${key}' is provided both as user input and security parameter. This could indicate a security misconfiguration in operation '${tool2.name}'.`)}queryParams.set(key,coerceToString(value,key,"security query"))});if(security.cookies&&Object.keys(security.cookies).length>0){Object.entries(security.cookies).forEach(([key,value])=>{appendCookie(headers,key,value)})}if(path.includes("{")){throw new Error(`Failed to resolve all path parameters in ${path} for operation ${tool2.name}`)}const queryString=queryParams.toString();const url=`${apiBaseUrl}${path}${queryString?`?${queryString}`:""}`;assertPathStaysOnOperation(tool2,apiBaseUrl,path,url);return{url,headers,body}}function applyAdditionalHeaders(headers,additionalHeaders){if(!additionalHeaders)return;Object.entries(additionalHeaders).forEach(([key,value])=>{headers.set(key,value)})}var DEFAULT_MAX_RESPONSE_SIZE=10*1024*1024;async function parseResponse(response,options){const maxSize=options?.maxResponseSize??DEFAULT_MAX_RESPONSE_SIZE;const contentLength=response.headers.get("content-length");if(contentLength){const length=parseInt(contentLength,10);if(!isNaN(length)&&isFinite(length)&&length>maxSize){throw new Error(`Response size (${length} bytes) exceeds maximum allowed (${maxSize} bytes)`)}}const text=await response.text();const byteSize=new TextEncoder().encode(text).length;if(byteSize>maxSize){throw new Error(`Response size (${byteSize} bytes) exceeds maximum allowed (${maxSize} bytes)`)}const contentType=response.headers.get("content-type");let data;if(contentType?.toLowerCase().includes("application/json")){try{data=JSON.parse(text)}catch{data=text}}else{data=text}if(!response.ok){return{status:response.status,ok:false,data,error:typeof data==="object"&&data!==null&&"message"in data?String(data.message):typeof data==="string"?data:`HTTP ${response.status} error`}}return{status:response.status,ok:true,data}}function createOpenApiTool(openapiTool,options,logger){const metadata=openapiTool.metadata;const inputTransforms=metadata.adapter?.inputTransforms??[];const toolTransform=metadata.adapter?.toolTransform??{};const postToolTransform=metadata.adapter?.postToolTransform;const serverFilledKeys=new Set(inputTransforms.map(transform=>transform.inputKey));const frontmcpValidation=validateFrontMcpExtension(metadata.frontmcp,openapiTool.name,logger);const frontmcpExt=frontmcpValidation.data;const schemaResult=getZodSchemaFromJsonSchema(openapiTool.inputSchema,openapiTool.name,logger);const argumentCheck=schemaResult.conversionFailed?void 0:getZodSchemaFromJsonSchema(toArgumentJsonSchema(openapiTool),openapiTool.name,logger);let wrappedOutputSchema;if(openapiTool.outputSchema!==void 0){const baseOutputSchema=openapiTool.outputSchema??{type:"string"};wrappedOutputSchema={type:"object",properties:{status:{type:"number",description:"HTTP status code"},ok:{type:"boolean",description:"Whether the response was successful"},data:baseOutputSchema,error:{type:"string",description:"Error message for non-ok responses"}},required:["status","ok"]}}const toolMetadata={id:openapiTool.name,name:openapiTool.name,...openapiTool.title&&{title:openapiTool.title},description:openapiTool.description,inputSchema:schemaResult.schema.shape||{},rawInputSchema:openapiTool.inputSchema,...wrappedOutputSchema&&{rawOutputSchema:wrappedOutputSchema},...openapiTool.annotations&&{annotations:{...openapiTool.annotations}},...openapiTool.icons?.length&&{icons:openapiTool.icons.map(icon=>({...icon}))},...openapiTool._meta&&{_meta:{...openapiTool._meta}}};if(schemaResult.conversionFailed){toolMetadata["_schemaConversionFailed"]=true;toolMetadata["_schemaConversionError"]=schemaResult.error}if(frontmcpExt){if(frontmcpExt.annotations){toolMetadata["annotations"]={...toolMetadata["annotations"]||{},...frontmcpExt.annotations}}if(frontmcpExt.tags){toolMetadata["tags"]=[...frontmcpExt.tags]}if(frontmcpExt.hideFromDiscovery!==void 0){toolMetadata["hideFromDiscovery"]=frontmcpExt.hideFromDiscovery}if(frontmcpExt.examples){toolMetadata["examples"]=[...frontmcpExt.examples]}if(frontmcpExt.cache){toolMetadata["cache"]={...frontmcpExt.cache}}if(frontmcpExt.codecall){toolMetadata["codecall"]={...frontmcpExt.codecall}}}if(toolTransform.annotations){toolMetadata["annotations"]={...toolMetadata["annotations"]||{},...toolTransform.annotations}}if(toolTransform.tags){const existingTags=toolMetadata["tags"]||[];toolMetadata["tags"]=[...existingTags,...toolTransform.tags]}if(toolTransform.hideFromDiscovery!==void 0){toolMetadata["hideFromDiscovery"]=toolTransform.hideFromDiscovery}if(toolTransform.examples){const existingExamples=toolMetadata["examples"]||[];toolMetadata["examples"]=[...existingExamples,...toolTransform.examples]}if(toolTransform.ui){toolMetadata["ui"]=toolTransform.ui}return(0,import_sdk4.tool)(toolMetadata)(async(input,toolCtx)=>{const ctx=toolCtx.context;const modelInput=omitKeys(input,serverFilledKeys);if(argumentCheck&&!argumentCheck.conversionFailed){const validation=argumentCheck.schema.safeParse(modelInput);if(!validation.success){const problems=validation.error.issues.map(issue=>`${issue.path.join(".")||"input"}: ${issue.message}`);throw new import_sdk4.InvalidInputError(`Invalid arguments for tool '${openapiTool.name}': ${problems.join("; ")}`)}}const transformContext={ctx,env:process.env,tool:openapiTool};const injectedInput=await injectTransformedValues(modelInput,inputTransforms,transformContext);const security=await resolveToolSecurity(openapiTool,ctx,options,{input:injectedInput,deferCredentialCheck:true});const{url,headers,body:requestBody}=buildRequest(openapiTool,injectedInput,security,options.baseUrl);applyAdditionalHeaders(headers,options.additionalHeaders);if(options.headersMapper){try{const mappedHeaders=options.headersMapper(ctx,headers);if(mappedHeaders&&typeof mappedHeaders.forEach==="function"){mappedHeaders.forEach((value,key)=>{headers.set(key,value)})}}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`headersMapper failed for tool '${openapiTool.name}': ${errorMessage}`,{cause:err})}}assertRequestHasCredential(openapiTool,url,headers);let finalBody=requestBody;if(options.bodyMapper&&requestBody){try{finalBody=options.bodyMapper(ctx,requestBody)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`bodyMapper failed for tool '${openapiTool.name}': ${errorMessage}`,{cause:err})}}if(finalBody&&!headers.has("content-type")){headers.set("content-type","application/json")}let serializedBody;if(finalBody){try{serializedBody=JSON.stringify(finalBody)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`Failed to serialize request body for tool '${openapiTool.name}': ${errorMessage}. Body may contain circular references, BigInt, or non-serializable values.`,{cause:err})}const maxRequestSize=options.maxRequestSize??DEFAULT_MAX_REQUEST_SIZE;if(serializedBody.length>maxRequestSize){throw new Error(`Request body size (${serializedBody.length} bytes) exceeds maximum allowed (${maxRequestSize} bytes)`)}}const requestTimeout=options.requestTimeoutMs??DEFAULT_REQUEST_TIMEOUT_MS;const controller=new AbortController;const timeoutId=setTimeout(()=>controller.abort(),requestTimeout);try{const response=await fetch(url,{method:openapiTool.metadata.method.toUpperCase(),headers,body:serializedBody,signal:controller.signal,redirect:"manual"});if((0,import_utils3.isRedirectResponse)(response)){logger.warn(`[${openapiTool.name}] upstream returned a redirect; not followed`,{status:response.status});return{content:[{type:"text",text:JSON.stringify({status:response.status,error:`Upstream returned a redirect (${response.status}); not followed to protect injected credentials.`})}],isError:true,_meta:{status:response.status,errorCode:"OPENAPI_REDIRECT_NOT_FOLLOWED"}}}const apiResponse=await parseResponse(response,{maxResponseSize:options.maxResponseSize});let transformedData=apiResponse.data;if(postToolTransform){const transformCtx={ctx,tool:openapiTool,status:apiResponse.status,ok:apiResponse.ok,adapterOptions:options};const shouldTransform=postToolTransform.filter?postToolTransform.filter(transformCtx):true;if(shouldTransform){try{transformedData=await postToolTransform.transform(apiResponse.data,transformCtx)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);const errorStack=err instanceof Error?err.stack:void 0;logger.error(`[${openapiTool.name}] Post-tool output transform failed`,{error:errorMessage,stack:errorStack,status:apiResponse.status,ok:apiResponse.ok})}}}if(!apiResponse.ok){return{content:[{type:"text",text:JSON.stringify({status:apiResponse.status,error:apiResponse.error,data:transformedData})}],isError:true,_meta:{status:apiResponse.status,errorCode:"OPENAPI_ERROR"}}}return{status:apiResponse.status,ok:true,data:transformedData}}catch(err){if(err instanceof Error&&err.name==="AbortError"){const timeoutError=new Error(`Request timeout after ${requestTimeout}ms for tool '${openapiTool.name}'`);logger.error(`[${openapiTool.name}] API request timeout`,{timeout:requestTimeout,url,method:openapiTool.metadata.method.toUpperCase()});throw timeoutError}logger.error(`[${openapiTool.name}] API request failed`,{url,method:openapiTool.metadata.method.toUpperCase(),error:err instanceof Error?{name:err.name,message:err.message,stack:err.stack}:err});throw err}finally{clearTimeout(timeoutId)}})}var DEFAULT_TRANSFORM_TIMEOUT_MS=5e3;var DEFAULT_REQUEST_TIMEOUT_MS=3e4;var DEFAULT_MAX_REQUEST_SIZE=10*1024*1024;var RESERVED_KEYS=["__proto__","constructor","prototype"];async function safeInject(transform,ctx,timeoutMs=DEFAULT_TRANSFORM_TIMEOUT_MS){let timeoutId;try{const result=await Promise.race([Promise.resolve(transform.inject(ctx)),new Promise((_,reject)=>{timeoutId=setTimeout(()=>reject(new Error(`Transform timeout after ${timeoutMs}ms`)),timeoutMs)})]);return result}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`Input transform for '${transform.inputKey}' failed: ${errorMessage}`,{cause:err})}finally{if(timeoutId!==void 0){clearTimeout(timeoutId)}}}function isPlainObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function omitKeys(input,keys){if(keys.size===0||!isPlainObject(input))return input;return Object.fromEntries(Object.entries(input).filter(([key])=>!keys.has(key)))}async function injectTransformedValues(input,transforms,ctx){if(!isPlainObject(input)){throw new Error(`Invalid input type: expected object, got ${input===null?"null":typeof input}`)}if(transforms.length===0)return input;const result={...input};for(const transform of transforms){if(RESERVED_KEYS.includes(transform.inputKey)){throw new Error(`Invalid inputKey '${transform.inputKey}': reserved keys (${RESERVED_KEYS.join(", ")}) cannot be used`)}const value=await safeInject(transform,ctx);if(value!==void 0){result[transform.inputKey]=value}}return result}var SUBSCHEMA_KEYWORDS=["items","additionalProperties","not","if","then","else","contains","propertyNames","unevaluatedItems","unevaluatedProperties"];var SUBSCHEMA_LIST_KEYWORDS=["allOf","anyOf","prefixItems"];var SUBSCHEMA_MAP_KEYWORDS=["properties","patternProperties","dependentSchemas","$defs","definitions"];function toArgumentJsonSchema(openapiTool){const argumentSchema=relaxSchema(openapiTool.inputSchema);const credentialKeys=new Set(openapiTool.mapper.filter(mapper=>mapper.security).map(mapper=>mapper.inputKey));const required=argumentSchema["required"];if(Array.isArray(required)){argumentSchema["required"]=required.filter(key=>!credentialKeys.has(key))}return argumentSchema}function relaxSchema(schema){if(Array.isArray(schema))return schema.map(relaxSchema);if(typeof schema!=="object"||schema===null)return schema;const relaxed={...schema};delete relaxed["format"];for(const keyword of SUBSCHEMA_KEYWORDS){if(keyword in relaxed)relaxed[keyword]=relaxSchema(relaxed[keyword])}for(const keyword of SUBSCHEMA_LIST_KEYWORDS){const subschemas=relaxed[keyword];if(Array.isArray(subschemas))relaxed[keyword]=subschemas.map(relaxSchema)}for(const keyword of SUBSCHEMA_MAP_KEYWORDS){const subschemasByName=relaxed[keyword];if(typeof subschemasByName==="object"&&subschemasByName!==null){relaxed[keyword]=Object.fromEntries(Object.entries(subschemasByName).map(([name,subschema])=>[name,relaxSchema(subschema)]))}}const exclusiveBranches=relaxed["oneOf"];if(Array.isArray(exclusiveBranches)){delete relaxed["oneOf"];const branches=exclusiveBranches.map(relaxSchema);if(Array.isArray(relaxed["anyOf"])){const allOf=Array.isArray(relaxed["allOf"])?relaxed["allOf"]:[];relaxed["allOf"]=[...allOf,{anyOf:branches}]}else{relaxed["anyOf"]=branches}}return relaxed}function getZodSchemaFromJsonSchema(jsonSchema,toolName,logger){if(typeof jsonSchema!=="object"||jsonSchema===null){logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);return{schema:import_lazy_zod2.z.looseObject({}),conversionFailed:true,error:"No valid JSON schema"}}try{const zodSchema=import_lazy_zod2.z.fromJSONSchema(jsonSchema,{defaultTarget:"draft-2020-12"});if(typeof zodSchema?.parse!=="function"){throw new Error("Conversion did not produce a valid Zod schema.")}return{schema:zodSchema,conversionFailed:false}}catch(err){const errorMessage=err instanceof Error?err.message:String(err);logger.warn(`[${toolName}] Failed to generate Zod schema, using permissive schema. Tool will accept any input but may fail at API level. Error: ${errorMessage}`);return{schema:import_lazy_zod2.z.looseObject({}),conversionFailed:true,error:errorMessage}}}var RESERVED_KEYS2=["__proto__","constructor","prototype"];var HTTP_METHODS=["get","post","put","patch","delete","head","options","trace"];function normalizeMethods(adapterName,optionName,methods){return methods?.map(method=>{const lowerMethod=method.toLowerCase();if(!HTTP_METHODS.includes(lowerMethod)){throw new Error(`[OpenAPI Adapter: ${adapterName}] generateOptions.${optionName} lists "${method}", which is not an HTTP method; use one of ${HTTP_METHODS.join(", ")}.`)}return lowerMethod})}function createConsoleLogger(prefix){const formatMessage=(level,msg)=>`[${prefix}] ${level}: ${msg}`;return{verbose:(msg,...args)=>console.debug(formatMessage("VERBOSE",msg),...args),debug:(msg,...args)=>console.debug(formatMessage("DEBUG",msg),...args),info:(msg,...args)=>console.info(formatMessage("INFO",msg),...args),warn:(msg,...args)=>console.warn(formatMessage("WARN",msg),...args),error:(msg,...args)=>console.error(formatMessage("ERROR",msg),...args),child:childPrefix=>createConsoleLogger(`${prefix}:${childPrefix}`)}}var OpenapiAdapter=class extends import_sdk5.DynamicAdapter{generator;logger;options;poller=null;updateCallbacks=new Set;rebuildChain=Promise.resolve();methodFilters;constructor(options){super();this.options=options;this.methodFilters={includeMethods:normalizeMethods(options.name,"includeMethods",options.generateOptions?.includeMethods),excludeMethods:normalizeMethods(options.name,"excludeMethods",options.generateOptions?.excludeMethods)};this.logger=options.logger??createConsoleLogger(`openapi:${options.name}`);if(options.polling?.enabled&&!("url"in options)){throw new Error(`[OpenAPI Adapter: ${options.name}] Polling requires URL-based options (use 'url' instead of 'spec').`)}}setLogger(logger){this.logger=logger}async fetch(){if(!this.generator){this.generator=await this.initializeGenerator()}const inputSchemes=inputSecuritySchemes(this.options);const hasPerSchemeControl=inputSchemes!=="all"&&inputSchemes.size>0;const includeSecurityInInput=inputSchemes==="all"||hasPerSchemeControl;const generateOptions=this.options.generateOptions;let openapiTools=await this.generator.generateTools({...generateOptions,...this.methodFilters,filterFn:this.operationFilter(),preferredStatusCodes:generateOptions?.preferredStatusCodes??[200,201,202,204],includeDeprecated:generateOptions?.includeDeprecated??false,includeAllResponses:generateOptions?.includeAllResponses??true,includeSecurityInInput});openapiTools=openapiTools.map(tool2=>({...tool2,outputSchema:outputSchemaOf(tool2)}));if(hasPerSchemeControl){openapiTools=openapiTools.map(tool2=>this.filterSecuritySchemes(tool2,inputSchemes))}const validation=validateSecurityConfiguration(openapiTools,this.options);this.logger.info("Security Analysis:");this.logger.info(` Security Risk Score: ${validation.securityRiskScore.toUpperCase()}`);this.logger.info(` Valid Configuration: ${validation.valid?"YES":"NO"}`);if(validation.warnings.length>0){this.logger.info("Messages:");validation.warnings.forEach(warning=>{if(warning.startsWith("ERROR:")){this.logger.error(` - ${warning}`)}else if(warning.startsWith("SECURITY WARNING:")){this.logger.warn(` - ${warning}`)}else{this.logger.info(` - ${warning}`)}})}if(!validation.valid){throw new Error(formatMissingSecurityMappingsError(this.options.name,openapiTools,validation.missingMappings))}let transformedTools=openapiTools;if(this.options.descriptionMode&&this.options.descriptionMode!=="summaryOnly"){transformedTools=transformedTools.map(tool2=>this.applyDescriptionMode(tool2))}if(this.options.toolTransforms){transformedTools=transformedTools.map(tool2=>this.applyToolTransforms(tool2))}const nameMap=new Map;for(const tool2 of transformedTools){const meta=tool2.metadata;const source=`${meta["method"]?.toUpperCase()??"?"} ${meta["path"]??"?"}`;const existing=nameMap.get(tool2.name);if(existing){existing.push(source)}else{nameMap.set(tool2.name,[source])}}for(const[name,sources]of nameMap){if(sources.length>1){throw new Error(`Tool name collision: "${name}" produced by ${sources.length} operations: ${sources.join(", ")}. Rename conflicting operations in your OpenAPI spec or use toolTransforms.perTool to assign unique names.`)}}if(this.options.inputTransforms){transformedTools=transformedTools.map(tool2=>this.applyInputTransforms(tool2))}if(this.options.schemaTransforms){transformedTools=transformedTools.map(tool2=>this.applySchemaTransforms(tool2))}const dataTransforms=this.options.dataTransforms;if(this.options.outputSchema||dataTransforms){transformedTools=await Promise.all(transformedTools.map(tool2=>this.applyOutputSchemaOptions(tool2,dataTransforms)))}const tools=transformedTools.map(openapiTool=>createOpenApiTool(openapiTool,this.options,this.logger));return{tools}}resolveRefResolution(){return this.options.loadOptions?.refResolution??{allowedProtocols:[]}}operationFilter(){const{includeOperations,filterFn}=this.options.generateOptions??{};if(!includeOperations)return filterFn;return operation=>operation.operationId!==void 0&&includeOperations.includes(operation.operationId)&&(filterFn?.(operation)??true)}async initializeGenerator(){const loadOptions={...this.options.loadOptions,baseUrl:this.options.baseUrl,validate:this.options.loadOptions?.validate??true,dereference:this.options.loadOptions?.dereference??true,followRedirects:this.options.loadOptions?.followRedirects??false,refResolution:this.resolveRefResolution()};if("url"in this.options){return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromURL(this.options.url,loadOptions)}else if("spec"in this.options){return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromJSON(this.options.spec,loadOptions)}else{throw new Error("Either url or spec must be provided in OpenApiAdapterOptions")}}applyDescriptionMode(tool2){const mode=this.options.descriptionMode||"summaryOnly";const metadata=tool2.metadata;const summary=metadata["operationSummary"];const opDescription=metadata["operationDescription"];const operationId=metadata["operationId"];const method=metadata["method"];const path=metadata["path"];let description;switch(mode){case"descriptionOnly":description=opDescription||summary||`${method.toUpperCase()} ${path}`;break;case"combined":if(summary&&opDescription){description=`${summary}
4
+ `+solutions.join("\n"))}function requiredSecurityOf(tool2){return tool2.mapper.flatMap(mapper=>mapper.security&&mapper.required===true?[mapper.security]:[])}function authorizationSchemeOf(security){if(security?.type==="http")return(security.httpScheme??"bearer").toLowerCase();if(security?.type==="oauth2"||security?.type==="openIdConnect")return"bearer";return void 0}function carriesSchemeParameter(mapper,url,headers){if(mapper.type==="query")return!!url.searchParams.get(mapper.key);if(mapper.type==="cookie"){return(headers.get("cookie")??"").split(";").some(pair=>{const[name,...value2]=pair.trim().split("=");return name===mapper.key&&value2.join("=")!==""})}if(mapper.type!=="header")return false;const value=headers.get(mapper.key)?.trim();if(!value)return false;const scheme=authorizationSchemeOf(mapper.security);if(!scheme)return true;const space=value.indexOf(" ");return space>0&&value.slice(0,space).toLowerCase()===scheme&&value.slice(space+1).trim()!==""}function assertRequestHasCredential(tool2,url,headers){const securityMappers=tool2.mapper.filter(mapper=>mapper.security&&mapper.required===true);if(securityMappers.length===0)return;const parsedUrl=new URL(url);if(!securityMappers.some(mapper=>carriesSchemeParameter(mapper,parsedUrl,headers))){throw authenticationRequiredError(tool2)}}function validateSecurityConfiguration(tools,options){const result=validateCredentialSources(tools,options);const schemesInInput=inputSecuritySchemes(options);if(schemesInInput!=="all"&&schemesInInput.size>0){const include=options.generateOptions?.includeSecurityInInput;const sources=[(options.securitySchemesInInput?.length??0)>0?"securitySchemesInInput":void 0,Array.isArray(include)&&include.length>0?"an includeSecurityInInput list":void 0].filter(source=>source!==void 0);result.securityRiskScore="high";result.warnings.push(`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.`)}return result}function validateCredentialSources(tools,options){const result={valid:true,missingMappings:[],warnings:[],securityRiskScore:"low"};const securitySchemes=describeSecuritySchemes(tools);const inputSchemes=inputSecuritySchemes(options);if(inputSchemes==="all"){result.securityRiskScore="high";result.warnings.push("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.");return result}if(options.securityResolver){result.securityRiskScore="low";result.warnings.push("INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context.");return result}if(hasStaticAuth(options)){result.securityRiskScore="medium";result.warnings.push("SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager).");return withPassthroughRisk(result,securitySchemes,options)}const schemesInInput=inputSchemes;if(options.authProviderMapper||schemesInInput.size>0){result.securityRiskScore="low";const passthroughFallback=[];const perRequestHeaders=[];const schemeParameters=schemeParametersOf(tools);for(const[scheme,security]of securitySchemes){if(schemesInInput.has(scheme)){continue}if(!options.authProviderMapper?.[scheme]){const headerSource=headerCredentialSource(schemeParameters.get(scheme),options);if(headerSource==="static"){continue}else if(headerSource==="per-request"){perRequestHeaders.push(scheme)}else if(options.passthroughCallerToken===true&&isBearerScheme(security)){passthroughFallback.push(scheme)}else{result.valid=false;result.missingMappings.push(scheme)}}}if(!result.valid){result.warnings.push(`ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(", ")}`)}if(perRequestHeaders.length>0){result.warnings.push(`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.`)}withPassthroughRisk(result,securitySchemes,options);if(passthroughFallback.length>0){result.warnings.push(`SECURITY WARNING: Security schemes with no authProviderMapper entry (${passthroughFallback.join(", ")}) get the MCP client's own token, because passthroughCallerToken is enabled.`)}return result}if(securitySchemes.size>0&&options.passthroughCallerToken!==true){const schemesStr=Array.from(securitySchemes.keys()).join(", ");result.securityRiskScore="medium";result.warnings.push(`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.`)}const unfilled=[...securitySchemes].filter(([,security])=>!isBearerScheme(security)).map(([scheme])=>scheme);if(options.passthroughCallerToken===true&&unfilled.length>0){result.securityRiskScore="medium";result.warnings.push(`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.`)}return withPassthroughRisk(result,securitySchemes,options)}function canPassThroughCallerToken(options){return options.passthroughCallerToken===true&&!options.securityResolver&&!hasStaticAuth(options)}function withPassthroughRisk(result,securitySchemes,options){const bearerSchemes=[...securitySchemes].filter(([,security])=>isBearerScheme(security));if(bearerSchemes.length===0||!canPassThroughCallerToken(options)){return result}const schemesStr=bearerSchemes.map(([scheme])=>scheme).join(", ");const when=options.authProviderMapper?" whenever no authProviderMapper function returns a credential":"";result.securityRiskScore="high";result.warnings.push(`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.`);return result}async function resolveToolSecurity(tool2,ctx,options,request={}){const securityResolver=new import_mcp_from_openapi2.SecurityResolver;const securityContext=await createSecurityContextFromAuth(tool2,ctx,options);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;const requiresSecurity=tool2.mapper.some(m=>m.security&&m.required===true);const fromInput=request.input?await resolveInputSecurity(tool2,request.input,options,securityResolver):void 0;const hasInputCredential=!!fromInput&&Object.keys(fromInput.headers).length+Object.keys(fromInput.query).length+Object.keys(fromInput.cookies).length>0;if(requiresSecurity&&!hasAuth&&!hasInputCredential&&!request.deferCredentialCheck){throw authenticationRequiredError(tool2)}const resolved=await securityResolver.resolve(tool2.mapper,securityContext);if(!fromInput)return resolved;return{...resolved,headers:{...fromInput.headers,...resolved.headers},query:{...fromInput.query,...resolved.query},cookies:{...fromInput.cookies,...resolved.cookies}}}function inputSecuritySchemes(options){const include=options.generateOptions?.includeSecurityInInput;if(include===true)return"all";return new Set([...Array.isArray(include)?include:[],...options.securitySchemesInInput??[]])}function isInputScheme(scheme,options){const schemes=inputSecuritySchemes(options);return schemes==="all"||schemes.has(scheme)}function inputCredentialContext(security,value){const bare=value.replace(/^(?:bearer|basic)\s+/i,"");if(security.type==="apiKey"){return security.apiKeyName?{apiKeys:{[security.apiKeyName]:value}}:{apiKey:value}}if(security.type==="oauth2"||security.type==="openIdConnect")return{oauth2Token:bare};if(security.type==="http"){const httpScheme=(security.httpScheme??"bearer").toLowerCase();if(httpScheme==="bearer")return{jwt:bare};if(httpScheme==="basic")return{basic:bare}}return void 0}async function resolveInputSecurity(tool2,input,options,securityResolver){const resolved={headers:{},query:{},cookies:{}};for(const mapper of tool2.mapper){const security=mapper.security;if(!security||!isInputScheme(security.scheme,options))continue;const value=input[mapper.inputKey];if(typeof value!=="string"||value==="")continue;if(/[\r\n\x00\f\v]/.test(value)){throw new import_sdk2.PublicMcpError(`Invalid value for '${mapper.inputKey}': contains control characters (possible header injection attack)`,"INVALID_HEADER_VALUE",400)}const context=inputCredentialContext(security,value);if(!context)continue;const one=await securityResolver.resolve([mapper],(0,import_mcp_from_openapi2.createSecurityContext)(context));Object.assign(resolved.headers,one.headers);Object.assign(resolved.query,one.query);Object.assign(resolved.cookies,one.cookies)}return resolved}var import_lazy_zod2=require("@frontmcp/lazy-zod");var import_sdk4=require("@frontmcp/sdk");var import_utils3=require("@frontmcp/utils");var import_lazy_zod=require("@frontmcp/lazy-zod");var FRONTMCP_SCHEMA_VERSION="1.0";var SUPPORTED_VERSIONS=["1.0"];var FrontMcpAnnotationsSchema=import_lazy_zod.z.object({title:import_lazy_zod.z.string().optional(),readOnlyHint:import_lazy_zod.z.boolean().optional(),destructiveHint:import_lazy_zod.z.boolean().optional(),idempotentHint:import_lazy_zod.z.boolean().optional(),openWorldHint:import_lazy_zod.z.boolean().optional()});var FrontMcpCacheSchema=import_lazy_zod.z.object({ttl:import_lazy_zod.z.number().int().positive().optional(),slideWindow:import_lazy_zod.z.boolean().optional()});var FrontMcpCodeCallSchema=import_lazy_zod.z.object({enabledInCodeCall:import_lazy_zod.z.boolean().optional(),visibleInListTools:import_lazy_zod.z.boolean().optional()});var FrontMcpExampleSchema=import_lazy_zod.z.object({description:import_lazy_zod.z.string(),input:import_lazy_zod.z.record(import_lazy_zod.z.string(),import_lazy_zod.z.any()),output:import_lazy_zod.z.any().optional()});var KNOWN_EXTENSION_FIELDS=new Set(["version","annotations","cache","codecall","tags","hideFromDiscovery","examples","meta","icons"]);var KNOWN_ANNOTATION_FIELDS=new Set(["title","readOnlyHint","destructiveHint","idempotentHint","openWorldHint"]);var KNOWN_CACHE_FIELDS=new Set(["ttl","slideWindow"]);var KNOWN_CODECALL_FIELDS=new Set(["enabledInCodeCall","visibleInListTools"]);function validateFrontMcpExtension(rawData,toolName,logger){const warnings=[];if(rawData===null||rawData===void 0){return{success:true,data:null,warnings:[]}}if(typeof rawData!=="object"||Array.isArray(rawData)){warnings.push(`x-frontmcp must be an object, got ${Array.isArray(rawData)?"array":typeof rawData}`);logger.warn(`[${toolName}] Invalid x-frontmcp extension: ${warnings[0]}`);return{success:false,data:null,warnings}}const data=rawData;const version=typeof data["version"]==="string"?data["version"]:FRONTMCP_SCHEMA_VERSION;if(!SUPPORTED_VERSIONS.includes(version)){warnings.push(`Unsupported x-frontmcp version '${version}'. Supported versions: ${SUPPORTED_VERSIONS.join(", ")}`);logger.warn(`[${toolName}] ${warnings[0]}`);return{success:false,data:null,warnings}}const validData=extractValidFields(data,version,warnings);if(warnings.length>0){logger.warn(`[${toolName}] x-frontmcp extension has invalid fields that were ignored:`);warnings.forEach(w=>logger.warn(` - ${w}`))}return{success:true,data:validData,warnings}}function extractValidFields(data,version,warnings){const result={version};for(const key of Object.keys(data)){if(!KNOWN_EXTENSION_FIELDS.has(key)){warnings.push(`Unknown field '${key}' in x-frontmcp (will be ignored)`)}}if(data["annotations"]!==void 0){const annotationsResult=FrontMcpAnnotationsSchema.safeParse(data["annotations"]);if(annotationsResult.success){result.annotations=annotationsResult.data}else{const issues=formatZodIssues(annotationsResult.error.issues,"annotations");warnings.push(...issues);result.annotations=extractValidAnnotations(data["annotations"],warnings)}}if(data["cache"]!==void 0){const cacheResult=FrontMcpCacheSchema.safeParse(data["cache"]);if(cacheResult.success){result.cache=cacheResult.data}else{const issues=formatZodIssues(cacheResult.error.issues,"cache");warnings.push(...issues);result.cache=extractValidCache(data["cache"],warnings)}}if(data["codecall"]!==void 0){const codecallResult=FrontMcpCodeCallSchema.safeParse(data["codecall"]);if(codecallResult.success){result.codecall=codecallResult.data}else{const issues=formatZodIssues(codecallResult.error.issues,"codecall");warnings.push(...issues);result.codecall=extractValidCodeCall(data["codecall"],warnings)}}if(data["tags"]!==void 0){const tagsSchema=import_lazy_zod.z.array(import_lazy_zod.z.string());const tagsResult=tagsSchema.safeParse(data["tags"]);if(tagsResult.success){result.tags=tagsResult.data}else{warnings.push(`Invalid 'tags': expected array of strings`);result.tags=extractValidTags(data["tags"])}}if(data["hideFromDiscovery"]!==void 0){if(typeof data["hideFromDiscovery"]==="boolean"){result.hideFromDiscovery=data["hideFromDiscovery"]}else{warnings.push(`Invalid 'hideFromDiscovery': expected boolean, got ${typeof data["hideFromDiscovery"]}`)}}if(data["examples"]!==void 0){const examplesSchema=import_lazy_zod.z.array(FrontMcpExampleSchema);const examplesResult=examplesSchema.safeParse(data["examples"]);if(examplesResult.success){result.examples=examplesResult.data}else{warnings.push(`Invalid 'examples': some examples have invalid format`);result.examples=extractValidExamples(data["examples"],warnings)}}return result}function extractValidAnnotations(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};for(const field of KNOWN_ANNOTATION_FIELDS){if(obj[field]!==void 0){if(field==="title"&&typeof obj[field]==="string"){result.title=obj[field]}else if(field!=="title"&&typeof obj[field]==="boolean"){result[field]=obj[field]}}}for(const key of Object.keys(obj)){if(!KNOWN_ANNOTATION_FIELDS.has(key)){warnings.push(`Unknown field 'annotations.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidCache(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};if(typeof obj["ttl"]==="number"&&Number.isInteger(obj["ttl"])&&obj["ttl"]>0){result.ttl=obj["ttl"]}else if(obj["ttl"]!==void 0){warnings.push(`Invalid 'cache.ttl': expected positive integer`)}if(typeof obj["slideWindow"]==="boolean"){result.slideWindow=obj["slideWindow"]}else if(obj["slideWindow"]!==void 0){warnings.push(`Invalid 'cache.slideWindow': expected boolean`)}for(const key of Object.keys(obj)){if(!KNOWN_CACHE_FIELDS.has(key)){warnings.push(`Unknown field 'cache.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidCodeCall(data,warnings){if(typeof data!=="object"||data===null)return void 0;const obj=data;const result={};if(typeof obj["enabledInCodeCall"]==="boolean"){result.enabledInCodeCall=obj["enabledInCodeCall"]}else if(obj["enabledInCodeCall"]!==void 0){warnings.push(`Invalid 'codecall.enabledInCodeCall': expected boolean`)}if(typeof obj["visibleInListTools"]==="boolean"){result.visibleInListTools=obj["visibleInListTools"]}else if(obj["visibleInListTools"]!==void 0){warnings.push(`Invalid 'codecall.visibleInListTools': expected boolean`)}for(const key of Object.keys(obj)){if(!KNOWN_CODECALL_FIELDS.has(key)){warnings.push(`Unknown field 'codecall.${key}' (will be ignored)`)}}return Object.keys(result).length>0?result:void 0}function extractValidTags(data){if(!Array.isArray(data))return void 0;const validTags=data.filter(item=>typeof item==="string");return validTags.length>0?validTags:void 0}function extractValidExamples(data,warnings){if(!Array.isArray(data))return void 0;const validExamples=[];for(let i=0;i<data.length;i++){const item=data[i];const result=FrontMcpExampleSchema.safeParse(item);if(result.success){validExamples.push(result.data)}else{warnings.push(`Invalid example at index ${i}: ${formatZodIssues(result.error.issues,`examples[${i}]`).join(", ")}`)}}return validExamples.length>0?validExamples:void 0}function formatZodIssues(issues,prefix){return issues.map(issue=>{const path=issue.path.length>0?`${prefix}.${issue.path.join(".")}`:prefix;return`Invalid '${path}': ${issue.message}`})}var import_sdk3=require("@frontmcp/sdk");var import_utils2=require("@frontmcp/utils");function coerceToString(value,paramName,location){if(value===null||value===void 0){return""}if(typeof value==="object"){if(Array.isArray(value)){throw new Error(`${location} parameter '${paramName}' cannot be an array. Received: ${JSON.stringify(value)}`)}throw new Error(`${location} parameter '${paramName}' cannot be an object. Received: ${JSON.stringify(value)}`)}return String(value)}var QUERY_DELIMITERS={form:",",spaceDelimited:" ",pipeDelimited:"|"};function serializeQueryParameter(mapper,value){const style=mapper.style??"form";const explode=mapper.explode??style==="form";const name=mapper.key;const delimiter=QUERY_DELIMITERS[style]??",";if(Array.isArray(value)){const items=value.map(item=>coerceToString(item,name,"query"));return explode?items.map(item=>[name,item]):[[name,items.join(delimiter)]]}if(typeof value==="object"&&value!==null){const properties=Object.entries(value).filter(([,propertyValue])=>propertyValue!==void 0).map(([property,propertyValue])=>[property,coerceToString(propertyValue,name,"query")]);if(style==="deepObject"){return properties.map(([property,propertyValue])=>[`${name}[${property}]`,propertyValue])}return explode?properties:[[name,properties.flat().join(delimiter)]]}return[[name,coerceToString(value,name,"query")]]}function appendCookie(headers,name,value){if(!/^[\w!#$%&'*+\-.^`|~]+$/.test(name)){throw new Error(`Invalid cookie name: '${name}'. Cookie names must be valid tokens.`)}const existing=headers.get("Cookie")||"";const cookiePair=`${name}=${encodeURIComponent(coerceToString(value,name,"cookie"))}`;const combined=existing?`${existing}; ${cookiePair}`:cookiePair;headers.set("Cookie",combined)}var DOT_SEGMENTS=new Set([".",".."]);function assertPathStaysOnOperation(tool2,apiBaseUrl,resolvedPath,url){const templatePath=tool2.metadata.path;const templateSegments=templatePath.split("/");const addsDotSegment=resolvedPath.split("/").some((segment,index)=>DOT_SEGMENTS.has(segment)&&segment!==templateSegments[index]);const literalPrefix=templatePath.split("{")[0]??"";const expectedPathPrefix=new URL(`${apiBaseUrl}${literalPrefix}`).pathname;if(addsDotSegment||!new URL(url).pathname.startsWith(expectedPathPrefix)){throw new import_sdk3.PublicMcpError(`The path parameters of operation '${tool2.name}' do not resolve to its path`,"INVALID_PATH_PARAMETER",400)}}function specDefault(tool2,inputKey){const property=tool2.inputSchema.properties?.[inputKey];return typeof property==="object"?property.default:void 0}function buildRequest(tool2,input,security,baseUrl){const rawBaseUrl=tool2.metadata.servers?.[0]?.url||baseUrl;(0,import_utils2.validateBaseUrl)(rawBaseUrl);const apiBaseUrl=(0,import_utils2.trimTrailing)(rawBaseUrl,"/");let path=tool2.metadata.path;const queryParams=new URLSearchParams;const headers=new Headers({accept:"application/json",...security.headers});let body;for(const mapper of tool2.mapper){if(mapper.security)continue;const value=input[mapper.inputKey]??(mapper.required?specDefault(tool2,mapper.inputKey):void 0);if(value===void 0||value===null){if(mapper.required){throw new Error(`Required ${mapper.type} parameter '${mapper.key}' (input: '${mapper.inputKey}') is missing for operation '${tool2.name}'`)}continue}switch(mapper.type){case"path":{const pathValue=coerceToString(value,mapper.key,"path");if(DOT_SEGMENTS.has(pathValue)){throw new import_sdk3.PublicMcpError(`Path parameter '${mapper.key}' of operation '${tool2.name}' cannot be '.' or '..'`,"INVALID_PATH_PARAMETER",400)}path=path.replaceAll(`{${mapper.key}}`,encodeURIComponent(pathValue));break}case"query":for(const[queryName,queryValue]of serializeQueryParameter(mapper,value)){queryParams.append(queryName,queryValue)}break;case"header":{const headerValue=coerceToString(value,mapper.key,"header");if(/[\r\n\x00\f\v]/.test(headerValue)){throw new import_sdk3.PublicMcpError(`Invalid header value for '${mapper.key}': contains control characters (possible header injection attack)`,"INVALID_HEADER_VALUE",400)}headers.set(mapper.key,headerValue);break}case"cookie":appendCookie(headers,mapper.key,value);break;case"body":if(!body)body={};body[mapper.key]=value;break;default:throw new Error(`Unknown mapper type '${mapper.type}' for parameter '${mapper.key}' in operation '${tool2.name}'`)}}Object.entries(security.query).forEach(([key,value])=>{if(queryParams.has(key)){throw new Error(`Query parameter collision: '${key}' is provided both as user input and security parameter. This could indicate a security misconfiguration in operation '${tool2.name}'.`)}queryParams.set(key,coerceToString(value,key,"security query"))});if(security.cookies&&Object.keys(security.cookies).length>0){Object.entries(security.cookies).forEach(([key,value])=>{appendCookie(headers,key,value)})}if(path.includes("{")){throw new Error(`Failed to resolve all path parameters in ${path} for operation ${tool2.name}`)}const queryString=queryParams.toString();const url=`${apiBaseUrl}${path}${queryString?`?${queryString}`:""}`;assertPathStaysOnOperation(tool2,apiBaseUrl,path,url);return{url,headers,body}}function applyAdditionalHeaders(headers,additionalHeaders){if(!additionalHeaders)return;Object.entries(additionalHeaders).forEach(([key,value])=>{headers.set(key,value)})}var DEFAULT_MAX_RESPONSE_SIZE=10*1024*1024;async function parseResponse(response,options){const maxSize=options?.maxResponseSize??DEFAULT_MAX_RESPONSE_SIZE;const contentLength=response.headers.get("content-length");if(contentLength){const length=parseInt(contentLength,10);if(!isNaN(length)&&isFinite(length)&&length>maxSize){throw new Error(`Response size (${length} bytes) exceeds maximum allowed (${maxSize} bytes)`)}}let text;try{text=await(0,import_utils2.readTextWithLimit)(response,maxSize)}catch(error){if(error instanceof import_utils2.ResponseTooLargeError){throw new Error(`Response size exceeds maximum allowed (${maxSize} bytes)`,{cause:error})}throw error}const contentType=response.headers.get("content-type");let data;if(contentType?.toLowerCase().includes("application/json")){try{data=JSON.parse(text)}catch{data=text}}else{data=text}if(!response.ok){return{status:response.status,ok:false,data,error:typeof data==="object"&&data!==null&&"message"in data?String(data.message):typeof data==="string"?data:`HTTP ${response.status} error`}}return{status:response.status,ok:true,data}}function createOpenApiTool(openapiTool,options,logger){const metadata=openapiTool.metadata;const inputTransforms=metadata.adapter?.inputTransforms??[];const toolTransform=metadata.adapter?.toolTransform??{};const postToolTransform=metadata.adapter?.postToolTransform;const serverFilledKeys=new Set(inputTransforms.map(transform=>transform.inputKey));const frontmcpValidation=validateFrontMcpExtension(metadata.frontmcp,openapiTool.name,logger);const frontmcpExt=frontmcpValidation.data;const schemaResult=getZodSchemaFromJsonSchema(openapiTool.inputSchema,openapiTool.name,logger);const argumentCheck=schemaResult.conversionFailed?void 0:getZodSchemaFromJsonSchema(toArgumentJsonSchema(openapiTool),openapiTool.name,logger);let wrappedOutputSchema;if(openapiTool.outputSchema!==void 0){const baseOutputSchema=openapiTool.outputSchema??{type:"string"};wrappedOutputSchema={type:"object",properties:{status:{type:"number",description:"HTTP status code"},ok:{type:"boolean",description:"Whether the response was successful"},data:baseOutputSchema,error:{type:"string",description:"Error message for non-ok responses"}},required:["status","ok"]}}const toolMetadata={id:openapiTool.name,name:openapiTool.name,...openapiTool.title&&{title:openapiTool.title},description:openapiTool.description,inputSchema:schemaResult.schema.shape||{},rawInputSchema:openapiTool.inputSchema,...wrappedOutputSchema&&{rawOutputSchema:wrappedOutputSchema},...openapiTool.annotations&&{annotations:{...openapiTool.annotations}},...openapiTool.icons?.length&&{icons:openapiTool.icons.map(icon=>({...icon}))},...openapiTool._meta&&{_meta:{...openapiTool._meta}}};if(schemaResult.conversionFailed){toolMetadata["_schemaConversionFailed"]=true;toolMetadata["_schemaConversionError"]=schemaResult.error}if(frontmcpExt){if(frontmcpExt.annotations){toolMetadata["annotations"]={...toolMetadata["annotations"]||{},...frontmcpExt.annotations}}if(frontmcpExt.tags){toolMetadata["tags"]=[...frontmcpExt.tags]}if(frontmcpExt.hideFromDiscovery!==void 0){toolMetadata["hideFromDiscovery"]=frontmcpExt.hideFromDiscovery}if(frontmcpExt.examples){toolMetadata["examples"]=[...frontmcpExt.examples]}if(frontmcpExt.cache){toolMetadata["cache"]={...frontmcpExt.cache}}if(frontmcpExt.codecall){toolMetadata["codecall"]={...frontmcpExt.codecall}}}if(toolTransform.annotations){toolMetadata["annotations"]={...toolMetadata["annotations"]||{},...toolTransform.annotations}}if(toolTransform.tags){const existingTags=toolMetadata["tags"]||[];toolMetadata["tags"]=[...existingTags,...toolTransform.tags]}if(toolTransform.hideFromDiscovery!==void 0){toolMetadata["hideFromDiscovery"]=toolTransform.hideFromDiscovery}if(toolTransform.examples){const existingExamples=toolMetadata["examples"]||[];toolMetadata["examples"]=[...existingExamples,...toolTransform.examples]}if(toolTransform.ui){toolMetadata["ui"]=toolTransform.ui}return(0,import_sdk4.tool)(toolMetadata)(async(input,toolCtx)=>{const ctx=toolCtx.context;const modelInput=omitKeys(input,serverFilledKeys);if(argumentCheck&&!argumentCheck.conversionFailed){const validation=argumentCheck.schema.safeParse(modelInput);if(!validation.success){const problems=validation.error.issues.map(issue=>`${issue.path.join(".")||"input"}: ${issue.message}`);throw new import_sdk4.InvalidInputError(`Invalid arguments for tool '${openapiTool.name}': ${problems.join("; ")}`)}}const transformContext={ctx,env:process.env,tool:openapiTool};const injectedInput=await injectTransformedValues(modelInput,inputTransforms,transformContext);const security=await resolveToolSecurity(openapiTool,ctx,options,{input:injectedInput,deferCredentialCheck:true});const{url,headers,body:requestBody}=buildRequest(openapiTool,injectedInput,security,options.baseUrl);applyAdditionalHeaders(headers,options.additionalHeaders);if(options.headersMapper){try{const mappedHeaders=options.headersMapper(ctx,headers);if(mappedHeaders&&typeof mappedHeaders.forEach==="function"){mappedHeaders.forEach((value,key)=>{headers.set(key,value)})}}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`headersMapper failed for tool '${openapiTool.name}': ${errorMessage}`,{cause:err})}}assertRequestHasCredential(openapiTool,url,headers);let finalBody=requestBody;if(options.bodyMapper&&requestBody){try{finalBody=options.bodyMapper(ctx,requestBody)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`bodyMapper failed for tool '${openapiTool.name}': ${errorMessage}`,{cause:err})}}if(finalBody&&!headers.has("content-type")){headers.set("content-type","application/json")}let serializedBody;if(finalBody){try{serializedBody=JSON.stringify(finalBody)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`Failed to serialize request body for tool '${openapiTool.name}': ${errorMessage}. Body may contain circular references, BigInt, or non-serializable values.`,{cause:err})}const maxRequestSize=options.maxRequestSize??DEFAULT_MAX_REQUEST_SIZE;if(serializedBody.length>maxRequestSize){throw new Error(`Request body size (${serializedBody.length} bytes) exceeds maximum allowed (${maxRequestSize} bytes)`)}}const requestTimeout=options.requestTimeoutMs??DEFAULT_REQUEST_TIMEOUT_MS;const controller=new AbortController;const timeoutId=setTimeout(()=>controller.abort(),requestTimeout);try{const response=await fetch(url,{method:openapiTool.metadata.method.toUpperCase(),headers,body:serializedBody,signal:controller.signal,redirect:"manual"});if((0,import_utils3.isRedirectResponse)(response)){logger.warn(`[${openapiTool.name}] upstream returned a redirect; not followed`,{status:response.status});return{content:[{type:"text",text:JSON.stringify({status:response.status,error:`Upstream returned a redirect (${response.status}); not followed to protect injected credentials.`})}],isError:true,_meta:{status:response.status,errorCode:"OPENAPI_REDIRECT_NOT_FOLLOWED"}}}const apiResponse=await parseResponse(response,{maxResponseSize:options.maxResponseSize});let transformedData=apiResponse.data;if(postToolTransform){const transformCtx={ctx,tool:openapiTool,status:apiResponse.status,ok:apiResponse.ok,adapterOptions:options};const shouldTransform=postToolTransform.filter?postToolTransform.filter(transformCtx):true;if(shouldTransform){try{transformedData=await postToolTransform.transform(apiResponse.data,transformCtx)}catch(err){const errorMessage=err instanceof Error?err.message:String(err);const errorStack=err instanceof Error?err.stack:void 0;logger.error(`[${openapiTool.name}] Post-tool output transform failed`,{error:errorMessage,stack:errorStack,status:apiResponse.status,ok:apiResponse.ok})}}}if(!apiResponse.ok){return{content:[{type:"text",text:JSON.stringify({status:apiResponse.status,error:apiResponse.error,data:transformedData})}],isError:true,_meta:{status:apiResponse.status,errorCode:"OPENAPI_ERROR"}}}return{status:apiResponse.status,ok:true,data:transformedData}}catch(err){if(err instanceof Error&&err.name==="AbortError"){const timeoutError=new Error(`Request timeout after ${requestTimeout}ms for tool '${openapiTool.name}'`);logger.error(`[${openapiTool.name}] API request timeout`,{timeout:requestTimeout,url:urlWithoutQuery(url),method:openapiTool.metadata.method.toUpperCase()});throw timeoutError}logger.error(`[${openapiTool.name}] API request failed`,{url:urlWithoutQuery(url),method:openapiTool.metadata.method.toUpperCase(),error:err instanceof Error?{name:err.name,message:err.message,stack:err.stack}:err});throw err}finally{clearTimeout(timeoutId)}})}function urlWithoutQuery(url){const queryStart=url.indexOf("?");const fragmentStart=url.indexOf("#");const cutPoints=[queryStart,fragmentStart].filter(index=>index!==-1);return cutPoints.length===0?url:url.slice(0,Math.min(...cutPoints))}var DEFAULT_TRANSFORM_TIMEOUT_MS=5e3;var DEFAULT_REQUEST_TIMEOUT_MS=3e4;var DEFAULT_MAX_REQUEST_SIZE=10*1024*1024;var RESERVED_KEYS=["__proto__","constructor","prototype"];async function safeInject(transform,ctx,timeoutMs=DEFAULT_TRANSFORM_TIMEOUT_MS){let timeoutId;try{const result=await Promise.race([Promise.resolve(transform.inject(ctx)),new Promise((_,reject)=>{timeoutId=setTimeout(()=>reject(new Error(`Transform timeout after ${timeoutMs}ms`)),timeoutMs)})]);return result}catch(err){const errorMessage=err instanceof Error?err.message:String(err);throw new Error(`Input transform for '${transform.inputKey}' failed: ${errorMessage}`,{cause:err})}finally{if(timeoutId!==void 0){clearTimeout(timeoutId)}}}function isPlainObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function omitKeys(input,keys){if(keys.size===0||!isPlainObject(input))return input;return Object.fromEntries(Object.entries(input).filter(([key])=>!keys.has(key)))}async function injectTransformedValues(input,transforms,ctx){if(!isPlainObject(input)){throw new Error(`Invalid input type: expected object, got ${input===null?"null":typeof input}`)}if(transforms.length===0)return input;const result={...input};for(const transform of transforms){if(RESERVED_KEYS.includes(transform.inputKey)){throw new Error(`Invalid inputKey '${transform.inputKey}': reserved keys (${RESERVED_KEYS.join(", ")}) cannot be used`)}const value=await safeInject(transform,ctx);if(value!==void 0){result[transform.inputKey]=value}}return result}var SUBSCHEMA_KEYWORDS=["items","additionalProperties","not","if","then","else","contains","propertyNames","unevaluatedItems","unevaluatedProperties"];var SUBSCHEMA_LIST_KEYWORDS=["allOf","anyOf","prefixItems"];var SUBSCHEMA_MAP_KEYWORDS=["properties","patternProperties","dependentSchemas","$defs","definitions"];function toArgumentJsonSchema(openapiTool){const argumentSchema=relaxSchema(openapiTool.inputSchema);const credentialKeys=new Set(openapiTool.mapper.filter(mapper=>mapper.security).map(mapper=>mapper.inputKey));const required=argumentSchema["required"];if(Array.isArray(required)){argumentSchema["required"]=required.filter(key=>!credentialKeys.has(key))}return argumentSchema}function relaxSchema(schema){if(Array.isArray(schema))return schema.map(relaxSchema);if(typeof schema!=="object"||schema===null)return schema;const relaxed={...schema};delete relaxed["format"];if(typeof relaxed["pattern"]==="string"&&!(0,import_utils3.isPatternSafe)(relaxed["pattern"]))delete relaxed["pattern"];const propertyPatterns=relaxed["patternProperties"];if(typeof propertyPatterns==="object"&&propertyPatterns!==null){if(Object.keys(propertyPatterns).some(propertyPattern=>!(0,import_utils3.isPatternSafe)(propertyPattern))){delete relaxed["patternProperties"];delete relaxed["additionalProperties"]}}for(const keyword of SUBSCHEMA_KEYWORDS){if(keyword in relaxed)relaxed[keyword]=relaxSchema(relaxed[keyword])}for(const keyword of SUBSCHEMA_LIST_KEYWORDS){const subschemas=relaxed[keyword];if(Array.isArray(subschemas))relaxed[keyword]=subschemas.map(relaxSchema)}for(const keyword of SUBSCHEMA_MAP_KEYWORDS){const subschemasByName=relaxed[keyword];if(typeof subschemasByName==="object"&&subschemasByName!==null){relaxed[keyword]=Object.fromEntries(Object.entries(subschemasByName).map(([name,subschema])=>[name,relaxSchema(subschema)]))}}const exclusiveBranches=relaxed["oneOf"];if(Array.isArray(exclusiveBranches)){delete relaxed["oneOf"];const branches=exclusiveBranches.map(relaxSchema);if(Array.isArray(relaxed["anyOf"])){const allOf=Array.isArray(relaxed["allOf"])?relaxed["allOf"]:[];relaxed["allOf"]=[...allOf,{anyOf:branches}]}else{relaxed["anyOf"]=branches}}return relaxed}function getZodSchemaFromJsonSchema(jsonSchema,toolName,logger){if(typeof jsonSchema!=="object"||jsonSchema===null){logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);return{schema:import_lazy_zod2.z.looseObject({}),conversionFailed:true,error:"No valid JSON schema"}}try{const zodSchema=import_lazy_zod2.z.fromJSONSchema(jsonSchema,{defaultTarget:"draft-2020-12"});if(typeof zodSchema?.parse!=="function"){throw new Error("Conversion did not produce a valid Zod schema.")}return{schema:zodSchema,conversionFailed:false}}catch(err){const errorMessage=err instanceof Error?err.message:String(err);logger.warn(`[${toolName}] Failed to generate Zod schema, using permissive schema. Tool will accept any input but may fail at API level. Error: ${errorMessage}`);return{schema:import_lazy_zod2.z.looseObject({}),conversionFailed:true,error:errorMessage}}}var RESERVED_KEYS2=["__proto__","constructor","prototype"];var HTTP_METHODS=["get","post","put","patch","delete","head","options","trace"];function normalizeMethods(adapterName,optionName,methods){return methods?.map(method=>{const lowerMethod=method.toLowerCase();if(!HTTP_METHODS.includes(lowerMethod)){throw new Error(`[OpenAPI Adapter: ${adapterName}] generateOptions.${optionName} lists "${method}", which is not an HTTP method; use one of ${HTTP_METHODS.join(", ")}.`)}return lowerMethod})}function createConsoleLogger(prefix){const formatMessage=(level,msg)=>`[${prefix}] ${level}: ${msg}`;return{verbose:(msg,...args)=>console.debug(formatMessage("VERBOSE",msg),...args),debug:(msg,...args)=>console.debug(formatMessage("DEBUG",msg),...args),info:(msg,...args)=>console.info(formatMessage("INFO",msg),...args),warn:(msg,...args)=>console.warn(formatMessage("WARN",msg),...args),error:(msg,...args)=>console.error(formatMessage("ERROR",msg),...args),child:childPrefix=>createConsoleLogger(`${prefix}:${childPrefix}`)}}var OpenapiAdapter=class extends import_sdk5.DynamicAdapter{generator;logger;options;poller=null;updateCallbacks=new Set;rebuildChain=Promise.resolve();methodFilters;constructor(options){super();this.options=options;this.methodFilters={includeMethods:normalizeMethods(options.name,"includeMethods",options.generateOptions?.includeMethods),excludeMethods:normalizeMethods(options.name,"excludeMethods",options.generateOptions?.excludeMethods)};this.logger=options.logger??createConsoleLogger(`openapi:${options.name}`);if(options.polling?.enabled&&!("url"in options)){throw new Error(`[OpenAPI Adapter: ${options.name}] Polling requires URL-based options (use 'url' instead of 'spec').`)}}setLogger(logger){this.logger=logger}async fetch(){if(!this.generator){this.generator=await this.initializeGenerator()}const inputSchemes=inputSecuritySchemes(this.options);const hasPerSchemeControl=inputSchemes!=="all"&&inputSchemes.size>0;const includeSecurityInInput=inputSchemes==="all"||hasPerSchemeControl;const generateOptions=this.options.generateOptions;let openapiTools=await this.generator.generateTools({...generateOptions,...this.methodFilters,filterFn:this.operationFilter(),preferredStatusCodes:generateOptions?.preferredStatusCodes??[200,201,202,204],includeDeprecated:generateOptions?.includeDeprecated??false,includeAllResponses:generateOptions?.includeAllResponses??true,includeSecurityInInput});openapiTools=openapiTools.map(tool2=>({...tool2,outputSchema:outputSchemaOf(tool2)}));if(hasPerSchemeControl){openapiTools=openapiTools.map(tool2=>this.filterSecuritySchemes(tool2,inputSchemes))}const validation=validateSecurityConfiguration(openapiTools,this.options);this.logger.info("Security Analysis:");this.logger.info(` Security Risk Score: ${validation.securityRiskScore.toUpperCase()}`);this.logger.info(` Valid Configuration: ${validation.valid?"YES":"NO"}`);if(validation.warnings.length>0){this.logger.info("Messages:");validation.warnings.forEach(warning=>{if(warning.startsWith("ERROR:")){this.logger.error(` - ${warning}`)}else if(warning.startsWith("SECURITY WARNING:")){this.logger.warn(` - ${warning}`)}else{this.logger.info(` - ${warning}`)}})}if(!validation.valid){throw new Error(formatMissingSecurityMappingsError(this.options.name,openapiTools,validation.missingMappings))}let transformedTools=openapiTools;if(this.options.descriptionMode&&this.options.descriptionMode!=="summaryOnly"){transformedTools=transformedTools.map(tool2=>this.applyDescriptionMode(tool2))}if(this.options.toolTransforms){transformedTools=transformedTools.map(tool2=>this.applyToolTransforms(tool2))}const nameMap=new Map;for(const tool2 of transformedTools){const meta=tool2.metadata;const source=`${meta["method"]?.toUpperCase()??"?"} ${meta["path"]??"?"}`;const existing=nameMap.get(tool2.name);if(existing){existing.push(source)}else{nameMap.set(tool2.name,[source])}}for(const[name,sources]of nameMap){if(sources.length>1){throw new Error(`Tool name collision: "${name}" produced by ${sources.length} operations: ${sources.join(", ")}. Rename conflicting operations in your OpenAPI spec or use toolTransforms.perTool to assign unique names.`)}}if(this.options.inputTransforms){transformedTools=transformedTools.map(tool2=>this.applyInputTransforms(tool2))}if(this.options.schemaTransforms){transformedTools=transformedTools.map(tool2=>this.applySchemaTransforms(tool2))}const dataTransforms=this.options.dataTransforms;if(this.options.outputSchema||dataTransforms){transformedTools=await Promise.all(transformedTools.map(tool2=>this.applyOutputSchemaOptions(tool2,dataTransforms)))}const tools=transformedTools.map(openapiTool=>createOpenApiTool(openapiTool,this.options,this.logger));return{tools}}resolveRefResolution(){return this.options.loadOptions?.refResolution??{allowedProtocols:[]}}operationFilter(){const{includeOperations,filterFn}=this.options.generateOptions??{};if(!includeOperations)return filterFn;return operation=>operation.operationId!==void 0&&includeOperations.includes(operation.operationId)&&(filterFn?.(operation)??true)}async initializeGenerator(){const loadOptions={...this.options.loadOptions,baseUrl:this.options.baseUrl,validate:this.options.loadOptions?.validate??true,dereference:this.options.loadOptions?.dereference??true,followRedirects:this.options.loadOptions?.followRedirects??false,refResolution:this.resolveRefResolution()};if("url"in this.options){return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromURL(this.options.url,loadOptions)}else if("spec"in this.options){return await import_mcp_from_openapi3.OpenAPIToolGenerator.fromJSON(this.options.spec,loadOptions)}else{throw new Error("Either url or spec must be provided in OpenApiAdapterOptions")}}applyDescriptionMode(tool2){const mode=this.options.descriptionMode||"summaryOnly";const metadata=tool2.metadata;const summary=metadata["operationSummary"];const opDescription=metadata["operationDescription"];const operationId=metadata["operationId"];const method=metadata["method"];const path=metadata["path"];let description;switch(mode){case"descriptionOnly":description=opDescription||summary||`${method.toUpperCase()} ${path}`;break;case"combined":if(summary&&opDescription){description=`${summary}
5
5
 
6
6
  ${opDescription}`}else{description=summary||opDescription||`${method.toUpperCase()} ${path}`}break;case"full":{const parts=[];if(summary)parts.push(summary);if(opDescription&&opDescription!==summary)parts.push(opDescription);if(operationId)parts.push(`Operation: ${operationId}`);parts.push(`${method.toUpperCase()} ${path}`);description=parts.join("\n\n");break}default:return tool2}return{...tool2,description}}resolvePerTool(perTool,tool2){if(!perTool)return void 0;if(Object.prototype.hasOwnProperty.call(perTool,tool2.name))return perTool[tool2.name];return void 0}collectToolTransforms(tool2){const result={};const opts=this.options.toolTransforms;if(!opts)return result;if(opts.global){Object.assign(result,opts.global);if(opts.global.annotations){result.annotations={...opts.global.annotations}}if(opts.global.tags){result.tags=[...opts.global.tags]}if(opts.global.examples){result.examples=[...opts.global.examples]}}const perToolMatch=this.resolvePerTool(opts.perTool,tool2);if(perToolMatch){const perTool=perToolMatch;if(perTool.name)result.name=perTool.name;if(perTool.description)result.description=perTool.description;if(perTool.hideFromDiscovery!==void 0)result.hideFromDiscovery=perTool.hideFromDiscovery;if(perTool.ui)result.ui=perTool.ui;if(perTool.annotations){result.annotations={...result.annotations,...perTool.annotations}}if(perTool.tags){result.tags=[...result.tags||[],...perTool.tags]}if(perTool.examples){result.examples=[...result.examples||[],...perTool.examples]}}if(opts.generator){const generated=opts.generator(tool2);if(generated){if(generated.name)result.name=generated.name;if(generated.description)result.description=generated.description;if(generated.hideFromDiscovery!==void 0)result.hideFromDiscovery=generated.hideFromDiscovery;if(generated.ui)result.ui=generated.ui;if(generated.annotations){result.annotations={...result.annotations,...generated.annotations}}if(generated.tags){result.tags=[...result.tags||[],...generated.tags]}if(generated.examples){result.examples=[...result.examples||[],...generated.examples]}}}return result}applyToolTransforms(tool2){const transforms=this.collectToolTransforms(tool2);if(Object.keys(transforms).length===0)return tool2;let newName=tool2.name;let newDescription=tool2.description;if(transforms.name){newName=typeof transforms.name==="function"?transforms.name(tool2.name,tool2):transforms.name}if(transforms.description){newDescription=typeof transforms.description==="function"?transforms.description(tool2.description,tool2):transforms.description}this.logger.debug(`Applied tool transforms to '${tool2.name}'`);const metadataRecord=tool2.metadata;const existingAdapter=metadataRecord["adapter"];return{...tool2,name:newName,description:newDescription,metadata:{...tool2.metadata,adapter:{...existingAdapter||{},toolTransform:transforms}}}}collectTransformsForTool(tool2){const transforms=[];const opts=this.options.inputTransforms;if(!opts)return transforms;if(opts.global){transforms.push(...opts.global)}const perToolInputTransforms=this.resolvePerTool(opts.perTool,tool2);if(perToolInputTransforms){transforms.push(...perToolInputTransforms)}if(opts.generator){transforms.push(...opts.generator(tool2))}return transforms}applyInputTransforms(tool2){const transforms=this.collectTransformsForTool(tool2);if(transforms.length===0)return tool2;for(const transform of transforms){if(RESERVED_KEYS2.includes(transform.inputKey)){throw new Error(`Invalid inputKey '${transform.inputKey}' in tool '${tool2.name}': reserved keys (${RESERVED_KEYS2.join(", ")}) cannot be used`)}}const transformedInputKeys=new Set(transforms.map(t=>t.inputKey));const inputSchema=tool2.inputSchema;const properties=inputSchema?.["properties"]||{};const required=inputSchema?.["required"]||[];const newProperties={...properties};for(const key of transformedInputKeys){delete newProperties[key]}const newRequired=required.filter(key=>!transformedInputKeys.has(key));this.logger.debug(`Applied ${transforms.length} input transforms to tool '${tool2.name}'`);const metadataRecord=tool2.metadata;const existingAdapter=metadataRecord["adapter"];return{...tool2,inputSchema:{...inputSchema,properties:newProperties,...newRequired.length>0?{required:newRequired}:{}},metadata:{...tool2.metadata,adapter:{...existingAdapter||{},inputTransforms:transforms}}}}filterSecuritySchemes(tool2,allowedSchemes){if(allowedSchemes.size===0)return tool2;const schemesToRemove=new Set;const inputKeysToRemove=new Set;for(const mapper of tool2.mapper){if(mapper.security?.scheme&&!allowedSchemes.has(mapper.security.scheme)){schemesToRemove.add(mapper.security.scheme);inputKeysToRemove.add(mapper.inputKey)}}if(inputKeysToRemove.size===0)return tool2;const inputSchema=tool2.inputSchema;const properties=inputSchema?.["properties"]||{};const required=inputSchema?.["required"]||[];const newProperties={...properties};for(const key of inputKeysToRemove){delete newProperties[key]}const newRequired=required.filter(key=>!inputKeysToRemove.has(key));this.logger.debug(`[${tool2.name}] Filtered security schemes from input: ${Array.from(schemesToRemove).join(", ")}. Kept in input: ${Array.from(allowedSchemes).filter(s=>!schemesToRemove.has(s)).join(", ")||"none"}`);const metadataRecord=tool2.metadata;const existingAdapter=metadataRecord["adapter"];return{...tool2,inputSchema:{...inputSchema,properties:newProperties,...newRequired.length>0?{required:newRequired}:{}},metadata:{...tool2.metadata,adapter:{...existingAdapter||{},securitySchemesInInput:Array.from(allowedSchemes),securitySchemesFromContext:Array.from(schemesToRemove)}}}}applySchemaTransforms(tool2){const opts=this.options.schemaTransforms;if(!opts)return tool2;const ctx={tool:tool2,adapterOptions:this.options};let newInputSchema=tool2.inputSchema;let newOutputSchema=tool2.outputSchema;if(opts.input){const inputTransform=this.collectInputSchemaTransform(tool2);if(inputTransform){newInputSchema=inputTransform(newInputSchema,ctx)}}if(opts.output){const outputTransform=this.collectOutputSchemaTransform(tool2);if(outputTransform){newOutputSchema=outputTransform(newOutputSchema,ctx)}}if(newInputSchema===tool2.inputSchema&&newOutputSchema===tool2.outputSchema){return tool2}this.logger.debug(`Applied schema transforms to '${tool2.name}'`);return{...tool2,inputSchema:newInputSchema,outputSchema:newOutputSchema}}collectInputSchemaTransform(tool2){const opts=this.options.schemaTransforms?.input;if(!opts)return void 0;if(opts.generator){const generated=opts.generator(tool2);if(generated)return generated}const perToolInputSchema=this.resolvePerTool(opts.perTool,tool2);if(perToolInputSchema){return perToolInputSchema}return opts.global}collectOutputSchemaTransform(tool2){const opts=this.options.schemaTransforms?.output;if(!opts)return void 0;if(opts.generator){const generated=opts.generator(tool2);if(generated)return generated}const perToolOutputSchema=this.resolvePerTool(opts.perTool,tool2);if(perToolOutputSchema){return perToolOutputSchema}return opts.global}async applyOutputSchemaOptions(tool2,dataTransforms){const outputSchemaOpts=this.options.outputSchema;let newDescription=tool2.description;let newOutputSchema=tool2.outputSchema;const mode=outputSchemaOpts?.mode??"definition";if(newOutputSchema&&(mode==="description"||mode==="both")){const descriptionFormat=outputSchemaOpts?.descriptionFormat??"summary";const formatter=outputSchemaOpts?.descriptionFormatter;const formatterCtx={tool:tool2,adapterOptions:this.options,originalDescription:tool2.description};let schemaText;if(formatter){schemaText=await Promise.resolve(formatter(newOutputSchema,formatterCtx))}else{schemaText=this.formatSchemaForDescription(newOutputSchema,descriptionFormat)}newDescription=tool2.description+schemaText}if(mode==="description"){newOutputSchema=void 0}const preTransform=this.collectPreToolTransformsFromDataTransforms(tool2,dataTransforms);if(preTransform){const ctx={tool:tool2,adapterOptions:this.options};if(preTransform.transformSchema){newOutputSchema=preTransform.transformSchema(newOutputSchema,ctx)}if(preTransform.transformDescription){newDescription=preTransform.transformDescription(newDescription,newOutputSchema,ctx)}}const postTransform=this.collectPostToolTransformsFromDataTransforms(tool2,dataTransforms);if(newDescription===tool2.description&&newOutputSchema===tool2.outputSchema&&!postTransform){return tool2}this.logger.debug(`Applied output schema options to '${tool2.name}' (mode: ${mode})`);const metadataRecord=tool2.metadata;const existingAdapter=metadataRecord["adapter"];return{...tool2,description:newDescription,outputSchema:newOutputSchema,metadata:{...tool2.metadata,adapter:{...existingAdapter||{},...postTransform&&{postToolTransform:postTransform}}}}}formatSchemaForDescription(schema,mode){switch(mode){case"jsonSchema":return`
7
7
 
@@ -41,6 +41,10 @@ type OpenAPIDocument = OpenAPIV3.Document | OpenAPIV3_1.Document;
41
41
  * Modify OpenAPI spec to force JWT/Bearer security on operations.
42
42
  * Returns a new spec object (does not mutate input).
43
43
  *
44
+ * The scheme is added as one more alternative to an operation's existing `security` list, so an
45
+ * operation that already accepts another scheme still accepts it. To make the scheme the only one,
46
+ * clear those operations first with `removeSecurityFromOperations`.
47
+ *
44
48
  * @param spec - Original OpenAPI specification
45
49
  * @param options - Security configuration options
46
50
  * @returns Modified OpenAPI specification with security applied
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.spec-utils.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.spec-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IAE3C;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IAEzC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,eAAe,GAAG,SAAS,CAAC,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;AAUjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,GAAE,oBAAyB,GAAG,eAAe,CAuG3G;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,eAAe,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,eAAe,CAgC1G"}
1
+ {"version":3,"file":"openapi.spec-utils.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.spec-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IAE3C;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IAEzC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,eAAe,GAAG,SAAS,CAAC,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;AAUjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,GAAE,oBAAyB,GAAG,eAAe,CAsG3G;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,eAAe,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,eAAe,CAgC1G"}
@@ -1 +1 @@
1
- {"version":3,"file":"openapi.utils.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAmB,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAK1F;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAwGD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,EAC1D,OAAO,EAAE,MAAM,GACd,aAAa,CA2Hf;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAMzG;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAKD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,EAAE,EAAE,OAAO,CAAC;IACZ,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAgEhH"}
1
+ {"version":3,"file":"openapi.utils.d.ts","sourceRoot":"","sources":["../../src/openapi/openapi.utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAmB,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAK1F;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAwGD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,EAC1D,OAAO,EAAE,MAAM,GACd,aAAa,CA2Hf;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAMzG;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAKD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,EAAE,EAAE,OAAO,CAAC;IACZ,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CA6DhH"}