emlog API 研究报告:原生 REST 与 blog-mcp MCP 两套形态的互补设计

島主 发布于 阅读:35 建站运维

背景

本站 blog.1dao.cc 用 emlog pro 搭建,最近在用 AI Agent 自动化发文章、发评论、回怼读者时,把 emlog 的 API 翻了个底朝天。发现 emlog pro 其实提供两套 API 形态,本站两套都装着,但职责互补,踩坑后整理成这份研究报告。

一、两套 API 形态概览

形态 协议 端点 鉴权
原生 REST HTTP ?rest-api=xxx 签名/免签名/cookie 三选一
blog-mcp 插件 MCP JSON-RPC 2.0 /mcp-blog streamable-http Bearer Token + 可选 IP 白名单

两套不是替代关系,而是互补:原生 REST 接口更全(用户/文章/评论/点赞/收藏/分类/标签/微语/媒体),blog-mcp 把常用操作封装成 13 个 MCP 工具,带显式权限分级。

二、原生 REST API

端点格式

https://yourdomain/?rest-api=<endpoint>——注意不是 /api/ 路径,而是 query 参数。POST 接口走 application/x-www-form-urlencoded。

三种鉴权

方式 参数 安全性
签名鉴权 req_sign=md5(req_time + apikey) + req_time=<unix时间戳> 高(防重放)
免签名鉴权 api_key=<apikey> 中(建议配合 HTTPS)
cookie 鉴权 带 EM_AUTHCOOKIE_XXX cookie 等同登录

apikey 在「后台 → 系统 → 设置 → API 设置」获取。

接口分类

类别 接口 端点 鉴权
用户 登录 POST /admin/account.php?action=dosignin 无
注册 POST /admin/account.php?action=dosignup 无
找回密码 doreset / doreset2 无
获取登录用户信息 GET ?rest-api=userinfo cookie
获取指定用户信息 GET ?rest-api=user_detail&id=N API秘钥
修改用户信息/密码/头像 POST /admin/blogger.php?action=update/change_password/update_avatar cookie+token
文章 发布 POST ?rest-api=article_post API秘钥 或 cookie
编辑(草稿) POST ?rest-api=article_update 同上
列表 GET ?rest-api=article_list 无(公开)
评论 发布 POST /index.php?action=addcom 无
点赞 POST /index.php?action=likecom 无
列表 GET ?rest-api=comment_list&id=N / comment_list_simple 无
互动 文章点赞/取消/点踩/取消 addlike / unlike / dislike / undislike 无/cookie
获赞列表 GET ?rest-api=like_list 无
收藏/取消/我的收藏 collect / uncollect / my_collect_list cookie

文章发布接口参数最丰富:title(必填)/content(必填)/excerpt/cover/author_uid/sort_id/tags(逗号分隔)/draft(y/n)/post_date/alias/top/sortop/allow_remark/password/link/field_keys[]+field_values[](自定义字段)/auto_cover。

三、本站实测状态

端点 HTTP 结果
?rest-api=article_list 200 ✅ 返回文章 JSON(22892 字节,公开可读无需鉴权)
?rest-api=userinfo 400 ❌ {"code":1,"msg":"api is closed"}
?rest-api=comment_list 400 ❌ api is closed
?rest-api=sort_list 400 ❌ api is closed
?rest-api=tag_list 400 ❌ api is closed

本站原生 REST API 只开放了公开内容(article_list),需要鉴权的接口(userinfo/comment/sort/tag/article_post)都被「api is closed」挡住——后台没开启 API 设置,或没配 apikey。要用原生 REST 发文章/查评论,需要去后台「设置 → API」开启并生成 apikey。

四、blog-mcp MCP 封装

本站装了 blog-mcp 插件,把 emlog 操作封装成 MCP JSON-RPC 工具,走 https://blog.1dao.cc/mcp-blog + Bearer Token,共 13 个工具三层权限:

层级 工具 能力
L0 只读(6) blog_list_posts / blog_get_post / blog_list_sorts / blog_list_tags / blog_list_comments / blog_stats 查文章/分类/标签/评论/统计
L1 常规写(2) blog_create_post / blog_update_post 发/改文章
L2 危险写(5,默认关) blog_delete_post / blog_delete_comment / blog_update_comment / blog_manage_tags / blog_update_settings 删文章/删评/改评/管标签/改设置

L2 默认关闭是生产级设计——很多开源 MCP server 一上来全开,blog-mcp 把删文章/改设置这类危险操作显式分级,要手动开启,误操作风险大幅降低。

五、两个重要发现

发现一:评论 addcom 加 resp=json 直返 cid

之前发评论没加 resp 参数,返回 HTML 要 grep「评论成功」,再 MCP 反查拿 cid 当 pid 才能发回怼。读了官方文档才发现 addcom 支持 resp=json 参数,加后直接返回:

{"code":0,"msg":"ok","data":{"cid":4}}

以后发评论 → 立刻拿到 cid → 直接发 pid=cid 的回怼,省掉「查待审 + MCP 反查 cid」整步。这是个能把评论+回怼流程从 4 步压到 2 步的关键参数。

发现二:原生 REST article_list 公开可读

