api_endpoint_detail
Retrieve complete endpoint details including parameters, body schema, and responses. Use to determine the required data structure for any HTTP request.
Instructions
Muestra el detalle completo de un endpoint: parámetros, body schema, y respuestas. Útil para saber qué datos enviar.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Nombre del API importada. Si se omite y solo hay un spec, lo usa automáticamente | |
| method | Yes | Método HTTP del endpoint | |
| path | Yes | Path exacto del endpoint (ej: "/blog", "/auth/login") |
Implementation Reference
- src/tools/api-spec.ts:325-465 (registration)Registration of the 'api_endpoint_detail' tool via server.tool(), including its Zod schema for parameters (name, method, path) and the handler function.
server.tool( 'api_endpoint_detail', 'Muestra el detalle completo de un endpoint: parámetros, body schema, y respuestas. Útil para saber qué datos enviar.', { name: z .string() .optional() .describe('Nombre del API importada. Si se omite y solo hay un spec, lo usa automáticamente'), method: z .enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']) .describe('Método HTTP del endpoint'), path: z .string() .describe('Path exacto del endpoint (ej: "/blog", "/auth/login")'), }, async (params) => { try { const resolved = await resolveSpecName(params.name, storage) if (resolved.error) { return { content: [{ type: 'text' as const, text: resolved.error }], isError: true, } } const resolvedName = resolved.name as string const spec = await storage.getSpec(resolvedName) if (!spec) { return { content: [ { type: 'text' as const, text: `Error: API '${resolvedName}' no encontrada. Usa api_import para importarla primero.`, }, ], isError: true, } } const endpoint = spec.endpoints.find( (ep) => ep.method === params.method && ep.path === params.path, ) if (!endpoint) { // Try partial match const similar = spec.endpoints.filter((ep) => ep.path.includes(params.path) || params.path.includes(ep.path), ) const suggestion = similar.length > 0 ? `\n\nEndpoints similares:\n${similar.map((ep) => ` ${ep.method} ${ep.path}`).join('\n')}` : '' return { content: [ { type: 'text' as const, text: `Error: Endpoint ${params.method} ${params.path} no encontrado.${suggestion}`, }, ], isError: true, } } // Build detailed output const sections: string[] = [] // Header sections.push(`## ${endpoint.method} ${endpoint.path}`) if (endpoint.summary) sections.push(`**${endpoint.summary}**`) if (endpoint.description) sections.push(endpoint.description) if (endpoint.tags?.length) sections.push(`Tags: ${endpoint.tags.join(', ')}`) // Parameters if (endpoint.parameters?.length) { sections.push('') sections.push('### Parámetros') for (const param of endpoint.parameters) { const required = param.required ? ' (requerido)' : ' (opcional)' const type = param.schema?.type ?? 'string' const desc = param.description ? ` — ${param.description}` : '' sections.push(`- **${param.name}** [${param.in}] ${type}${required}${desc}`) } } // Request body if (endpoint.requestBody) { sections.push('') sections.push('### Body') const required = endpoint.requestBody.required ? ' (requerido)' : ' (opcional)' sections.push(`Body${required}`) if (endpoint.requestBody.content) { for (const [contentType, media] of Object.entries(endpoint.requestBody.content)) { sections.push(`\nContent-Type: ${contentType}`) if (media.schema) { sections.push('```json') sections.push(formatSchema(media.schema)) sections.push('```') } } } } // Responses if (endpoint.responses) { sections.push('') sections.push('### Respuestas') for (const [status, resp] of Object.entries(endpoint.responses)) { const desc = resp.description ? ` — ${resp.description}` : '' sections.push(`\n**${status}**${desc}`) if (resp.content) { for (const [, media] of Object.entries(resp.content)) { if (media.schema) { sections.push('```json') sections.push(formatSchema(media.schema)) sections.push('```') } } } } } return { content: [ { type: 'text' as const, text: sections.join('\n'), }, ], } } catch (error) { const message = error instanceof Error ? error.message : String(error) return { content: [{ type: 'text' as const, text: `Error: ${message}` }], isError: true, } } }, ) - src/tools/api-spec.ts:340-464 (handler)Handler function for api_endpoint_detail: resolves the spec name, finds the endpoint by method+path, builds detailed output with parameters, request body, and responses, and returns formatted text.
async (params) => { try { const resolved = await resolveSpecName(params.name, storage) if (resolved.error) { return { content: [{ type: 'text' as const, text: resolved.error }], isError: true, } } const resolvedName = resolved.name as string const spec = await storage.getSpec(resolvedName) if (!spec) { return { content: [ { type: 'text' as const, text: `Error: API '${resolvedName}' no encontrada. Usa api_import para importarla primero.`, }, ], isError: true, } } const endpoint = spec.endpoints.find( (ep) => ep.method === params.method && ep.path === params.path, ) if (!endpoint) { // Try partial match const similar = spec.endpoints.filter((ep) => ep.path.includes(params.path) || params.path.includes(ep.path), ) const suggestion = similar.length > 0 ? `\n\nEndpoints similares:\n${similar.map((ep) => ` ${ep.method} ${ep.path}`).join('\n')}` : '' return { content: [ { type: 'text' as const, text: `Error: Endpoint ${params.method} ${params.path} no encontrado.${suggestion}`, }, ], isError: true, } } // Build detailed output const sections: string[] = [] // Header sections.push(`## ${endpoint.method} ${endpoint.path}`) if (endpoint.summary) sections.push(`**${endpoint.summary}**`) if (endpoint.description) sections.push(endpoint.description) if (endpoint.tags?.length) sections.push(`Tags: ${endpoint.tags.join(', ')}`) // Parameters if (endpoint.parameters?.length) { sections.push('') sections.push('### Parámetros') for (const param of endpoint.parameters) { const required = param.required ? ' (requerido)' : ' (opcional)' const type = param.schema?.type ?? 'string' const desc = param.description ? ` — ${param.description}` : '' sections.push(`- **${param.name}** [${param.in}] ${type}${required}${desc}`) } } // Request body if (endpoint.requestBody) { sections.push('') sections.push('### Body') const required = endpoint.requestBody.required ? ' (requerido)' : ' (opcional)' sections.push(`Body${required}`) if (endpoint.requestBody.content) { for (const [contentType, media] of Object.entries(endpoint.requestBody.content)) { sections.push(`\nContent-Type: ${contentType}`) if (media.schema) { sections.push('```json') sections.push(formatSchema(media.schema)) sections.push('```') } } } } // Responses if (endpoint.responses) { sections.push('') sections.push('### Respuestas') for (const [status, resp] of Object.entries(endpoint.responses)) { const desc = resp.description ? ` — ${resp.description}` : '' sections.push(`\n**${status}**${desc}`) if (resp.content) { for (const [, media] of Object.entries(resp.content)) { if (media.schema) { sections.push('```json') sections.push(formatSchema(media.schema)) sections.push('```') } } } } } return { content: [ { type: 'text' as const, text: sections.join('\n'), }, ], } } catch (error) { const message = error instanceof Error ? error.message : String(error) return { content: [{ type: 'text' as const, text: `Error: ${message}` }], isError: true, } } }, - src/tools/api-spec.ts:328-339 (schema)Zod schema for api_endpoint_detail inputs: 'name' (optional string), 'method' (enum of HTTP methods), 'path' (string for exact endpoint path).
{ name: z .string() .optional() .describe('Nombre del API importada. Si se omite y solo hay un spec, lo usa automáticamente'), method: z .enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']) .describe('Método HTTP del endpoint'), path: z .string() .describe('Path exacto del endpoint (ej: "/blog", "/auth/login")'), }, - src/server.ts:65-65 (registration)Registration call that wires registerApiSpecTools into the server, making api_endpoint_detail available.
registerApiSpecTools(server, storage) - src/tools/api-spec.ts:468-550 (helper)formatSchema helper function used by the handler to generate human-readable JSON examples from schema definitions.
/** * Formatea un schema como ejemplo JSON legible. * Genera un ejemplo basado en los tipos y propiedades del schema. */ function formatSchema(schema: { type?: string; properties?: Record<string, unknown>; items?: unknown; required?: string[]; enum?: unknown[]; example?: unknown; format?: string; description?: string }, depth = 0): string { if (depth > 5) return '"..."' const indent = ' '.repeat(depth) const innerIndent = ' '.repeat(depth + 1) if (schema.example !== undefined) { return JSON.stringify(schema.example, null, 2) .split('\n') .map((line, i) => (i === 0 ? line : indent + line)) .join('\n') } if (schema.enum) { return JSON.stringify(schema.enum[0]) } if (schema.type === 'object' && schema.properties) { const props = Object.entries(schema.properties as Record<string, Record<string, unknown>>) if (props.length === 0) return '{}' const requiredFields = new Set(schema.required ?? []) const lines: string[] = ['{'] for (const [key, prop] of props) { const isRequired = requiredFields.has(key) const comment = [] if (prop.description) comment.push(prop.description as string) if (!isRequired) comment.push('opcional') const commentStr = comment.length > 0 ? ` // ${comment.join(' — ')}` : '' const value = formatSchema(prop as typeof schema, depth + 1) lines.push(`${innerIndent}"${key}": ${value},${commentStr}`) } lines.push(`${indent}}`) return lines.join('\n') } if (schema.type === 'array' && schema.items) { const itemValue = formatSchema(schema.items as typeof schema, depth + 1) return `[${itemValue}]` } // Primitive types switch (schema.type) { case 'string': if (schema.format === 'date-time') return '"2024-01-01T00:00:00Z"' if (schema.format === 'email') return '"user@example.com"' if (schema.format === 'uri' || schema.format === 'url') return '"https://example.com"' return '"string"' case 'number': case 'integer': return '0' case 'boolean': return 'true' default: return 'null' } }