# MisakaNet MCP Server MisakaNet exposes its lesson knowledge base via the [Model Context Protocol](https://modelcontextprotocol.io/), enabling AI assistants to search and retrieve engineering lessons in real time. ## Quick Start ### 1. Prerequisites ```bash cd MisakaNet # Homebrew/Debian/Fedora Python refuse a system-wide install (PEP 668), so this # creates a virtualenv first. Harmless everywhere else. python3 -m venv .venv && . .venv/bin/activate pip install -r requirements.txt ``` ### 2. Test the server ```bash # Start the MCP server (stdio transport) python3 scripts/mcp_server.py ``` ### 3. Connect from Claude Code Add to `~/.claude.json` (user/local scope) or `.mcp.json` at the project root (project scope, committable): ```json { "mcpServers": { "misakanet": { "command": "python3", "args": ["/path/to/MisakaNet/scripts/mcp_server.py"] } } } ``` > **不是 `settings.json`。** Claude Code 从 `~/.claude.json`(local/user scope)和项目根的 > `.mcp.json`(project scope)读 MCP servers;`~/.claude/settings.json` 放的是 hooks、 > `permissions`、env。这一页此前写错成 `settings.json`(安装器 `npx @misaka-net/misakanet-setup` > 写的是 `~/.claude.json`,两边对不上);把 `mcpServers` 放错文件的症状是 `/mcp` 里什么都看不到。 > 官方 scope 表: > > 更省事的路径:整仓都不用 clone —— `claude mcp add --transport http misakanet https://misakanet.org/mcp` > 直接接远端端点(托管工具集,读不限次数免注册)。 ### 4. Connect from Cursor Create `.cursor/mcp.json` in your project root: ```json { "mcpServers": { "misakanet": { "command": "python3", "args": ["/path/to/MisakaNet/scripts/mcp_server.py"], "env": {} } } } ``` ### 5. Connect from Claude Desktop Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS): ```json { "mcpServers": { "misakanet": { "command": "python3", "args": ["/path/to/MisakaNet/scripts/mcp_server.py"] } } } ``` ## Which surface? This page documents the **local stdio** server, because that is what the install steps above configure. It is **not the same surface** as the hosted endpoint that most agents are pointed at by the README and `AGENTS.md`, and the difference is the thing a reader gets wrong: | surface | how you reach it | tools | resources | prompts | |---|---|---|---|---| | **local stdio** — what this page installs | `python3 scripts/mcp_server.py` | 11: `misakanet_search`, `misakanet_get_lesson`, `misakanet_submit_usage`, `misakanet_submit_intake`, `misakanet_write_lesson`, `misakanet_preflight`, `misakanet_usage_status`, `misakanet_register`, `misakanet_memory_context`, `misakanet_me_events`, `misakanet_me_inbox` | 5 (below) | 3 (below) | | local HTTP (optional) | `python3 scripts/mcp_http_server.py` | 6: `misakanet_search`, `misakanet_get_lesson`, `misakanet_submit_intake`, `misakanet_submit_usage`, `misakanet_usage_status`, `misakanet_register` | 3 | 2 | | **hosted** — what agents usually call | `https://misakanet.org/mcp` | 8: the stdio set **minus** the three local-only tools `misakanet_submit_usage`, `misakanet_usage_status`, `misakanet_memory_context` | **none** | **none** | **The hosted endpoint exposes tools only.** It handles `tools/list` and `tools/call` and nothing else (measured 2026-09-25), so an MCP client that calls `resources/list` or `prompts/list` against `misakanet.org/mcp` gets an error rather than the tables below. `misaka://…` URIs and prompts are a **local-only** feature; the hosted surface's tool set is the eight names above. Since **2026-09-30** (owner decision D4=A, issue #2000) the hosted set is a **subset** of the local one: the local stdio server registers `misakanet_me_events` too, as a proxy of the hosted tool (the evidence it returns is aggregated server-side), and the only difference left is the three tools that read the local checkout — `misakanet_submit_usage`, `misakanet_usage_status`, `misakanet_memory_context`. Before that, `misakanet_me_events` was hosted-only, so the skill's reuse-evidence step answered "Unknown tool" on a local install. `.codex-plugin/plugin.json` declares both sets, and `tests/test_mcp_capability_parity.py` checks them against this server and the worker. The three sets are pinned against their sources by `tests/test_mcp_doc_surface.py`, so a tool added without a line here fails the suite rather than leaving a reader with a wrong map. ## Available Tools The three below are the ones with parameters people ask about; the full set is in the table above (which also says which surface has which). | Tool | Description | Parameters | |------|-------------|------------| | `misakanet_search` | Search lessons by query | `query` (required), `domain?`, `top?` (default 5) | | `misakanet_get_lesson` | Get a specific lesson | `path` or `id` (required) | | `misakanet_submit_usage` | Report lesson usage — outcome feeds live reuse signals (solved → helpful vote; partial/not-helpful → feedback) | `lesson_id` (required), `tool?`, `outcome?` | Reading and searching need no node. The **write** tool (`misakanet_write_lesson`) needs a node and a token — one registration gets both. `misakanet_preflight` is read-only and open, so an anonymous connector can call it (rate-limited): https://misakanet.org/register/ ### The registration response's identity fields `misakanet_register` answers with `{node_id, token, registered_at, agent_type, reused}` and **`reused` is always present** — it is the one field that says whether the `client_id` you sent was recognised: | `reused` | Meaning | What to do | |---|---|---| | `true` | an existing node was found for this `client_id`, and its token was renewed | keep using it; this is the renewal path | | `false` | this call **minted a new node** | the `client_id` you sent was not recognised, so this token is not attached to whatever history you thought you were reusing | The `false` case used to be indistinguishable from a server that never implemented the field, because it was simply omitted (#4072). The server cannot tell you *which* id was the right one — that mapping lives on your side — so a client that stores its `client_id` somewhere durable (not in a hint header, which the endpoint treats as a hint and never as identity) is the only way to keep one node across token expiries. **The name is not the key (2026-10-31).** A renewal now expects the token it was given, sent the normal way: ```bash # renewal: the same client_id AND the token you already hold curl -sS https://misakanet.org/mcp -H "Authorization: Bearer $MISAKANET_TOKEN" ... -d '… "misakanet_register", "arguments": {"client_id": "8f14e45f-…"} …' ``` | what you send | what happens | |---|---| | `client_id` + a valid token for that node | renewed, `reused: true` — the supported path | | `client_id` alone, during the grace window | renewed, `reused: true`, **plus `deprecated`** telling you to add the token | | `client_id` alone, strict mode | `{error, code: "client_id_proof_required"}` and **no token** | | a fresh `client_id` | a new node, as before | The reason is one sentence: an agent's `client_id` appears in configs, transcripts and tutorials, so a value that appears in prose cannot be the only thing standing between a stranger and a 30-day write token. ### Reading errors `misakanet_get_lesson` answers `{error, code}` when it cannot return a lesson, and the code is what says what to do next: | Code | Meaning | |------|---------| | `lesson_not_found` | No such lesson (id or path, on `main` or `data`). Search instead of retrying. | | `invalid_lesson_path` | The argument is not a lesson reference. `path` must be a file under `lessons/` ending in `.md` — other repository files are not readable through this tool. | | `internal_error` | A service fault. Retrying is reasonable. | Added 2026-09-25 (B35), because those last two were one code: a missing lesson answered `internal_error` — the message for a transient fault — so a caller that obeyed it retried a 404 forever, and a caller that quoted it reported MisakaNet as down for its own typo. In the same call `path` went into the GitHub contents URL unvalidated, so `path=docs/CI.md` returned that file. ## Resources **Local stdio surface only** — the hosted endpoint exposes no resources (see *Which surface?*). | URI | Description | |-----|-------------| | `misaka://lessons/index` | Browse all published lessons (core + contrib) | | `misaka://protocol/overview` | failure-memory protocol config (trust tiers, rings, scoring) | | `misaka://docs/readme` | Project overview and quickstart | | `misaka://docs/faq` | Troubleshooting FAQ | | `misaka://docs/changelog` | Latest release notes | ## Prompts **Local stdio surface only** — the hosted endpoint exposes no prompts (see *Which surface?*). | Name | Description | Arguments | |------|-------------|-----------| | `search_lesson` | Guided lesson search | `query` (required), `domain?` | | `triage_failure` | Structured failure triage | `error` (required), `context?` | | `release_audit` | Release readiness check | `version` (required) | ## Search Scopes By default, the server searches **core** and **contrib** lessons only. Drafts are excluded to avoid surfacing unverified content. ## Search Sources The server uses two search backends (auto-detected): 1. **SAG-Lite** (SQLite) — fast, pre-built index at `data/sag.db` 2. **BM25** (fallback) — real-time search via `misakanet.search.engine` If neither is available, the server returns an error suggesting index rebuild: ```bash python3 scripts/build_sag_index.py ``` ## Smoke Test Run the built-in smoke test to verify your setup: ```bash python3 tests/test_mcp_server.py ``` This tests: - `search` returns results with `path` and `status` at **every** detail level, plus `freshness` (`fresh` / `recent` / `aging` / `stale`) at `compact` and `summary`. **There is no `badge` field** — an earlier version of this line promised one, and the surface never sent it; the freshness tier is a plain label. (The offline CLI's `search_knowledge.py --json` *does* emit a `badge`, inside a `freshness` object — but that is a **score**, not this age bucket, so the two `freshness` fields are not comparable: see `docs/cli-reference.md`.) - `get_lesson` returns lesson content - Default scope excludes drafts ## Security & Boundaries - **Not a skill marketplace.** MisakaNet is a failure memory network — lessons come from real debugging sessions, not curated skill packs. - **Read-only by default.** Tools like `misakanet_search` and `misakanet_get_lesson` are read-only. `misakanet_submit_usage` reports the lesson outcome to the public worker endpoint (`/api/helpful` for solved, `/api/feedback` for partial/not-helpful) — offline-safe: it falls back to local logging when the worker is unreachable. - **No raw sensitive content uploaded.** Search queries stay local. Lesson content is public (open-source repo). Usage reports contain only lesson ID + outcome, not source code or error logs. - **Write operations require explicit confirmation.** `misakanet_write_lesson` and `misakanet_submit_intake` create GitHub issues only when called — nothing is sent without an explicit tool call. ## Glama MisakaNet is listed on [Glama.ai](https://glama.ai/mcp/servers) for MCP server discovery.