Skip to main content
Glama

hono-apcore

Adaptador de Hono para el ecosistema de módulos AI-Perceivable de apcore. Convierte una aplicación de Hono en herramientas MCP y definiciones de funciones compatibles con OpenAI, ya sea declarando herramientas explícitamente o escaneando las rutas que ya tienes.

Características

  • Dos formas de entrada — declara herramientas con defineTool() / defineToolset(), o escanea tus rutas existentes sin cambios de código.

  • Reproducción de rutas — una ruta escaneada se convierte en un módulo que vuelve a llamar a través de app.request(), de modo que el middleware, los validadores y los manejadores de errores siguen ejecutándose.

  • Un solo puertomountMcp() sirve el endpoint de MCP, el Tool Explorer y /health desde la misma aplicación de Hono.

  • Inferencia de anotacionesGET → readonly + cacheable, PUT → idempotent, DELETE → destructive (semántica de métodos seguros de RFC 9110).

  • Multi-esquema — TypeBox, Zod 3, Zod 4 y JSON Schema plano, auto-detectados mediante una cadena de prioridad.

  • Contexto, ACL e identidad — el middleware apcore() construye un Context de apcore por petición con propagación de trazas W3C, de modo que las reglas ACL también gobiernan tus rutas.

  • Núcleo independiente del runtimeapcore-mcp, apcore-cli y apcore-a2a son pares opcionales que se cargan de forma diferida, por lo que importar hono-apcore nunca arrastra node:http a una compilación de edge.

  • CLIhono-apcore scan | serve | export funciona con una aplicación de Hono simple.

  • Enlaces YAML — registra módulos de forma declarativa, sin tocar el código fuente.

Related MCP server: Graft

Instalación

npm install hono-apcore hono

Pares opcionales, instalados solo para las superficies que uses:

npm install apcore-mcp @modelcontextprotocol/sdk   # MCP server + Tool Explorer
npm install @hono/node-server                      # mountMcp() on the Node runtime
npm install apcore-cli                             # CLI surface
npm install apcore-a2a                             # A2A agent surface
npm install @sinclair/typebox                      # TypeBox schemas (recommended)
npm install zod                                    # Zod schemas

Requisitos: Node.js >= 18, Hono >= 4 (probado con Hono 4.13).

Inicio rápido

1. Declara algunas herramientas

// todo.tools.ts
import { Type } from '@sinclair/typebox';
import { defineToolset } from 'hono-apcore';

export const todoTools = defineToolset({
  namespace: 'todo',
  description: 'Todo list management',
  tags: ['todo'],
  tools: {
    list: {
      description: 'List all todos, optionally filtered by status',
      inputSchema: Type.Object({ done: Type.Optional(Type.Boolean()) }),
      annotations: { readonly: true, idempotent: true },
      handler: (inputs) => ({ todos: store.list(inputs.done as boolean | undefined) }),
    },
    add: {
      description: 'Add a new todo item',
      inputSchema: Type.Object({ title: Type.String() }),
      annotations: { readonly: false },
      handler: (inputs) => ({ todo: store.add(String(inputs.title)) }),
    },
  },
});

2. Conéctalo a la aplicación

// app.ts
import { Hono } from 'hono';
import { apcore, createApcore } from 'hono-apcore';
import { todoTools } from './todo.tools.js';

export const ap = createApcore({
  tools: todoTools,
  mcp: { name: 'my-app', explorer: true, allowExecute: true },
});

export const app = new Hono();
app.use('*', apcore(ap));
app.get('/todos', (c) => c.json(store.list()));

3. Arranca

// main.ts
import { serve } from '@hono/node-server';
import { app, ap } from './app.js';

await ap.init(app);              // register tools + scan routes
await ap.mountMcp(app);          // mount /mcp, /explorer, /health

serve({ fetch: app.fetch, port: 3000 });

Tu aplicación ahora responde:

  • REST en http://localhost:3000/todos

  • MCP en http://localhost:3000/mcp

  • Tool Explorer en http://localhost:3000/explorer/

Dos formas de exponer una capacidad

defineTool() — herramientas explícitas

La contraparte de Hono al decorador @ApTool de NestJS. Hono no tiene clases ni contenedor de DI que decorar, por lo que una herramienta es un objeto plano que lleva su propio metadato y manejador.

import { defineTool } from 'hono-apcore';

