# Upgrading to kairix v2026.5.3

This guide tells you what to do when upgrading. It's written so an agent (or human) can follow it without external context — drop it into your agent's reading list, point them at it, and the upgrade should self-manage.

If you're reading this in your project's vendored copy of kairix, your version is already current. If you're reading this on GitHub before upgrading, the changes below describe what will need to happen on your side after you pull.

## TL;DR

If you only read one thing: **change `/sse` to `/mcp` in your MCP client config.** That's the entire required action.

```diff
- "url": "http://your-kairix-host/sse"
+ "url": "http://your-kairix-host/mcp"
```

Same host, same port, same authentication (if any). No tunnels, no certs, no auth changes. The old `/sse` endpoint still works (deprecated, not removed) — clients can move at their own pace.

Everything else in this document is either new capability you can opt into, behavioural defaults that shifted, or troubleshooting if something goes wrong.

## 1. The required client-side migration

The MCP server now serves streamable HTTP at `/mcp` as the recommended transport. The legacy `/sse` endpoint is preserved for back-compat. Each MCP tool call is a normal HTTP request/response, so the gateway timeouts and dropped-connection failures that triggered repeated `-32602 Invalid request parameters` errors don't apply to `/mcp` at all.

Per-client steps:

| Client | What to change |
|---|---|
| Claude Desktop | `claude_desktop_config.json` — change the kairix entry's `url` from `/sse` to `/mcp`. Restart. |
| Claude Code | `.claude/mcp.json` (repo) or `~/.claude/mcp.json` (user) — same URL change. Restart. |
| OpenClaw | Agent config block — change `transport: sse` → `transport: streamable-http`, change `url` `/sse` → `/mcp`. Reapply the config. |
| Custom Python client | Replace `mcp.client.sse.sse_client(...)` with `mcp.client.streamable_http.streamablehttp_client(...)`. Bump `mcp>=1.20,<2`. |
| Custom Node / TypeScript | Replace `SSEClientTransport` with `StreamableHTTPClientTransport`. Bump `@modelcontextprotocol/sdk>=1.5`. |

Full per-client deep dive: [`docs/operations/MCP-CLIENT-MIGRATION.md`](../operations/MCP-CLIENT-MIGRATION.md).

**No auth changes are required.** If your kairix is on `localhost`, it stays on `localhost`. If your kairix sits behind a gateway with Cloudflare Access or any other auth, that gateway's auth keeps working unchanged for `/mcp` — the operator might need to add `/mcp` to their gateway routing, but that's an operator task, not a client task.

## 2. New: typed scope on every retrieval tool

`search`, `prep`, `timeline`, and `contradict` now accept a typed `scope` parameter with five values:

| Scope | Reaches | When to use |
|---|---|---|
| `shared` | Shared collections only — curated knowledge, no agent memory | Fact-check a claim against curated sources without your own memory contaminating the answer |
| `agent` | Only the calling agent's own collection | Recall what *this agent* has previously written — session continuity |
| `shared+agent` (default) | Shared + the calling agent's memory | Day-to-day default. Same as before this release. |
| `all-agents` | Every registered agent's collection, no shared | Cross-team synthesis — "what has the team collectively discovered about X?" |
| `everything` | Shared + every agent | Maximum recall. Treat as a last resort because it dilutes precision. |

For `scope=all-agents` and `scope=everything` to return content, your `kairix.config.yaml` must declare an `agents:` registry. Without one, those scope values return a structured "agent registry not configured" error rather than crashing. Example:

```yaml
agents:
  - name: alpha
    write_path: /data/workspaces/alpha
  - name: beta
    write_path: /data/workspaces/beta
```

When `paths:` is omitted, kairix uses `/data/workspaces/{agent}` as the default — appropriate for the simple deployment where each agent has a workspace folder. Deployments that maintain agent knowledge in additional locations (a documentation vault, a shared knowledge area) can declare those paths explicitly. See [`docs/operations/MCP-DEPLOYMENT.md`](../operations/MCP-DEPLOYMENT.md) for the full schema.

If you don't configure an `agents:` registry, the default scope (`shared+agent`) keeps working as before.

## 3. Behavioural changes that may affect saved invocations

Things that were broken now work; things that always worked still work. Three changes deserve attention because they may affect commands or scripts you have saved.

**Research confidence values are real.** Previously, `mcp-kairix__research` always returned `confidence: 0.0` because the LLM occasionally responds with prose instead of strict JSON. The new parser chain handles both prose and JSON. If any code path filters research results by `confidence > 0`, those results will now flow through where they previously didn't.

**Timeline returns search results for non-temporal queries.** Previously, a timeline call with a query that had no date expression returned an empty rewriter response. The MCP tool now falls through to a normal search using the original query, so timeline returns results either way. Response carries `is_temporal: false, fell_back: true` when the rewrite was a no-op, so you can tell which path ran.

**Contradict default threshold is now 0.45 (was 0.6).** The scoring now runs three categories — `direct`, `overstatement`, `status_mismatch` — and aggregates by max. Each individual category scores more conservatively than the historic single-prompt scorer, so the threshold is calibrated lower. Saved invocations with explicit `--threshold 0.6` still work but will surface fewer contradictions than the new default would. Result objects carry a `category` field so callers can filter for, e.g., overstatements only. To preserve old behaviour, pass an explicit `--threshold 0.6` and ignore the `category` field.

