Skip to content

feat(mcp): MCP server (search + publish) & fix empty English search index#365

Open
Crokily wants to merge 6 commits into
mainfrom
feat/Crokily/mcp-server
Open

feat(mcp): MCP server (search + publish) & fix empty English search index#365
Crokily wants to merge 6 commits into
mainfrom
feat/Crokily/mcp-server

Conversation

@Crokily

@Crokily Crokily commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

用法

社区成员现在可以把本站作为 MCP Server 接入 Claude Code 或其他支持 Streamable HTTP 的 MCP 客户端。匿名连接后即可调用 search,按中文或英文索引搜索站内文章,并取得标题、摘要、相关正文片段和文章链接。登录连接后则可快速方便地发布文章。

目前仅提供 search 和 publish 两个 tool,用于搜索文章,和发布文章

image image

主要入口是站内的 /mcp 页面。用户可以选择 Claude Code、Codex CLI、OpenCode、Gemini CLI、Cursor、VS Code、claude.ai 网页、ChatGPT 网页或 Pi,一键复制对应的安装命令或配置。登录后,页面生成的发布配置会自动填入当前账号的 satoken。

claude mcp add --transport http involutionhell https://involutionhell.com/api/mcp

需要发布内容时,必须使用附带 satoken 的安装方式,例如:

claude mcp add --transport http involutionhell https://involutionhell.com/api/mcp \
  --header "Authorization: Bearer <你的satoken>"

搜索不要求登录,配置了 token 的客户端也不会在搜索时访问鉴权后端。当前 satoken 最长有效 30 天,过期后需要重新登录,并在 /mcp 页面重新复制配置。(该情况后续可通过后端配合优化,附带了一个文档用于后端团队参考:dev_docs/mcp_auth_upgrade.md)

网页类 MCP 客户端目前还没有安全的 OAuth 授权和续期流程,因此现阶段只能可靠地使用匿名搜索。发布功能暂时面向能够由用户显式配置 token 的可信本地客户端。

安装后指明让 agent 调用 involutionhell mcp 即可工作:
image
image
image
image

配套的 Agent Skill 和 CLI

本 PR 还配套做了一个独立仓库:InvolutionHell/involutionhell-agent-tools。仓库中包含一个采用 Agent Skills 开放格式的 SKILL.md,可供支持该格式的多种 agent 使用;同时提供一个 Node CLI,包含 searchpublishwhoami,可以直接通过 npx 运行。

做这部分的原因很直接。现在不少厂商正在把 CLI 作为比 MCP 更基础的 agent 接口。例如,Notion CLI 出现后基本取代原有的 Notion MCP,因此这次没有把本站能力只绑定在 MCP 上,而是顺便把 CLI 做成基础,实现了 MCP 同样的功能,并可用于未来拓展,再通过配套 Skill 告诉 agent 如何在 MCP、CLI、curl 和 GitHub PR 之间选择。

MCP 仍然是首选集成:客户端已经连接 involutionhell MCP Server 时,agent 可以直接调用结构化的 searchpublish 工具,不需要管理额外命令。CLI 则适合能够使用 shell、但没有 MCP 连接的 agent (例如 Pi),也可以作为本地调试和轻量自动化的 fallback。两者共享搜索语义和发布 API,独立仓库不会复制一套 MCP Server。

安装 Agent Skill:

npx skills add InvolutionHell/involutionhell-agent-tools

没有 MCP 连接时,可以直接运行 CLI:

npx --yes github:InvolutionHell/involutionhell-agent-tools search "数组" --limit 3
npx --yes github:InvolutionHell/involutionhell-agent-tools publish post.md --dry-run

搜索默认使用中文索引,也支持 --locale en--json--no-cache。发布读取 Markdown 文件及其 YAML frontmatter,命令行参数可以覆盖标题、摘要、标签和 slug。--dry-run 只打印即将发送的 JSON,不访问网络,也不会打印 token。

真实发布和 whoami 只从环境变量读取凭证,避免 token 进入 shell history 或进程列表:

export INVOLUTIONHELL_SATOKEN="..."
npx --yes github:InvolutionHell/involutionhell-agent-tools whoami
npx --yes github:InvolutionHell/involutionhell-agent-tools publish post.md