const sendEmail = defineTool({
  namespace: 'email',
  name: 'send',                 // -> module id "email.send"
  description: 'Send an email',
  inputSchema: Type.Object({ to: Type.String(), body: Type.String() }),
  outputSchema: Type.Object({ messageId: Type.String() }),
  annotations: { readonly: false, destructive: false, requiresApproval: true },
  tags: ['email'],
  params: { to: 'Recipient address' },   // merged into the schema descriptions
  handler: async (inputs, context) => mailer.send(inputs, context),
});

Campo

Notas

id

Se usa tal cual. De lo contrario, "<namespace>.<name>", con name en snake_case

inputSchema / outputSchema

TypeBox, Zod o JSON Schema plano

annotations

readonly, destructive, idempotent, requiresApproval, openWorld, streaming, cacheable, …

params

Prosa por parámetro fusionada en el esquema de entrada. JavaScript no puede leer los comentarios iniciales de una función en tiempo de ejecución como Python lee un docstring, por lo que esto es explícito

handler

(inputs, context) => result. Un resultado que no es objeto se envuelve como { result }

Escaneo de rutas — herramientas sin intrusión

Apunta el escáner a una aplicación y cada ruta se convierte en un módulo que la reproduce en proceso a través de app.request():

const ap = createApcore({
  routes: {
    excludePaths: ['/health', '/mcp*', '/explorer*'],
    modulePrefix: 'api',
  },
});

await ap.init(app);   // -> api.todos.list, api.todos.get, api.todos.create, …

Los IDs de módulo provienen de la ruta y del verbo HTTP:

Ruta

ID de módulo

Anotaciones inferidas

GET /todos

todos.list

readonly, cacheable

GET /todos/:id

todos.get

readonly, cacheable

POST /todos

todos.create

PUT /todos/:id

todos.update

idempotent

DELETE /todos/:id

todos.delete

destructive

El esquema de entrada generado lleva una propiedad de cadena obligatoria por parámetro de ruta, más un objeto query de forma libre (GET/DELETE) o un objeto body (POST/PUT/PATCH). Sobrescribe cualquiera de ellos por ruta:

routes: {
  overrides: {
    'GET /todos': {
      id: 'todo.all',
      description: 'Every todo, newest first',
      inputSchema: Type.Object({ done: Type.Optional(Type.Boolean()) }),
      annotations: { readonly: true, idempotent: true },
    },
    'DELETE /admin/wipe': { skip: true },
  },
}

Debido a que la ejecución vuelve a pasar por app.request(), una llamada de IA ejecuta el mismo camino de código que una llamada HTTP — middleware de autenticación, validadores, manejadores de errores y todo. La identidad y las cabeceras de traza W3C del Context de apcore se reenvían a la petición reproducida.

Referencia de la API

createApcore(options)

Devuelve un HonoApcore — el Registry, el Executor y todas las superficies cuelgan de él.

createApcore({
  extensionsDir?: string | null,   // scanned by Registry.discover()
  acl?: ACL,                       // enforced by the Executor on every call
  middleware?: Middleware[],       // apcore middleware installed on the Executor
  bindings?: string,               // YAML bindings file loaded during init()
  tools?: ApToolDefinition[],      // registered during init()
  routes?: RouteScanOptions,       // route-scanner configuration
  settings?: Partial<ApcoreSettings>,  // overrides for the APCORE_* settings
  mcp?: ApcoreMcpOptions,          // presence enables the MCP surface
  cli?: ApcoreCliOptions,          // presence enables the CLI surface
  a2a?: ApcoreA2aOptions,          // presence enables the A2A surface
})

Método

Descripción

init(app?, routeOptions?)

Descubre, registra herramientas y enlaces, escanea rutas, inicia superficies independientes. Idempotente

ready()

Espera un init() en curso

registerTool(tool) / registerTools(tools)

Registra definiciones de herramientas en tiempo de ejecución

registerMethod(opts) / registerObject(opts)

Registra los métodos de un objeto de servicio plano

scanRoutes(app, opts?)

Escanea y registra las rutas de una aplicación

routeOptions

Las opciones de escaneo de rutas fusionadas que esta instancia usaría

loadBindings(path?, resolver?)

Carga un archivo de enlaces YAML

mountMcp(app, opts?)

Monta /mcp, el Explorer y /health en la aplicación

toOpenaiTools(opts?)

Definiciones de funciones compatibles con OpenAI

close()

Apaga las superficies MCP y A2A