**Errors return real exception class names.** Previously, any uncaught exception inside a kairix MCP tool got mapped to JSON-RPC `-32602 Invalid request parameters`, which masked the actual cause. Tool responses now carry `{"error": "<ExceptionClass>: <message>"}` with the real class name. **If your client code retries on `-32602`**, update the retry condition — `-32602` now exclusively means parameter validation failed, not "something went wrong inside the tool."

## 4. Minor — operator-facing changes you might notice

These don't require client action but are worth noting if you skim logs or operate the deployment.

- The container entrypoint now uses `--transport http` instead of the deprecated `--transport sse` alias. The deprecation warning that previously appeared on every container start is gone.
- Search log gains four new fields: `agent`, `scope`, `collections_searched`, `vec_failed`. Default location for Docker deployments moves to `/data/kairix/logs/search.jsonl`; non-Docker stays at `~/.cache/kairix/logs/search.jsonl`.
- `kairix config validate` is a new sub-command that checks your YAML for misconfigurations (missing collection names, duplicate agent definitions, overlapping write paths, unknown retrieval-override keys). Wire it into your pre-deploy check.
- The bundled `docker-compose.yml` now binds the host port to `127.0.0.1` only by default — kairix has no built-in auth, so external exposure requires explicit operator action (drop the prefix and put a gateway with auth in front).

## 5. Verifying your upgrade

After updating your MCP client:

1. Run any tool you'd normally use. If results come back, you're on the new transport.
2. Optional explicit check: call `mcp-kairix__usage_guide` with `topic="scope"` — should return a section explaining the five scope values. If that section is missing, your client may still be talking to an older kairix.
3. From the deployment host, `curl http://your-kairix-host/healthz` returns `{"ready": true, "uptime_s": N}` once kairix has finished cold-starting.

If any of those don't behave as expected, see the troubleshooting table below.

## 6. If something breaks

Most likely failure modes, in rough order:

| Symptom | Likely cause | Fix |
|---|---|---|
| `-32602 Invalid request parameters` on every call | Client still on `/sse`; gateway dropped the idle connection | Change URL to `/mcp` |
| `404 Not Found` when posting to `/mcp` | Hitting an older kairix where `/mcp` doesn't exist yet | Either upgrade kairix or stay on `/sse` for now |
| Tool calls silently hang | Client library too old for streamable HTTP | Update: Python `mcp>=1.20`, Node `@modelcontextprotocol/sdk>=1.5` |
| `connection refused` | kairix isn't running, wrong host/port, or networking | Operator-side: check `docker compose ps kairix` and `/healthz` |
| `scope=all-agents` returns "agent registry not configured" | YAML doesn't declare `agents:` | Add an `agents:` section per [`docs/operations/MCP-DEPLOYMENT.md`](../operations/MCP-DEPLOYMENT.md), or use `scope=shared+agent` |
| Anything else | Capture the exact `error` string from the tool response | Real exception class names come through now — the message is informative |

If you're an agent, **don't try to fix server-side issues yourself.** Anything to do with auth, gateway routing, or kairix not running is the operator's problem. Capture the error and ask the operator.

## 7. Rollback

If migration breaks something for you and you can't debug it right now:

- **Client-side rollback:** change `/mcp` back to `/sse` in your client config. The legacy endpoint stays mounted in kairix, so you're back to pre-migration behaviour.
- **Server-side rollback:** pin to the previous kairix tag (`v2026.5.2` or older). The standard rollback procedure: `docker compose down && docker compose pull <previous-tag> && docker compose up -d`.

There's no kairix-side rollback to perform when only clients need to change — the server is happy serving both `/mcp` and `/sse` simultaneously.

## 8. Things that haven't changed

Worth listing explicitly because the list of changes is long enough that you might wonder.

- Tool names: `search`, `entity`, `prep`, `timeline`, `research`, `contradict`, `usage_guide`. All seven still there.
- Tool parameters: same JSON schema, same defaults (apart from `contradict --threshold` mentioned above and the new optional `scope` and `agent` parameters).
- `--agent` parameter behaviour: unchanged.
- Authentication: kairix has none built in, same as before.
- Token budgets: unchanged.
- Embedding pipeline: unchanged. The `mcp` package floor moved from `>=1.0,<2` to `>=1.20,<2`; no other dependency changes.
- Existing `kairix.config.yaml` fields: backwards compatible. New `agents:` section is additive.

## 9. Where to find more

- **CHANGELOG** entry for this release: [`CHANGELOG.md`](../../CHANGELOG.md)
- **Client migration deep dive:** [`docs/operations/MCP-CLIENT-MIGRATION.md`](../operations/MCP-CLIENT-MIGRATION.md)
- **Operator deployment guide:** [`docs/operations/MCP-DEPLOYMENT.md`](../operations/MCP-DEPLOYMENT.md)
- **Agent usage guide** (with new Scope section): [`docs/user-guide/agent-usage-guide.md`](../user-guide/agent-usage-guide.md)
- **Architecture reference** (for contributors): [`docs/architecture/ENGINEERING.md`](../architecture/ENGINEERING.md)
