mcpField
T
tabnas

tabnas

远程服务
tabnas.dev开发工具03 周前更新

关于 tabnas

tabnas 为解析引擎提供 TypeScript MCP 服务和 CLI,面向语法开发与测试。两种入口共享核心,并确保 JSON 结果一致;语法以数据形式验证,不执行代码。

主要功能

  1. 01解析输入并生成语法树
  2. 02验证语法规范并诊断错误
  3. 03运行 TSV 语法测试夹具
  4. 04列出并查看语法插件
  5. 05比较语法接受范围与输出
  6. 06提供语法和诊断资源

适用场景

  1. 01检查输入能否按给定语法解析
  2. 02定位解析失败原因
  3. 03用 TSV 夹具回归测试语法
  4. 04评估语法修改的兼容性

MCP 相关

MCP 服务通过 stdio 提供七种语法操作,并公开语法、诊断、错误和插件等资源。托管端点也通过 streamable HTTP 提供相同工具。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://mcp.tabnas.dev/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
npm@tabnas/mcp0.1.20

工具

7
参数类型必填说明
inputstring是要解析的源文本。
grammarobject否序列化的 GrammarSpec(纯 JSON,不含函数)。架构:资源 tabnas://schema/grammar。使用前会验证语法;包含 `ref` 键或非内置函数引用的语法会被拒绝。
optionsobject否在语法之前应用于新实例的 TabnasOptions。仅限数据:如果包含 plugins 条目则会被拒绝。

详细介绍

tabnas/mcp

tabnas Agent 工具:一套 TypeScript 代码,两种前端: 一个 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 不写明版本号:仓库无法固定写入自身已发布版本的确切版本号,因为更新版本号的提交会成为下一次发布的内容,导致 README 永远落后一个版本。

服务器由 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 检查。)

七个工具

工具解答的问题结果
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某个插件的完整描述符tabnas.plugin.json 对象
compare_grammars语法变更后,是否仍接受旧语法接受的内容,并生成相同的树?{normalForm, proven[], observed[], changes[], counterexamples[], confidence, why}

