T2 token 管理(src/api/mcp_tokens.rs):create/list/reveal/revoke + get_mcp_client_configs
服务端函数,均经 get_current_admin_user 鉴权;TokenLifetime 枚举(1/7/30/90天/永不过期)。
src/mcp/config.rs 生成 4 种客户端配置(Claude Code/Cursor/Cline/通用 + CLI)。
src/pages/admin/mcp.rs 令牌管理页:列表 + 新建表单 + 一次性明文展示/重查 + 撤销 +
配置片段卡片。路由 /admin/mcp,导航项加入 admin_layout。
T3 read 工具 + Resources(tools/read.rs, resources.rs):search_posts/get_post/list_tags
(read 作用域,仅已发布);published-post Resources(post://{slug},游标分页)。
search_published 提取为共享函数。
T4 write 工具(tools/{posts,comments,tags,media}.rs):create/update/publish/trash/delete_post、
评论审核、标签 CRUD、媒体 base64 上传(WebP 转码 + 去重)。复用既有 helper 的 SQL 与
缓存失效(moka + ssr_cache)。write 作用域,可读草稿。
T5 admin 工具(tools/{settings,runner}.rs):get/update_settings、run_code(沙箱执行)。
admin 作用域。
合并(server.rs):用 rmcp tool_router 的「命名路由 + 组合」模式,7 个工具组在
YggMcpServer 上 impl,combined_router 用 + 合并成单一 ServerHandler。各工具组鉴权
独立,经 Extension<Parts> 读 McpPrincipal + scope.grants 校验。
新增依赖 base64 0.22(媒体上传解码)。验证:server/web 双目标编译通过、clippy
--all-features -D warnings 干净、659 单测 + 1 集成全绿(+20 新测试)。
33 lines
1.7 KiB
Markdown
33 lines
1.7 KiB
Markdown
# T4 — write-scope tools (post CRUD, comments, tags, media)
|
|
|
|
## Blocking edges
|
|
- **Blocks:** T6 (hardening covers these).
|
|
- **Blocked by:** T1 (mount + auth + dispatch exist).
|
|
|
|
## Target files
|
|
- `src/mcp/tools/posts.rs`, `src/mcp/tools/comments.rs`, `src/mcp/tools/tags.rs`,
|
|
`src/mcp/tools/media.rs` — new.
|
|
- `src/mcp/server.rs` — register write tools (scope-gated).
|
|
|
|
## Change
|
|
Reuse existing server-fn / helper logic — do NOT duplicate business rules. Each write
|
|
tool calls the same helpers the web admin uses, then runs the same cache invalidation
|
|
(moka `invalidate_*` + `ssr_cache::invalidate_ssr_*`).
|
|
1. **Posts:** `create_post`, `update_post`, `publish_post`, `trash_post`, `delete_post`.
|
|
`write`/`admin` scope. These tokens MAY read drafts (decision 7). `create_post` must
|
|
`spawn_blocking(render_markdown_enhanced)` and persist `content_html`, exactly like
|
|
`src/api/posts/create.rs`.
|
|
2. **Comments:** `list_comments`, `approve_comment`, `delete_comment`,
|
|
`set_comment_status` — delegate to `src/api/comments/*` helpers.
|
|
3. **Tags:** `create_tag`, `rename_tag` — delegate to `src/api/posts/tags.rs`.
|
|
4. **Media:** `upload_media(filename, base64, alt?)` — feed the existing upload pipeline
|
|
(`src/api/upload.rs`); return the served URL for embedding in posts.
|
|
|
|
## Acceptance
|
|
- A `write`-token `create_post` writes a row, renders `content_html`, and invalidates the
|
|
matching moka + SSR caches (web admin sees the new post immediately).
|
|
- A `read` token calling any write tool → `insufficient_scope` rejection.
|
|
- `write`/`admin` tokens can read drafts via `get_post`; `read` tokens cannot.
|
|
- Media upload returns a usable image URL consumable in post body.
|
|
- Both targets compile; clippy clean; existing tests pass.
|