第 8 章 · 01 FastAPI 服务与 MCP 接入


第 8 章 · 01 FastAPI 服务与 MCP 接入

本节摘要:漫游动作 serve:上下文数据库不能只躺在本地库里,得对外开放。openviking/server/ 用 FastAPI 把整套能力铺成 HTTP 服务:二十余个 router 覆盖资源 CRUD、文件系统、检索、会话、技能、快照、任务、WebDAV 与 bot 代理;auth/(插件式认证、OIDC、LDAP、身份映射)、oauth/(provider/OTP/存储)与 api_keys/ 三道门守住入口。压轴的是 mcp_endpoint.py——server 目录里最大的一个文件(约 5.2 万字节),把 OpenViking 暴露成 MCP server:Claude Code 等任何 MCP 客户端挂上来,viking:// 空间就成了那个 Agent 的长期记忆。本节末尾看 ov 命令双前台(Python openviking_cli + Rust ov_cli TUI)与 doctor 自检。

内容来源:原项目源码 openviking/server/(app.py、routers/、auth/、oauth/、api_keys/、mcp_endpoint.py)、openviking_cli/(doctor.py、rust_cli.py)、crates/ov_cli/

⚠️ 注意:MCP 工具的身份不是匿名。每个 MCP 请求的 X-OpenViking-Account/X-OpenViking-User 头经 middleware 提取、通过 contextvars 传播进每个工具函数——_get_ctx() 拿不到身份直接抛 UnauthenticatedError。换句话说,Claude Code 挂载的每个用户看到的是自己的 viking://user 空间,多租户在 MCP 层同样成立。

学习目标

  1. 盘点 app.py 的路由全景与中间件栈(request_id、profile、body_dump、observability)。
  2. 说出三道认证门的分工:auth 插件注册表(OIDC/LDAP)、oauth 设备流、API keys(new/legacy)。
  3. 精读 mcp_endpoint.py:FastMCP 挂载方式、16 个工具、身份传播、workspace URI 解析。
  4. 理解「把 OpenViking 当 Claude Code 的记忆」意味着什么:检索/写入/遗忘全在工具面里。
  5. 会用 ov 命令与 openviking-server doctor 自检,知道 doctor 都查什么。

一、app.py:路由与中间件全景

app.py 约 3.2 万字节,是服务的装配车间。app = FastAPI(...) 之后是一长串 include_router,数下来二十余个:

app.include_router(system_router) app.include_router(admin_router) app.include_router(agent_evolution_router) app.include_router(resources_router) # 资源 CRUD/入库 app.include_router(filesystem_router) # ls/read/write/mv/rm/glob/grep app.include_router(content_router) app.include_router(console_router) app.include_router(search_router) # 检索 app.include_router(relations_router) app.include_router(privacy_configs_router) app.include_router(skills_router) # 技能 app.include_router(sessions_router) # 会话 app.include_router(snapshot_router) app.include_router(stats_router) app.include_router(pack_router) # ovpack app.include_router(debug_router) app.include_router(observer_router) app.include_router(openviking_assets_router) app.include_router(metrics_router) app.include_router(tasks_router) app.include_router(user_settings_router) app.include_router(watches_router) # watch 任务 app.include_router(webdav_router) app.include_router(bot_router, prefix="/bot/v1") # VikingBot 代理 ... app.include_router(oauth_router)

对照漫游前八章:resources/filesystem 对应 add/ls/read,search 对应第 4 章检索,sessions 对应第 5 章会话沉淀,pack 对应第 7 章 ovpack,watches 对应第 6 章轮询入库——HTTP 路由面就是本书的动作面。一个文件一个路由域的切分方式(routers/ 目录 24 个文件)也让「找接口」变成「找文件」,与 viking_fs 的 mixin 切片(第 7 章)是同一种洁癖。中间件栈同样各有其位:request_id.py 给每个请求发可追踪 ID、profile_middleware 识别客户端 profile、body_dump_middleware 按需落请求体供调试、http_observability_middleware 接第 9 章的观测。bootstrap.py(约 1.7 万字节)负责把配置、存储、队列、bot 逐层拉起——openviking-server 命令的启动路径。

二、三道门:auth、oauth 与 API keys