apcore(instance | options, middlewareOptions?)

Middleware de Hono que coloca la instancia y un Context de apcore por petición en el contexto de Hono.

app.use('*', apcore(ap));

app.get('/orders', async (c) =>
  c.json(await getApcore(c).executor.call('orders.list', {}, getApcoreContext(c))),
);

El mapa de variables se amplía, por lo que c.get('apcore') y c.get('apcoreContext') también están tipados. Pasa { skipContext: true } en rutas que nunca llaman a módulos, o { contextFactory } para conectar autenticación real.

HonoContextFactory

Construye el Context de apcore a partir de un contexto de Hono, una Request o Headers simples.

Resolución de identidad, en orden: x-user-idAuthorization: Bearer … (id de identidad "bearer") → una cabecera x-roles simple (un atajo de demostración) → anónimo. Una cabecera traceparent proporciona el id de traza; x-correlation-id (o x-request-id) aterriza en context.data.

new HonoContextFactory({
  resolveIdentity: (headers) => identityFromSession(headers),  // wins over the above
  data: (headers) => ({ tenant: headers.get('x-tenant') }),
});

MCP

ApcoreMcpService ejecuta el servidor MCP de dos maneras.

Integrado — un proceso, un puerto:

await ap.mountMcp(app, { endpoint: '/mcp', explorer: true, allowExecute: true });

Esto necesita los objetos de petición y respuesta de Node en bruto que @hono/node-server expone en c.env, por lo que es solo para Node; un manejador montado en otro runtime responde 501 con esa explicación. endpoint debe ser la ruta tal como la ve el servidor HTTP — incluye el prefijo si la aplicación está bajo un basePath.

Independiente — un puerto separado, o stdio para un servidor lanzado por CLI:

createApcore({ mcp: { transport: 'streamable-http', host: '0.0.0.0', port: 8000 } });
// init() starts it, because `transport` was set explicitly

Opciones clave de MCP:

Campo

Tipo

Descripción

transport

'stdio' | 'streamable-http' | 'sse'

Transporte independiente. Configurarlo hace que init() inicie el servidor

host / port

string / number

Dirección de enlace para transportes HTTP

name / version

string

Identidad del servidor

explorer / explorerPrefix / allowExecute

Interfaz web del Tool Explorer

authenticator / requireAuth / exemptPaths

JWT o autenticación personalizada

tags / prefix

Exponer solo módulos coincidentes

validateInputs

boolean

Aplicar esquemas de entrada en cada llamada

observability

Métricas + middleware de uso y sus endpoints

outputFormat / outputFormatter / redactOutput / trace

Serialización de resultados

approvalHandler / approvalStore / approvalNotify

Puerta de aprobación para herramientas destructivas

mcpMiddleware / mcpAcl

Middleware apcore adicional / ACL para el ejecutor MCP

Adaptadores de esquema

Los esquemas se auto-detectan y convierten mediante una cadena de prioridad:

Adaptador

Prioridad

Entrada

TypeBoxAdapter

100

Esquemas de @sinclair/typebox

ZodAdapter

50

Zod 3 (_def.typeName) y Zod 4 (_zod.def.type)

JsonSchemaAdapter

30

Objetos JSON Schema planos

La detección es estructural — ni TypeBox ni Zod se importan en tiempo de ejecución — por lo que cualquiera que instale la aplicación anfitriona (o ninguno) está bien. Registra el tuyo con SchemaExtractor.registerAdapter().

Enlaces YAML

Registra módulos sin tocar el código fuente:

bindings:
  - module_id: email.send
    target: EmailService.send
    description: Send an email
    input_schema:
      type: object
      properties:
        to: { type: string }
    tags: [email, mutate]
    annotations:
      readonly: false
import { resolverFromObjects } from 'hono-apcore';

await ap.loadBindings('./bindings.yaml', resolverFromObjects({ EmailService: mailer }));

En el otro sentido, writeBindingsFile() serializa los módulos escaneados de vuelta — que es lo que hace hono-apcore scan --format yaml.

CLI

hono-apcore scan   ./src/app.ts            # print the modules a scan would produce
hono-apcore scan   ./src/app.ts --format yaml --out bindings.yaml
hono-apcore serve  ./src/app.ts --transport http --port 8000 --explorer
hono-apcore export ./src/app.ts --out tools.json

