hono-apcore
hono-apcore
Hono 适配器,用于 apcore AI-Perceivable 模块生态系统。将 Hono 应用转换为 MCP 工具和 OpenAI 兼容的函数定义——既可以通过显式声明工具,也可以通过扫描已有的路由。
特性
两种方式 — 使用
defineTool()/defineToolset()声明工具,或零代码更改扫描现有路由路由重放 — 扫描的路由成为通过
app.request()回调的模块,因此中间件、验证器和错误处理程序仍然全部运行单端口 —
mountMcp()从同一个 Hono 应用提供 MCP 端点、工具浏览器和/health注解推断 —
GET→ readonly + cacheable,PUT→ idempotent,DELETE→ destructive(RFC 9110 安全方法语义)多模式 — TypeBox、Zod 3、Zod 4 和纯 JSON Schema,通过优先级链自动检测
上下文、ACL 和身份 —
apcore()中间件构建每个请求的 apcoreContext,并带有 W3C 跟踪传播,因此 ACL 规则也管理你的路由运行时无关核心 —
apcore-mcp、apcore-cli和apcore-a2a是可选的对等依赖,按需加载,因此导入hono-apcore永远不会将node:http拖入边缘构建CLI —
hono-apcore scan | serve | export可针对普通 Hono 应用工作YAML 绑定 — 以声明方式注册模块,无需修改源代码
Related MCP server: hono-mcp-server
安装
npm install hono-apcore hono可选的对等依赖,仅为你使用的功能安装:
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要求: Node.js >= 18,Hono >= 4(已在 Hono 4.13 上测试)。
快速开始
1. 声明一些工具
// 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. 将其接入应用
// 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. 启动
// 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 });你的应用现在响应:
REST 位于
http://localhost:3000/todosMCP 位于
http://localhost:3000/mcp工具浏览器 位于
http://localhost:3000/explorer/
暴露能力的两种方式
defineTool() — 显式工具
这是 NestJS 的 @ApTool 装饰器的 Hono 对应物。Hono 没有可装饰的类或 DI 容器,因此工具是一个携带自身元数据和处理程序的普通对象。
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),
});字段 | 说明 |
| 原样使用。否则为 |
| TypeBox、Zod 或纯 JSON Schema |
|
|
| 每个参数的说明文本合并到输入模式中。JavaScript 无法像 Python 读取 docstring 那样在运行时读取函数的前导注释,因此这是显式的 |
|
|
路由扫描 — 零侵入工具
将扫描器指向应用,每个路由都会成为一个通过 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, …模块 ID 来自路径和 HTTP 动词:
路由 | 模块 ID | 推断的注解 |
|
|
|
|
|
|
|
| — |
|
|
|
|
|
|
生成的输入模式为每个路径参数携带一个必需的字符串属性,外加一个自由形式的 query 对象(GET/DELETE)或 body 对象(POST/PUT/PATCH)。可以按路由覆盖其中任何部分:
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 },
},
}由于执行通过 app.request() 返回,AI 调用与 HTTP 调用运行相同的代码路径——包括认证中间件、验证器、错误处理程序等。来自 apcore Context 的身份和 W3C 跟踪头会被转发到重放的请求上。
API 参考
createApcore(options)
返回一个 HonoApcore — 注册表、执行器和所有表面都挂载在它上面。
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
})方法 | 说明 |
| 发现、注册工具和绑定,扫描路由,启动独立表面。幂等 |
| 等待进行中的 |
| 在运行时注册工具定义 |
| 注册普通服务对象的方法 |
| 扫描并注册应用的路由 |
| 此实例将使用的合并路由扫描选项 |
| 加载 YAML 绑定文件 |
| 将 |
| OpenAI 兼容的函数定义 |
| 关闭 MCP 和 A2A 表面 |
apcore(instance | options, middlewareOptions?)
Hono 中间件,将实例和每个请求的 apcore Context 放到 Hono 上下文上。
app.use('*', apcore(ap));
app.get('/orders', async (c) =>
c.json(await getApcore(c).executor.call('orders.list', {}, getApcoreContext(c))),
);变量映射被增强,因此 c.get('apcore') 和 c.get('apcoreContext') 也有类型。在从不调用模块的路由上传递 { skipContext: true },或传递 { contextFactory } 以接入真实认证。
HonoContextFactory
从 Hono 上下文、Request 或裸 Headers 构建 apcore Context。
身份解析顺序:x-user-id → Authorization: Bearer …(身份 id "bearer")→ 裸 x-roles 头(演示快捷方式)→ 匿名。traceparent 头提供跟踪 id;x-correlation-id(或 x-request-id)进入 context.data。
new HonoContextFactory({
resolveIdentity: (headers) => identityFromSession(headers), // wins over the above
data: (headers) => ({ tenant: headers.get('x-tenant') }),
});MCP
ApcoreMcpService 以两种方式运行 MCP 服务器。
嵌入式 — 一个进程,一个端口:
await ap.mountMcp(app, { endpoint: '/mcp', explorer: true, allowExecute: true });这需要 @hono/node-server 在 c.env 上暴露的原始 Node 请求和响应对象,因此仅限 Node;其他运行时上的挂载处理程序会以该说明回答 501。endpoint 必须是 HTTP 服务器看到的路径——如果应用位于 basePath 下,请包含前缀。
独立 — 单独的端口,或用于 CLI 启动的服务器的 stdio:
createApcore({ mcp: { transport: 'streamable-http', host: '0.0.0.0', port: 8000 } });
// init() starts it, because `transport` was set explicitly关键 MCP 选项:
字段 | 类型 | 说明 |
|
| 独立传输。设置它会使 |
|
| HTTP 传输的绑定地址 |
|
| 服务器身份 |
| 工具浏览器 Web UI | |
| JWT 或自定义认证 | |
| 仅暴露匹配的模块 | |
|
| 在每次调用时强制执行输入模式 |
| 指标 + 使用中间件及其端点 | |
| 结果序列化 | |
| 破坏性工具的审批门 | |
| 为 MCP 执行器提供的额外 apcore 中间件 / ACL |
模式适配器
模式通过优先级链自动检测和转换:
适配器 | 优先级 | 输入 |
| 100 |
|
| 50 | Zod 3( |
| 30 | 纯 JSON Schema 对象 |
检测是结构性的——运行时不会导入 TypeBox 或 Zod——因此宿主应用安装哪个(或都不安装)都可以。使用 SchemaExtractor.registerAdapter() 注册你自己的适配器。
YAML 绑定
无需修改源代码即可注册模块:
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 }));反过来,writeBindingsFile() 将扫描的模块序列化输出——这正是 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入口是 path[:export];导出默认为 default,然后是 app。如果模块以任何名称导出 HonoApcore,其配置——路由过滤器、模块前缀、MCP 选项——会被尊重,因此 scan 报告应用自身注册的模块;CLI 标志会覆盖它。没有实例的入口仍然有效,因此 serve 可以针对从未听说过 apcore 的应用运行。TypeScript 入口需要加载器:
npx tsx node_modules/.bin/hono-apcore scan ./src/app.ts配置(APCORE_*)
每个 apcore 集成实现的标准设置,从环境读取并可通过 settings 覆盖:
Variable | Type | Default | Purpose |
| bool |
| 主开关—— |
| bool |
| 详细日志/内省 |
| list |
| 启用的扫描器标识符 |
| list |
| 要包含的路由模式(空 = 全部) |
| list |
| 要排除的路由模式 |
| str |
| 附加到生成的模块 ID 的前缀 |
| bool |
| MCP/A2A 端点需要身份验证 |
| str |
|
|
| str |
| MCP 传输: |
| str |
| 当传输不是 stdio 时的绑定地址 |
| int |
| 当传输不是 stdio 时的绑定端口 |
可选对等依赖不会被重新导出
与 NestJS 适配器不同,hono-apcore 不重新导出 apcore-mcp / apcore-cli / apcore-a2a 接口。这样做会使它们被急切加载,而 apcore-mcp 会引入 node:http——这会破坏从不使用 MCP 接口的 Workers、Deno 或 Bun 应用构建。请从它们各自的包中导入这些符号:
import { JWTAuthenticator, getCurrentIdentity } from 'apcore-mcp';
import { createCli } from 'apcore-cli';
import { A2AClient } from 'apcore-a2a';apcore-js 和 apcore-toolkit 是硬依赖,因此它们的公共符号(ACL、Config、registerSysModules、TraceContext、BaseScanner、formatModules 等)直接从 hono-apcore 重新导出。
示例
示例 | 展示 |
完整应用:手写工具和路由扫描、JWT、ACL、系统模块、Docker | |
由 apcore ACL 管理的路由—— |
pnpm install && pnpm build
cd examples/demo && pnpm install && pnpm dev详细文档
功能概览 — 架构和依赖关系图
工具定义 —
defineTool、defineToolset、模块 ID路由扫描器 — 路由如何成为模块,以及重放的成本
MCP 集成 — 嵌入式与独立式,Node 桥接
模式提取 — 适配器链和自定义适配器
上下文和 ACL — 身份、追踪和路由治理
脚本
命令 | 描述 |
| 编译 TypeScript |
| 监视模式编译 |
| 运行测试套件(vitest) |
| 带覆盖率的测试(90% 阈值) |
| 类型检查(不输出) |
| 检查源代码和测试 |
许可证
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