auth/ 是插件式认证:registry 收纳多个插件,oidc_config/ldap_config 是两份现成配置,identity_mapping 负责把外部身份映射成 OpenViking 的 account/user。auth 目录下的 health_check.py 让认证链路本身也可探测——企业内网接 LDAP 时,配错过滤器是高频事故,先健康检查再上线。oauth/ 提供 OAuth 流程(provider/router/storage 外加 otp.py 一次性口令),docs/design 里还有 mcp-oauth2-1.md 的 RFC 专门讲 MCP 场景的 OAuth 授权——公网暴露 MCP endpoint 时,浏览器外的 Agent 需要一套设备码式授权。api_keys/ 管理长期凭证,分 new.py 与 legacy.py 两代:server.root_api_key 是多租户总钥匙(第 9 章 LoCoMo 复现要靠它按 sample 建租户),普通用户则持个人 API key。三道门不是并列冗余:浏览器用户走 oauth/oidc、CLI 与 SDK 用户走 API key、企业内网挂 LDAP——同一服务的三类访客,鉴权失败统一映射成 error_mapping.py 的标准错误码(401/403 语义分家),客户端不用为每种门单独写重试逻辑。

三、mcp_endpoint.py:十六把工具

MCP(Model Context Protocol)是 Agent 世界的「USB 口」:一个标准协议,Agent 与工具服务互相发现。mcp_endpoint.py 用官方 mcp.server.fastmcp.FastMCP 把 OpenViking 挂载在 /mcp 路径(streamable HTTP 传输),文件头写明定位:

"""MCP (Model Context Protocol) endpoint for OpenViking server. Exposes OpenViking tools (filesystem, retrieval, memory, watch management, health) to Claude Code (or any MCP client) via streamable HTTP; the `@mcp.tool` registrations below are the authoritative list. """

@mcp.tool 注册共 16 个,恰好是本书动作面的一个紧凑子集:

工具 对应章节动作
find / search 第 4 章检索:意图化查找/语义搜索
read / list / tree 第 2-3 章:读多层内容、列目录、看树
grep / glob 正则与通配检索
remember / write / edit / forget 第 5 章:写记忆、写文件、改文件、删
add_resource / list_watches / cancel_watch 第 6 章:入库与 watch 管理
health 健康检查

(完整清单以源码 @mcp.tool 注册为准——docstring 里那句「the registrations below are the authoritative list」就是给读源码的人的路标;16 个工具名与 server 路由一一相认,只是换了 Agent 友好的皮。)

list 为例看工具的典型长相(448-470 行):

@mcp.tool(name="list") async def ls(uri: str, recursive: bool = False) -> str: """List files and subdirectories under a viking:// directory URI. Use recursive=true for deep listing.""" service = get_service() ctx = _get_ctx() resolved_uri = _resolve_mcp_workspace_uri(uri, ctx) entries = await service.fs.ls(resolved_uri, ctx=ctx, recursive=recursive, output="original")

三步骨架:取服务 → 取身份(contextvars)→ 解析 workspace URI 后转发内部 API。docstring 是给 Agent 看的说明书——MCP 客户端会把它当工具描述喂给模型,所以这里写得像 API 文档而非代码注释;返回值拼成 [dir] docs[file] readme.md 这样的纯文本行,LLM 读起来零摩擦。_resolve_mcp_workspace_uri 有个贴心设计:viking://user/... 开头的相对写法解析成当前用户自己的工作区——Claude Code 不必知道自己的 user_id,写 viking://user/memories 就落到自己的空间。工具面刻意做成了「Agent 友好」的形态:参数是简单标量、返回是拼好的字符串(而非嵌套 JSON)、错误信息可读——add_resource(749 行起)甚至内置了临时上传 token 的处理,让 Agent 能把用户拖进对话的文件直接入库。

这就是「给 Claude Code 加长期记忆」的全部机制:在 MCP 客户端配置里指到 http://server:1933/mcp,带上身份头,十六把工具立即可用。第 5 章 LoCoMo 的 80-83% 成绩里,Claude Code 侧的接入正是走这条路。

再从清单里捞三个容易错过的细节。其一,rememberforget:前者把消息批量存进会话(触发第 5 章的沉淀链),后者按 URI 删除——记忆的写入与遗忘都是 Agent 的一等工具,不是管理员特权。其二,edit(595 行起)支持对 viking:// 文件的原地修改,这让 Agent 能维护自己的笔记与技能文件,而不只读。其三,health 让 Agent 自己探测服务状态,配合客户端的重连逻辑——工具面连「体检」都给了 Agent,自治闭环不留死角。

四、ov 命令与 doctor 自检

