关于 site-mcp
site-mcp 是面向 MCP 客户端的本地只读服务,公开 robertdelanghe.dev 的身份资料、文章及其他站点数据。它按 Sigstore 签名清单验证响应,并让 MCP 工具与 CLI 共用操作定义。
主要功能
- 01读取文章列表与单篇文章
- 02获取合规报告和 GitHub 语料
- 03提供个人资料、简历凭证等资源
- 04按 SHA-256 清单校验响应
- 05MCP 与 CLI 共用操作定义
适用场景
- 01浏览站点文章及文章内容
- 02检查页面合规报告
- 03读取 GitHub 语料数据
MCP 相关
通过 stdio 向 MCP 客户端提供只读工具和资源。响应会与站点的签名 SHA-256 清单核对;校验失败时不返回数据。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
@bounded-systems/site-mcp
一个本地、只读的 MCP 服务(以及配套 CLI),用于访问 robertdelanghe.dev 的签名静态 API。
它向任何 MCP 客户端(Claude Desktop、Claude Code 等)提供该站点的身份数据——个人资料、文章、GitHub 语料库、简历凭证和 OpenAPI 文档——并在返回数据前,逐字节验证每个响应是否与该站点经 Sigstore 签名的 sha256 清单一致。如果客户端将收到的字节与签名清单不符,它就会拒绝返回数据。
它通过 stdio 在本地运行——客户端以子进程方式启动它。它没有托管服务,也不会监听网络端口,因此保留了该站点静态且无攻击面的特性。
通用核心的轻量实现
此软件包现在是一个轻量封装。所有可复用机制——验证型获取客户端、sha256 清单与 Sigstore 检查,以及 VerbSpec → MCP (tools + resources) / VerbSpec → CLI 投影——均位于
@bounded-systems/static-mcp 中。site-mcp 仅提供:
- 动词(
src/verbs.ts)——list_posts、get_post、get_conformance、get_corpus,每个动词都只定义一次,作为@bounded-systems/verbspecVerbSpec; - 资源目录(
src/catalog.ts)——site://…资源; - 配置值(
src/config.ts)——源站和预期的签名者身份;以及 - 入口(
src/index.ts)——选择一个接口,并将规范交给核心。
src/verbs.ts ─┐
src/catalog.ts ├─▶ buildSiteSpec(config) ─▶ @bounded-systems/static-mcp
src/config.ts ─┘ serveVerifiedStaticMcp(spec, config) (MCP, stdio)
runStaticCli(spec, config, argv) (CLI)
两个接口,一份定义。 verbspec 会将每个动词投影为一个 MCP 工具和一个 CLI 子命令。同一组动词同时为
site-mcp的 MCP 工具和 CLI 命令提供支持——无需重复定义,也不会出现偏差。
安装 / 运行
需要 Node ≥ 18.17。site-mcp 的 verbspec 依赖发布在 JSR 上,因此安装时会通过 JSR 的 npm 桥接解析该依赖——随附的 .npmrc
设置了 @jsr:registry=https://npm.jsr.io。(在全新环境中使用时,请将这一行添加到 npm 配置中。)
# MCP server over stdio (what an MCP client launches):
npx -y @bounded-systems/site-mcp
# CLI — the SAME verbs, printing the verified JSON:
npx -y @bounded-systems/site-mcp list_posts
npx -y @bounded-systems/site-mcp get_conformance # the index
npx -y @bounded-systems/site-mcp get_conformance accessibility # one area
npx -y @bounded-systems/site-mcp get_conformance --full # every criterion
npx -y @bounded-systems/site-mcp get_corpus # the index
npx -y @bounded-systems/site-mcp get_corpus topics # one full list
npx -y @bounded-systems/site-mcp get_post agent-authored-code-drift
MCP 服务会将就绪信息写入 stderr(stdout 是 MCP 通道):
site-mcp ready (stdio) → https://robertdelanghe.dev; signature mode=off
MCP 客户端配置
{
"mcpServers": {
"robertdelanghe": {
"command": "npx",
"args": ["-y", "@bounded-systems/site-mcp"],
"env": { "SITE_MCP_SIGNATURE_MODE": "warn" }
}
}
}
资源
| 资源 URI | 端点 | 内容 |
|---|---|---|
site://profile | profile.json | 标题、简介、标签、链接 |
site://posts | posts.json | 文章的 JSON Feed(文章列表) |
site://post/{slug} | posts/{slug}.json | 单篇文章(模板化;list 从 Feed 中枚举文章) |
site://corpus | corpus.json | GitHub 语料库:统计数据与精选内容 |
site://conformance | conformance.json | 各页面 DOM 一致性报告 |
site://resume-vc | resume.vc.json | 作为可验证凭证的简历 |
site://openapi | openapi.json | 该 API 的 OpenAPI 3.2 文档 |
工具 / CLI 命令(只读)
两个接口提供相同的四个动词:
| 工具 / 命令 | 参数 | 返回内容 |
|---|---|---|
list_posts | — | 文章 Feed(slug、标题、摘要、标签) |
get_post | slug | 根据 slug 获取单篇文章 |
get_conformance | — | area | --full | 一致性索引(3.2 KB)| 一个区域 | 每项标准(19.7 KB) |
get_corpus | — | list | --full | 语料库索引(9.2 KB)| 一个排名列表 | 完整语料库(71.7 KB) |
每个主题一个动词,而非每次下钻一个动词
客户端会在发起任何调用之前,将每个工具的名称、描述和输入架构加载到上下文中。无论是否使用该工具,每次会话都要付出这笔成本;在这些工具中进行选择本身也是一次扇出。因此,工具列表是一个折叠过程:F 是列表,一次调用是生成器规则的一步,而终端响应则是展开停止的位置。
因此,每次下钻设置一个动词并不合适:它缩小了有时付出的成本,却扩大了始终付出的成本。get_conformance_index + get_conformance_area + get_corpus_index + get_corpus_list 会让此服务的工具从 3 个增至 8 个。
我们改为每个主题设置一个动词,并让参数决定生成器规则:不带参数时返回索引,带参数时展开其中一个分支,而 --full 仍会从文档自身的路径获取完整展开的文档。API 没有删减任何内容——site://conformance 和 site://corpus 仍提供完整文档,同时新增了 site://conformance/index 和 site://corpus/index 作为入口。
默认行为已更改。 不带参数调用
get_conformance过去会返回完整的 19.7 KB 报告;现在会返回 3.2 KB 的索引。传入--full(CLI)或{"full": true}(MCP)即可恢复之前的行为。
资源读取和工具结果都包含 _meta.verification 区块(相对于清单的路径、源 URL、已验证的 sha256 以及清单签名状态)。CLI 会输出已验证的 JSON;验证失败时会以非零状态退出,且 stdout 不会输出任何内容。
验证/信任模型
网站发布一份签名清单 https://robertdelanghe.dev/site.sha256(sha256sum 格式),并提供对应的 Sigstore bundle site.sha256.sigstore.json。核心逻辑会执行以下操作:
- 逐文件哈希检查(始终启用)。 每个进程获取一次清单;对于每个资源,获取其内容并对收到的字节计算 SHA-256,要求摘要与清单条目一致。文件遭篡改、CDN 边缘节点内容过期或遭遇中间人攻击 → 摘要不匹配 → 返回
VerificationError,而非响应。清单中不存在的路径同样会被拒绝。 - 清单签名检查(可选)。
SITE_MCP_SIGNATURE_MODE=warn|require会根据部署工作流身份(…/bdelanghe/site/.github/workflows/deploy.yml@refs/heads/main)验证 Sigstore bundle。
Sigstore 后端/
@bounded-systems/verify。 可选的清单签名检查步骤原本计划委托给@bounded-systems/verify,这是规范的进程内 bundle 验证器。截至[email protected],该包以可自行执行的 CLI 形式发布,不导出任何函数(导入时会运行并退出进程),因此核心逻辑保留了一份行为完全相同的最小检查副本;该问题已向上游提交。请参阅 static-mcp 的 README。
配置
| 变量 | 默认值 | 含义 |
|---|---|---|
SITE_MCP_BASE_URL | https://robertdelanghe.dev | 提供网站、API 和清单的源 |
SITE_MCP_SIGNATURE_MODE | off | off | warn | require |
SITE_MCP_SIGNER_IDENTITY | deploy workflow SAN | 预期的 Sigstore 证书身份 |
SITE_MCP_SIGNER_ISSUER | GitHub Actions OIDC | 预期的 Sigstore OIDC 颁发者 |
SITE_MCP_FETCH_TIMEOUT_MS | 15000 | 每次请求的获取超时时间 |
开发
npm install # resolves @bounded-systems/static-mcp (npm) + verbspec (JSR bridge)
npm run build # tsc → dist/
npm test # node --test via tsx (server + CLI; no network)
npm run typecheck
发布
一个标签即可将同一版本镜像发布到三个注册表。 推送
v* 标签会运行 publish.yml,并分发到:
| # | 注册表 | 标识符 | 身份验证 |
|---|---|---|---|
| 1 | npm | @bounded-systems/site-mcp | 可信发布(OIDC)+ 出处证明 |
| 2 | JSR(镜像) | @bounded-systems/site-mcp | 无令牌 OIDC(npx jsr publish) |
| 3 | MCP Registry | io.github.bounded-systems/site-mcp | GitHub-OIDC 命名空间身份验证(mcp-publisher) |
没有长期有效的密钥——每个注册表都使用作业的短期 GitHub Actions OIDC 令牌(id-token: write)进行身份验证。npm 需要 npm ≥ 11.5(工作流会升级 npm 以确保满足此要求)。
重要
版本必须保持一致。 发布版本位于四处,必须全部一致:
package.json、deno.json、server.json和v<version>git 标签。工作流的verify作业会在任何一处不匹配时彻底中止发布,因此 npm 和 JSR 的版本绝不会出现偏差。MCP Registry 还要求package.json包含"mcpName": "io.github.bounded-systems/site-mcp"(它会读取已发布 npm 包中的此字段来验证所有权)。
MCP Registry 作业会在 npm 作业之后运行,因为该注册表会通过读取刚发布的 npm 包中的 mcpName 来验证所有权。
一次性设置(维护者)——请在第一个标签之前完成
这三项注册表端授权只需执行一次。其中两项(JSR、MCP Registry)只需关联仓库 / 使用 OIDC——不会生成令牌。
(a) npm——可信发布者(在 npmjs.com 上)
- 以
@bounded-systems作用域所有者身份登录。 - 打开
@bounded-systems/site-mcp包页面 → Settings → Trusted Publisher。对于全新包,你可能需要先手动发布一次0.1.0(或创建该包),然后再切换到可信发布。 - 选择 GitHub Actions 并填写:
- Organization / user:
bounded-systems - Repository:
site-mcp - Workflow filename:
publish.yml←(原为publish-npm.yml) - Environment:(留空)
- Organization / user:
- 保存。不会生成或存储任何令牌。请确保包的发布访问策略允许自动化 / OIDC(可信发布者符合双重身份验证要求)。
(b) JSR——创建并关联包(在 jsr.io 上)
- 使用 GitHub 登录 jsr.io,并在
@bounded-systems作用域下创建包@bounded-systems/site-mcp。 - 打开包的 Settings 标签页 → 在 GitHub Repository 下填写
bounded-systems/site-mcp并点击 Link。关联仓库即可启用此工作流的无令牌 OIDC 发布(原理与 npm 的可信发布者相同)。不会创建令牌。
(c) MCP Registry——无需预先授权
io.github.bounded-systems/* 命名空间会通过 GitHub OIDC 自动授权:
由于此仓库位于 github.com/bounded-systems 下,mcp-publisher login github-oidc 会通过 Actions 运行本身证明命名空间所有权。无需提前执行注册表端的声明 / 同意 / 关联步骤——首次运行 publish.yml 时会自行完成身份验证并注册服务端。
(npm 条目的包所有权通过 mcpName 字段单独证明;请参阅上方说明。)
发布版本(单条命令)
# 1. Bump the version in ALL of: package.json, deno.json, server.json
# (and the package entry in server.json). Commit.
# 2. Tag with the SAME version and push — this is the only command:
git tag v0.1.0 && git push origin v0.1.0
这个 v* 标签会触发 publish.yml → npm + JSR + MCP Registry,且全部使用同一版本。你也可以在 Actions 标签页通过 workflow_dispatch 运行它(此时会使用现有的 package.json 版本,而非标签)。
本地试运行(验证但不发布)
npm pack --dry-run # npm tarball contents
npx --yes jsr publish --dry-run --allow-slow-types # JSR (or: deno publish --dry-run --allow-slow-types)
mcp-publisher validate ./server.json # MCP Registry schema check
site-mcp 依赖
@bounded-systems/static-mcp;请先发布核心包 (为它自己的v*标签 → JSR + npm),然后再为 site-mcp 创建标签。
许可证
MIT — 详见 LICENSE。网站数据本身采用 CC BY 4.0 许可发布。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。