weknora-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@weknora-mcpsave to WeKnora: title "Async Python Tips", content from this page about asyncio"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
weknora-mcp
极简 MCP 写入服务:让 Grok 把一个 URL 填进自定义连接器,就能把文档写进你的 WeKnora 知识库。
只有一个工具 write_wiki(title, content),只做写入,不做查询。
⚠️ 注意事项(部署前必读)
下面每一条都踩过坑或会直接导致服务不可用,请先看完再动手。
事项 | 说明 |
只能单实例 | SQLite outbox 和后台 worker 都假设只有一个写者。不要加 |
| 程序从工作目录读 |
仓库放 | systemd unit 里的 |
| 先 |
nginx 必须加 | 否则 Streamable HTTP / SSE 会被缓冲,Grok 一直转圈。 |
token 会进 nginx access log | 默认 |
token 本身就在 URL 里 | 它会留在 Grok 连接器配置和浏览器历史中,务必用长随机串,泄露了就换一个。 |
服务只监听 | 别直接绑 |
| 权限收紧到 |
只写不读 | 没有任何查询接口,Grok 无法确认写入结果。写入失败得自己看 |
停止要留时间 | 停止时 worker 可能正在 POST,unit 的 |
两个刻意的重复窗口 | 极端情况下可能重复写一条,这是换取一半代码量的取舍,见「状态与重试」。 |
Related MCP server: web2kb
为什么是「异步 + 本地队列」
Grok 对 MCP 工具调用有超时限制。一旦超时,它就会重发同一个调用,于是同一篇 文档在知识库里出现两遍 —— 这是最常见的投诉。
本服务的解法是:让工具调用路径上不存在任何网络请求。
Grok ──write_wiki──> 写入本地 SQLite ──> 立刻返回 accepted(<10ms)
│
└──> 后台 worker ──> POST WeKnora
成功 → done
失败 → 每 30s 重推,20 次后 failed由此得到两个保证:
问题 | 解法 |
Grok 超时重发导致重复 | 调用瞬间返回,不触发超时;再加 |
WeKnora 挂了文档丢失 | 先落本地 SQLite,worker 自动重推,进程重启后继续 |
快速开始
需要 Python 3.12+ 和 uv。
uv sync # 装依赖(含 dev 组)
cp .env.example .env # 然后填写 .env
uv run python -m app --check # 配置自检,不启动
uv run python -m app # 启动服务.env 里三样必填:
WEKNORA_API_KEY=sk-...
WEKNORA_DEFAULT_KB_ID=kb_... # 唯一的写入目标
MCP_TOKEN=$(openssl rand -hex 32) # 至少 32 字符启动成功后日志会打印:
监听 http://127.0.0.1:8765/mcp(Grok 填写 https://<域名>/mcp?token=<MCP_TOKEN>)接入 Grok
在 Grok 的 grok.com/connectors → New Connector → Custom,填入:
https://你的域名/mcp?token=<MCP_TOKEN>Grok 只支持 Streamable HTTP / SSE,所以必须经 HTTPS 暴露到公网。
本服务本身不监听公网,只监听
127.0.0.1:8765,由你的反向代理转发。
nginx 配置(本项目不自动安装,只给文档)
location /mcp {
proxy_pass http://127.0.0.1:8765/mcp;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
# ↓↓↓ 这三行是 Streamable HTTP / SSE 的命门,漏了就一定出问题
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
chunked_transfer_encoding on;
add_header X-Accel-Buffering no;
}两个提醒(已汇总到顶部「注意事项」):proxy_buffering off 必须加,
token 会进 nginx access log。
如果你把 MCP_ALLOWED_HOSTS=你的域名 填上,服务会启用 Host 白名单校验,
非白名单 Host 直接返回 421。留空则关闭该校验。
注意:不要把服务直接绑到
0.0.0.0又不填MCP_ALLOWED_HOSTS。
部署:Linux + systemd
仓库里带了一份可直接用的 unit 文件:deploy/weknora-mcp.service。
0. 前提
服务器上装好 Python 3.12+。
依赖由 uv 管理。venv 建好后就自包含了,运行期不需要 uv,
只在建环境 / 更新时用一次。
1. 准备目录(用默认用户,不新建账号)
不需要 useradd。 直接用你要运行服务的那个用户就行,unit 里也不写 Group=,
systemd 会自动使用该用户的默认主组。
mkdir -p /opt/weknora-mcp # 换成你自己的部署目录如果部署目录在 /root 或 /home 下,就由对应的归属用户运行,
unit 里的 User= 与该用户保持一致即可。
2. 放代码、建 venv
下面都假设你已经以「要运行服务的那个用户」登录。uv 会装到 ~/.local/bin,
所以要用登录 shell(bash -lc)才找得到它:
curl -LsSf https://astral.sh/uv/install.sh | sh
git clone <你的仓库地址> /opt/weknora-mcp
cd /opt/weknora-mcp
uv sync换过部署目录的话,unit 文件顶部写明了哪 5 处要一起改,并给了 sed 命令。
3. 写 .env、建 data 目录
cp .env.example .env
chmod 600 .env
vi .env # 填 API Key / KB ID / MCP_TOKEN
mkdir -p data
chmod 700 data # 里面有你的文档原文,别对别人开放
uv run python -m app --check # 配置自检,通过后再继续不需要配 EnvironmentFile=。 .env 由程序自己从 WorkingDirectory 读取,
这就是「配置放在项目根目录」的含义。所以 .env 必须可被服务用户读到,
且 data/ 必须可写(这个目录必须先存在,否则 unit 的 ReadWritePaths 会让
systemd 拒绝启动)。
4. 安装并启动
sudo cp deploy/weknora-mcp.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now weknora-mcp5. 查看状态与日志
systemctl status weknora-mcp
journalctl -u weknora-mcp -f # 实时日志
journalctl -u weknora-mcp -n 100 --no-pager # 最近 100 行如果 ExecStartPre 的配置自检失败,服务会直接进入 failed 而不会带病运行,
具体原因看 journalctl -u weknora-mcp -n 50。
6. 更新代码
cd /opt/weknora-mcp
git pull
uv sync
sudo systemctl restart weknora-mcp只改 .env 的话不用 systemctl daemon-reload,直接 restart 即可
(只有改 unit 文件本身才需要 reload)。
调用行为(给模型看的语义)
write_wiki 的返回永远是「已受理」,不是「已写入」:
{
"ok": true,
"status": "accepted",
"task_id": "w-20260912-7f3a1c",
"title": "会议纪要",
"characters": 1234,
"message": "已受理并排队写入知识库,请勿重复调用本工具。"
}重复调用同一份内容时:
{
"ok": true,
"status": "accepted",
"task_id": "w-20260912-7f3a1c",
"deduplicated": true,
"message": "同一内容已受理过,本次未重复入队,请勿再次调用本工具。"
}参数非法是唯一会返回 ok: false 的情况:
{ "ok": false, "status": "rejected", "error": "title_required", "message": "title 不能为空" }ok: true 只表示「传输层收到了」,业务状态永远放在 status 字段里。
状态与重试
状态 | 含义 | 会重推吗 |
| 已入队,等待推送 | ✅ 每 30s |
| POST 成功(2xx) | ❌ |
| 连续失败 20 次(≈10 分钟) | ❌ 永久终止,需人工 |
两个刻意接受的重复窗口(换取一半的代码量):
POST 成功后、写
done之前进程崩溃 → 重启后重推,可能重复一条POST 超时但 WeKnora 其实已收到 → 重推,可能重复一条
如果实际中真的遇到,再补「重推前按标题查一次」即可。
运维:outbox CLI
乐观确认的代价是失败会静默,所以必须有地方看。这些不是 MCP 工具,Grok 调不到。
uv run python -m app outbox list # 概览
uv run python -m app outbox list --status failed # 只看失败的
uv run python -m app outbox show <task_id> # 看完整内容与错误
uv run python -m app outbox retry <task_id> # 重置为 pending,让 worker 重推健康检查(免鉴权):
curl http://127.0.0.1:8765/healthz
# {"status":"ok","pending":0,"done":12,"failed":1,...}failed > 0 时 status 会变成 degraded,可直接接监控告警。
配置项
变量 | 默认值 | 说明 |
|
| WeKnora API 地址 |
| 必填 | WeKnora 凭证 |
| 必填 | 唯一目标知识库 |
|
| 监听地址 |
|
| MCP 端点路径 |
| 必填 | URL token,≥32 字符 |
|
| outbox 数据库 |
|
| POST 回 JSON(推荐)而非 SSE 流 |
| 空 | 逗号分隔的 Host 白名单;空=关闭校验 |
|
| 单次推送超时(秒) |
|
| 重推间隔(秒) |
|
| 连续失败上限(≈10 分钟) |
|
| 正文长度上限 |
|
| 日志级别 |
必须单进程运行。 SQLite outbox 与 worker 都假设只有一个写者,
不要用 --workers 2 或同时起多个实例。
开发
uv sync # 装依赖(含 dev 组的 pytest / ruff)
uv run ruff check . # 静态检查
uv run ruff check --fix . # 自动修复(改完务必重跑测试)
uv run pytest # 54 个测试
uv run python -m app --check # 配置自检tests/test_server.py 会真的起一个 HTTP 服务,走完整的 MCP 握手,
并覆盖三个最容易翻车的点:nginx 反代的 Host 头、token 鉴权、幂等去重。
tests/test_weknora.py 用 MockTransport 盯住发往 WeKnora 的请求形状
(尤其是 X-API-Key 这个头,写错会得到 401)。
防泄漏钩子
仓库带了一个 pre-commit 钩子,拦住 .env、密钥样式和大文件。
它在 .git/ 里不会被版本控制,所以要用仓库内这份:
git config core.hooksPath .githooks注意:
core.hooksPath是本地配置,重新 clone 或删掉.git后需要重新设一次。
目录结构
app/ 服务代码(7 个模块)
tests/ 单元测试 + 真实 HTTP 的 MCP 端到端测试
deploy/ systemd unit 文件(文档用途,不自动安装)
.githooks/ pre-commit 防泄漏钩子
pyproject.toml 依赖、打包与 ruff 配置
uv.lock 锁定版本
README.md
LICENSE MITLicense
This server cannot be deployed
Maintenance
Related MCP Connectors
- hiveWikiOAuthai.hivewiki
Shared project wiki for AI agents: read and write pages, next actions, and activity logs over MCP.
- FlowdexOAuthdk.flowdex
Read and write your team's shared, AI-readable wiki from any MCP client.
- wikiOAuthcom.talkamore
A wiki about your life that writes itself. Save from any AI chat, recall it in the next.
Self-hostable team wiki; agents read & write it via MCP; Atlas turns your repo into a cited wiki.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables querying a local wiki through MCP-style tools, including search, Q\&A, and knowledge map, with a web viewer for human browsing.-
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to fetch webpages, convert them to Markdown, index into SQLite FTS5, and query the knowledge base through MCP tools.-
- FlicenseNot gradedqualityDmaintenanceProvides structured search, schema-validated writes, and linting for a markdown knowledge base, enabling agents to operate the wiki over a single streamable-HTTP MCP endpoint.1-
- FlicenseAqualityBmaintenanceProvides a lightweight personal knowledge base MCP server that compiles raw materials into interconnected Wiki pages, with hybrid search (BM25, optional vector, link expansion) and tools for querying, reading, writing, and ingesting content.5-