命令行有两个前台。Python 侧 openviking_cli 提供 openviking-server(init/start/doctor)等管理命令;Rust 侧 ov(上一节介绍的 ov_cli)是日常驾驶舱,rust_cli.py 负责把 Python 入口桥到原生二进制。ov config 的 TUI 交互式向导(选模型、填 endpoint、生成 ov.conf)是新用户的第一站;ov 还能导入资源、浏览 viking:// 路径、检查服务状态、管理会话——Rust 实现换来秒级启动与跨平台单二进制分发(npm 装的是预编译二进制,不依赖 Python 环境)。

doctor 是装完先跑的自检命令,openviking_cli/doctor.py 把检查项拆成一列小函数:

def check_config() -> tuple[bool, str, Optional[str]]: ... def check_python() -> ... def check_native_engine() -> ... # C++ 引擎加载 def check_agfs() -> ... # RAGFS 绑定 def check_embedding() -> ... # 嵌入连通(探测 provider) def check_vlm() -> ... # VLM 可用 def check_ollama() -> ... # 本地 ollama

七项检查从上到下恰好是一条依赖链:配置 → 运行时 → 原生组件 → 外部模型服务,坏在哪一环,后面全部不可用——doctor 的检查顺序就是排障顺序。

从配置文件格式、Python 版本,到第 7 章的 C++ 原生引擎与 RAGFS 绑定能否加载,再到嵌入/VLM/ollama 的真实连通(嵌入探测会真发一次请求),doctor 与 ov health(只 ping 活着的服务器)分工明确:前者在服务器没起时就能定位装坏了什么。文件头的对比注释写得直白:「与 ov health 不同,openviking-server doctor 检查的是安装环境本身」。检查结果三态(ok/warn/fail),失败项附修复建议,嵌入探测还会把 provider 与模型名打进标签——报错时附上诊断输出,issue 都好修一半。全绿的样子:

图: doctor 自检通过

诊断输出逐项打勾,失败项给修复建议(比如提示启动 ollama serve)。教程第 1 章 quickstart 里「先 doctor 后启动」的顺序,出处就在这里。顺带一提,doctor 的彩蛋价值在「装坏了什么」之外:检查项本身就是一张系统依赖地图——第一次读 doctor.py 就能知道 OpenViking 运行时到底依赖哪些东西(配置/Python/原生引擎/AGFS/嵌入/VLM),比读部署文档更快建立心智模型。

💡 漫游要点:server 章的分寸感在于「同一内核,多种皮肤」——HTTP router 面向应用与 SDK,MCP endpoint 面向 Agent,bot 代理(下一节)面向聊天平台,WebDAV 面向传统办公流;而所有皮肤底下是同一个 service 层与同一套身份模型。MCP 的 16 个工具就是本书九章动作的浓缩版,viking://user/... 的 workspace 解析让多租户对 Agent 无感;doctor 则示范了开源项目的第一美德:让用户在求助之前先能自救。

本节要点回顾

  • app.py 装配:二十余个 router(resources/filesystem/search/sessions/skills/snapshot/pack/watches/webdav/bot @ /bot/v1/oauth...),中间件栈 request_id/profile/body_dump/observability;bootstrap.py 负责分层启动。
  • 三道门:auth 插件注册表(OIDC/LDAP/identity_mapping)、oauth(provider/otp/storage,mcp-oauth2 RFC)、api_keys(new/legacy;server.root_api_key=多租户总钥匙)。
  • mcp_endpoint.py(server/ 最大文件):FastMCP 挂 /mcp(streamable HTTP),16 工具=find/search/read/list/tree/grep/glob/remember/write/edit/forget/add_resource/list_watches/cancel_watch/health;docstring 声明「@mcp.tool 注册即权威清单」。
  • 身份:请求头 X-OpenViking-Account/X-OpenViking-User → contextvars(_mcp_ctx)→ _get_ctx() 无身份即抛错;viking://user/... 解析为当前用户工作区,Agent 免记 user_id。
  • 工具设计:简单标量入参、字符串返回、可读错误、add_resource 内置上传 token;Claude Code 挂 /mcp 即得长期记忆。
  • ov 双前台:Python openviking_cli(openviking-server init/doctor/start)+ Rust ov_cli(ov config TUI);doctor 查 config/python/native_engine/agfs/embedding/vlm/ollama,与 ov health(只 ping)分工。

下一节:02 VikingBot、Web Studio 与插件生态——服务之上再长生态:多渠道 Agent 框架 VikingBot(飞书/Slack/Telegram 网关+沙箱执行+子 agent)、React 版 Web Studio、三语言 SDK,以及给主流 coding agent 用的 8+ 个记忆插件。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U