export_curl
Convert saved API requests into ready-to-use cURL commands, with optional variable resolution for copying and pasting.
Instructions
Genera un comando cURL a partir de un request guardado en la colección. Listo para copiar y pegar.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Nombre del request guardado en la colección | |
| resolve_variables | No | Resolver {{variables}} del entorno activo (default: true) |
Implementation Reference
- src/tools/utilities.ts:25-118 (handler)The async handler function for the 'export_curl' tool. It retrieves a saved request from storage by name, optionally resolves {{variables}} from the active environment, then builds a cURL command string. The cURL includes method (-X), URL with query params, headers (-H), auth (bearer/api-key/basic), and body (-d). Returns the command formatted for copying/pasting.
async (params) => { try { const saved = await storage.getCollection(params.name) if (!saved) { return { content: [ { type: 'text' as const, text: `Error: Request '${params.name}' no encontrado en la colección.`, }, ], isError: true, } } let config = saved.request const resolveVars = params.resolve_variables ?? true if (resolveVars) { const variables = await storage.getActiveVariables() const resolvedUrl = resolveUrl(config.url, variables) config = { ...config, url: resolvedUrl } config = interpolateRequest(config, variables) } // Build cURL command const parts: string[] = ['curl'] if (config.method !== 'GET') { parts.push(`-X ${config.method}`) } let url = config.url if (config.query && Object.keys(config.query).length > 0) { const queryStr = Object.entries(config.query) .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) .join('&') url += (url.includes('?') ? '&' : '?') + queryStr } parts.push(`'${url}'`) if (config.headers) { for (const [key, value] of Object.entries(config.headers)) { parts.push(`-H '${key}: ${value}'`) } } if (config.auth) { switch (config.auth.type) { case 'bearer': if (config.auth.token) { parts.push(`-H 'Authorization: Bearer ${config.auth.token}'`) } break case 'api-key': if (config.auth.key) { const header = config.auth.header ?? 'X-API-Key' parts.push(`-H '${header}: ${config.auth.key}'`) } break case 'basic': if (config.auth.username && config.auth.password) { parts.push(`-u '${config.auth.username}:${config.auth.password}'`) } break } } if (config.body !== undefined && config.body !== null) { const bodyStr = typeof config.body === 'string' ? config.body : JSON.stringify(config.body) parts.push(`-H 'Content-Type: application/json'`) parts.push(`-d '${bodyStr}'`) } const curlCommand = parts.join(' \\\n ') return { content: [ { type: 'text' as const, text: `cURL para '${params.name}':\n\n${curlCommand}`, }, ], } } catch (error) { const message = error instanceof Error ? error.message : String(error) return { content: [{ type: 'text' as const, text: `Error: ${message}` }], isError: true, } } }, ) - src/tools/utilities.ts:18-23 (schema)Input schema for the 'export_curl' tool: 'name' (string, required) - the saved request name; 'resolve_variables' (boolean, optional, default true) - whether to resolve {{variables}} from the active environment.
{ name: z.string().describe('Nombre del request guardado en la colección'), resolve_variables: z .boolean() .optional() .describe('Resolver {{variables}} del entorno activo (default: true)'), - src/tools/utilities.ts:12-118 (registration)The tool is registered via server.tool('export_curl', ...) inside the registerUtilityTools() function exported from src/tools/utilities.ts. This function is called with the MCP server instance from src/server.ts (line 68) during server creation.
export function registerUtilityTools(server: McpServer, storage: Storage): void { // ── export_curl ── server.tool( 'export_curl', 'Genera un comando cURL a partir de un request guardado en la colección. Listo para copiar y pegar.', { name: z.string().describe('Nombre del request guardado en la colección'), resolve_variables: z .boolean() .optional() .describe('Resolver {{variables}} del entorno activo (default: true)'), }, async (params) => { try { const saved = await storage.getCollection(params.name) if (!saved) { return { content: [ { type: 'text' as const, text: `Error: Request '${params.name}' no encontrado en la colección.`, }, ], isError: true, } } let config = saved.request const resolveVars = params.resolve_variables ?? true if (resolveVars) { const variables = await storage.getActiveVariables() const resolvedUrl = resolveUrl(config.url, variables) config = { ...config, url: resolvedUrl } config = interpolateRequest(config, variables) } // Build cURL command const parts: string[] = ['curl'] if (config.method !== 'GET') { parts.push(`-X ${config.method}`) } let url = config.url if (config.query && Object.keys(config.query).length > 0) { const queryStr = Object.entries(config.query) .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) .join('&') url += (url.includes('?') ? '&' : '?') + queryStr } parts.push(`'${url}'`) if (config.headers) { for (const [key, value] of Object.entries(config.headers)) { parts.push(`-H '${key}: ${value}'`) } } if (config.auth) { switch (config.auth.type) { case 'bearer': if (config.auth.token) { parts.push(`-H 'Authorization: Bearer ${config.auth.token}'`) } break case 'api-key': if (config.auth.key) { const header = config.auth.header ?? 'X-API-Key' parts.push(`-H '${header}: ${config.auth.key}'`) } break case 'basic': if (config.auth.username && config.auth.password) { parts.push(`-u '${config.auth.username}:${config.auth.password}'`) } break } } if (config.body !== undefined && config.body !== null) { const bodyStr = typeof config.body === 'string' ? config.body : JSON.stringify(config.body) parts.push(`-H 'Content-Type: application/json'`) parts.push(`-d '${bodyStr}'`) } const curlCommand = parts.join(' \\\n ') return { content: [ { type: 'text' as const, text: `cURL para '${params.name}':\n\n${curlCommand}`, }, ], } } catch (error) { const message = error instanceof Error ? error.message : String(error) return { content: [{ type: 'text' as const, text: `Error: ${message}` }], isError: true, } } }, ) - src/lib/interpolation.ts:66-80 (helper)interpolateRequest() is called from the handler to resolve {{variables}} in all request fields (url, headers, body, query, auth) before building the cURL command.
export function interpolateRequest( config: RequestConfig, variables: Record<string, string>, ): RequestConfig { return { ...config, url: interpolateString(config.url, variables), headers: interpolateRecord(config.headers, variables), query: interpolateRecord(config.query, variables), body: config.body !== undefined ? interpolateValue(config.body, variables) : undefined, auth: config.auth ? (interpolateValue(config.auth, variables) as RequestConfig['auth']) : undefined, } } - src/lib/url.ts:5-11 (helper)resolveUrl() is called from the handler to prepend BASE_URL to relative URLs (starting with '/') before building the cURL command.
export function resolveUrl(url: string, variables: Record<string, string>): string { if (url.startsWith('/') && variables.BASE_URL) { const baseUrl = variables.BASE_URL.replace(/\/+$/, '') return `${baseUrl}${url}` } return url }