Skill 还规定发布前必须先用中英文关键词和同义词查重,并根据内容形态选择发布轻量帖子,或通过 GitHub PR 收录进知识库。

CLI 和 Skill 也已通过测试:
image
image

开发思路

MCP Server 作为无状态的 Streamable HTTP 路由放在 /api/mcp,随现有 Next.js 站点部署。搜索没有另建内容库,而是复用站内搜索的 Fumadocs、pageToIndex 和 Orama 索引管线,按中英文建立延迟加载的 shard,并沿用中文分词。发布则把 MCP 输入转换成现有后端格式,调用 POST /api/posts,因此文章创建、slug 冲突和用户身份仍由原有后端处理。

连接页是 /[locale]/mcp 下的 SSG 页面。各客户端的命令语法依据 2026 年 7 月各自的官方文档逐项核对,而不是凭记忆编写。Gemini 配置使用 httpUrl;VS Code 使用顶层 servers.vscode/mcp.json,避开已知的 header 问题;Codex 配置保存环境变量名,而不是直接保存 token;Pi 本身不支持 MCP,因此对应标签页指向配套的 Skill/CLI 仓库。satoken 只在客户端挂载后从 localStorage 读取,不会出现在预渲染 HTML 中。所有配置片段都由纯函数生成,并有单元测试覆盖。

鉴权集中在 lib/mcp/auth.ts。只有 publish 调用会校验 bearer satoken,工具层只接收已经验证的身份和后端请求头。项目同时加入了 /.well-known/oauth-protected-resource 和后端升级文档,后续接入 OAuth 时可以替换 token 校验方式,不需要修改工具参数和发布流程。

目前 satoken 过期后需要在 /mcp 页面重新复制。文档向后端提出了 sa-token 基于活动自动续期的滑动续期方案,作为 OAuth 落地前降低 30 天 token 更新频率的低成本缓解。纯滑动续期的安全代价是,泄漏但持续活跃的 token 可能永不过期,因此建议同时设置绝对最长生命周期。根治方案仍是支持 refresh token 的 OAuth,具体方案见 dev_docs/mcp_auth_upgrade.md

开发过程中还发现了一个原有站点问题:source.getPages() 不传语言时只返回中文页面,导致 /search.en.json 一直生成空索引。现在英文路由改用 source.getPages("en"),并同时识别 lang: en.en.md.en.mdx 文件名,缺少语言 frontmatter 的英文页面也能进入正确索引。

对抗性 review 发现,畸形 JSON 会让上游处理器挂到函数超时,因此路由现在会先读取并解析请求体:畸形 JSON 返回 400,JSON-RPC batch 直接拒绝,超过 1 MB 返回 413。工具字段加入长度和数量限制,鉴权与发布请求都设置 10 秒超时;缺失或无效 token 返回带 challenge 的 401,鉴权服务超时、网络失败或 5xx 返回 503,避免把服务故障误报成凭证失效。失败的索引构建也会清除缓存,允许后续请求重试。

当前 14 个测试文件中的 110 个测试全部通过。构建路由表新增 /api/mcp/.well-known/oauth-protected-resource 两个动态路由,以及 /[locale]/mcp SSG 页面,没有改变既有路由的渲染模式。完整的 MCP 协议流程,包括 initialize、tools/list、中英文搜索、发布鉴权路径和畸形请求等异常用例,已经在本地完成端到端验证,并在两个 Vercel Preview 部署上实测了真实搜索调用。

本 PR 当前涉及 33 个文件,共新增 3201 行、删除 6 行。其中测试目录新增 725 行,覆盖上述安全修复、英文索引修复和连接配置,并随 pre-commit 和 content-check CI 执行。另有两份共 278 行的 dev_docs 文档:mcp_server.md 是本功能的设计与运维说明,mcp_auth_upgrade.md 是给后端团队的 OAuth 升级配合方案,供后续排期使用。

@vercel

vercel Bot commented Jul 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
involutionhell-github-io Ready Ready Preview, Comment Jul 19, 2026 1:35am
website-preview Ready Ready Preview, Comment Jul 19, 2026 1:35am

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f0c9156e8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/api/mcp/route.ts Outdated
Comment thread lib/mcp/search-core.ts
@longsizhuo

Copy link
Copy Markdown
Member