La entrada es path[:export]; la exportación por defecto es default, luego app. Si el módulo exporta un HonoApcore bajo cualquier nombre, su configuración — filtros de ruta, prefijo de módulo, opciones de MCP — se respeta, por lo que scan informa exactamente los módulos que la propia aplicación registra; las banderas de CLI lo sobrescriben. Una entrada sin instancia también funciona, por lo que serve se ejecuta contra una aplicación que nunca ha oído hablar de apcore. Las entradas TypeScript necesitan un cargador:

npx tsx node_modules/.bin/hono-apcore scan ./src/app.ts

Configuración (APCORE_*)

La configuración canónica que implementa cada integración de apcore, leída del entorno y sobrescribible mediante settings:

Variable

Tipo

Predeterminado

Propósito

APCORE_ENABLED

bool

true

Interruptor principal: false hace que init() no haga nada

APCORE_DEBUG

bool

false

Registro detallado / introspección

APCORE_SCANNERS

list

["auto"]

Identificadores de escáner habilitados

APCORE_INCLUDE_PATHS

list

[]

Patrones de ruta a incluir (vacío = todos)

APCORE_EXCLUDE_PATHS

list

[]

Patrones de ruta a excluir

APCORE_MODULE_PREFIX

str

""

Prefijo antepuesto a los IDs de módulo generados

APCORE_AUTH_ENABLED

bool

false

Exigir autenticación para los endpoints MCP/A2A

APCORE_AUTH_STRATEGY

str

"bearer"

bearer / session / custom

APCORE_TRANSPORT

str

"stdio"

Transporte MCP: stdio / http / sse

APCORE_HOST

str

"0.0.0.0"

Dirección de enlace cuando el transporte no es stdio

APCORE_PORT

int

8808

Puerto de enlace cuando el transporte no es stdio

Los pares opcionales no se reexportan

A diferencia del adaptador NestJS, hono-apcore no reexporta las superficies apcore-mcp / apcore-cli / apcore-a2a. Hacerlo haría que se cargaran de forma anticipada, y apcore-mcp incorpora node:http, lo que rompe una compilación de Workers, Deno o Bun de una aplicación que nunca usa la superficie MCP. Importa esos símbolos desde sus propios paquetes:

import { JWTAuthenticator, getCurrentIdentity } from 'apcore-mcp';
import { createCli } from 'apcore-cli';
import { A2AClient } from 'apcore-a2a';

apcore-js y apcore-toolkit son dependencias directas, por lo que sus símbolos comunes (ACL, Config, registerSysModules, TraceContext, BaseScanner, formatModules, …) se reexportan desde hono-apcore directamente.

Ejemplos

Ejemplo

Muestra

examples/demo

Aplicación completa: herramientas escritas a mano y escaneo de rutas, JWT, ACL, módulos de sistema, Docker

examples/acl_demo

Rutas gobernadas por la ACL de apcore: orders.delete solo para administradores

pnpm install && pnpm build
cd examples/demo && pnpm install && pnpm dev

Documentación detallada

Scripts

Comando

Descripción

pnpm build

Compilar TypeScript

pnpm dev

Compilación en modo de observación

pnpm test

Ejecutar la suite de pruebas (vitest)

pnpm test:coverage

Pruebas con cobertura (umbrales del 90%)

pnpm typecheck

Comprobación de tipos sin emitir

pnpm lint

Lint de código fuente y pruebas

Licencia

Apache-2.0

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Exposes Hono API endpoints as Model Context Protocol tools, allowing LLMs to interact with your API routes through a dedicated MCP endpoint. It provides helpers to describe routes and includes a codemode for dynamic API interaction via search and execute tools.
    32
    86
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables building agent-ready APIs that expose tools as both HTTP and MCP endpoints from a single server definition, with automatic OpenAPI, discovery docs, and interactive API reference.
    5
    Apache 2.0
  • A
    license
    B
    quality
    C
    maintenance
    Transforms OpenAPI definitions into MCP tools for seamless LLM-API integration.
    8
    39
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Easily expose your Hono API endpoints as MCP tools with minimal configuration, supporting type-safe input handling and tool registration.
    32
    2
    MIT

View all related MCP servers

Related MCP Connectors

  • Point Gecko at an OpenAPI spec; get first-call-correct, auth-hidden agent tools.

  • Free public MCP for AI agents — 193 tools, 44 workflows. No API key.

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

View all MCP Connectors

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/aiperceivable/hono-apcore'

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