hono-apcore
hono-apcore
Hono-Adapter für das apcore Ökosystem der AI-Perceivable-Module. Verwandelt eine Hono-App in MCP-Tools und OpenAI-kompatible Funktionsdefinitionen – entweder durch explizite Tool-Deklaration oder durch Scannen der bereits vorhandenen Routen.
Funktionen
Zwei Wege hinein – Tools mit
defineTool()/defineToolset()deklarieren oder vorhandene Routen ohne eine einzige Codeänderung scannenRoute-Replay – eine gescannte Route wird zu einem Modul, das über
app.request()zurückruft, sodass Middleware, Validatoren und Fehlerbehandler weiterhin ausgeführt werdenEin Port –
mountMcp()bedient den MCP-Endpunkt, den Tool Explorer und/healthaus derselben Hono-AppAnnotations-Inferenz –
GET→ readonly + cacheable,PUT→ idempotent,DELETE→ destruktiv (RFC-9110-Semantik sicherer Methoden)Multi-Schema – TypeBox, Zod 3, Zod 4 und reines JSON Schema, automatisch erkannt über eine Prioritätskette
Context, ACL und Identität – die
apcore()-Middleware baut einen Pro-Request-apcore-Contextmit W3C-Trace-Propagation auf, sodass ACL-Regeln auch Ihre Routen regierenLaufzeit-agnostischer Kern –
apcore-mcp,apcore-cliundapcore-a2asind optionale Peers, die lazy geladen werden, sodass der Import vonhono-apcoreniemalsnode:httpin einen Edge-Build ziehtCLI –
hono-apcore scan | serve | exportfunktioniert mit einer einfachen Hono-AppYAML-Bindings – Module deklarativ registrieren, ohne den Quellcode anzufassen
Related MCP server: hono-mcp-server
Installation
npm install hono-apcore honoOptionale Peers, nur für die Oberflächen installieren, die Sie nutzen:
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 schemasVoraussetzungen: Node.js >= 18, Hono >= 4 (getestet mit Hono 4.13).
Schnellstart
1. Einige Tools deklarieren
// 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. In die App einbinden
// 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. Starten
// 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 });Ihre App antwortet nun auf:
REST unter
http://localhost:3000/todosMCP unter
http://localhost:3000/mcpTool Explorer unter
http://localhost:3000/explorer/
Zwei Wege, eine Fähigkeit bereitzustellen
defineTool() – explizite Tools
Das Hono-Pendant zum @ApTool-Decorator von NestJS. Hono hat keine Klassen oder
DI-Container, die dekoriert werden könnten, also ist ein Tool ein schlichtes
Objekt, das seine eigenen Metadaten und seinen Handler mit sich führt.
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),
});Feld | Hinweise |
| Wird unverändert verwendet. Andernfalls |
| TypeBox, Zod oder reines JSON Schema |
|
|
| Pro-Parameter-Prosa, die in das Eingabeschema eingearbeitet wird. JavaScript kann die führenden Kommentare einer Funktion zur Laufzeit nicht so lesen, wie Python einen Docstring liest, daher ist dies explizit |
|
|
Routen-Scanning – Tools ohne Eingriff
Zeigen Sie den Scanner auf eine App, und jede Route wird zu einem Modul, das sie
in-process über app.request() repliziert:
const ap = createApcore({
routes: {
excludePaths: ['/health', '/mcp*', '/explorer*'],
modulePrefix: 'api',
},
});
await ap.init(app); // -> api.todos.list, api.todos.get, api.todos.create, …Modul-IDs ergeben sich aus Pfad und HTTP-Verb:
Route | Modul-ID | Abgeleitete Annotationen |
|
|
|
|
|
|
|
| — |
|
|
|
|
|
|
Das generierte Eingabeschema trägt eine erforderliche String-Eigenschaft pro
Pfadparameter plus ein frei formbares query-Objekt (GET/DELETE) oder
body-Objekt (POST/PUT/PATCH). Überschreiben Sie alles davon pro Route:
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 },
},
}Da die Ausführung über app.request() zurückläuft, durchläuft ein KI-Aufruf
denselben Codepfad wie ein HTTP-Aufruf – Auth-Middleware, Validatoren,
Fehlerbehandler und alles andere. Identität und W3C-Trace-Header aus dem
apcore-Context werden auf den replizierten Request übertragen.
API-Referenz
createApcore(options)
Gibt eine HonoApcore zurück – Registry, Executor und jede Oberfläche hängen
daran.
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
})Methode | Beschreibung |
| Tools und Bindings entdecken, registrieren, Routen scannen, eigenständige Oberflächen starten. Idempotent |
| Auf ein laufendes |
| Tool-Definitionen zur Laufzeit registrieren |
| Die Methoden eines einfachen Service-Objekts registrieren |
| Die Routen einer App scannen und registrieren |
| Die zusammengeführten Routen-Scan-Optionen, die diese Instanz verwenden würde |
| Eine YAML-Bindings-Datei laden |
|
|
| OpenAI-kompatible Funktionsdefinitionen |
| Die MCP- und A2A-Oberflächen herunterfahren |
apcore(instance | options, middlewareOptions?)
Hono-Middleware, die die Instanz und einen Pro-Request-apcore-Context auf den
Hono-Context legt.
app.use('*', apcore(ap));
app.get('/orders', async (c) =>
c.json(await getApcore(c).executor.call('orders.list', {}, getApcoreContext(c))),
);Die Variablenzuordnung wird erweitert, sodass c.get('apcore') und
c.get('apcoreContext') ebenfalls typisiert sind. Übergeben Sie
{ skipContext: true } auf Routen, die nie Module aufrufen, oder
{ contextFactory }, um echte Authentifizierung anzustöpseln.
HonoContextFactory
Baut den apcore-Context aus einem Hono-Context, einem Request oder nackten
Headers auf.
Identitätsauflösung, in dieser Reihenfolge: x-user-id → Authorization: Bearer …
(Identitäts-ID "bearer") → ein nackter x-roles-Header (eine Demo-Abkürzung) →
anonym. Ein traceparent-Header liefert die Trace-ID; x-correlation-id (oder
x-request-id) landet in context.data.
new HonoContextFactory({
resolveIdentity: (headers) => identityFromSession(headers), // wins over the above
data: (headers) => ({ tenant: headers.get('x-tenant') }),
});MCP
ApcoreMcpService betreibt den MCP-Server auf zwei Arten.
Eingebettet – ein Prozess, ein Port:
await ap.mountMcp(app, { endpoint: '/mcp', explorer: true, allowExecute: true });Dies benötigt die rohen Node-Request- und Response-Objekte, die
@hono/node-server auf c.env bereitstellt, ist also nur für Node gedacht;
ein eingehängter Handler auf einer anderen Laufzeit antwortet mit 501 und
dieser Erklärung. endpoint muss der Pfad sein, wie ihn der HTTP-Server sieht –
den Präfix einschließen, wenn die App unter einem basePath liegt.
Eigenständig – ein separater Port oder stdio für einen per CLI gestarteten Server:
createApcore({ mcp: { transport: 'streamable-http', host: '0.0.0.0', port: 8000 } });
// init() starts it, because `transport` was set explicitlyWichtige MCP-Optionen:
Feld | Typ | Beschreibung |
|
| Eigenständiger Transport. Das Setzen startet den Server über |
|
| Bindeadresse für HTTP-Transports |
|
| Server-Identität |
| Tool-Explorer-Web-UI | |
| JWT- oder benutzerdefinierte Authentifizierung | |
| Nur passende Module bereitstellen | |
|
| Eingabeschemas bei jedem Aufruf erzwingen |
| Metrik- + Usage-Middleware und deren Endpunkte | |
| Ergebnis-Serialisierung | |
| Genehmigungs-Gate für destruktive Tools | |
| Zusätzliche apcore-Middleware / ACL für den MCP-Executor |
Schema-Adapter
Schemas werden automatisch erkannt und über eine Prioritätskette konvertiert:
Adapter | Priorität | Eingabe |
| 100 |
|
| 50 | Zod 3 ( |
| 30 | Reine JSON-Schema-Objekte |
Die Erkennung ist strukturell – weder TypeBox noch Zod werden zur Laufzeit
importiert –, sodass egal ist, was die Host-App installiert (oder auch nichts).
Registrieren Sie eigene Adapter mit SchemaExtractor.registerAdapter().
YAML-Bindings
Module registrieren, ohne den Quellcode anzufassen:
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: falseimport { resolverFromObjects } from 'hono-apcore';
await ap.loadBindings('./bindings.yaml', resolverFromObjects({ EmailService: mailer }));In die andere Richtung serialisiert writeBindingsFile() gescannte Module
wieder heraus – genau das tut 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.jsonDer Einstieg ist pfad[:export]; der Export standardmäßig default, dann app.
Wenn das Modul eine HonoApcore unter irgendeinem Namen exportiert, werden
deren Konfiguration – Routenfilter, Modul-Präfix, MCP-Optionen – berücksichtigt,
sodass scan genau die Module meldet, die die App selbst registriert;
CLI-Flags überschreiben sie. Ein Einstieg ohne Instanz funktioniert ebenfalls,
sodass serve gegen eine App läuft, die nie von apcore gehört hat.
TypeScript-Einstiege benötigen einen Loader:
npx tsx node_modules/.bin/hono-apcore scan ./src/app.tsKonfiguration (APCORE_*)
Die kanonischen Einstellungen, die jede apcore-Integration implementiert, aus
der Umgebung gelesen und über settings überschreibbar:
Variable | Type | Default | Purpose |
| bool |
| Hauptschalter — |
| bool |
| Ausführliche Protokollierung / Introspection |
| list |
| Aktivierte Scanner-Identifikatoren |
| list |
| Einzubeziehende Routenmuster (leer = alle) |
| list |
| Auszuschließende Routenmuster |
| str |
| Präfix, das generierten Modul-IDs vorangestellt wird |
| bool |
| Auth für MCP/A2A-Endpunkte erforderlich |
| str |
|
|
| str |
| MCP-Transport: |
| str |
| Bind-Adresse, wenn der Transport nicht stdio ist |
| int |
| Bind-Port, wenn der Transport nicht stdio ist |
Optionale Peers werden nicht re-exportiert
Im Gegensatz zum NestJS-Adapter exportiert hono-apcore die apcore-mcp
/ apcore-cli / apcore-a2a-Oberflächen nicht erneut. Andernfalls würden
sie eager geladen, und apcore-mcp zieht node:http mit ein — was einen
Workers-, Deno- oder Bun-Build einer App bricht, die die MCP-Oberfläche nie
nutzt. Importieren Sie diese Symbole aus ihren eigenen Paketen:
import { JWTAuthenticator, getCurrentIdentity } from 'apcore-mcp';
import { createCli } from 'apcore-cli';
import { A2AClient } from 'apcore-a2a';apcore-js und apcore-toolkit sind harte Abhängigkeiten, daher werden ihre
gemeinsamen Symbole (ACL, Config, registerSysModules, TraceContext,
BaseScanner, formatModules, …) direkt aus hono-apcore re-exportiert.
Beispiele
Beispiel | Zeigt |
Vollständige App: handgeschriebene Tools und Routen-Scanning, JWT, ACL, Systemmodule, Docker | |
Routen, die von der apcore-ACL verwaltet werden — |
pnpm install && pnpm build
cd examples/demo && pnpm install && pnpm devAusführliche Dokumentation
Funktionsübersicht — Architektur und Abhängigkeitsgraph
Tool-Definition —
defineTool,defineToolset, Modul-IDsRouten-Scanner — wie Routen zu Modulen werden und was Replay kostet
MCP-Integration — eingebettet vs. eigenständig, die Node-Brücke
Schema-Extraktion — die Adapterkette und benutzerdefinierte Adapter
Kontext und ACL — Identität, Tracing und verwaltende Routen
Skripte
Befehl | Beschreibung |
| TypeScript kompilieren |
| Kompilierung im Watch-Modus |
| Test-Suite ausführen (vitest) |
| Tests mit Coverage (90%-Schwellen) |
| Typprüfung ohne Ausgabe |
| Lint für Quellcode und Tests |
Lizenz
Apache-2.0
This server cannot be deployed
Maintenance
Related MCP Connectors
The OpenRouter for tools. One MCP connection gives any AI agent 254 hosted tools, pay per call.
Build, validate, deploy — HTTP APIs, cron jobs, webhooks and MCP tools — from your AI client.
Give any MCP-compatible AI assistant a builder for live, hosted web tools and workflows.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceExposes 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.34 npm86MIT
- AlicenseNot gradedqualityCmaintenanceEasily expose your Hono API endpoints as MCP tools with minimal configuration, supporting type-safe input handling and tool registration.34 npm2MIT
- AlicenseNot gradedqualityDmaintenanceExposes OpenAPI endpoints as MCP tools, enabling LLMs to discover and interact with REST APIs through the MCP protocol.9 npmMIT
- AlicenseNot gradedqualityCmaintenanceExposes FastAPI routes as MCP tools with auto-discovery, Pydantic schema extraction, and built-in observability.Apache 2.0