@frontmcp/adapters 0.3.1 → 0.4.0

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.
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildRequest = buildRequest;
4
+ exports.applyAdditionalHeaders = applyAdditionalHeaders;
5
+ exports.parseResponse = parseResponse;
6
+ /**
7
+ * Build HTTP request from OpenAPI tool and input parameters
8
+ *
9
+ * @param tool - OpenAPI tool definition with mapper
10
+ * @param input - User input parameters
11
+ * @param security - Resolved security (headers, query params, etc.)
12
+ * @param baseUrl - API base URL
13
+ * @returns Request configuration ready for fetch
14
+ */
15
+ function buildRequest(tool, input, security, baseUrl) {
16
+ const apiBaseUrl = tool.metadata.servers?.[0]?.url || baseUrl;
17
+ let path = tool.metadata.path;
18
+ const queryParams = new URLSearchParams();
19
+ const headers = new Headers({
20
+ accept: 'application/json',
21
+ ...security.headers,
22
+ });
23
+ let body;
24
+ // Process each mapper entry
25
+ for (const mapper of tool.mapper) {
26
+ // Skip security parameters (already handled by SecurityResolver)
27
+ if (mapper.security)
28
+ continue;
29
+ const value = input[mapper.inputKey];
30
+ // Check required parameters
31
+ if (value === undefined || value === null) {
32
+ if (mapper.required) {
33
+ throw new Error(`Required parameter '${mapper.inputKey}' is missing for operation ${tool.name}`);
34
+ }
35
+ continue;
36
+ }
37
+ // Apply parameter to correct location
38
+ switch (mapper.type) {
39
+ case 'path':
40
+ path = path.replace(`{${mapper.key}}`, encodeURIComponent(String(value)));
41
+ break;
42
+ case 'query':
43
+ queryParams.set(mapper.key, String(value));
44
+ break;
45
+ case 'header':
46
+ headers.set(mapper.key, String(value));
47
+ break;
48
+ case 'cookie':
49
+ // Simple cookie header merge; you may want a more robust cookie encoder.
50
+ {
51
+ const existing = headers.get('cookie') ?? headers.get('Cookie');
52
+ const cookiePair = `${mapper.key}=${encodeURIComponent(String(value))}`;
53
+ const combined = existing ? `${existing}; ${cookiePair}` : cookiePair;
54
+ headers.set('Cookie', combined);
55
+ }
56
+ break;
57
+ case 'body':
58
+ if (!body)
59
+ body = {};
60
+ body[mapper.key] = value;
61
+ break;
62
+ }
63
+ }
64
+ // Add query parameters from security (e.g., API keys in query string)
65
+ Object.entries(security.query).forEach(([key, value]) => {
66
+ queryParams.set(key, value);
67
+ });
68
+ // Add cookies from a security context
69
+ if (security.cookies && Object.keys(security.cookies).length > 0) {
70
+ const existing = headers.get('cookie') ?? headers.get('Cookie');
71
+ const securityCookieString = Object.entries(security.cookies)
72
+ .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
73
+ .join('; ');
74
+ const combined = existing ? `${existing}; ${securityCookieString}` : securityCookieString;
75
+ headers.set('Cookie', combined);
76
+ }
77
+ // Ensure all path parameters are resolved
78
+ if (path.includes('{')) {
79
+ throw new Error(`Failed to resolve all path parameters in ${path} for operation ${tool.name}`);
80
+ }
81
+ // Build final URL
82
+ const queryString = queryParams.toString();
83
+ const url = `${apiBaseUrl}${path}${queryString ? `?${queryString}` : ''}`;
84
+ return { url, headers, body };
85
+ }
86
+ /**
87
+ * Apply custom headers to request
88
+ *
89
+ * @param headers - Current headers
90
+ * @param additionalHeaders - Additional static headers to add
91
+ */
92
+ function applyAdditionalHeaders(headers, additionalHeaders) {
93
+ if (!additionalHeaders)
94
+ return;
95
+ Object.entries(additionalHeaders).forEach(([key, value]) => {
96
+ headers.set(key, value);
97
+ });
98
+ }
99
+ /**
100
+ * Parse API response based on content type
101
+ *
102
+ * @param response - Fetch response
103
+ * @returns Parsed response data
104
+ */
105
+ async function parseResponse(response) {
106
+ const contentType = response.headers.get('content-type');
107
+ const text = await response.text();
108
+ // Check for error responses
109
+ if (!response.ok) {
110
+ throw new Error(`API request failed: ${response.status} ${response.statusText}\n${text}`);
111
+ }
112
+ // Parse JSON responses
113
+ if (contentType?.includes('application/json')) {
114
+ try {
115
+ return { data: JSON.parse(text) };
116
+ }
117
+ catch (error) {
118
+ // Invalid JSON, return as text
119
+ console.warn('Failed to parse JSON response:', error);
120
+ return { data: text };
121
+ }
122
+ }
123
+ // Return text for non-JSON responses
124
+ return { data: text };
125
+ }
126
+ //# sourceMappingURL=openapi.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.utils.js","sourceRoot":"","sources":["../../../src/openapi/openapi.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { McpOpenAPITool, SecurityResolver } from 'mcp-from-openapi';\n\n/**\n * Request configuration for building HTTP requests\n */\nexport interface RequestConfig {\n url: string;\n headers: Headers;\n body?: Record<string, unknown>;\n}\n\n/**\n * Build HTTP request from OpenAPI tool and input parameters\n *\n * @param tool - OpenAPI tool definition with mapper\n * @param input - User input parameters\n * @param security - Resolved security (headers, query params, etc.)\n * @param baseUrl - API base URL\n * @returns Request configuration ready for fetch\n */\nexport function buildRequest(\n tool: McpOpenAPITool,\n input: Record<string, unknown>,\n security: Awaited<ReturnType<SecurityResolver['resolve']>>,\n baseUrl: string,\n): RequestConfig {\n const apiBaseUrl = tool.metadata.servers?.[0]?.url || baseUrl;\n let path = tool.metadata.path;\n const queryParams = new URLSearchParams();\n const headers = new Headers({\n accept: 'application/json',\n ...security.headers,\n });\n let body: Record<string, unknown> | undefined;\n\n // Process each mapper entry\n for (const mapper of tool.mapper) {\n // Skip security parameters (already handled by SecurityResolver)\n if (mapper.security) continue;\n\n const value = input[mapper.inputKey];\n\n // Check required parameters\n if (value === undefined || value === null) {\n if (mapper.required) {\n throw new Error(`Required parameter '${mapper.inputKey}' is missing for operation ${tool.name}`);\n }\n continue;\n }\n\n // Apply parameter to correct location\n switch (mapper.type) {\n case 'path':\n path = path.replace(`{${mapper.key}}`, encodeURIComponent(String(value)));\n break;\n\n case 'query':\n queryParams.set(mapper.key, String(value));\n break;\n\n case 'header':\n headers.set(mapper.key, String(value));\n break;\n case 'cookie':\n // Simple cookie header merge; you may want a more robust cookie encoder.\n {\n const existing = headers.get('cookie') ?? headers.get('Cookie');\n const cookiePair = `${mapper.key}=${encodeURIComponent(String(value))}`;\n const combined = existing ? `${existing}; ${cookiePair}` : cookiePair;\n headers.set('Cookie', combined);\n }\n break;\n\n case 'body':\n if (!body) body = {};\n body[mapper.key] = value;\n break;\n }\n }\n\n // Add query parameters from security (e.g., API keys in query string)\n Object.entries(security.query).forEach(([key, value]) => {\n queryParams.set(key, value);\n });\n\n // Add cookies from a security context\n if (security.cookies && Object.keys(security.cookies).length > 0) {\n const existing = headers.get('cookie') ?? headers.get('Cookie');\n const securityCookieString = Object.entries(security.cookies)\n .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)\n .join('; ');\n const combined = existing ? `${existing}; ${securityCookieString}` : securityCookieString;\n headers.set('Cookie', combined);\n }\n\n // Ensure all path parameters are resolved\n if (path.includes('{')) {\n throw new Error(`Failed to resolve all path parameters in ${path} for operation ${tool.name}`);\n }\n\n // Build final URL\n const queryString = queryParams.toString();\n const url = `${apiBaseUrl}${path}${queryString ? `?${queryString}` : ''}`;\n\n return { url, headers, body };\n}\n\n/**\n * Apply custom headers to request\n *\n * @param headers - Current headers\n * @param additionalHeaders - Additional static headers to add\n */\nexport function applyAdditionalHeaders(headers: Headers, additionalHeaders?: Record<string, string>): void {\n if (!additionalHeaders) return;\n\n Object.entries(additionalHeaders).forEach(([key, value]) => {\n headers.set(key, value);\n });\n}\n\n/**\n * Parse API response based on content type\n *\n * @param response - Fetch response\n * @returns Parsed response data\n */\nexport async function parseResponse(response: Response): Promise<{ data: unknown }> {\n const contentType = response.headers.get('content-type');\n const text = await response.text();\n\n // Check for error responses\n if (!response.ok) {\n throw new Error(`API request failed: ${response.status} ${response.statusText}\\n${text}`);\n }\n\n // Parse JSON responses\n if (contentType?.includes('application/json')) {\n try {\n return { data: JSON.parse(text) };\n } catch (error) {\n // Invalid JSON, return as text\n console.warn('Failed to parse JSON response:', error);\n return { data: text };\n }\n }\n\n // Return text for non-JSON responses\n return { data: text };\n}\n"]}