@frontmcp/adapters 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.mjs +1168 -0
- package/esm/openapi/index.mjs +1168 -0
- package/esm/package.json +63 -0
- package/index.js +1193 -0
- package/openapi/index.js +1192 -0
- package/package.json +30 -12
- package/src/index.js +0 -8
- package/src/index.js.map +0 -1
- package/src/openapi/README.md +0 -1215
- package/src/openapi/index.js +0 -8
- package/src/openapi/index.js.map +0 -1
- package/src/openapi/openapi.adapter.js +0 -434
- package/src/openapi/openapi.adapter.js.map +0 -1
- package/src/openapi/openapi.frontmcp-schema.js +0 -358
- package/src/openapi/openapi.frontmcp-schema.js.map +0 -1
- package/src/openapi/openapi.security.js +0 -242
- package/src/openapi/openapi.security.js.map +0 -1
- package/src/openapi/openapi.tool.js +0 -267
- package/src/openapi/openapi.tool.js.map +0 -1
- package/src/openapi/openapi.types.js +0 -29
- package/src/openapi/openapi.types.js.map +0 -1
- package/src/openapi/openapi.utils.js +0 -229
- package/src/openapi/openapi.utils.js.map +0 -1
- /package/{src/index.d.ts → index.d.ts} +0 -0
- /package/{src/openapi → openapi}/index.d.ts +0 -0
- /package/{src/openapi → openapi}/openapi.adapter.d.ts +0 -0
- /package/{src/openapi → openapi}/openapi.frontmcp-schema.d.ts +0 -0
- /package/{src/openapi → openapi}/openapi.security.d.ts +0 -0
- /package/{src/openapi → openapi}/openapi.tool.d.ts +0 -0
- /package/{src/openapi → openapi}/openapi.types.d.ts +0 -0
- /package/{src/openapi → openapi}/openapi.utils.d.ts +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.security.js","sourceRoot":"","sources":["../../../src/openapi/openapi.security.ts"],"names":[],"mappings":"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","sourcesContent":["import { SecurityResolver, createSecurityContext, type McpOpenAPITool, type SecurityContext } from 'mcp-from-openapi';\nimport type { FrontMcpContext } from '@frontmcp/sdk';\nimport type { OpenApiAdapterOptions } from './openapi.types';\n\n/**\n * Security scheme information extracted from OpenAPI spec\n */\nexport interface SecuritySchemeInfo {\n name: string;\n type: string;\n scheme?: string;\n in?: string;\n description?: string;\n}\n\n/**\n * Security validation result\n */\nexport interface SecurityValidationResult {\n valid: boolean;\n missingMappings: string[];\n warnings: string[];\n securityRiskScore: 'low' | 'medium' | 'high';\n}\n\n/**\n * Resolve security context from FrontMCP context with support for multiple auth providers\n *\n * @param tool - OpenAPI tool to resolve security for\n * @param ctx - FrontMCP request context with authInfo, sessionId, traceId, etc.\n * @param options - Adapter options with auth configuration\n * @returns Security context for resolver\n */\nexport async function createSecurityContextFromAuth(\n tool: McpOpenAPITool,\n ctx: FrontMcpContext,\n options: Pick<OpenApiAdapterOptions, 'securityResolver' | 'authProviderMapper' | 'staticAuth'>,\n): Promise<SecurityContext> {\n // 1. Use custom security resolver if provided (highest priority)\n if (options.securityResolver) {\n return await options.securityResolver(tool, ctx);\n }\n\n // 2. Use auth provider mapper if provided\n if (options.authProviderMapper) {\n const context = createSecurityContext({});\n\n // Find all security schemes used by this tool\n const securitySchemes = new Set<string>();\n for (const mapper of tool.mapper) {\n if (mapper.security?.scheme) {\n securitySchemes.add(mapper.security.scheme);\n }\n }\n\n // Map each security scheme to its auth provider\n // Process all schemes - first matching token for each auth type (jwt, apiKey, basic, oauth2Token)\n for (const scheme of securitySchemes) {\n const authExtractor = options.authProviderMapper[scheme];\n if (authExtractor) {\n try {\n const token = authExtractor(ctx);\n\n // Validate return type - must be string or undefined/null\n if (token !== undefined && token !== null && typeof token !== 'string') {\n throw new Error(\n `authProviderMapper['${scheme}'] must return a string or undefined, ` + `but returned: ${typeof token}`,\n );\n }\n\n // Reject empty string tokens explicitly - indicates misconfiguration\n if (token === '') {\n throw new Error(\n `authProviderMapper['${scheme}'] returned empty string. ` +\n `Return undefined/null if no token is available, or provide a valid token.`,\n );\n }\n\n if (token) {\n // Route token to correct context field based on scheme type\n // Look up the scheme info from the mapper to determine type\n const schemeMapper = tool.mapper.find((m) => m.security?.scheme === scheme);\n const schemeType = schemeMapper?.security?.type?.toLowerCase();\n const httpScheme = schemeMapper?.security?.httpScheme?.toLowerCase();\n\n // Route based on security scheme type (first token for each type wins)\n if (schemeType === 'apikey') {\n if (!context.apiKey) {\n context.apiKey = token;\n }\n } else if (schemeType === 'http' && httpScheme === 'basic') {\n if (!context.basic) {\n context.basic = token;\n }\n } else if (schemeType === 'oauth2') {\n if (!context.oauth2Token) {\n context.oauth2Token = token;\n }\n } else {\n // Default to jwt for http bearer and unknown types\n if (!context.jwt) {\n context.jwt = token;\n }\n }\n // Continue checking other schemes - don't break\n // This allows validation to see all configured providers\n }\n } catch (err) {\n // Re-throw validation errors as-is\n if (err instanceof Error && err.message.includes('authProviderMapper')) {\n throw err;\n }\n // Wrap other errors with context\n const errorMessage = err instanceof Error ? err.message : String(err);\n throw new Error(`authProviderMapper['${scheme}'] threw an error: ${errorMessage}`);\n }\n }\n }\n\n // If no auth was set from providers, fall back to ctx.authInfo.token\n // Only fall back if ALL auth fields are empty (not just jwt)\n const hasAnyAuth = context.jwt || context.apiKey || context.basic || context.oauth2Token;\n const authToken = ctx.authInfo?.token;\n if (!hasAnyAuth && authToken) {\n // Validate type before assignment to prevent non-string values\n if (typeof authToken !== 'string') {\n throw new Error(`authInfo.token must be a string, but got: ${typeof authToken}`);\n }\n context.jwt = authToken;\n }\n\n return context;\n }\n\n // 3. Use static auth if provided\n if (options.staticAuth) {\n return createSecurityContext(options.staticAuth);\n }\n\n // 4. Default: use main JWT token from auth context\n return createSecurityContext({\n jwt: ctx.authInfo?.token,\n });\n}\n\n/**\n * Extract all security schemes used by a set of tools\n *\n * @param tools - OpenAPI tools\n * @returns Set of security scheme names\n */\nexport function extractSecuritySchemes(tools: McpOpenAPITool[]): Set<string> {\n const schemes = new Set<string>();\n\n for (const tool of tools) {\n for (const mapper of tool.mapper) {\n if (mapper.security?.scheme) {\n schemes.add(mapper.security.scheme);\n }\n }\n }\n\n return schemes;\n}\n\n/**\n * Validate security configuration against OpenAPI security requirements\n *\n * @param tools - OpenAPI tools\n * @param options - Adapter options\n * @returns Validation result with errors and warnings\n */\nexport function validateSecurityConfiguration(\n tools: McpOpenAPITool[],\n options: Pick<\n OpenApiAdapterOptions,\n 'securityResolver' | 'authProviderMapper' | 'staticAuth' | 'generateOptions' | 'securitySchemesInInput'\n >,\n): SecurityValidationResult {\n const result: SecurityValidationResult = {\n valid: true,\n missingMappings: [],\n warnings: [],\n securityRiskScore: 'low',\n };\n\n // Extract all security schemes used\n const securitySchemes = extractSecuritySchemes(tools);\n\n // If includeSecurityInInput is true, auth is provided by user (high security risk)\n const includeSecurityInInput = options.generateOptions?.includeSecurityInInput ?? false;\n\n if (includeSecurityInInput) {\n result.securityRiskScore = 'high';\n result.warnings.push(\n 'SECURITY WARNING: includeSecurityInInput is enabled. Users will provide authentication directly in tool inputs. This increases security risk as credentials may be logged or exposed.',\n );\n // Don't validate mappings if security is in input\n return result;\n }\n\n // Check if we have custom security resolver (most flexible, low risk)\n if (options.securityResolver) {\n result.securityRiskScore = 'low';\n result.warnings.push(\n 'INFO: Using custom securityResolver. Ensure your resolver properly validates and secures credentials from context.',\n );\n return result;\n }\n\n // Check if we have static auth (medium risk - static credentials)\n if (options.staticAuth && Object.keys(options.staticAuth).length > 0) {\n result.securityRiskScore = 'medium';\n result.warnings.push(\n 'SECURITY INFO: Using staticAuth with hardcoded credentials. Ensure credentials are stored securely (environment variables, secrets manager).',\n );\n // If static auth is provided, assume it covers all schemes\n return result;\n }\n\n // Get schemes that will be provided via input (don't need mapping)\n const schemesInInput = new Set(options.securitySchemesInInput || []);\n\n // Check authProviderMapper (low risk - context-based auth)\n if (options.authProviderMapper || schemesInInput.size > 0) {\n result.securityRiskScore = schemesInInput.size > 0 ? 'medium' : 'low';\n\n // Log info about per-scheme control\n if (schemesInInput.size > 0) {\n result.warnings.push(\n `INFO: Per-scheme security control enabled. Schemes in input: ${Array.from(schemesInInput).join(', ')}`,\n );\n }\n\n // Validate that all schemes have mappings (except those in input)\n for (const scheme of securitySchemes) {\n // Skip schemes that will be provided via input\n if (schemesInInput.has(scheme)) {\n continue;\n }\n // Check if there's a mapping for this scheme\n if (!options.authProviderMapper?.[scheme]) {\n result.valid = false;\n result.missingMappings.push(scheme);\n }\n }\n\n if (!result.valid) {\n result.warnings.push(\n `ERROR: Missing auth provider mappings for security schemes: ${result.missingMappings.join(', ')}`,\n );\n }\n\n return result;\n }\n\n // No auth configuration provided - will use default ctx.authInfo.token\n // This only works if there's a single Bearer auth scheme\n if (securitySchemes.size > 0) {\n result.securityRiskScore = 'medium';\n result.warnings.push(\n `INFO: No auth configuration provided. Using default ctx.authInfo.token for all security schemes: ${Array.from(\n securitySchemes,\n ).join(', ')}`,\n );\n result.warnings.push(\n 'RECOMMENDATION: For multiple auth providers, use authProviderMapper or securityResolver to map each security scheme to the correct auth provider.',\n );\n }\n\n return result;\n}\n\n/**\n * Resolve security for an OpenAPI tool with validation\n *\n * @param tool - OpenAPI tool with mapper\n * @param ctx - FrontMCP request context with authInfo, sessionId, traceId, etc.\n * @param options - Adapter options with auth configuration\n * @returns Resolved security (headers, query params, etc.)\n * @throws Error if security cannot be resolved\n */\nexport async function resolveToolSecurity(\n tool: McpOpenAPITool,\n ctx: FrontMcpContext,\n options: Pick<OpenApiAdapterOptions, 'securityResolver' | 'authProviderMapper' | 'staticAuth'>,\n) {\n const securityResolver = new SecurityResolver();\n const securityContext = await createSecurityContextFromAuth(tool, ctx, options);\n\n // Validate that we have auth for this tool\n const hasAuth =\n securityContext.jwt ||\n securityContext.apiKey ||\n securityContext.basic ||\n securityContext.oauth2Token ||\n (securityContext.apiKeys && Object.keys(securityContext.apiKeys).length > 0) ||\n (securityContext.customHeaders && Object.keys(securityContext.customHeaders).length > 0);\n\n // Check if this tool requires security\n // A tool requires security ONLY if a mapper has security with required=true\n // Optional security schemes (required=false or undefined) should not block requests\n const requiresSecurity = tool.mapper.some((m) => m.security && m.required === true);\n\n if (requiresSecurity && !hasAuth) {\n // Extract required security scheme names for error message\n const requiredSchemes = tool.mapper\n .filter((m) => m.security && m.required === true)\n .map((m) => m.security?.scheme ?? 'unknown');\n const uniqueSchemes = [...new Set(requiredSchemes)];\n const schemesStr = uniqueSchemes.join(', ') || 'unknown';\n const firstScheme = uniqueSchemes[0] || 'BearerAuth';\n\n throw new Error(\n `Authentication required for tool '${tool.name}' but no auth configuration found.\\n` +\n `Required security schemes: ${schemesStr}\\n` +\n `Solutions:\\n` +\n ` 1. Add authProviderMapper: { '${firstScheme}': (ctx) => ctx.authInfo.user?.token }\\n` +\n ` 2. Add securityResolver: (tool, ctx) => ({ jwt: ctx.authInfo.token })\\n` +\n ` 3. Add staticAuth: { jwt: process.env.API_TOKEN }\\n` +\n ` 4. Set generateOptions.includeSecurityInInput: true (not recommended for production)`,\n );\n }\n\n return await securityResolver.resolve(tool.mapper, securityContext);\n}\n"]}
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createOpenApiTool = createOpenApiTool;
|
|
4
|
-
const zod_1 = require("zod");
|
|
5
|
-
const sdk_1 = require("@frontmcp/sdk");
|
|
6
|
-
const zod_from_json_schema_1 = require("zod-from-json-schema");
|
|
7
|
-
const openapi_utils_1 = require("./openapi.utils");
|
|
8
|
-
const openapi_security_1 = require("./openapi.security");
|
|
9
|
-
const openapi_frontmcp_schema_1 = require("./openapi.frontmcp-schema");
|
|
10
|
-
/**
|
|
11
|
-
* Create a FrontMCP tool from an OpenAPI tool definition
|
|
12
|
-
*
|
|
13
|
-
* @param openapiTool - OpenAPI tool with mapper
|
|
14
|
-
* @param options - Adapter options
|
|
15
|
-
* @param logger - Logger instance
|
|
16
|
-
* @returns FrontMCP tool
|
|
17
|
-
*/
|
|
18
|
-
function createOpenApiTool(openapiTool, options, logger) {
|
|
19
|
-
// Cast metadata to extended type (includes adapter-added fields)
|
|
20
|
-
const metadata = openapiTool.metadata;
|
|
21
|
-
// Get transforms stored in metadata by adapter
|
|
22
|
-
const inputTransforms = metadata.adapter?.inputTransforms ?? [];
|
|
23
|
-
const toolTransform = metadata.adapter?.toolTransform ?? {};
|
|
24
|
-
// Validate and parse x-frontmcp extension from OpenAPI spec
|
|
25
|
-
const frontmcpValidation = (0, openapi_frontmcp_schema_1.validateFrontMcpExtension)(metadata.frontmcp, openapiTool.name, logger);
|
|
26
|
-
const frontmcpExt = frontmcpValidation.data;
|
|
27
|
-
// Convert JSON Schema to Zod schema for input validation
|
|
28
|
-
const schemaResult = getZodSchemaFromJsonSchema(openapiTool.inputSchema, openapiTool.name, logger);
|
|
29
|
-
// Build tool metadata with transforms applied
|
|
30
|
-
// Priority: OpenAPI x-frontmcp → toolTransforms (adapter can override spec)
|
|
31
|
-
const toolMetadata = {
|
|
32
|
-
id: openapiTool.name,
|
|
33
|
-
name: openapiTool.name,
|
|
34
|
-
description: openapiTool.description,
|
|
35
|
-
inputSchema: schemaResult.schema.shape || {},
|
|
36
|
-
rawInputSchema: openapiTool.inputSchema,
|
|
37
|
-
};
|
|
38
|
-
// Track schema conversion failure in metadata for debugging
|
|
39
|
-
if (schemaResult.conversionFailed) {
|
|
40
|
-
toolMetadata['_schemaConversionFailed'] = true;
|
|
41
|
-
toolMetadata['_schemaConversionError'] = schemaResult.error;
|
|
42
|
-
}
|
|
43
|
-
// 1. Apply validated x-frontmcp extensions from OpenAPI spec (base layer)
|
|
44
|
-
if (frontmcpExt) {
|
|
45
|
-
if (frontmcpExt.annotations) {
|
|
46
|
-
toolMetadata['annotations'] = { ...frontmcpExt.annotations };
|
|
47
|
-
}
|
|
48
|
-
if (frontmcpExt.tags) {
|
|
49
|
-
toolMetadata['tags'] = [...frontmcpExt.tags];
|
|
50
|
-
}
|
|
51
|
-
if (frontmcpExt.hideFromDiscovery !== undefined) {
|
|
52
|
-
toolMetadata['hideFromDiscovery'] = frontmcpExt.hideFromDiscovery;
|
|
53
|
-
}
|
|
54
|
-
if (frontmcpExt.examples) {
|
|
55
|
-
toolMetadata['examples'] = [...frontmcpExt.examples];
|
|
56
|
-
}
|
|
57
|
-
if (frontmcpExt.cache) {
|
|
58
|
-
toolMetadata['cache'] = { ...frontmcpExt.cache };
|
|
59
|
-
}
|
|
60
|
-
if (frontmcpExt.codecall) {
|
|
61
|
-
toolMetadata['codecall'] = { ...frontmcpExt.codecall };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
// 2. Apply toolTransforms (adapter-level overrides)
|
|
65
|
-
if (toolTransform.annotations) {
|
|
66
|
-
toolMetadata['annotations'] = {
|
|
67
|
-
...(toolMetadata['annotations'] || {}),
|
|
68
|
-
...toolTransform.annotations,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
if (toolTransform.tags) {
|
|
72
|
-
const existingTags = toolMetadata['tags'] || [];
|
|
73
|
-
toolMetadata['tags'] = [...existingTags, ...toolTransform.tags];
|
|
74
|
-
}
|
|
75
|
-
if (toolTransform.hideFromDiscovery !== undefined) {
|
|
76
|
-
toolMetadata['hideFromDiscovery'] = toolTransform.hideFromDiscovery;
|
|
77
|
-
}
|
|
78
|
-
if (toolTransform.examples) {
|
|
79
|
-
const existingExamples = toolMetadata['examples'] || [];
|
|
80
|
-
toolMetadata['examples'] = [...existingExamples, ...toolTransform.examples];
|
|
81
|
-
}
|
|
82
|
-
if (toolTransform.ui) {
|
|
83
|
-
toolMetadata['ui'] = toolTransform.ui;
|
|
84
|
-
}
|
|
85
|
-
return (0, sdk_1.tool)(toolMetadata)(async (input, toolCtx) => {
|
|
86
|
-
// Get the FrontMcpContext for full context access (sessionId, traceId, authInfo, etc.)
|
|
87
|
-
const ctx = toolCtx.context;
|
|
88
|
-
// 1. Inject transformed values (from inputTransforms)
|
|
89
|
-
const transformContext = {
|
|
90
|
-
ctx,
|
|
91
|
-
env: process.env,
|
|
92
|
-
tool: openapiTool,
|
|
93
|
-
};
|
|
94
|
-
const injectedInput = await injectTransformedValues(input, inputTransforms, transformContext);
|
|
95
|
-
// 2. Resolve security from context
|
|
96
|
-
const security = await (0, openapi_security_1.resolveToolSecurity)(openapiTool, ctx, options);
|
|
97
|
-
// 3. Build request from mapper (now uses injectedInput)
|
|
98
|
-
const { url, headers, body: requestBody } = (0, openapi_utils_1.buildRequest)(openapiTool, injectedInput, security, options.baseUrl);
|
|
99
|
-
// 4. Apply additional headers
|
|
100
|
-
(0, openapi_utils_1.applyAdditionalHeaders)(headers, options.additionalHeaders);
|
|
101
|
-
// 5. Apply custom headers mapper with error handling
|
|
102
|
-
if (options.headersMapper) {
|
|
103
|
-
try {
|
|
104
|
-
const mappedHeaders = options.headersMapper(ctx, headers);
|
|
105
|
-
if (mappedHeaders && typeof mappedHeaders.forEach === 'function') {
|
|
106
|
-
mappedHeaders.forEach((value, key) => {
|
|
107
|
-
headers.set(key, value);
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
113
|
-
throw new Error(`headersMapper failed for tool '${openapiTool.name}': ${errorMessage}`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
// 6. Apply custom body mapper with error handling
|
|
117
|
-
let finalBody = requestBody;
|
|
118
|
-
if (options.bodyMapper && requestBody) {
|
|
119
|
-
try {
|
|
120
|
-
finalBody = options.bodyMapper(ctx, requestBody);
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
124
|
-
throw new Error(`bodyMapper failed for tool '${openapiTool.name}': ${errorMessage}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
// 7. Set content-type if we have a body
|
|
128
|
-
if (finalBody && !headers.has('content-type')) {
|
|
129
|
-
headers.set('content-type', 'application/json');
|
|
130
|
-
}
|
|
131
|
-
// 8. Serialize body and check size limit
|
|
132
|
-
let serializedBody;
|
|
133
|
-
if (finalBody) {
|
|
134
|
-
try {
|
|
135
|
-
serializedBody = JSON.stringify(finalBody);
|
|
136
|
-
}
|
|
137
|
-
catch (err) {
|
|
138
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
139
|
-
throw new Error(`Failed to serialize request body for tool '${openapiTool.name}': ${errorMessage}. ` +
|
|
140
|
-
`Body may contain circular references, BigInt, or non-serializable values.`);
|
|
141
|
-
}
|
|
142
|
-
// Check request body size limit (10MB default)
|
|
143
|
-
const maxRequestSize = options.maxRequestSize ?? DEFAULT_MAX_REQUEST_SIZE;
|
|
144
|
-
if (serializedBody.length > maxRequestSize) {
|
|
145
|
-
throw new Error(`Request body size (${serializedBody.length} bytes) exceeds maximum allowed (${maxRequestSize} bytes)`);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
// 9. Execute request with timeout
|
|
149
|
-
const requestTimeout = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
150
|
-
const controller = new AbortController();
|
|
151
|
-
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
|
|
152
|
-
try {
|
|
153
|
-
const response = await fetch(url, {
|
|
154
|
-
method: openapiTool.metadata.method.toUpperCase(),
|
|
155
|
-
headers,
|
|
156
|
-
body: serializedBody,
|
|
157
|
-
signal: controller.signal,
|
|
158
|
-
});
|
|
159
|
-
// 10. Parse and return response
|
|
160
|
-
return await (0, openapi_utils_1.parseResponse)(response, { maxResponseSize: options.maxResponseSize });
|
|
161
|
-
}
|
|
162
|
-
catch (err) {
|
|
163
|
-
if (err instanceof Error && err.name === 'AbortError') {
|
|
164
|
-
throw new Error(`Request timeout after ${requestTimeout}ms for tool '${openapiTool.name}'`);
|
|
165
|
-
}
|
|
166
|
-
throw err;
|
|
167
|
-
}
|
|
168
|
-
finally {
|
|
169
|
-
clearTimeout(timeoutId);
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
/** Default timeout for transform injection: 5 seconds */
|
|
174
|
-
const DEFAULT_TRANSFORM_TIMEOUT_MS = 5000;
|
|
175
|
-
/** Default request timeout: 30 seconds */
|
|
176
|
-
const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
177
|
-
/** Default max request body size: 10MB */
|
|
178
|
-
const DEFAULT_MAX_REQUEST_SIZE = 10 * 1024 * 1024;
|
|
179
|
-
/** Reserved keys that cannot be used as inputKey (prototype pollution protection) */
|
|
180
|
-
const RESERVED_KEYS = ['__proto__', 'constructor', 'prototype'];
|
|
181
|
-
/**
|
|
182
|
-
* Safely inject a single transform value with timeout and error handling
|
|
183
|
-
*
|
|
184
|
-
* @param transform - Transform to apply
|
|
185
|
-
* @param ctx - Transform context
|
|
186
|
-
* @param timeoutMs - Timeout in milliseconds
|
|
187
|
-
* @returns Injected value or undefined
|
|
188
|
-
*/
|
|
189
|
-
async function safeInject(transform, ctx, timeoutMs = DEFAULT_TRANSFORM_TIMEOUT_MS) {
|
|
190
|
-
let timeoutId;
|
|
191
|
-
try {
|
|
192
|
-
const result = await Promise.race([
|
|
193
|
-
Promise.resolve(transform.inject(ctx)),
|
|
194
|
-
new Promise((_, reject) => {
|
|
195
|
-
timeoutId = setTimeout(() => reject(new Error(`Transform timeout after ${timeoutMs}ms`)), timeoutMs);
|
|
196
|
-
}),
|
|
197
|
-
]);
|
|
198
|
-
return result;
|
|
199
|
-
}
|
|
200
|
-
catch (err) {
|
|
201
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
202
|
-
throw new Error(`Input transform for '${transform.inputKey}' failed: ${errorMessage}`);
|
|
203
|
-
}
|
|
204
|
-
finally {
|
|
205
|
-
// Always clear the timeout to prevent memory leaks
|
|
206
|
-
if (timeoutId !== undefined) {
|
|
207
|
-
clearTimeout(timeoutId);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Validate that input is a plain object (not null, array, or primitive)
|
|
213
|
-
*/
|
|
214
|
-
function isPlainObject(value) {
|
|
215
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Inject transformed values into the input object
|
|
219
|
-
*/
|
|
220
|
-
async function injectTransformedValues(input, transforms, ctx) {
|
|
221
|
-
// Validate input is a plain object to prevent prototype pollution
|
|
222
|
-
if (!isPlainObject(input)) {
|
|
223
|
-
throw new Error(`Invalid input type: expected object, got ${input === null ? 'null' : typeof input}`);
|
|
224
|
-
}
|
|
225
|
-
if (transforms.length === 0)
|
|
226
|
-
return input;
|
|
227
|
-
const result = { ...input };
|
|
228
|
-
for (const transform of transforms) {
|
|
229
|
-
// Prototype pollution protection: reject reserved keys
|
|
230
|
-
if (RESERVED_KEYS.includes(transform.inputKey)) {
|
|
231
|
-
throw new Error(`Invalid inputKey '${transform.inputKey}': reserved keys (${RESERVED_KEYS.join(', ')}) cannot be used`);
|
|
232
|
-
}
|
|
233
|
-
const value = await safeInject(transform, ctx);
|
|
234
|
-
if (value !== undefined) {
|
|
235
|
-
result[transform.inputKey] = value;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return result;
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Converts a JSON Schema to a Zod schema for runtime validation
|
|
242
|
-
*
|
|
243
|
-
* @param jsonSchema - JSON Schema
|
|
244
|
-
* @param toolName - Tool name for error reporting
|
|
245
|
-
* @param logger - Logger instance
|
|
246
|
-
* @returns Schema conversion result with success indicator
|
|
247
|
-
*/
|
|
248
|
-
function getZodSchemaFromJsonSchema(jsonSchema, toolName, logger) {
|
|
249
|
-
if (typeof jsonSchema !== 'object' || jsonSchema === null) {
|
|
250
|
-
logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);
|
|
251
|
-
return { schema: zod_1.z.looseObject({}), conversionFailed: true, error: 'No valid JSON schema' };
|
|
252
|
-
}
|
|
253
|
-
try {
|
|
254
|
-
const zodSchema = (0, zod_from_json_schema_1.convertJsonSchemaToZod)(jsonSchema);
|
|
255
|
-
if (typeof zodSchema?.parse !== 'function') {
|
|
256
|
-
throw new Error('Conversion did not produce a valid Zod schema.');
|
|
257
|
-
}
|
|
258
|
-
return { schema: zodSchema, conversionFailed: false };
|
|
259
|
-
}
|
|
260
|
-
catch (err) {
|
|
261
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
262
|
-
logger.warn(`[${toolName}] Failed to generate Zod schema, using permissive schema. ` +
|
|
263
|
-
`Tool will accept any input but may fail at API level. Error: ${errorMessage}`);
|
|
264
|
-
return { schema: zod_1.z.looseObject({}), conversionFailed: true, error: errorMessage };
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
//# sourceMappingURL=openapi.tool.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.tool.js","sourceRoot":"","sources":["../../../src/openapi/openapi.tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport { tool, FrontMcpLogger } from '@frontmcp/sdk';\nimport { convertJsonSchemaToZod } from 'zod-from-json-schema';\nimport type { McpOpenAPITool } from 'mcp-from-openapi';\nimport type {\n OpenApiAdapterOptions,\n InputTransformContext,\n ExtendedToolMetadata,\n InputTransform,\n} from './openapi.types';\nimport type { JSONSchema } from 'zod/v4/core';\n\n/** JSON Schema type from Zod v4 */\ntype JsonSchema = JSONSchema.JSONSchema;\nimport { buildRequest, applyAdditionalHeaders, parseResponse } from './openapi.utils';\nimport { resolveToolSecurity } from './openapi.security';\nimport { validateFrontMcpExtension, type ValidatedFrontMcpExtension } from './openapi.frontmcp-schema';\n\n/**\n * Create a FrontMCP tool from an OpenAPI tool definition\n *\n * @param openapiTool - OpenAPI tool with mapper\n * @param options - Adapter options\n * @param logger - Logger instance\n * @returns FrontMCP tool\n */\nexport function createOpenApiTool(openapiTool: McpOpenAPITool, options: OpenApiAdapterOptions, logger: FrontMcpLogger) {\n // Cast metadata to extended type (includes adapter-added fields)\n const metadata = openapiTool.metadata as ExtendedToolMetadata;\n\n // Get transforms stored in metadata by adapter\n const inputTransforms = metadata.adapter?.inputTransforms ?? [];\n const toolTransform = metadata.adapter?.toolTransform ?? {};\n\n // Validate and parse x-frontmcp extension from OpenAPI spec\n const frontmcpValidation = validateFrontMcpExtension(metadata.frontmcp, openapiTool.name, logger);\n const frontmcpExt: ValidatedFrontMcpExtension | null = frontmcpValidation.data;\n\n // Convert JSON Schema to Zod schema for input validation\n const schemaResult = getZodSchemaFromJsonSchema(openapiTool.inputSchema, openapiTool.name, logger);\n\n // Build tool metadata with transforms applied\n // Priority: OpenAPI x-frontmcp → toolTransforms (adapter can override spec)\n const toolMetadata: Record<string, unknown> = {\n id: openapiTool.name,\n name: openapiTool.name,\n description: openapiTool.description,\n inputSchema: schemaResult.schema.shape || {},\n rawInputSchema: openapiTool.inputSchema,\n };\n\n // Track schema conversion failure in metadata for debugging\n if (schemaResult.conversionFailed) {\n toolMetadata['_schemaConversionFailed'] = true;\n toolMetadata['_schemaConversionError'] = schemaResult.error;\n }\n\n // 1. Apply validated x-frontmcp extensions from OpenAPI spec (base layer)\n if (frontmcpExt) {\n if (frontmcpExt.annotations) {\n toolMetadata['annotations'] = { ...frontmcpExt.annotations };\n }\n if (frontmcpExt.tags) {\n toolMetadata['tags'] = [...frontmcpExt.tags];\n }\n if (frontmcpExt.hideFromDiscovery !== undefined) {\n toolMetadata['hideFromDiscovery'] = frontmcpExt.hideFromDiscovery;\n }\n if (frontmcpExt.examples) {\n toolMetadata['examples'] = [...frontmcpExt.examples];\n }\n if (frontmcpExt.cache) {\n toolMetadata['cache'] = { ...frontmcpExt.cache };\n }\n if (frontmcpExt.codecall) {\n toolMetadata['codecall'] = { ...frontmcpExt.codecall };\n }\n }\n\n // 2. Apply toolTransforms (adapter-level overrides)\n if (toolTransform.annotations) {\n toolMetadata['annotations'] = {\n ...((toolMetadata['annotations'] as object) || {}),\n ...toolTransform.annotations,\n };\n }\n if (toolTransform.tags) {\n const existingTags = (toolMetadata['tags'] as string[]) || [];\n toolMetadata['tags'] = [...existingTags, ...toolTransform.tags];\n }\n if (toolTransform.hideFromDiscovery !== undefined) {\n toolMetadata['hideFromDiscovery'] = toolTransform.hideFromDiscovery;\n }\n if (toolTransform.examples) {\n const existingExamples = (toolMetadata['examples'] as unknown[]) || [];\n toolMetadata['examples'] = [...existingExamples, ...toolTransform.examples];\n }\n if (toolTransform.ui) {\n toolMetadata['ui'] = toolTransform.ui;\n }\n\n return tool(toolMetadata as unknown as Parameters<typeof tool>[0])(async (input, toolCtx) => {\n // Get the FrontMcpContext for full context access (sessionId, traceId, authInfo, etc.)\n const ctx = toolCtx.context;\n\n // 1. Inject transformed values (from inputTransforms)\n const transformContext: InputTransformContext = {\n ctx,\n env: process.env,\n tool: openapiTool,\n };\n const injectedInput = await injectTransformedValues(\n input as Record<string, unknown>,\n inputTransforms,\n transformContext,\n );\n\n // 2. Resolve security from context\n const security = await resolveToolSecurity(openapiTool, ctx, options);\n\n // 3. Build request from mapper (now uses injectedInput)\n const { url, headers, body: requestBody } = buildRequest(openapiTool, injectedInput, security, options.baseUrl);\n\n // 4. Apply additional headers\n applyAdditionalHeaders(headers, options.additionalHeaders);\n\n // 5. Apply custom headers mapper with error handling\n if (options.headersMapper) {\n try {\n const mappedHeaders = options.headersMapper(ctx, headers);\n if (mappedHeaders && typeof mappedHeaders.forEach === 'function') {\n mappedHeaders.forEach((value, key) => {\n headers.set(key, value);\n });\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n throw new Error(`headersMapper failed for tool '${openapiTool.name}': ${errorMessage}`);\n }\n }\n\n // 6. Apply custom body mapper with error handling\n let finalBody = requestBody;\n if (options.bodyMapper && requestBody) {\n try {\n finalBody = options.bodyMapper(ctx, requestBody);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n throw new Error(`bodyMapper failed for tool '${openapiTool.name}': ${errorMessage}`);\n }\n }\n\n // 7. Set content-type if we have a body\n if (finalBody && !headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n\n // 8. Serialize body and check size limit\n let serializedBody: string | undefined;\n if (finalBody) {\n try {\n serializedBody = JSON.stringify(finalBody);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Failed to serialize request body for tool '${openapiTool.name}': ${errorMessage}. ` +\n `Body may contain circular references, BigInt, or non-serializable values.`,\n );\n }\n // Check request body size limit (10MB default)\n const maxRequestSize = options.maxRequestSize ?? DEFAULT_MAX_REQUEST_SIZE;\n if (serializedBody.length > maxRequestSize) {\n throw new Error(\n `Request body size (${serializedBody.length} bytes) exceeds maximum allowed (${maxRequestSize} bytes)`,\n );\n }\n }\n\n // 9. Execute request with timeout\n const requestTimeout = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout);\n\n try {\n const response = await fetch(url, {\n method: openapiTool.metadata.method.toUpperCase(),\n headers,\n body: serializedBody,\n signal: controller.signal,\n });\n\n // 10. Parse and return response\n return await parseResponse(response, { maxResponseSize: options.maxResponseSize });\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Request timeout after ${requestTimeout}ms for tool '${openapiTool.name}'`);\n }\n throw err;\n } finally {\n clearTimeout(timeoutId);\n }\n });\n}\n\n/** Default timeout for transform injection: 5 seconds */\nconst DEFAULT_TRANSFORM_TIMEOUT_MS = 5000;\n\n/** Default request timeout: 30 seconds */\nconst DEFAULT_REQUEST_TIMEOUT_MS = 30000;\n\n/** Default max request body size: 10MB */\nconst DEFAULT_MAX_REQUEST_SIZE = 10 * 1024 * 1024;\n\n/** Reserved keys that cannot be used as inputKey (prototype pollution protection) */\nconst RESERVED_KEYS = ['__proto__', 'constructor', 'prototype'];\n\n/**\n * Safely inject a single transform value with timeout and error handling\n *\n * @param transform - Transform to apply\n * @param ctx - Transform context\n * @param timeoutMs - Timeout in milliseconds\n * @returns Injected value or undefined\n */\nasync function safeInject(\n transform: InputTransform,\n ctx: InputTransformContext,\n timeoutMs: number = DEFAULT_TRANSFORM_TIMEOUT_MS,\n): Promise<unknown> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n try {\n const result = await Promise.race([\n Promise.resolve(transform.inject(ctx)),\n new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(`Transform timeout after ${timeoutMs}ms`)), timeoutMs);\n }),\n ]);\n return result;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n throw new Error(`Input transform for '${transform.inputKey}' failed: ${errorMessage}`);\n } finally {\n // Always clear the timeout to prevent memory leaks\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n }\n }\n}\n\n/**\n * Validate that input is a plain object (not null, array, or primitive)\n */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Inject transformed values into the input object\n */\nasync function injectTransformedValues(\n input: unknown,\n transforms: InputTransform[],\n ctx: InputTransformContext,\n): Promise<Record<string, unknown>> {\n // Validate input is a plain object to prevent prototype pollution\n if (!isPlainObject(input)) {\n throw new Error(`Invalid input type: expected object, got ${input === null ? 'null' : typeof input}`);\n }\n\n if (transforms.length === 0) return input;\n\n const result = { ...input };\n\n for (const transform of transforms) {\n // Prototype pollution protection: reject reserved keys\n if (RESERVED_KEYS.includes(transform.inputKey)) {\n throw new Error(\n `Invalid inputKey '${transform.inputKey}': reserved keys (${RESERVED_KEYS.join(', ')}) cannot be used`,\n );\n }\n\n const value = await safeInject(transform, ctx);\n if (value !== undefined) {\n result[transform.inputKey] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Result of schema conversion with success indicator\n */\ninterface SchemaConversionResult {\n schema: z.ZodObject;\n conversionFailed: boolean;\n error?: string;\n}\n\n/**\n * Converts a JSON Schema to a Zod schema for runtime validation\n *\n * @param jsonSchema - JSON Schema\n * @param toolName - Tool name for error reporting\n * @param logger - Logger instance\n * @returns Schema conversion result with success indicator\n */\nfunction getZodSchemaFromJsonSchema(\n jsonSchema: JsonSchema,\n toolName: string,\n logger: FrontMcpLogger,\n): SchemaConversionResult {\n if (typeof jsonSchema !== 'object' || jsonSchema === null) {\n logger.warn(`[${toolName}] No valid JSON schema provided, using permissive schema`);\n return { schema: z.looseObject({}), conversionFailed: true, error: 'No valid JSON schema' };\n }\n\n try {\n const zodSchema = convertJsonSchemaToZod(jsonSchema);\n if (typeof zodSchema?.parse !== 'function') {\n throw new Error('Conversion did not produce a valid Zod schema.');\n }\n return { schema: zodSchema as unknown as z.ZodObject, conversionFailed: false };\n } catch (err: unknown) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n logger.warn(\n `[${toolName}] Failed to generate Zod schema, using permissive schema. ` +\n `Tool will accept any input but may fail at API level. Error: ${errorMessage}`,\n );\n return { schema: z.looseObject({}), conversionFailed: true, error: errorMessage };\n }\n}\n"]}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FRONTMCP_EXTENSION_KEY = void 0;
|
|
4
|
-
// ============================================================================
|
|
5
|
-
// OpenAPI Extension Types (x-frontmcp)
|
|
6
|
-
// ============================================================================
|
|
7
|
-
/**
|
|
8
|
-
* The OpenAPI extension key for FrontMCP metadata.
|
|
9
|
-
* Add this to operations in your OpenAPI spec to configure tool behavior.
|
|
10
|
-
*
|
|
11
|
-
* @example OpenAPI YAML
|
|
12
|
-
* ```yaml
|
|
13
|
-
* paths:
|
|
14
|
-
* /users:
|
|
15
|
-
* get:
|
|
16
|
-
* operationId: listUsers
|
|
17
|
-
* summary: List all users
|
|
18
|
-
* x-frontmcp:
|
|
19
|
-
* annotations:
|
|
20
|
-
* readOnlyHint: true
|
|
21
|
-
* idempotentHint: true
|
|
22
|
-
* cache:
|
|
23
|
-
* ttl: 300
|
|
24
|
-
* tags:
|
|
25
|
-
* - users
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
exports.FRONTMCP_EXTENSION_KEY = 'x-frontmcp';
|
|
29
|
-
//# sourceMappingURL=openapi.types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.types.js","sourceRoot":"","sources":["../../../src/openapi/openapi.types.ts"],"names":[],"mappings":";;;AA+DA,+EAA+E;AAC/E,uCAAuC;AACvC,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;GAoBG;AACU,QAAA,sBAAsB,GAAG,YAAY,CAAC","sourcesContent":["import { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\nimport type { LoadOptions, GenerateOptions, McpOpenAPITool, SecurityContext, ToolMetadata } from 'mcp-from-openapi';\nimport type { FrontMcpLogger, ToolAnnotations, ToolExample, ToolUIConfig, FrontMcpContext } from '@frontmcp/sdk';\n\n// ============================================================================\n// Input Transform Types\n// ============================================================================\n\n/**\n * Context available when injecting values at request time\n */\nexport interface InputTransformContext {\n /** FrontMCP request context with authInfo, sessionId, traceId, etc. */\n ctx: FrontMcpContext;\n /** Environment variables */\n env: NodeJS.ProcessEnv;\n /** The OpenAPI tool being executed */\n tool: McpOpenAPITool;\n}\n\n/**\n * Single input transform configuration.\n * Removes an input from the schema and injects its value at request time.\n */\nexport interface InputTransform {\n /**\n * The input key (property name in inputSchema) to transform.\n * This input will be removed from the schema visible to AI/users.\n */\n inputKey: string;\n\n /**\n * Value injector function called at request time.\n * Returns the value to inject for this input.\n */\n inject: (ctx: InputTransformContext) => unknown | Promise<unknown>;\n}\n\n/**\n * Input transform configuration options.\n * Supports global, per-tool, and dynamic transforms.\n */\nexport interface InputTransformOptions {\n /**\n * Global transforms applied to ALL tools.\n * Use for common patterns like tenant headers.\n */\n global?: InputTransform[];\n\n /**\n * Per-tool transforms keyed by tool name.\n * These are combined with global transforms.\n */\n perTool?: Record<string, InputTransform[]>;\n\n /**\n * Dynamic transform generator function.\n * Called for each tool to generate transforms programmatically.\n * Useful when transforms depend on tool metadata.\n */\n generator?: (tool: McpOpenAPITool) => InputTransform[];\n}\n\n// ============================================================================\n// OpenAPI Extension Types (x-frontmcp)\n// ============================================================================\n\n/**\n * The OpenAPI extension key for FrontMCP metadata.\n * Add this to operations in your OpenAPI spec to configure tool behavior.\n *\n * @example OpenAPI YAML\n * ```yaml\n * paths:\n * /users:\n * get:\n * operationId: listUsers\n * summary: List all users\n * x-frontmcp:\n * annotations:\n * readOnlyHint: true\n * idempotentHint: true\n * cache:\n * ttl: 300\n * tags:\n * - users\n * ```\n */\nexport const FRONTMCP_EXTENSION_KEY = 'x-frontmcp';\n\n/**\n * Cache configuration for tools.\n */\nexport interface FrontMcpCacheConfig {\n /**\n * Time-to-live in seconds for cached responses.\n */\n ttl?: number;\n\n /**\n * If true, cache window slides on each access.\n * If false, cache expires at fixed time from first access.\n */\n slideWindow?: boolean;\n}\n\n/**\n * CodeCall configuration for tools.\n */\nexport interface FrontMcpCodeCallConfig {\n /**\n * Whether this tool can be used via CodeCall.\n * @default true\n */\n enabledInCodeCall?: boolean;\n\n /**\n * If true, this tool stays visible in `list_tools`\n * even when CodeCall is hiding most tools.\n * @default false\n */\n visibleInListTools?: boolean;\n}\n\n/**\n * Tool annotations that hint at tool behavior.\n * These map directly to MCP ToolAnnotations.\n */\nexport interface FrontMcpAnnotations {\n /**\n * A human-readable title for the tool.\n */\n title?: string;\n\n /**\n * If true, the tool does not modify its environment.\n * @default false\n */\n readOnlyHint?: boolean;\n\n /**\n * If true, the tool may perform destructive updates.\n * If false, the tool performs only additive updates.\n * (Meaningful only when readOnlyHint == false)\n * @default true\n */\n destructiveHint?: boolean;\n\n /**\n * If true, calling repeatedly with same args has no additional effect.\n * (Meaningful only when readOnlyHint == false)\n * @default false\n */\n idempotentHint?: boolean;\n\n /**\n * If true, tool may interact with external entities (open world).\n * If false, tool's domain is closed (e.g., memory tool).\n * @default true\n */\n openWorldHint?: boolean;\n}\n\n/**\n * FrontMCP extension schema for OpenAPI operations.\n * Add `x-frontmcp` to any operation to configure tool behavior.\n *\n * @example\n * ```yaml\n * x-frontmcp:\n * annotations:\n * readOnlyHint: true\n * idempotentHint: true\n * cache:\n * ttl: 300\n * codecall:\n * enabledInCodeCall: true\n * visibleInListTools: true\n * tags:\n * - users\n * - public-api\n * hideFromDiscovery: false\n * ```\n */\nexport interface FrontMcpExtension {\n /**\n * Tool annotations for AI behavior hints.\n */\n annotations?: FrontMcpAnnotations;\n\n /**\n * Cache configuration for response caching.\n */\n cache?: FrontMcpCacheConfig;\n\n /**\n * CodeCall-specific configuration.\n */\n codecall?: FrontMcpCodeCallConfig;\n\n /**\n * Tags/labels for categorization and filtering.\n */\n tags?: string[];\n\n /**\n * If true, hide tool from discovery/listing.\n * @default false\n */\n hideFromDiscovery?: boolean;\n\n /**\n * Usage examples for the tool.\n */\n examples?: Array<{\n description: string;\n input: Record<string, unknown>;\n output?: unknown;\n }>;\n}\n\n// ============================================================================\n// Tool Transform Types\n// ============================================================================\n\n/**\n * How to generate tool descriptions from OpenAPI operations.\n * - 'summaryOnly': Use only the operation summary (default, current behavior)\n * - 'descriptionOnly': Use only the operation description\n * - 'combined': Combine summary and description (summary first, then description)\n * - 'full': Include summary, description, and operation ID\n */\nexport type DescriptionMode = 'summaryOnly' | 'descriptionOnly' | 'combined' | 'full';\n\n/**\n * Transform configuration for modifying generated tools.\n * Can override or augment any tool property.\n */\nexport interface ToolTransform {\n /**\n * Override or transform the tool name.\n * - string: Replace the name entirely\n * - function: Transform the existing name\n */\n name?: string | ((originalName: string, tool: McpOpenAPITool) => string);\n\n /**\n * Override or transform the tool description.\n * - string: Replace the description entirely\n * - function: Transform with access to original description and tool metadata\n *\n * @example\n * ```typescript\n * // Combine summary and description\n * description: (original, tool) => {\n * const summary = tool.metadata.operationSummary || '';\n * const desc = tool.metadata.operationDescription || '';\n * return summary && desc ? `${summary}\\n\\n${desc}` : original;\n * }\n * ```\n */\n description?: string | ((originalDescription: string, tool: McpOpenAPITool) => string);\n\n /**\n * Annotations to add or merge with existing tool annotations.\n * These hint at tool behavior for AI clients.\n *\n * @example\n * ```typescript\n * annotations: {\n * readOnlyHint: true, // Tool doesn't modify state\n * openWorldHint: true, // Tool interacts with external systems\n * destructiveHint: false, // Tool doesn't delete data\n * idempotentHint: true, // Repeated calls have same effect\n * }\n * ```\n */\n annotations?: ToolAnnotations;\n\n /**\n * UI configuration for the tool (forms, rendering hints).\n */\n ui?: ToolUIConfig;\n\n /**\n * If true, hide the tool from tool discovery/listing.\n * The tool can still be called directly.\n */\n hideFromDiscovery?: boolean;\n\n /**\n * Tags to add to the tool for categorization.\n */\n tags?: string[];\n\n /**\n * Usage examples to add to the tool.\n */\n examples?: ToolExample[];\n}\n\n/**\n * Tool transform configuration options.\n * Supports global, per-tool, and dynamic transforms.\n */\nexport interface ToolTransformOptions {\n /**\n * Global transforms applied to ALL tools.\n * Use for common patterns like adding readOnlyHint to all GET operations.\n */\n global?: ToolTransform;\n\n /**\n * Per-tool transforms keyed by tool name.\n * Takes precedence over global transforms for overlapping properties.\n */\n perTool?: Record<string, ToolTransform>;\n\n /**\n * Dynamic transform generator function.\n * Called for each tool to generate transforms programmatically.\n * Useful when transforms depend on tool metadata (e.g., HTTP method).\n *\n * @example\n * ```typescript\n * generator: (tool) => {\n * // Mark all GET operations as read-only\n * if (tool.metadata.method === 'get') {\n * return {\n * annotations: { readOnlyHint: true, destructiveHint: false },\n * };\n * }\n * // Mark DELETE operations as destructive\n * if (tool.metadata.method === 'delete') {\n * return {\n * annotations: { destructiveHint: true },\n * };\n * }\n * return undefined;\n * }\n * ```\n */\n generator?: (tool: McpOpenAPITool) => ToolTransform | undefined;\n}\n\n// ============================================================================\n// Extended Metadata Types (internal)\n// ============================================================================\n\n/**\n * Extended tool metadata that includes adapter-specific fields.\n * This extends the base ToolMetadata from mcp-from-openapi with\n * fields used for transforms and extensions.\n */\nexport interface ExtendedToolMetadata extends ToolMetadata {\n /**\n * Adapter-specific runtime configuration.\n * Contains transforms and other metadata added during tool processing.\n */\n adapter?: {\n /** Input transforms to apply at request time */\n inputTransforms?: InputTransform[];\n /** Tool transform configuration */\n toolTransform?: ToolTransform;\n /** Security schemes that are included in tool input (user provides) */\n securitySchemesInInput?: string[];\n /** Security schemes resolved from context (authProviderMapper, etc.) */\n securitySchemesFromContext?: string[];\n };\n}\n\n/**\n * McpOpenAPITool with extended metadata type.\n * Use this type when accessing adapter-extended metadata.\n */\nexport interface ExtendedMcpOpenAPITool extends Omit<McpOpenAPITool, 'metadata'> {\n metadata: ExtendedToolMetadata;\n}\n\ninterface BaseOptions {\n /**\n * The name of the adapter.\n * This is used to identify the adapter in the MCP configuration.\n * Also used to prefix tools if conflicted with other adapters in the same app.\n */\n name: string;\n\n /**\n * The base URL of the API.\n * This is used to construct the full URL for each request.\n * For example, if the API is hosted at https://api.example.com/v1,\n * the baseUrl should be set to https://api.example.com/v1.\n * This overrides the baseUrl in LoadOptions.\n */\n baseUrl: string;\n\n /**\n * Additional headers to be sent with each request.\n * This can be used to set authentication headers,\n * such as Authorization or API Key.\n */\n additionalHeaders?: Record<string, string>;\n\n /**\n * This can be used to map request information to specific\n * headers as required by the API.\n * For example, mapping tenantId from authenticated session payload to\n * a specific header, this key will be hidden to mcp clients\n * and filled by the adapter before sending the request to the API.\n * @param ctx - FrontMCP request context with authInfo, sessionId, traceId, etc.\n * @param headers\n */\n headersMapper?: (ctx: FrontMcpContext, headers: Headers) => Headers;\n\n /**\n * This can be used to map request information to specific\n * body values as required by the API.\n * For example, mapping tenantId from authenticated session payload to\n * a specific property in the body, this key will be hidden to mcp clients\n * and filled by the adapter before sending the request to the API.\n *\n * @param ctx - FrontMCP request context with authInfo, sessionId, traceId, etc.\n * @param body\n */\n bodyMapper?: (ctx: FrontMcpContext, body: Record<string, unknown>) => Record<string, unknown>;\n\n /**\n * Custom security resolver for resolving authentication from context.\n * This allows you to map different auth providers to different tools/security schemes.\n *\n * Use this when:\n * - You have multiple auth providers (e.g., GitHub OAuth, Google OAuth, API keys)\n * - Different tools need different authentication\n * - You need custom logic to select the right auth provider\n *\n * @example\n * ```typescript\n * securityResolver: (tool, ctx) => {\n * const authInfo = ctx.authInfo;\n * // Use GitHub token for GitHub API tools\n * if (tool.name.startsWith('github_')) {\n * return { jwt: authInfo.user?.githubToken };\n * }\n * // Use Google token for Google API tools\n * if (tool.name.startsWith('google_')) {\n * return { jwt: authInfo.user?.googleToken };\n * }\n * // Default to main JWT token\n * return { jwt: authInfo.token };\n * }\n * ```\n */\n securityResolver?: (tool: McpOpenAPITool, ctx: FrontMcpContext) => SecurityContext | Promise<SecurityContext>;\n\n /**\n * Map security scheme names to auth provider extractors.\n * This allows different security schemes to use different auth providers.\n *\n * Use this when your OpenAPI spec has multiple security schemes\n * and each should use a different auth provider from the context.\n *\n * @example\n * ```typescript\n * authProviderMapper: {\n * // GitHub OAuth security scheme\n * 'GitHubAuth': (ctx) => ctx.authInfo.user?.githubToken,\n * // Google OAuth security scheme\n * 'GoogleAuth': (ctx) => ctx.authInfo.user?.googleToken,\n * // API Key security scheme\n * 'ApiKeyAuth': (ctx) => ctx.authInfo.user?.apiKey,\n * }\n * ```\n */\n authProviderMapper?: Record<string, (ctx: FrontMcpContext) => string | undefined>;\n\n /**\n * Static authentication configuration when not using dynamic auth from context.\n * Useful for server-to-server APIs with static credentials.\n *\n * @example\n * ```typescript\n * staticAuth: {\n * jwt: process.env.API_JWT_TOKEN,\n * apiKey: process.env.API_KEY,\n * }\n * ```\n */\n staticAuth?: Partial<SecurityContext>;\n\n /**\n * Options for loading the OpenAPI specification\n * @see LoadOptions from mcp-from-openapi\n */\n loadOptions?: Omit<LoadOptions, 'baseUrl'>; // baseUrl is in BaseOptions\n\n /**\n * Options for generating tools from the OpenAPI specification\n * @see GenerateOptions from mcp-from-openapi\n */\n generateOptions?: GenerateOptions;\n\n /**\n * Specify which security schemes should be included in the tool's input schema.\n * Use this for per-scheme control over authentication handling.\n *\n * - Schemes in this list → included in input (user/AI provides the value)\n * - Schemes NOT in this list → resolved from context (authProviderMapper, staticAuth, etc.)\n *\n * This allows hybrid authentication where some schemes come from user input\n * and others come from the session/context.\n *\n * @example\n * ```typescript\n * // OpenAPI spec has: GitHubAuth (Bearer), ApiKeyAuth (API key)\n * // You want: GitHubAuth from session, ApiKeyAuth from user input\n *\n * const adapter = new OpenapiAdapter({\n * name: 'my-api',\n * baseUrl: 'https://api.example.com',\n * spec: mySpec,\n *\n * // ApiKeyAuth will be in tool input schema\n * securitySchemesInInput: ['ApiKeyAuth'],\n *\n * // GitHubAuth will be resolved from context\n * authProviderMapper: {\n * 'GitHubAuth': (ctx) => ctx.authInfo?.user?.githubToken,\n * },\n * });\n * ```\n */\n securitySchemesInInput?: string[];\n\n /**\n * Input schema transforms for hiding inputs and injecting values at request time.\n *\n * Use cases:\n * - Hide tenant headers from AI/users and inject from session\n * - Hide internal correlation IDs and inject from environment\n * - Remove API-internal fields that should be computed server-side\n *\n * @example\n * ```typescript\n * inputTransforms: {\n * global: [\n * { inputKey: 'X-Tenant-Id', inject: (ctx) => ctx.authInfo.user?.tenantId },\n * ],\n * perTool: {\n * 'createUser': [\n * { inputKey: 'createdBy', inject: (ctx) => ctx.authInfo.user?.email },\n * ],\n * },\n * generator: (tool) => {\n * if (['post', 'put', 'patch'].includes(tool.metadata.method)) {\n * return [{ inputKey: 'X-Correlation-Id', inject: () => crypto.randomUUID() }];\n * }\n * return [];\n * },\n * }\n * ```\n */\n inputTransforms?: InputTransformOptions;\n\n /**\n * Tool transforms for modifying generated tools (description, annotations, UI, etc.).\n *\n * Use cases:\n * - Add annotations (readOnlyHint, openWorldHint) based on HTTP method\n * - Override tool descriptions with combined summary + description\n * - Add UI configuration for tool forms\n * - Hide internal tools from discovery\n *\n * @example\n * ```typescript\n * toolTransforms: {\n * global: {\n * annotations: { openWorldHint: true },\n * },\n * perTool: {\n * 'createUser': {\n * annotations: { destructiveHint: false },\n * tags: ['user-management'],\n * },\n * },\n * generator: (tool) => {\n * if (tool.metadata.method === 'get') {\n * return { annotations: { readOnlyHint: true } };\n * }\n * if (tool.metadata.method === 'delete') {\n * return { annotations: { destructiveHint: true } };\n * }\n * return undefined;\n * },\n * }\n * ```\n */\n toolTransforms?: ToolTransformOptions;\n\n /**\n * How to generate tool descriptions from OpenAPI operations.\n * - 'summaryOnly': Use only summary (default)\n * - 'descriptionOnly': Use only description\n * - 'combined': Summary followed by description\n * - 'full': Summary, description, and operation details\n *\n * @default 'summaryOnly'\n */\n descriptionMode?: DescriptionMode;\n\n /**\n * Logger instance for adapter diagnostics.\n * Optional - if not provided, the SDK will inject it automatically via setLogger().\n */\n logger?: FrontMcpLogger;\n\n /**\n * Timeout for HTTP requests in milliseconds.\n * If a request takes longer than this, it will be aborted.\n * @default 30000 (30 seconds)\n */\n requestTimeoutMs?: number;\n\n /**\n * Maximum request body size in bytes.\n * Requests with bodies larger than this will be rejected before sending.\n * @default 10485760 (10MB)\n */\n maxRequestSize?: number;\n\n /**\n * Maximum response size in bytes.\n * Responses larger than this will be rejected.\n * The check is performed first on Content-Length header (if present),\n * then on actual response size.\n * @default 10485760 (10MB)\n */\n maxResponseSize?: number;\n}\n\ninterface SpecOptions extends BaseOptions {\n /**\n * The OpenAPI specification as a JSON object.\n *\n * Accepts:\n * - `OpenAPIV3.Document` (typed)\n * - `OpenAPIV3_1.Document` (typed)\n * - Plain object from `import spec from './openapi.json'`\n *\n * @example\n * ```typescript\n * // From typed constant\n * import { OpenAPIV3 } from 'openapi-types';\n * const spec: OpenAPIV3.Document = { ... };\n * new OpenapiAdapter({ spec, ... })\n *\n * // From JSON import\n * import openapiJson from './my-openapi.json';\n * new OpenapiAdapter({ spec: openapiJson, ... })\n * ```\n */\n spec: OpenAPIV3.Document | OpenAPIV3_1.Document | object;\n}\n\ninterface UrlOptions extends BaseOptions {\n /**\n * The URL of the OpenAPI specification.\n * Can be a local file path or a remote URL.\n */\n url: string;\n}\n\nexport type OpenApiAdapterOptions = SpecOptions | UrlOptions;\n"]}
|