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 新测试)。
3.8 KiB
3.8 KiB
T1 — Tracer bullet: end-to-end MCP skeleton (read path)
Type: tracer bullet. Proves the whole stack on BOTH build targets before any tool-surface flesh-out. Do this FIRST and get it green end-to-end.
Blocking edges
- Blocks: T2 (token mgmt+UI), T3 (read tools+resources), T4 (write tools), T5 (admin tools), T6 (hardening).
- Blocked by: nothing (this is the root).
Target files
Cargo.toml— addrmcp+aes-gcm(optional, underserverfeature).migrations/015_mcp_tokens.sql— themcp_tokenstable (see spec §5.1).src/db/migrate.rs— register("015", include_str!(...))inMIGRATIONS.src/models/mcp_token.rs—TokenScopeenum (Read/Write/Admin,>=ordering, serde),McpToken,McpTokenSummary,CreateTokenResponse.src/mcp/mod.rs,src/mcp/crypto.rs,src/mcp/auth.rs,src/mcp/server.rs,src/mcp/router.rs— new module (server-only impl + WASM stubs).src/main.rs— buildmcp_routeand.merge(mcp_route)into the app router (alongside existing merges at ~line 332).src/lib.rs/src/main.rs—pub mod mcp;gated by feature..env.example— documentMCP_TOKEN_ENC_KEY.
Change
- Add deps; verify
rmcpbuilds against axum 0.8 and exposes a TowerStreamableHttpServicemountable vianest_service. If the version is incompatible, STOP and report — do not silently hand-roll JSON-RPC (that's a spec-level decision). - Migration + model (spec §5).
token_hash= SHA-256 hex for lookup;token_enc= AES-GCM (nonce‖ct‖tag) hex. crypto.rs:encrypt_token(plain, &key) -> String/decrypt_token(enc, &key) -> Option<String>usingaes-gcm. Read key fromMCP_TOKEN_ENC_KEY(base64 32-byte)..expect()only at LazyLock init of a parsed key is acceptable per AGENTS.md §16.auth.rs: bearer extractor — parseAuthorization: Bearer ygg_..., hash, DB-lookup the active (non-revoked, non-expired) row, return(user_id, scope), bumplast_used_at. Origin check → 403 (reuse CSRF trusted-origin allowlist helper).server.rs: minimal rmcpServerHandlerexposing ONE tool —search_posts(query)— wired to the existing FTS search helper insrc/api/posts/search.rs. Return summaries. (Full Resources/pagination is T3; here just prove dispatch works.)router.rs: assembleStreamableHttpService(stateless) and return anaxum::Routerfor/mcp. Merge into the app router inmain.rs.- WASM stubs: every public symbol gets a
#[cfg(not(feature="server"))]stub so--features webcompiles.
Acceptance — STATUS (2026-07-28)
- rmcp version pinned:
=3.0.0-beta.3(NOT stable 0.2.1 — see spec §7). Axum-0.8 compatibility verified by a throwaway probe:nest_service("/mcp", StreamableHttpService)mounts; auth flows viafrom_fnmiddleware →request.extensions→Extension<Parts>; real MCPtools/list+tools/callround-trip confirmed; Origin→403 confirmed. - No-token → 401, bad Origin → 403 (rmcp built-in): verified at probe level. (Live-server token-seed smoke test deferred to T7 integration — needs a running DB.)
token_enccolumn stores AES-GCM ciphertext (crypto.rs unit-tested: round-trip, tamper-fail, wrong-key-fail, nonce-distinct — 8 tests green).cargo build --no-default-features --features web✓ (mcp module is#[cfg(server)], so WASM build never touches rmcp/aes-gcm — no stubs needed by design).cargo build --no-default-features --features server✓.cargo clippy --all-features -- -D warnings✓ (added#[allow(dead_code)]on the mcp module + mcp_token model: forward-public symbols consumed by T2/T3).cargo test --features server✓ 639 unit + 1 integration, +13 new MCP tests.- Deferred to T7: real-client end-to-end against a live DB (T1 proved the mechanism via probe, not against the real DB-backed auth path).