关于契约的说明:

  • 每次调用都会为每项操作创建一个全新的引擎实例。parse 会先应用 options,再应用 grammar。如果没有提供语法,实例 与 new Tabnas() 完全相同:基础引擎不定义任何规则,因此每个输入 都会生成 undefined 树(序列化为 {"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);任何非 $ 结尾引擎内置项的函数引用; plugins 键,无论它是请求选项还是 grammar.options 中的键(插件是实时 代码);以及规则数超过 5000 的语法(CPU 限制)。“验证此语法”绝不会变成“运行 此代码”或“污染此进程”。
  • 非诊断类的引擎抛错(例如,options.parser.start 被设为 非函数)会被捕获,并以相同的干净格式 {ok:false, errors:[{path:"",message}]} 返回,因此 CLI 和 MCP 工具的行为一致。
  • explain_parse_error 会将诊断与捆绑的错误代码注册表条目({code, message, hint})关联;对于注册表未知的代码(例如插件声明的代码),registry 为 null。
  • test_grammar 接收符合 fleet 测试用例约定(@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 时,会输出易读的呈现结果;解析失败时,会输出引擎自身呈现的错误消息。

退出代码:

Code含义
0成功:解析成功/语法有效/所有 fixture 行均通过
1操作未通过:解析失败、语法无效、fixture 失败、未知插件
2用法错误:未知标志或命令、文件缺失/不可读、语法 JSON 格式错误

传入尚未成为 GrammarSpec 的语法

每个工具都接受序列化后的 GrammarSpec,即纯 JSON。它不接受 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。 这是专为此用途设计的函数;另外两个显而易见的 替代方案都不合适:

  • abnfCompile() 返回的是 jsonic 文本,不是对象。适合写入 语法文件,但不是工具参数所需的内容。
  • 单独调用 abnfConvert() 会返回带有 ref(使用 builtins: true 转换时为空)和标记字段的 spec。防火墙会拒绝 ref 的存在,而不仅仅是其内容;这是有意为之,因为在安全边界上,不值得推敲“足够为空”究竟是什么属性,而且 m 标记不属于序列化格式。toPureSpec 会剥离这两者并添加 v。

对于只需判断接受/拒绝、无需构建树的语法,toRecognitionSpec 作用相同,但不包含构建树的内置项。

其他前端的等效方式是 tabnas parse --grammar g.json, 其中 g.json 是构建步骤写出的文件。

语法兼容性(compare)

分别报告两个问题,因为它们失败的方式不同:

  1. 接受性。 候选语法是否仍接受基线语法接受的内容?
  2. 输出。 对于两者都接受的输入,生成的树是否相同?

用户感受最明显的是第二点。即使仍接受所有历史文档,但树的结构发生变化,也会悄无声息地破坏所有下游使用方;而仅测试接受性的测试却会报告成功。

报告提供证据和置信度,而非空洞的结论。 它特意不提供 compatible: true 字段。语言包含关系通常不可判定,因此如果工具输出这样的字段,最终会在生产环境中出错:

  • proven[]。静态确立的内容及其依据。任何超出可判定子集的内容都会标记为 not-proven;这是对本工具能力的说明,并非声称语法不兼容。
  • observed[]。实际运行的内容及其覆盖范围。
  • changes[] / counterexamples[]。具体差异及对应输入。
  • confidence + why。对未发现问题这一结果应有多大信心。带有明确原因的 confidence: "low" 仍是一次成功运行。

真正实用的检查是备选项的顺序。备选项按顺序匹配,命中第一个即停止,因此插入一个较早的备选项可能会遮蔽较晚的备选项,从而缩小接受的语言范围,而集合比较却会将其视为新增。compare 检查的是位置,而非成员关系,并报告过去可达、现在被遮蔽的备选项。

--corpus 接受 .tsv fixture 文件或包含此类文件的目录,并通过 @tabnas/support 加载;fixture 运行器也使用同一个加载器。真实输入是唯一能衡量文档实际表现的层级:

tabnas compare --a v1.json --b v2.json --corpus ../json/test/spec

发现任何变化时,退出代码为 1,因此可用作发布门禁。

托管端点

mcp.tabnas.dev 通过可流式传输的 HTTP(POST /mcp,以及 GET /health 和 GET /.well-known/mcp)提供相同的七种工具,供无法运行 npx 的 Agent 使用。本地 stdio 仍是推荐方式:免费、私密、可复现且不受限制。

托管服务使用相同的核心,因此响应完全一致;同时它也有使用边界,因为它会在共享基础设施上解析攻击者可控的文本。请求正文上限为 256 KB,每个 IP 每分钟最多 60 个请求;这两项限制都会由 /.well-known/mcp 预先报告,并在拒绝请求时(limit_exceeded / rate_limited)连同本地替代方案一并说明。速率限制由 Cloudflare 执行,按每个数据中心内的每个 IP进行近似计数,因此它是抵御持续滥用的屏障,而非精确配额;短时间突发请求可能超过 60 次,之后才开始拒绝。文档内容绝不会被记录、存储或用于训练;遥测只记录形态信息:工具名称、大小区间、时长、状态、错误代码。

捆绑数据

已发布的包不包含整个 fleet 的契约文件(解析器的 npm 文件不包含 schema/;插件包不会附带 tabnas.plugin.json),因此本仓库会在 data/ 中提交生成的副本:语法和诊断 schema、错误代码注册表、DIVERGENCE.md,以及 fleet 中每个插件的描述符(按名称排序的 plugins.json)。从同级检出目录(本仓库旁的 ../<repo>)重新生成:

cd ts && npm run gen-data

构建会将 data/ 编译到 ts/src/data-bundle.ts(生成文件,由 git 忽略),代码读取这个静态导入,而绝不访问文件系统,因为托管 Worker 没有文件系统。测试套件会在重新生成内容过时或嵌入内容过时时失败,并将嵌入的集合与目录进行核对,而不是依赖手动维护的列表。应当推导,而不是重复(ADR-10)。

data/grammar.schema.json 也会以相同方式处理,但原因不同:Ajv 通过生成 JavaScript 并调用 new Function 来验证,而 Cloudflare Workers 完全禁止这样做,因此 tools/build-validator.js 会在构建时将 schema 预编译到 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 测试中都曾通过。

在 fleet 布局中工作(本仓库旁边有同级检出目录)时,运行 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。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。