跳转到主要内容

MCP Server

以 Model Context Protocol 暴露给 AI 客户端的只读检索接口,可选开放运维工具组

MCP Server 把站点已发布的文章以 Model Context Protocol 暴露给 AI 客户端(如 Claude、Cursor),让模型在不抓取网页的前提下检索站内公开内容,并可在配置令牌后开放线上运维工具。本节介绍端点位置、暴露的工具、运维工具组、配置开关与限速策略。

启用与关闭

MCP 端点的开关在 site.config.ts 的 features.mcp(默认 true)。改动该字段后必须重新 bun run build,开关在构建期烘焙到运行时配置;关闭后端点保持注册但一律返回 404,与高德地图服务端代理的关闭模式一致。

端点位置

POST /mcp 是唯一的 MCP 入口,采用 JSON-RPC 协议且不建立 session(stateless),每次请求都会新建一个 MCP Server 实例并就地销毁。端点位于根级 URL,不走 /api/* 前缀,因此不受 Referer 校验和后台访问日志约束。AI 客户端无浏览器 Referer,但端点本身已自带限速、只读白名单与字段筛选,公开检索无须额外门禁;唯一的写操作清缓存另受 MCP_OPS_TOKEN 令牌门禁,见 运维工具组。

非 POST 方法会得到 405 与 Allow: POST 响应头,请求体超过 1 MB 会直接被 SDK 拒收。

暴露的工具

默认暴露十九个只读检索工具,全部带 readOnlyHint: true,避免 prompt injection 把 AI 引导到删文章、改评论;配置 MCP_OPS_TOKEN 后还会追加五个运维工具,见下节。按 AI Agent 浏览站点的完整路径分组:

分组工具入参用途
检索search_contentq: string、limit?: 1~20、offset?: ≥0按关键词搜索已发布文章,返回标题、摘要、链接、发布时间与正文命中摘录,不含全文
阅读get_contentcid / slug 二选一、type?: post/page、raw?、offset?、maxChars?取一篇文章或独立页面的正文,Markdown 源码转纯文本后输出,长文用 offset 续读
阅读list_content_imagescid: number、limit?: 1~100列出文章配图(封面 + 图片附件)的 URL 与尺寸,不含视频附件
浏览list_recent_contentslimit?: 1~50列出最近发布的文章标题、链接、发布时间
浏览get_popular_contentssort?: likes/comments、limit?: 1~20热门文章,按点赞数或评论数倒序
浏览list_archivesyear?全站归档时间线,按年月分组的整站文章目录
浏览get_random_contentcategorySlug?随机返回一篇文章的 cid,可按分类 slug 限定
浏览list_travels—旅行足迹地图的全部地点(名称、经纬度)及关联游记
浏览list_pageslimit?: 1~50列出独立页面(留言板、协议、关于等),返回前台 URL
导航list_categories—列出全部分类及每分类下的文章数
导航list_tags—列出全部标签及每标签下的文章数
导航list_category_articlesslug: string、limit?分类下文章列表
导航list_tag_articlesslug: string、limit?标签下文章列表
导航get_related_contentscid: number、limit?: 1~20相关文章,按共享标签数倒序
互动get_recent_commentslimit?: 1~50全站最新已审核评论,含文章标题与链接
互动get_commentscid: number、limit?: 1~100单篇文章已审核评论
站圈list_friend_links—已启用且已审核的友情链接
演进list_changelogslimit?: 1~50公开更新日志(按时间倒序)
自述get_site_info—站点名、URL、描述、备案号(来自 informations 表)

所有检索工具的返回字段均经过公开接口白名单筛选:标题、描述、slug、文章链接、发布时间、正文纯文本与作者昵称可下发;ip、agent、uid、status 等内部字段一概不下发(get_content 返回的 type 是 post/page 语义标记,非内部列)。凡返回里带站内链接的工具,顶层都附 site_url(后台设置的站点地址,已剥尾斜杠);链接字段本身是相对路径,与 site_url 拼接即得绝对地址。

工具完整入参与返回

下表列出每个工具完整可选入参(默认值列说明客户端不传时使用什么)与关键返回字段。运维工具的 token 字段必须带,调用方自己持有 MCP_OPS_TOKEN 的值;本节示例均假定该变量已配置。

内容工具(19 个,全部只读)

工具入参(完整)关键返回
search_contentq(必填)、limit(默认 10,1~20)、offset(默认 0,配合 has_more 翻页)、categorySlug?、tagSlug?、days?(1~3650,限定时间窗)顶层 site_url、q、offset、has_more(多查一条探测得出);命中数组含 cid、title、desc、slug、url、published_at、comment_num、like_num,正文命中附 match_excerpt(命中词前 40 后 80 字符)
get_contentcid / slug 二选一(都传报 cid_slug_exclusive)、type(post 默认 / page,独立页面只能 slug 直查)、raw?(默认 false,true 返回原始 Markdown 字段名为 markdown 而非 plain_text)、offset(默认 0,长文续读入口)、maxChars(默认 8192,256~32768)顶层 site_url;条目含 cid、type、title、desc、url、author、published_at、updated_at、word_count(全文长度)、reading_time_min、comment_num、like_num、categories、tags、offset、returned_chars、has_more 与 next_offset(has_more 为真时),plain_text(或 markdown)截断时附 用 offset=N 续读 提示
list_content_imagescid(必填)、limit(默认 50,1~100,封面优先)顶层 site_url;条目含 url 与 source(cover/attachment),封面附 desc、width、height,附件另带 aid、name、format;文章不存在报 article_not_found
list_recent_contentslimit(默认 10)、categorySlug?、days?顶层 site_url;文章数组含 comment_num、like_num
get_popular_contentssort(likes 默认 / comments)、limit(默认 10,1~20)顶层 site_url 与 sort;条目含 like_num、comment_num、url;只列真有热度的文章(likes 口径要求有点赞,comments 口径要求 comment_num > 0)
list_archivesyear?(只看某一年,UTC)顶层 site_url 与 total;groups 按 UTC 年月分组,每组含 year、month 与 items(cid、title、url),一次调用拿整站目录
list_categories—顶层 site_url;分类数组含 content_count 与 latest_article_at(ISO 字符串或 null)
list_tagssort?(name 默认 / count 按文章数降序)顶层 site_url;标签数组含 content_count
list_pageslimit(默认 20)顶层 site_url;独立页面数组含 slug、title、url、updated_at
get_random_contentcategorySlug?直接返回完整条目 {site_url, cid, title, desc, url, note},不必再调一次 get_content
list_travels—顶层 site_url;地点数组含 id、name、desc、cover、longitude、latitude 与 articles(关联游记,无分类或无 slug 的关联会被过滤以免死链)
list_category_articlesslug(必填)、limit(默认 20)顶层 site_url;含 comment_num、like_num
list_tag_articlesslug(必填)、limit(默认 20)同上
get_related_contentscid(必填)、limit(默认 5)顶层 site_url;含 shared_tags(计数)与 shared_tag_names(标签名数组)
get_recent_commentslimit(默认 20)顶层 site_url;评论为回复时附 parent_coid 与 parent_author(无名父评论时为 null)
get_commentscid(必填)、limit(默认 20)、order?(desc 默认 / asc)返回 total 总数 + items
list_friend_links—仅含 name、desc、url、avatar
list_changelogslimit(默认 10)entries 数组由 changelog 的 content JSON 字段解析而来,解析失败兜底为 []
get_site_info—站点基础信息 + stats 子对象(articles、comments、categories、tags、pages、friend_links、latest_publish_at、first_publish_at)

运维工具(5 个;4 只读 + 1 写)

工具入参关键返回
get_system_statustoken(必填)time、node、node_env、platform、inDocker、buildHash、uptimeSec、heapUsedMB、rssMB、database(含 latencyMs 与版本)、redis(含 latencyMs、status、version,未配置时 configured: false)
get_recent_logstoken、category(默认 app)、lines(默认 50,1~200)、level(默认 all,info/warn/error 可选)、keyword?(按子串过滤,最长 100 字符)、date?(YYYY-MM-DD 格式,默认今天)category、date、shards、totalLines、returnedLines、lines(每行 ≤4000 字符,总量 ≤256 KB 兜底)
get_content_statstokenarticlesByStatus、commentsByStatus、pagesPublished、links、attachments、subscribes、likes(total/last30days)、commentsLast24h、scheduledTotal、latestPublished、scheduledPublishQueue
get_cache_infotokenRedis status、pingLatencyMs、dbSize、usedMemory、peakMemory、keyspace(hits/misses/hitRatePercent)、keyCounts(按 nitro:routes、search、custom、error:notify、rl:mcp:post 前缀分组计数)
clear_cachetoken、target(pages/search/footprint/rl/keyword)、keyword?(仅 target=keyword 时需要,通配符会被剥除)、confirm(必须显式 true 才执行)target、cleared(整组清时为 -1)、note(rl 模式附带"误伤的 429 立即解除"说明)

典型调用样例

下面给出几个真实使用场景,调用方按 JSON-RPC 工具调用协议发请求即可。所有示例均假定 MCP_OPS_TOKEN 已配置。

按分类与时间窗搜索近 30 天的文章:

JSON{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_content",
    "arguments": { "q": "Nuxt", "categorySlug": "tech", "days": 30, "limit": 10 }
  }
}

取单篇文章的原始 Markdown(含字数、阅读时长、分类标签):

JSON{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_content",
    "arguments": { "cid": 42, "raw": true }
  }
}

响应里 has_more 为真时按 next_offset 续读长文,读到的片段按 offset 顺序拼接即还原全文;独立页面把 cid 换成 slug 并配 type: "page":

JSON{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "get_content",
    "arguments": { "cid": 42, "offset": 8192, "maxChars": 8192 }
  }
}

排查「改了内容前台不刷新」:先看缓存键空间命中率与各前缀键数,定位哪类缓存数量异常,再决定清哪一组。

JSON{ "params": { "name": "get_cache_info", "arguments": { "token": "REPLACE_WITH_MCP_OPS_TOKEN" } } }

命中 keyspace.hitRatePercent 长期低于 50% 时考虑提高缓存 TTL 或扩大缓存容量;keyCounts.rl:mcp:post 飙高表示有 IP 在试探 MCP 端点。

误伤一个 IP 永久 429 时,清限流计数键即可立即解除(不再等窗口重置):

JSON{
  "params": {
    "name": "clear_cache",
    "arguments": { "token": "REPLACE_WITH_MCP_OPS_TOKEN", "target": "rl", "confirm": true }
  }
}

读访问日志末尾 20 行、只看 ERROR、并过滤某个 cid 的报错:

JSON{
  "params": {
    "name": "get_recent_logs",
    "arguments": { "token": "REPLACE_WITH_MCP_OPS_TOKEN", "category": "access", "lines": 20, "level": "error", "keyword": "cid=42" }
  }
}

降级到本月初看统计,定位近期内容走势:

JSON{
  "params": {
    "name": "get_content_stats",
    "arguments": { "token": "REPLACE_WITH_MCP_OPS_TOKEN" }
  }
}

调用结果中的 scheduledPublishQueue 若非空说明有定时发布待执行;commentsLast24h 为 0 且 likes.last30days 持续为 0 时再去翻 access 日志查访问量是否同样跌零,定位站点侧还是流量侧问题。

运维工具组

在运行环境配置 MCP_OPS_TOKEN 后,端点会额外注册五个运维工具,供 AI Agent 直接排查线上问题;变量留空则整组不注册,客户端只能看到十九个检索工具。令牌每次请求都从环境变量现读,生产环境补配后无须重新构建。配置后调用运维工具必须携带 token 入参(即 MCP_OPS_TOKEN 的值),校验不符时返回 invalid_ops_token:

工具入参用途
get_system_status—系统健康快照:运行时长与内存、构建哈希、是否容器、数据库与 Redis 的连通性和延迟
get_recent_logscategory、lines?: 1~200、level?: all/info/warn/error、date?: YYYY-MM-DD读结构化日志(logs/<类别>/<日期>.log,开启大小切分后自动合并全天分片)末尾若干行并可按级别过滤;类别限 access、audit、auth、external、cache、ratelimit、cron、monitor、app 九个白名单值,单行超 4000 字符截断
get_content_stats—内容数据概览:文章与评论按状态分布、已发布页面、友链、附件、订阅数、最近发布一篇与定时发布队列
get_cache_info—Redis 缓存诊断:连通性与延迟、键总数、内存占用、按前缀统计键量(ISR 页面缓存、搜索、自定义、错误通知去重、MCP 限流)
clear_cachetarget: pages/search/footprint/keyword、keyword?、confirm: true清 Redis 缓存,清后自动重建;pages 清整组 ISR 页面缓存,keyword 按键名子串清理,子串中的通配符会被剥除

表中入参不含各工具必带的 token。前四个运维工具仍是只读,clear_cache 是全部二十四个工具中唯一的写操作。除令牌外还必须显式传 confirm: true 才执行。

限速

POST /mcp 自带按 IP 限速:单 IP 每分钟最多 60 次,超额返回 429 与 Retry-After(秒)。AI Agent 一次对话通常只有 1 至 5 次工具调用,60/分钟已很宽松;Redis 不可用时回落内存计数,重启清零。限速校验异常一律 fail-open,不阻断业务。

客户端接入

支持 MCP 的客户端只需配置端点 URL(如 https://imqi1.com/mcp)即可将工具纳入上下文:未配置 MCP_OPS_TOKEN 时可见十九个检索工具,配置后追加五个运维工具。在 Claude Desktop 中,把端点写入 MCP server 配置;在 Cursor 中作为自定义 MCP server 注册即可生效。开关关闭后客户端仍会看到 server,但调用工具时会收到 404。