Skip to main content
Glama

api_endpoints

List API endpoints from an imported API specification, filtered by tag, method, or path. Auto-selects the only imported spec if name is not given.

Instructions

Lista los endpoints de un API importada. Filtra por tag, método o path. Si no se especifica nombre y solo hay un spec importado, lo usa automáticamente.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameNoNombre del API importada. Si se omite y solo hay un spec, lo usa automáticamente
tagNoFiltrar por tag (ej: "blog", "auth", "users")
methodNoFiltrar por método HTTP
pathNoFiltrar por path (búsqueda parcial, ej: "/blog" muestra todos los que contienen /blog)

Implementation Reference

  • The 'api_endpoints' tool handler. Registered as an MCP tool that lists endpoints of an imported OpenAPI spec. Accepts optional filters: name (spec name), tag, method, path. Resolves the spec name, fetches endpoints from storage, applies filters, and returns formatted output.
    server.tool(
      'api_endpoints',
      'Lista los endpoints de un API importada. Filtra por tag, método o path. Si no se especifica nombre y solo hay un spec importado, lo usa automáticamente.',
      {
        name: z
          .string()
          .optional()
          .describe('Nombre del API importada. Si se omite y solo hay un spec, lo usa automáticamente'),
        tag: z
          .string()
          .optional()
          .describe('Filtrar por tag (ej: "blog", "auth", "users")'),
        method: z
          .enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])
          .optional()
          .describe('Filtrar por método HTTP'),
        path: z
          .string()
          .optional()
          .describe('Filtrar por path (búsqueda parcial, ej: "/blog" muestra todos los que contienen /blog)'),
      },
      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,
            }
          }
    
          let endpoints = spec.endpoints
    
          // Apply filters
          if (params.tag) {
            endpoints = endpoints.filter((ep) =>
              (ep.tags ?? []).some((t) => t.toLowerCase() === params.tag!.toLowerCase()),
            )
          }
          if (params.method) {
            endpoints = endpoints.filter((ep) => ep.method === params.method)
          }
          if (params.path) {
            const search = params.path.toLowerCase()
            endpoints = endpoints.filter((ep) => ep.path.toLowerCase().includes(search))
          }
    
          if (endpoints.length === 0) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: 'No se encontraron endpoints con los filtros aplicados.',
                },
              ],
            }
          }
    
          // Format output
          const lines = endpoints.map((ep) => {
            const tags = ep.tags?.length ? ` [${ep.tags.join(', ')}]` : ''
            const summary = ep.summary ? ` — ${ep.summary}` : ''
            return `${ep.method.padEnd(7)} ${ep.path}${summary}${tags}`
          })
    
          return {
            content: [
              {
                type: 'text' as const,
                text: [
                  `API: ${spec.name} (${endpoints.length} endpoints)`,
                  '',
                  ...lines,
                  '',
                  'Usa api_endpoint_detail para ver parámetros, body y respuestas de un endpoint.',
                ].join('\n'),
              },
            ],
          }
        } catch (error) {
          const message = error instanceof Error ? error.message : String(error)
          return {
            content: [{ type: 'text' as const, text: `Error: ${message}` }],
            isError: true,
          }
        }
      },
    )
  • Zod schema definitions for the api_endpoints tool inputs: optional name (string), optional tag (string), optional method (enum of HTTP methods), optional path (string).
    {
      name: z
        .string()
        .optional()
        .describe('Nombre del API importada. Si se omite y solo hay un spec, lo usa automáticamente'),
      tag: z
        .string()
        .optional()
        .describe('Filtrar por tag (ej: "blog", "auth", "users")'),
      method: z
        .enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])
        .optional()
        .describe('Filtrar por método HTTP'),
      path: z
        .string()
        .optional()
        .describe('Filtrar por path (búsqueda parcial, ej: "/blog" muestra todos los que contienen /blog)'),
    },
  • The api_endpoints tool is registered inside registerApiSpecTools() by calling server.tool('api_endpoints', ...). The registration function is exported and invoked at src/server.ts:65.
    server.tool(
      'api_endpoints',
      'Lista los endpoints de un API importada. Filtra por tag, método o path. Si no se especifica nombre y solo hay un spec importado, lo usa automáticamente.',
      {
        name: z
          .string()
          .optional()
          .describe('Nombre del API importada. Si se omite y solo hay un spec, lo usa automáticamente'),
        tag: z
          .string()
          .optional()
          .describe('Filtrar por tag (ej: "blog", "auth", "users")'),
        method: z
          .enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])
          .optional()
          .describe('Filtrar por método HTTP'),
        path: z
          .string()
          .optional()
          .describe('Filtrar por path (búsqueda parcial, ej: "/blog" muestra todos los que contienen /blog)'),
      },
      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,
            }
          }
    
          let endpoints = spec.endpoints
    
          // Apply filters
          if (params.tag) {
            endpoints = endpoints.filter((ep) =>
              (ep.tags ?? []).some((t) => t.toLowerCase() === params.tag!.toLowerCase()),
            )
          }
          if (params.method) {
            endpoints = endpoints.filter((ep) => ep.method === params.method)
          }
          if (params.path) {
            const search = params.path.toLowerCase()
            endpoints = endpoints.filter((ep) => ep.path.toLowerCase().includes(search))
          }
    
          if (endpoints.length === 0) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: 'No se encontraron endpoints con los filtros aplicados.',
                },
              ],
            }
          }
    
          // Format output
          const lines = endpoints.map((ep) => {
            const tags = ep.tags?.length ? ` [${ep.tags.join(', ')}]` : ''
            const summary = ep.summary ? ` — ${ep.summary}` : ''
            return `${ep.method.padEnd(7)} ${ep.path}${summary}${tags}`
          })
    
          return {
            content: [
              {
                type: 'text' as const,
                text: [
                  `API: ${spec.name} (${endpoints.length} endpoints)`,
                  '',
                  ...lines,
                  '',
                  'Usa api_endpoint_detail para ver parámetros, body y respuestas de un endpoint.',
                ].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/server.ts:65-65 (registration)
    Wire-up call: registerApiSpecTools(server, storage) registers all API spec tools including api_endpoints on the MCP server.
    registerApiSpecTools(server, storage)
  • The resolveSpecName helper function used by api_endpoints to determine which imported spec to query. Supports explicit name, active environment spec, or automatic single-spec fallback.
    async function resolveSpecName(
      name: string | undefined,
      storage: Storage,
    ): Promise<{ name: string; error?: never } | { name?: never; error: string }> {
      if (name) return { name }
    
      // Try active environment spec
      const activeSpec = await storage.getActiveSpec()
      if (activeSpec) return { name: activeSpec }
    
      // Fallback to single spec
      const specs = await storage.listSpecs()
      if (specs.length === 0) {
        return { error: 'No hay specs importados. Usa api_import para importar uno.' }
      }
      if (specs.length === 1) {
        return { name: specs[0].name }
      }
      return {
        error: `Hay ${specs.length} specs importados. Especifica cuál usar: ${specs.map((s) => s.name).join(', ')}`,
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It states the tool lists and filters endpoints, but does not disclose any behavioral traits like read-onlyness, authentication requirements, rate limits, or side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no fluff. The purpose and key functionality are front-loaded. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple listing tool with 4 optional parameters and no output schema, the description adequately covers purpose and filtering. However, it lacks information on return format, pagination, or what fields are included in the endpoint list.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so baseline is 3. The description adds the auto-selection behavior for the 'name' parameter when omitted, which provides meaning beyond the schema. No further parameter details.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states it lists endpoints of an imported API, with explicit verb 'lista' and resource 'endpoints'. It also mentions filtering by tag, method, or path, differentiating it from sibling tools like api_endpoint_detail (likely details on a single endpoint) and api_spec_list (lists specs).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use or when-not-to-use guidance against siblings. It does mention auto-selection of the spec if only one is imported and name omitted, which is a usage hint, but lacks alternatives or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cocaxcode/api-testing-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server