tabnas について
tabnasは、解析エンジン向けのTypeScript製MCPサーバーとCLIで、文法の開発やテストに使えます。両者はコアを共有し、同一のJSON結果を返します。文法はコードとして実行せず、データとして検証します。
主な機能
- 01入力を構文木に解析
- 02文法仕様の検証とエラー診断
- 03TSV文法フィクスチャの実行
- 04文法プラグインの一覧と詳細表示
- 05文法の受理範囲と出力の比較
- 06文法・診断リソースの提供
活用シーン
- 01文法に沿って入力を解析できるか確認
- 02解析失敗の原因を特定
- 03TSVフィクスチャで文法を回帰テスト
- 04文法変更の互換性を評価
MCP 対応
MCPサーバーはstdio経由で7種類の文法操作を公開し、文法、診断、エラー、プラグインのリソースを提供します。ホステッドエンドポイントでは同じツールをstreamable HTTP経由で利用できます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://mcp.tabnas.dev/mcpclaude mcp add --transport http dev-tabnas https://mcp.tabnas.dev/mcp{"mcpServers":{"dev-tabnas":{"type":"http","url":"https://mcp.tabnas.dev/mcp"}}}Cursor で開く{"servers":{"dev-tabnas":{"type":"http","url":"https://mcp.tabnas.dev/mcp"}}}VS Code で開く{"mcpServers":{"dev-tabnas":{"type":"http","url":"https://mcp.tabnas.dev/mcp"}}}{"mcpServers":{"dev-tabnas":{"serverUrl":"https://mcp.tabnas.dev/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
7| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| input | string | はい | 解析するソーステキスト。 |
| grammar | object | いいえ | シリアライズされた GrammarSpec(純粋な JSON、関数なし)。スキーマ:リソース tabnas://schema/grammar。文法は使用前に検証されます。`ref` キー、または組み込みではない関数参照を含む文法は拒否されます。 |
| options | object | いいえ | 文法の適用前に新しいインスタンスに適用する TabnasOptions。データのみを指定してください。plugins エントリーがある場合は拒否されます。 |
詳細
tabnas/mcp
tabnas エージェント向けツール群です。1 つの TypeScript コードベースに 2 つのフロントエンドを備えています。
MCP サーバー(stdio)と統合された
tabnas CLI で、単一のコア(ts/src/core.ts)を共有するため、両者の動作が食い違うことはありません。各操作について、CLI の --json 出力と MCP
ツールの結果はバイト単位で同一であり、テストスイートでそれを検証しています。
このパッケージのウェブサイトページには、クライアントごとのセットアップ方法、ツールの仕様、ホスト型エンドポイントの制限事項が記載されています。tabnas.dev/mcp
@tabnas/mcp として公開されています。このリポジトリは TypeScript のみを使用しています。エンジン上のツール群であり、パリティパッケージではないため、Go 版はありません。
インストール
npm install -g @tabnas/mcp # the `tabnas` CLI
npx --yes @tabnas/mcp # run the MCP server directly (stdio)
MCP クライアントの設定(stdio):
{
"mcpServers": {
"tabnas": {
"command": "npx",
"args": ["--yes", "@tabnas/mcp@<x.y.z>", "mcp"]
}
}
}
<x.y.z> には現在のバージョンを入力してください:npm view @tabnas/mcp version。この README ではバージョンを指定していません。リポジトリに自身が公開したバージョンを正確に固定すると、更新を含むコミットが次のリリースの内容となり、永遠に 1 リリース遅れてしまうためです。
サーバーは CLI の mcp サブコマンド(tabnas mcp)で起動します。これは skills パッケージの mcp.json が npx --yes @tabnas/mcp@<x.y.z> mcp として実行するコマンドと完全に同じです。(--yes は重要です。キャッシュにない場合、npx は MCP トランスポートが使用する stdin 上で確認を求めてしまいます。インストール済みクライアントのもとでツールのバージョンが変わらないよう、正確なバージョンを固定してください。skills/mcp.json には、レジストリから tools/sync-mcp-pin.js が書き込み、tools/validate.js --online が検証する実際のバージョンが記載されています。)
7 つのツール
| ツール | 回答する内容 | 結果 |
|---|---|---|
parse | この入力は解析できるか。どのようなツリーになるか。 | {ok:true, tree} | {ok:false, diagnostic} |
validate_grammar | このシリアライズされた GrammarSpec は有効か。 | {ok:true, v} | {ok:false, errors:[{path,message}]} |
explain_parse_error | なぜこの解析は失敗したのか。 | {failed:false} | {failed:true, diagnostic, registry} |
test_grammar | これらの TSV フィクスチャは合格するか。 | {pass, fail, rows:[{row,input,expected,got,ok}]} |
list_plugins | どのような文法プラグインがあるか。 | {plugins:[...]} |
describe_plugin | 1 つのプラグインの完全な記述子 | tabnas.plugin.json オブジェクト |
compare_grammars | 文法の変更後も、以前の文法が受け入れていた入力を受け入れ、同じツリーを構築できるか。 | {normalForm, proven[], observed[], changes[], counterexamples[], confidence, why} |
コントラクトに関する注意事項:
- 各操作は呼び出しごとに新しいエンジンインスタンスを構築します。
parseはまずoptionsを適用し、その後にgrammarを適用します。文法が指定されていない場合、インスタンスはnew Tabnas()とまったく同じです。ベアエンジンにはルールが定義されていないため、すべての入力で未定義のツリーが返されます({"ok":true}としてシリアライズされます)。 grammar引数を受け取るすべての操作では、使用前に必ず検証されます。無効な文法はvalidate_grammarのエラー形式{ok:false, errors:[{path,message}]}で拒否されます。validate_grammarの各レイヤー:ADR-10 セキュリティスキャン(後述)、同梱のgrammar.schema.jsonに対する構造検証(Ajv、draft 2020-12)、そして新しいインスタンスでのエンジン読み込み。エンジン読み込み時にスローされたメッセージがエラーになります。vは文法で宣言された組み込み設定スキーマのバージョンです(指定がない場合は 1)。- **セキュリティ(ADR-10):**シリアライズされた文法とそのオプションはコードではなくデータです。ファイアウォールは、文法を受け取るすべての操作とリクエストオプションに対して最初に実行され、次のものを拒否します。ツリー内の任意の場所にある
__proto__、constructor、prototypeという名前の独自キー(エンジンの文法マージに__proto__ガードがないため、プロトタイプ汚染を防止します)、refキー(ライブ関数は JSON ではありません)、$接尾辞の付いたエンジン組み込み関数ではない関数参照、リクエストオプションまたはgrammar.options内にあるpluginsキー(プラグインはライブコードです)、および 5000 ルールを超える文法(CPU 使用量の上限)。「この文法を検証する」が「このコードを実行する」や「このプロセスを汚染する」ことになることはありません。 - 診断以外のエンジンスロー(たとえば、
options.parser.startに関数以外を設定した場合)は捕捉され、同じクリーンな形式{ok:false, errors:[{path:"",message}]}で返されます。これにより、CLI と MCP ツールの挙動が一致します。 explain_parse_errorは診断を同梱のエラーコードレジストリーのエントリー({code, message, hint})と結合します。レジストリーに存在しないコード(たとえば、プラグインが宣言したコード)の場合、registryはnullです。test_grammarは、フリートのフィクスチャ規約(@tabnas/support)に従った TSV コンテンツを受け取ります。1 行目はヘッダーで、入力列はエスケープ解除され、期待値列は JSON またはERROR/ERROR:<code>です。列の位置は既定で 0 と 1 です。options.inputCol/options.expectedColでは、位置またはヘッダー名で列を指定します。10000 行を超える仕様は拒否されます。
MCP リソース(同梱の data/ からそのまま提供):
tabnas://schema/grammar、tabnas://schema/diagnostic、tabnas://errors、tabnas://plugins、tabnas://divergence。
CLI
tabnas parse [file|-] [--grammar g.json] [--json]
tabnas validate --grammar g.json [--json]
tabnas diagnose [file|-] [--grammar g.json] [--json]
tabnas test --spec fixtures.tsv [--grammar g.json] [--json]
tabnas plugins [name] [--json]
tabnas compare --a old.json --b new.json [--corpus dir|file] [--depth n] [--json]
tabnas mcp # run the MCP server (stdio)
入力は file から取得します。引数が - または指定されていない場合は、標準入力から取得します。
CLI がネットワークにアクセスすることはありません。tabnas mcp は stdio MCP サーバーを起動します(npx @tabnas/mcp と同じサーバーです)。stdout では JSON-RPC を出力し、それ以外は何も出力しません。
--json はコア結果の JSON をそのまま出力します。同じリクエストに対して MCP ツールが返すものと同一のバイト列です(キー順は固定され、ts/test/golden.test.js によってゴールデンコントラクトが検証されます)。--json を指定しない場合は、読みやすい形式で出力します。解析に失敗すると、エンジン独自の整形済みエラーメッセージを出力します。
終了コード:
| コード | 意味 |
|---|---|
| 0 | 成功:解析成功/文法が有効/すべてのフィクスチャ行に合格 |
| 1 | 操作が失敗を返した場合:解析失敗、文法が無効、フィクスチャの失敗、不明なプラグイン |
| 2 | 使用法エラー:不明なフラグまたはコマンド、ファイルが存在しない/読み取れない、文法 JSON が不正 |
すでに GrammarSpec になっていない文法を渡す
すべてのツールが受け取るのは、純粋な JSON でシリアライズされた GrammarSpec です。 ABNF、EBNF、GBNF、jsonic のソースは受け取りませんし、今後も受け取りません。これらをコンパイルするにはコンパイラーの実行が必要であり、ツールの最優先ルールは、文法はデータであってコードではないことだからです(ADR-10)。まずコンパイルしてから、結果を渡してください。
const { abnfConvert, toPureSpec } = require('@tabnas/abnf')
const spec = toPureSpec(abnfConvert(abnfSource, { builtins: true }))
// -> { options, rule, v, meta } — validates clean, safe to send
toPureSpec を使用してください。 この用途に使う関数です。一見妥当に思える次の 2 つの代替手段は、どちらも適切ではありません。
abnfCompile()が返すのはオブジェクトではなく、jsonic テキストです。文法ファイルへの書き込みには便利ですが、ツールの引数として必要なものではありません。abnfConvert()だけを使うと、ref(builtins: trueで変換した場合は空)とマークフィールドを持つ仕様が返されます。ファイアウォールが拒否するのはrefの内容ではなく、refの存在自体です。これは意図的な仕様です。セキュリティ境界で「十分に空である」かどうかを判断する価値はなく、mマークもシリアライズ形式には含まれません。toPureSpecは両方を取り除き、vを付与します。
toRecognitionSpec は同じ処理を、ツリー構築用の組み込み機能を使わず、受け入れるか拒否するかの判定だけが必要な文法に対して行います。
他のフロントエンドで同等の操作を行うには、tabnas parse --grammar g.json を使用します。g.json はビルド手順で出力されたファイルです。
文法の互換性(compare)
結果が異なるため、次の 2 つの問いを個別に報告します。
- 受理性。 候補の文法は、ベースラインが受理したものを引き続き受理しますか?
- 出力。 両方が受理する入力に対して、生成されるツリーは同じですか?
ユーザーが実際に影響を感じるのは 2 つ目です。過去のすべてのドキュメントを引き続き受理していても、ツリーの形が変われば、下流のすべてのコンシューマーがひそかに壊れます。一方、受理性だけを検証するテストでは成功と報告されます。
レポートが示すのは、根拠と確信度であり、単なる判定結果ではありません。 意図的に compatible: true フィールドは設けていません。言語包含問題は一般に決定不能であり、そのような値を出力するツールは、いずれ本番環境で誤った判定を出すことになるためです。
proven[]。静的に立証されたことと、その根拠です。決定可能な部分集合の範囲外にあるものはnot-provenとなります。これはこのツールについての記述であり、文法に互換性がないという主張ではありません。observed[]。実際に実行された検査と、その範囲です。changes[]/counterexamples[]。入力を含む、具体的な差異です。confidence+why。検出事項がなかったことを、どの程度信頼できるかを示します。理由が明記されたconfidence: "low"も、成功した実行です。
特に役立つ検査は、代替候補の順序です。代替候補は最初に一致したものが優先されるため、前に挿入した候補が後の候補をシャドーイングし、集合の比較では追加と判定されても、受理される言語が狭まることがあります。compare は集合ではなく位置を調べ、以前は到達可能だった代替候補がシャドーイングされたことを報告します。
--corpus には .tsv フィクスチャファイル、またはそのようなファイルを格納したディレクトリを指定します。@tabnas/support を通じて読み込まれます。これはフィクスチャランナーが使うものと同じローダーです。実際の入力だけが、ドキュメントで何が起きているかを測定する唯一の層です。
tabnas compare --a v1.json --b v2.json --corpus ../json/test/spec
変更が見つかった場合、終了コードは 1 です。そのため、リリースゲートとして機能します。
ホスト型エンドポイント
mcp.tabnas.dev は、npx を実行できないエージェント向けに、ストリーミング可能な HTTP(POST /mcp、および GET /health と GET /.well-known/mcp)を通じて、同じ 7 つのツールを提供します。引き続きローカル stdio を推奨します。無料で、プライベートかつ再現可能で、制限もありません。
ホスト型サービスは同じコアを使用するため、同じ内容で応答します。ただし、共有インフラストラクチャ上で攻撃者が制御するテキストを解析するため、制限が設けられています。本文サイズの上限は 256 KB、IP あたりのリクエスト数は 1 分間に 60 件です。どちらも /.well-known/mcp で事前に通知され、拒否時にはローカルでの代替手段とともに(limit_exceeded/rate_limited)として示されます。レート制限は Cloudflare によるもので、IP ごとにデータセンター単位で概算されるため、継続的な不正利用に対する防御であり、厳密なクォータではありません。短時間のバーストでは、拒否が始まるまでに 60 件を超える場合があります。ドキュメントの内容がログに記録、保存、またはトレーニングに使用されることはありません。テレメトリに記録されるのは、形状のみです。ツール名、サイズの範囲、所要時間、ステータス、エラーコードです。
同梱データ
公開済みパッケージにはフリートのコントラクトファイルが含まれていません(パーサーの npm ファイルには schema/ が含まれず、プラグインパッケージには tabnas.plugin.json が含まれません)。そのため、このリポジトリには生成済みのコピーを data/ にコミットしています。文法と診断スキーマ、エラーコードのレジストリ、DIVERGENCE.md、およびすべてのフリートプラグイン記述子(名前順にソートされた plugins.json)です。このリポジトリの隣にある兄弟チェックアウト(../<repo>)から、次のように再生成します。
cd ts && npm run gen-data
ビルド時に data/ を ts/src/data-bundle.ts(生成物、gitignore 対象)にコンパイルし、コードはファイルシステムではなく、その静的インポートを読み込みます。ホスト型 Worker にはファイルシステムがないためです。テストスイートは、再生成の古さや埋め込みデータの古さがあると失敗し、手作業で管理するリストではなく、ディレクトリと埋め込みデータのセットを照合します。重複させず、導出してください(ADR-10)。
data/grammar.schema.json も別の理由から同じように扱います。Ajv は JavaScript を生成して new Function を呼び出して検証しますが、Cloudflare Workers ではこれが全面的に禁止されています。そのため、tools/build-validator.js がビルド時にスキーマを ts/src/grammar-validator.js に事前コンパイルします。同じ Ajv、同じエラー形式を、より早い段階でコンパイルします。
ビルドとテスト
cd ts
npm install
npm test # builds first, then runs every test/*.test.js
npm test は test/workerd.test.js で終了します。このテストは実際の workerd で実際の wrangler.json を起動し、HTTP で通信します。失敗した場合に「ホスト型エンドポイントをデプロイできない」ことを意味する唯一のテストであり、wrangler の devDependency(および、それと一緒に npm がインストールする workerd バイナリ)が必要です。数秒余計にかかりますが、Node レベルのテストでは置き換えられません。このリポジトリでこれまでデプロイを妨げた不具合は、どれも Node ではテストに合格していたためです。
フリートのレイアウト(このリポジトリの隣に兄弟チェックアウトがある構成)で作業する場合は、npm install の後に兄弟リポジトリへのシンボリックリンクを作成し、ソースに対してテストしてください(npm はインストールのたびにこれらを置き換えるため、インストール後に再作成してください)。
rm -rf node_modules/@tabnas/parser node_modules/@tabnas/support
ln -s ../../../../parser/ts node_modules/@tabnas/parser
ln -s ../../../../support/ts node_modules/@tabnas/support
CI
.github/workflows/ci.yml は、組織の tabnas/.github にある polyglot-ci.yml の呼び出し元です(ts のみ、parser と support を兄弟リポジトリとしてクローン)。a14741c で ci/ci.yml から昇格しました。このファイルへの変更は、レビュー済みプルリクエストを通じて .github/workflows/ で直接行います(管理者 ADR-8、2026-09-24 改訂)。
CI は test/workerd.test.js を実行します。このテストは実際の workerd で実際の wrangler.json を起動するため、ホスト型エンドポイントをデプロイできることがすべてのプッシュで検証され、デプロイ時に初めて問題が判明することはありません。
ライセンス
MIT。LICENSE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。