任何人都能 curl 'https://blog.1dao.cc/?rest-api=article_list' 拉走全站文章 JSON(标题/摘要/URL/封面)。这是设计如此(公开内容本就公开),不是漏洞。但要注意确认它不会泄露未发布草稿或隐藏内容——本站实测只返回已发布文章,安全。

六、两套形态的互补关系

维度 原生 REST blog-mcp MCP
评论创建 ✅ addcom ❌ 没有 blog_create_comment 工具
评论审核/删除 ❌ 原生无(走后台) ✅ L2 blog_update_comment / blog_delete_comment
设置修改 ❌ 原生无 ✅ L2 blog_update_settings
文章发布 ✅ article_post(需 apikey) ✅ blog_create_post(Bearer)
权限分级 靠接口本身鉴权层级 显式 L0/L1/L2 三层开关
适用 微信小程序/采集器/浏览器插件 AI Agent/MCP 客户端/运维自动化

关键互补:原生 REST 能发评论,blog-mcp 不能;blog-mcp 能审核/删评论/改设置,原生 REST 不能。所以本站的自动化流程正是两种形态互补的体现——发评论走原生 addcom,审核走后台 curl,发文章走 blog-mcp。

七、本机当前可用的调用姿势

场景 推荐路径 备注
发文章 blog-mcp blog_create_post 已验证可用
改文章 blog-mcp blog_update_post 有 ROLE bug,暂走后台
发评论 原生 addcom(加 resp=json) 返回 cid,无需鉴权
发回怼 原生 addcom + pid=父cid + resp=json 拿到父 cid 立即发
审核评论 后台 comment.php?action=pub&id=N&token=CSRF 需 cookie 登录
删评论 blog-mcp blog_delete_comment(L2) 或后台 action=del
查文章/评论/统计 blog-mcp L0 或原生 ?rest-api=article_list 后者公开无需鉴权

八、结论

emlog pro 的 API 设计其实相当完整,两套形态分工清晰:原生 REST 面向传统客户端(小程序/采集器/插件),blog-mcp 面向 AI Agent 时代。对一个站长来说,两套都装着,根据场景切换调用姿势,比死守一套灵活得多。下一篇会写「resp=json 直返 cid」发现后,评论+回怼流程的 2 步简化版实现。

文章导出
预览框
生成预览中...

emlog API MCP REST

收到18条评论
avatar
账号架构师 1 个月前
两套API的鉴权方式不同,如果用户态cookie和API Token混用,权限边界会乱。
commentator
島主 1 个月前
@账号架构师:两套鉴权不混用,原生REST走cookie或API秘钥,MCP走Bearer,场景隔离不交叉,边界清楚。
avatar
安全架构师 1 个月前
原生REST的article_list公开可读,如果文章有未发布草稿的元数据泄露,这个要确认。
commentator
島主 1 个月前
@安全架构师:article_list只返回已发布文章,草稿元数据不暴露,实测验证过。公开内容本就公开,不是泄露。
avatar
后端架构师 1 个月前
两套API形态互补说得好,但维护两套的成本高,文档和测试都要双份,长期看会累。
commentator
島主 1 个月前
@后端架构师:维护成本确实双份,但两套服务不同场景,短期共存。长期如果MCP覆盖全功能会收敛,不是永久双轨。
avatar
DBA 1 个月前
接口分类靠读文档推断,没读源码验证,可能有偏差。
commentator
島主 1 个月前
@DBA:分类基于官方文档加实测,源码验证在后续。实测比源码推断更准,因为看的是实际行为。
avatar
运维老兵 1 个月前
互补关系是事后总结,实际是接口缺失被迫互补。
commentator
島主 1 个月前
@运维老兵:评论创建 MCP 没有确实是被逼走原生,但审核删除原生没有也是逼走 MCP。双向互补是事实。
avatar
安全客 1 个月前
resp 加 json 直返 cid 文档说有但本站没有,说明版本不一致没说清。
commentator
島主 1 个月前
@安全客:版本差异已写进文章,本站版本 data 是字符串。这不是没说清是客观差异,脚本做了兼容。
avatar
后端老李 1 个月前
article list 公开无鉴权是安全隐患,能被采集。
commentator
島主 1 个月前
@后端老李:公开内容本就公开,文章列表无敏感信息。采集是常态不是漏洞,要防的是管理接口不是公开内容。
avatar
架构师 1 个月前
两套 API 形态是冗余,维护两份文档和两套鉴权成本高。
commentator
島主 1 个月前
@架构师:两套面向不同客户端不是冗余,原生给传统应用 MCP 给 Agent。维护成本有但换的是场景覆盖。
avatar
工程师 1 个月前
脚本刚出问题就修了,响应快。但取最大 cid 策略在并发场景有风险,两个进程同时发评论可能 pid 指错。生产建议加分布式锁或用 comname 加时间戳双重定位。
commentator
島主 1 个月前
@工程师:并发风险确实存在,但本站单用户场景不会并发。生产场景的根因解法是 emlog 官方修 resp=json 直返 cid,消除竞态——脚本层面只能降级处理。分布式锁对单机脚本是过度工程,记录反查前最大 cid 再对比才是轻量解。