收到,我看看

Crokily added 2 commits July 12, 2026 17:57
source.getPages() without a locale argument only returns default-locale
(zh) pages, so the static /search.en.json index has been empty since the
i18n split. Enumerate pages with getPages("en") and classify English
pages by the .en.md(x) file suffix in addition to lang frontmatter, so
translations missing lang: en are indexed and excluded from the zh shard.
Expose /api/mcp (Streamable HTTP, stateless) with two tools:

- search: server-side Orama query over the existing zh/en Fumadocs
  index pipeline, public with Upstash rate limiting
- publish: forwards to the backend POST /api/posts with the caller's
  satoken (Authorization: Bearer), returning the public post URL

Credential verification is isolated in lib/mcp/auth.ts and only runs
for publish calls; invalid tokens get a 401 challenge, auth-service
outages a 503, and both backend fetches carry 10s timeouts. The route
validates body size (1 MB), JSON syntax, and rejects JSON-RPC batches
before the transport. /.well-known/oauth-protected-resource prepares
the OAuth resource-server metadata; the authorization-server rollout
plan for the backend team is documented in dev_docs/mcp_auth_upgrade.md.
/mcp (SSG, zh/en) lets users pick their MCP client and copy install
commands with their satoken auto-filled client-side after login. Covers
Claude Code, Codex CLI, OpenCode, Gemini CLI, Cursor, VS Code, the two
web clients (search-only until OAuth), and Pi (via the companion
skill/CLI since Pi has no MCP support). Command syntax per client was
verified against current official docs. The token is read from
localStorage only after mount and never appears in prerendered HTML.

Also documents the sa-token sliding-renewal option for the backend as a
near-term way to reduce 30-day token churn before OAuth.
@Crokily Crokily reopened this Jul 19, 2026
Browser-hosted MCP clients preflight OPTIONS and need
Access-Control-Allow-Origin on responses. Add an OPTIONS handler and a
centralized CORS wrapper over GET/POST (streaming-safe), exposing
WWW-Authenticate so browser clients can read the auth challenge.
Wildcard origin is safe here: auth is bearer-header based, not cookies.

Co-authored-by: chatgpt-codex-connector[bot] <chatgpt-codex-connector[bot]@users.noreply.github.com>
The /mcp page now builds install commands against the current origin
after mount, so local dev and Vercel previews produce directly usable
/api/mcp URLs while prerendered HTML keeps the production default.
@Crokily

Crokily commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

该 PR 合并后,维护者需要进行一下 Registry 的登记,把我们的 MCP server( https://involutionhell.com/api/mcp )收录进官方 MCP Registry,收录后会自动同步到 GitHub MCP Registry,用户在各类 AI 客户端里搜 "involutionhell" 就能直接找到并接入。大概的做法就是:安装官方工具 mcp-publisher,进入 involutionhell-agent-tools 仓库的 docs/registry/ 目录(已备好 server.json 模板和详细 runbook),依次跑 mcp-publisher init、mcp-publisher login github(跳浏览器,用有 InvolutionHell org 身份的 GitHub 账号授权一次)、mcp-publisher publish,最后去 registry.modelcontextprotocol.io 搜 involutionhell 确认条目存在即可,全程不改代码、约十分钟。

@longsizhuo

Copy link
Copy Markdown
Member

该 PR 合并后,维护者需要进行一下 Registry 的登记,把我们的 MCP server( https://involutionhell.com/api/mcp )收录进官方 MCP Registry,收录后会自动同步到 GitHub MCP Registry,用户在各类 AI 客户端里搜 "involutionhell" 就能直接找到并接入。大概的做法就是:安装官方工具 mcp-publisher,进入 involutionhell-agent-tools 仓库的 docs/registry/ 目录(已备好 server.json 模板和详细 runbook),依次跑 mcp-publisher init、mcp-publisher login github(跳浏览器,用有 InvolutionHell org 身份的 GitHub 账号授权一次)、mcp-publisher publish,最后去 registry.modelcontextprotocol.io 搜 involutionhell 确认条目存在即可,全程不改代码、约十分钟。

这一步我会,我其他项目就登记过了,Gallama和其他awsome-project我都去注册一下,到时候把链接发Discord群里,大家去表态一下就可以增加成功率

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants