Skip to main content
Glama

hono-apcore

Hono 用アダプタで、apcore AI-Perceivable モジュールエコシステム向けです。Hono アプリを MCP ツールや OpenAI 互換の関数定義に変換します。ツールを明示的に宣言するか、既存のルートをスキャンするかのどちらかで実現します。

特徴

  • 2つの入り口 — defineTool() / defineToolset() でツールを宣言するか、既存のルートをコード変更なしでスキャンする

  • ルートリプレイ — スキャンしたルートは app.request() を介してコールバックするモジュールになるため、ミドルウェア、バリデータ、エラーハンドラもすべて引き続き実行されます

  • 1つのポート — mountMcp() は MCP エンドポイント、Tool Explorer、/health を同じ Hono アプリから提供します

  • アノテーション推論 — GET → readonly + cacheable、PUT → idempotent、DELETE → destructive(RFC 9110 の安全なメソッドのセマンティクス)

  • マルチスキーマ — TypeBox、Zod 3、Zod 4、プレーンな JSON Schema を、優先度チェーンで自動検出

  • コンテキスト、ACL、アイデンティティ — apcore() ミドルウェアは、W3C トレース伝播を備えたリクエストごとの apcore Context を構築するため、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/todos

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

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

機能を公開する2つの方法

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),
});

フィールド

説明

id

そのまま使用されます。それ以外の場合は "<namespace>.<name>" で、name はスネークケースになります。

inputSchema / outputSchema

TypeBox、Zod、またはプレーンな JSON Schema

annotations

readonly、destructive、idempotent、requiresApproval、openWorld、streaming、cacheable など

params

パラメータごとの説明文を入力スキーマにマージします。JavaScript は Python が docstring を読むように実行時に関数の先頭コメントを読むことができないため、これは明示的です。

handler

(inputs, context) => result。オブジェクト以外の結果は { result } としてラップされます。

ルートスキャン — 侵入ゼロのツール

スキャナをアプリに向けると、すべてのルートが 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

推論されたアノテーション

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

生成された入力スキーマには、パスパラメータごとに必須の文字列プロパティが1つ含まれ、さらに自由形式の 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 を返します — Registry、Executor、およびすべてのサーフェスがそれにぶら下がります。

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
})

メソッド

説明

init(app?, routeOptions?)

ツールとバインディングを検出・登録し、ルートをスキャンし、スタンドアロンサーフェスを起動します。冪等です。

ready()

実行中の init() を待機します

registerTool(tool) / registerTools(tools)

実行時にツール定義を登録します

registerMethod(opts) / registerObject(opts)

プレーンなサービスオブジェクトのメソッドを登録します

scanRoutes(app, opts?)

アプリのルートをスキャンして登録します

routeOptions

このインスタンスが使用するマージ済みのルートスキャンオプション

loadBindings(path?, resolver?)

YAML バインディングファイルを読み込みます

mountMcp(app, opts?)

/mcp、Explorer、/health をアプリにマウントします

toOpenaiTools(opts?)

OpenAI 互換の関数定義

close()

MCP と A2A のサーフェスをシャットダウンします

apcore(instance | options, middlewareOptions?)

インスタンスとリクエストごとの apcore Context を Hono コンテキストに配置する 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 サーバーを2つの方法で実行します。

組み込み — 1つのプロセス、1つのポート:

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 オプション:

フィールド

タイプ

説明

transport

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

スタンドアロンのトランスポート。設定すると init() がサーバーを起動します

host / port

string / number

HTTP トランスポートのバインドアドレス

name / version

string

サーバーの識別情報

explorer / explorerPrefix / allowExecute

Tool Explorer の Web UI

authenticator / requireAuth / exemptPaths

JWT またはカスタム認証

tags / prefix

一致するモジュールのみを公開

validateInputs

boolean

すべての呼び出しで入力スキーマを強制

observability

メトリクス + 使用状況ミドルウェアとそのエンドポイント

outputFormat / outputFormatter / redactOutput / trace

結果のシリアライズ

approvalHandler / approvalStore / approvalNotify

破壊的なツールの承認ゲート

mcpMiddleware / mcpAcl

MCP エグゼキュータ用の追加の apcore ミドルウェア / ACL

スキーマアダプタ

スキーマは自動検出され、優先度チェーンを介して変換されます:

アダプタ

優先度

入力

TypeBoxAdapter

100

@sinclair/typebox スキーマ

ZodAdapter

50

Zod 3(_def.typeName)および Zod 4(_zod.def.type)

JsonSchemaAdapter

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: false
import { 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 で上書きできます:

変数

型

デフォルト

目的

APCORE_ENABLED

bool

true

マスタースイッチ — false にすると init() は何もしない

APCORE_DEBUG

bool

false

詳細ログ / イントロスペクション

APCORE_SCANNERS

list

["auto"]

有効なスキャナー識別子

APCORE_INCLUDE_PATHS

list

[]

含めるルートパターン(空 = すべて)

APCORE_EXCLUDE_PATHS

list

[]

除外するルートパターン

APCORE_MODULE_PREFIX

str

""

生成されたモジュールIDに付加されるプレフィックス

APCORE_AUTH_ENABLED

bool

false

MCP/A2A エンドポイントに認証を要求

APCORE_AUTH_STRATEGY

str

"bearer"

bearer / session / custom

APCORE_TRANSPORT

str

"stdio"

MCP トランスポート: stdio / http / sse

APCORE_HOST

str

"0.0.0.0"

トランスポートが stdio でない場合のバインドアドレス

APCORE_PORT

int

8808

トランスポートが 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 から直接再エクスポートされます。

例

例

内容

examples/demo

完全なアプリ: 手書きツールとルートスキャン、JWT、ACL、システムモジュール、Docker

examples/acl_demo

apcore ACL によって管理されるルート — 管理者のみ orders.delete

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

詳細ドキュメント

スクリプト

コマンド

説明

pnpm build

TypeScript をコンパイル

pnpm dev

ウォッチモードでコンパイル

pnpm test

テストスイートを実行(vitest)

pnpm test:coverage

カバレッジ付きテスト(90% しきい値)

pnpm typecheck

出力なしで型チェック

pnpm lint

ソースとテストをリント

ライセンス

Apache-2.0

Related MCP Connectors

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.
    34 npm
    86
    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.
    34 npm
    2
    MIT