# MCP tool server

The optional Model Context Protocol (MCP) server exposes Open Second Brain's
deterministic operations as tools that Hermes Agent (or any other MCP client)
can route through its tool registry.

The server is **optional**: the `o2b` CLI remains the supported baseline. Nothing
in Open Second Brain depends on the MCP server being running.

## Protocol

- Transport: stdio (JSON-RPC 2.0, newline-delimited).
- Protocol version: `2025-06-18`.
- Capabilities advertised: `tools` and `resources` (see "Resources"
  below). No `prompts` or `sampling`.
- Standard MCP lifecycle: `initialize`, `notifications/initialized`,
  `tools/list`, `tools/call`, optional `ping`.

## Tool Highlights

The full server currently advertises 57 tools; 18 further names stay callable
through `tools/call` as hidden deprecated aliases (see "Consolidated views and
deprecated aliases" below). The table highlights the operator-facing core,
schema, agent-source, health, and recovery tools; the full surface
also includes Brain writer, review, query, temporal, link-graph, and search
tools. In Claude Code, the full schema can push MCP definitions beyond 10% of
the context window, causing `MCPSearch` tool-search deferral; use the writer
split below for the always-loaded writer subset, or the runtime capability
flags for a narrower per-process full server.

| Tool                        | Purpose                                                                                                                                        | Required arguments                             |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| `second_brain_capabilities` | Report the tools available to this MCP process and the withheld-tool reasons after runtime capability filtering.                               | —                                              |
| `second_brain_status`       | Report config and vault status, with secrets redacted.                                                                                         | —                                              |
| `second_brain_query`        | List vault pages with an optional case-insensitive title substring.                                                                            | —                                              |
| `vault_health`              | Run vault, config, and plugin manifest health checks.                                                                                          | —                                              |
| `brain_health`              | Run semantic Brain Health checks and return the health verdict/domains.                                                                        | —                                              |
| `brain_mcp_landscape`       | List the MCP servers configured across the vault: name, source config file, packages, and required env-var names. Env values never read.       | —                                              |
| `brain_agent_query`         | Read-only source-agent retrieval over Brain provenance. Filters by agents, topic, free-text query, contribution kind, and limit.               | —                                              |
| `brain_agent_diff`          | Read-only comparison between source agents using browse/search/diff/map modes over the same provenance foundation.                             | —                                              |
| `brain_audit`               | Read-only per-preference mutation trail (create / promote / update / retire / merge) with agent, reason, revision + content-hash before/after. | `pref_id`                                      |
| `brain_brief`               | Read-only Brain summary for any window: `view: morning \| daily \| weekly \| monthly \| operator \| digest`.                                   | `view`                                         |
| `brain_analytics`           | Read-only Brain analytics for any lens: `view: timeline \| attention_flows \| belief_evolution \| concept_synthesis`.                          | `view`                                         |
| `brain_search`              | Read-only vault search with optional structured query lanes, explicit focus hints, time ranges, and evidence-pack diagnostics.                  | `query`                                        |
| `brain_recall_feedback`     | Record explicit up/down recall feedback for one search result; feeds the deterministic learned-weight fold.                                     | `query`, `result_path`, `verdict`              |
| `brain_recall_gate`         | Read-only classifier for whether an automatic recall attempt should run; returns `retrieve` plus a stable reason.                              | `prompt`                                       |
| `brain_context_pack`        | Budgeted context slice; pass `lanes: true` to return directives, constraints, and consider lanes. Filtered items include `safety.reasons`.     | `max_tokens`                                   |
| `brain_context_receipts`    | List or show opt-in prompt context receipt continuity records with budgets, hashes, source refs, safety/redaction metadata, and item IDs.      | `operation`                                    |
| `brain_recall_telemetry`    | List or summarise opt-in recall telemetry records for search, context-pack, and pre-compress calls.                                            | `operation`                                    |
| `brain_context_presets`     | Show, suggest, or diff read-only context budget presets (`tight-context`, `long-context`) without writing config.                              | `operation`                                    |
| `brain_pre_compact_extract` | Extract decision/commitment/outcome/rule/open-question records from bounded text into continuity storage.                                      | `session_id`, `turn_start`, `turn_end`, `text` |
| `brain_hygiene`             | Memory hygiene: `scan` findings (conflicts, dedup, freshness, usefulness), `apply` selected ids, `refresh` stale pages. Resolver command comes from `_brain.yaml` only. | `mode`                                         |
| `brain_anticipatory_context` | Turn-specific context bundle kept warm by lifecycle hooks, keyed by the session's lineage root; reports `cache_state` warm / stale / miss.   | `session_id`                                   |
| `brain_session_grep`        | Search imported session recall raw turns and deterministic summary nodes.                                                                      | `query`                                        |
| `brain_session_describe`    | Describe raw-turn counts and summary depths for one imported session recall DAG.                                                               | `session_id`                                   |
| `brain_session_expand`      | Expand a raw or summary session recall node to immediate sources and paginated raw turn content.                                               | `id`                                           |
| `brain_sources`             | Read-only dashboard of signals grouped by (agent, source_type) with active/processed and distinct-topic counts.                                | —                                              |
| `schema_inspect`            | Read-only schema inspection for any view: `view: graph \| lint \| stats \| orphans \| explain_type \| active_pack \| packs`.                   | `view` (`token` for `explain_type`)            |
| `schema_apply_mutations`    | Apply audited, locked schema mutations to `Brain/_brain.yaml`.                                                                                 | `mutations`                                    |
| `brain_watchdog`            | Probe Brain config, required dirs, and search-index health; optionally apply safe directory remediation.                                       | —                                              |
| `brain_switch_vault`        | Activate a named vault profile; the change takes effect on the next server launch.                                                             | `name`                                         |

### Consolidated views and deprecated aliases

`brain_brief`, `brain_analytics`, and `schema_inspect` replaced three
overlapping tool families in v0.34.0; per-view output is identical to the
predecessor tools because dispatch goes to the same handlers. The 18
predecessor names were removed in 1.0.0: calling one answers a precise
INVALID_PARAMS tombstone naming the replacement tool and `view` (for
example `brain_digest was removed in 1.0.0; call brain_brief with
view="digest"`), so a stale client learns the migration from the error
itself. Per-view parameters keep their old names (for example
`brain_brief` with `view: "daily"` accepts the same `date` argument
`brain_daily_brief` did, and `brain_analytics` with
`view: "attention_flows"` defaults `operation` to `list`). The full
alias-to-replacement table lives in `docs/updating.md`.

`second_brain_query` accepts `pattern` (string) and `limit` (1–500, default 50).
`vault_health` accepts `repo` (string) for plugin manifest validation.
`brain_agent_query` accepts `agents` (string array), `topic`, `query`, `kind`
(`signal`, `preference`, `log`), and `limit` (1-500, default 50).
`brain_agent_diff` accepts the same filters plus `mode` (`browse`, `search`,
`diff`, `map`). Omitting `agents` means all known source agents.
`brain_search` accepts `query_document` with line-oriented `intent:`, `lex:`,
`vec:`, and `hyde:` lanes; `focus_query` / `focus_path_prefix` to steer a
single call; `since` / `until` time ranges (ISO date/datetime, `today`,
`yesterday`, `last week`, `last month`, or `<n>h`/`<n>d`/`<n>w` shorthand,
filtered on document mtime); `include_superseded: true` to keep superseded
predecessors undemoted (history mode); and `evidence_pack: true` to return
significant/matched/missing terms, abstention text, terminal-state downrank
reasons, per-result `why_retrieved`, IDF-weighted coverage with rare-term
classification, per-token `union_records` for uncovered terms, and a
`completeness` verdict whose `uncovered_but_present_in_corpus` list is the
false-absence guard. It can also emit opt-in recall telemetry with
`telemetry: true`. `brain_recall_feedback` records one feedback event as a
JSON file under `Brain/search/feedback/` and returns the refreshed learned
weights (applied to ranking only when `search_learned_weights_enabled` is on).
`brain_context_pack` accepts opt-in `receipt`, `telemetry`, `cache_stable`, and
`dedup_repeated` diagnostics; `brain_pre_compress_pack` accepts opt-in `receipt`
and `telemetry`. `brain_context_receipts` supports `operation: "list"|"show"`;
`brain_recall_telemetry` supports `operation: "list"|"summary"`; and
`brain_context_presets` supports `operation: "show"|"suggest"|"diff"`.
`brain_pre_compact_extract` writes idempotent typed continuity records after
deterministic media/base64 sanitization. `brain_session_grep`,
`brain_session_describe`, and `brain_session_expand` inspect the opt-in session
recall DAG populated by CLI `import-session --recall` or the core API.
`brain_recall_gate` accepts optional `previous_prompt` and
`explicit`; `explicit: true` always returns `retrieve: true`.

> **Date format note.** Brain tools use ISO 8601 `YYYY-MM-DD`
> throughout; the `Brain/log/<date>.md` subdirectory layout shares that
> convention.

All tool results contain both an unstructured `content` text block (a JSON
serialization of the structured payload) and a `structuredContent` object so
clients that prefer typed results can use it directly.

## Resources

The server also exposes a `resources` capability for hosts that prefer
pull-style access (no tool call, no arguments). Three concrete URIs
come back from `resources/list`:

- `osb://preferences/active` — body of `Brain/active.md`, the auto-
  generated digest of confirmed + quarantined preferences plus the
  last three retired entries. Auto-regenerated on first read if the
  file does not exist yet.
- `osb://digest/latest` — same body as `brain_brief` `view="digest"`
  in its default (24h) Markdown window.
- `osb://status` — Brain operational snapshot: counts (inbox /
  preferences by status / retired / log_days / snapshots), last
  `dream` and `apply-evidence` timestamps, and a sanity flag for
  signals awaiting `dream`. Same data the `second_brain_status`
  tool returns under its `brain` field, rendered as markdown.

Four templated URIs come back from `resources/templates/list`:

- `osb://preference/{id}` — body of `pref-{id}.md`, with fallback to
  `ret-{id}.md` when the active copy is gone. Accepts the bare slug
  (`my-rule`) or the prefixed form (`pref-my-rule` / `ret-my-rule`).
- `osb://topic/{slug}` — synthesised markdown of every signal, the
  current preference (or retired), and the most recent log entries
  for the topic.
- `osb://log/{date}` — body of `Brain/log/<date>.md` (date is
  `YYYY-MM-DD`).
- `osb://backlinks/{id}` — inbound references to the given Brain
  artifact id, rendered as a count plus a list grouped by source
  kind. Same data as the `brain_backlinks` tool.

`resources/read` accepts both shapes uniformly and returns
`text/markdown` content. Malformed slug/date arguments produce
`INVALID_PARAMS`; missing files produce a tool-level error envelope
with a `not found` message — same shape as `brain_query`'s
`BrainNotFoundError`.

## Run from the CLI

```bash
scripts/o2b mcp --vault /path/to/vault
```

Optional flags:

- `--config PATH` — override the Open Second Brain config file location.
- `--repo PATH` — repository root used for plugin manifest checks.
- `--scope full|writer` — choose the full server or the always-loaded writer subset.
- `--writer-only` — alias for `--scope writer`.
- `--probe` — start an in-process handshake and print whether the server can advertise tools, then exit.
- `--json` — with `--probe`, print a machine-readable capability report.
- `--allow-tool NAME` — expose only named tools from the static scope. Repeatable.
- `--disable-tool NAME` — withhold named tools from the static scope. Repeatable.
- `--max-tools N` — expose only the first N non-diagnostic tools from the static scope.

The server logs its banner to `stderr` and only writes JSON-RPC frames to
`stdout`, so it is safe to use as a subprocess in any MCP client.

## Runtime capability window

Runtime capability flags are evaluated after the static scope. They can narrow
the tool list a process advertises, but they cannot widen `--scope writer` into
full-server tools. The full server always keeps `second_brain_capabilities`
available so clients and operators can inspect which tools were available or
withheld and why.

Examples:

```bash
o2b mcp --vault /path/to/vault --probe --json --disable-tool second_brain_query
o2b mcp --vault /path/to/vault --allow-tool brain_context --allow-tool brain_feedback
o2b mcp --vault /path/to/vault --max-tools 12
```

`second_brain_capabilities` returns `scope`, `server_name`, static and available
tool counts, an `available[]` list, and a `withheld[]` list. Withheld reasons
are stable strings such as `disabled by runtime capability window`, `not allowed
by runtime capability window`, and `outside runtime capability max tool window`.

## Tool-surface profiles and the two-pass catalog (since v0.37.0)

Named profiles bundle a scope plus capability window so hosts stop
hand-rolling allow/deny flag lists:

```bash
o2b mcp --vault /path/to/vault --tool-profile catalog
o2b mcp --vault /path/to/vault --tool-profile recall --probe
```

Profiles: `full` (default), `writer`, `catalog`, `recall` (memory
read/write surface, no admin tools), and `minimal` (writers + context +
search). The `mcp_tool_profile` config key (env:
`OPEN_SECOND_BRAIN_MCP_TOOL_PROFILE`) selects one without flags; an
explicit `--scope` or window flag wins over the profile's fields. An
unknown profile name FAILS OPEN to the full surface with a stderr note -
a typo can never lock an agent out. Hard-window profiles always retain
`second_brain_capabilities`, so withheld tools stay discoverable with
reasons.

The `catalog` scope is the two-pass surface: `tools/list` advertises
only the capability diagnostic, the five always-loaded Brain tools, and
`tool_hydrate`; every other tool stays callable through `tools/call`.
Call `tool_hydrate` with no arguments for the compact catalog (name,
one-line description, group), then with `names: [...]` for the full
input/output schemas of exactly the tools you need - unknown names are
reported per-name without failing the batch.

## Skill surface (since v0.37.0)

`list_skills` returns the agent skills shipped in the plugin's
`skills/` directory plus vault-local `Brain/skills/` (vault entries
shadow shipped ones by name). `get_skill` fetches a skill's SKILL.md by
name; an optional `file_path` reads an auxiliary file and is
path-traversal-guarded to the skill directory. `skills_attach` scores
skills against the current turn text with a deterministic BM25-style
scorer and returns a char-budgeted block of top matches; it returns
`enabled: false` with an empty block unless the `skill_auto_attach`
config key is `"true"`, so default per-turn injection is unchanged. The
native Hermes provider calls it from `prefetch()` fail-soft.

## Workspace Insight Suite tools (since v0.38.0)

`brain_search` accepts `global: true` for cross-vault union search:
one query fans out over the active vault, registered profile vaults,
and read-only recall sources (managed by `o2b brain source`), merging
results by score. Each result carries an additive `origin` field plus
an `origin:<label>` reason (`local`, `profile/<name>`,
`source/<alias>`). Non-active origins search with self-healing and the
query cache disabled, so an external vault is never written to; a
missing index degrades to a per-origin warning.

`brain_trigger` is the consolidated trigger-queue tool: `scan`
generates deduped triggers from semantic-health and retention data,
`list` / `history` read by effective lifecycle status,
`acknowledge` / `dismiss` / `act` transition one trigger. Cooldown keys
keep the same issue from reappearing while an earlier trigger is open
or cooling down; `brain_brief` `view="morning"` surfaces capped pending
triggers and marks them delivered (once per `trigger_cooldown_days`).

`brain_deep_synthesis` assembles a deterministic topic dossier
(matched notes, agreements, contradictions, stale claims, knowledge
gaps; `triggers: true` enqueues findings). `brain_idea_discovery`
ranks next-direction candidates from open questions, orphan notes, and
aging inbox signals.

`brain_recall_gate` emits a `gate_telemetry` continuity record per
decision when the `recall_gate_telemetry` config key is `"true"`
(default off) - decision, stable reason, host, SHA-256 prompt prefix;
never the raw prompt. `brain_recall_telemetry` gains `gate_list` /
`gate_summary` operations.

The full observability contract behind these tools - event kinds,
always-on vs opt-in status, correlation IDs, payload safety, and the
continuity schema version - lives in `docs/observability.md`.

## Hermes integration

Hermes discovers MCP servers from `~/.hermes/config.yaml` under the
`mcp_servers` key. After installing this plugin, register the MCP server on
the same machine that hosts the vault.

The Hermes CLI accepts the registration directly:

```bash
hermes mcp add open-second-brain --command o2b --args mcp --vault /path/to/vault
```

`--args` is a single flag; everything after it on the line (here
`mcp --vault /path/to/vault`) is collected as the argument list and forwarded
to the MCP server's command line. Do not wrap all of those arguments into one
quoted shell string and do not repeat `--args` per token — both forms make
Hermes pass a single concatenated argument to the MCP server.

You can also edit `~/.hermes/config.yaml` by hand:

```yaml
mcp_servers:
  open-second-brain:
    command: o2b
    args: ["mcp", "--vault", "/path/to/vault"]
    enabled: true
    timeout: 30
    tools:
      include:
        # Drop any line below to disable a specific tool, or remove the
        # whole `tools.include` block to expose every advertised tool.
        - second_brain_status
        - second_brain_query
        - vault_health
```

If you run Open Second Brain from a checkout instead of an installed package,
point `command` at the absolute path of `scripts/o2b`:

```yaml
mcp_servers:
  open-second-brain:
    command: /srv/projects/open-second-brain/scripts/o2b
    args: ["mcp", "--vault", "/path/to/vault"]
```

After editing the file, run `/reload-mcp` inside Hermes to pick up the new
server.

The Hermes plugin manifest (`plugin.yaml`) advertises this MCP entrypoint via
the `mcp_server` field so future Hermes releases can auto-register the server,
but the official Hermes config flow is the source of truth today.

## Updating the MCP registration

Updating the plugin via `hermes plugins update open-second-brain` does not
rewrite `~/.hermes/config.yaml`. Your existing `mcp_servers.open-second-brain`
entry keeps working as long as the `command` and `args` you originally
registered still resolve.

After an update:

- Restart the gateway so the MCP subprocess is reloaded:

  ```bash
  hermes gateway restart
  ```

- If the new release adds a flag, re-add the registration with the updated
  `--args` list (or edit the YAML by hand):

  ```bash
  hermes mcp remove open-second-brain
  hermes mcp add open-second-brain --command o2b --args mcp --vault /path/to/vault
  ```

`scripts/o2b mcp --vault /path/to/vault` from the checkout can be used to
sanity-check the server before re-registering it.

## Removing the MCP registration

To remove just the MCP server without uninstalling the plugin, run:

```bash
hermes mcp remove open-second-brain
hermes gateway restart
```

`hermes mcp remove` deletes the registration entry. Open Second Brain runs
over stdio (JSON-RPC 2.0) and does not use OAuth, so there are no tokens for
this server specifically; the OAuth-token cleanup `hermes mcp remove` performs
only matters for transports that authenticate that way. The installed plugin
and its CLI commands stay in place, so `hermes plugins update` will continue
to track new releases.

To remove both the MCP server and the plugin itself, follow the
`Uninstalling` section in the project README. Open Second Brain never edits
`~/.hermes/config.yaml` on your behalf, and `o2b uninstall` is a read-only
helper that prints the exact Hermes commands to run.

## Claude Code and Codex

The Claude Code plugin manifest exposes `o2b mcp` as a regular command that
Claude Code can invoke. Codex installs the same `scripts/o2b` script through
its plugin manifest, so the MCP entrypoint is reachable from a Codex shell as
well. There is no auto-registration into Codex's MCP discovery — add the
server to your Codex MCP config the same way as Hermes.

## Writer split (Claude Code 2.1.121+)

The plugin's `.mcp.json` ships **two** MCP-server entries:

- `open-second-brain` - the full surface: 48 advertised tools (including the consolidated `brain_brief`, `brain_analytics`, and `schema_inspect`, plus `brain_health`, `brain_mcp_landscape`, `brain_agent_query`, `brain_agent_diff`, `brain_recall_gate`, `brain_pinned_context`, `brain_pre_compress_pack`, `brain_audit`, `brain_sources`, and `brain_switch_vault`) and 18 hidden deprecated aliases listed under "Consolidated views and deprecated aliases" above; subject to Claude Code's `MCPSearch` tool-search deferral when MCP definitions push the system prompt past 10% of the context window.
- `open-second-brain-writer` - a minimal always-loaded surface of five tools: `brain_feedback`, `brain_apply_evidence`, `brain_note`, `brain_pinned_context` (writers) and `brain_context` (read-only pull-bootstrap of `Brain/active.md` plus pinned context, v0.16.0). The agent records taste signals, evidence events, milestone notes, and current-task pinned facts - and fetches the active rule digest at session start in runtimes without a SessionStart hook - without a ToolSearch round-trip on every session boot.

Both servers reuse the same backing CLI (`o2b mcp --scope writer` vs the default `--scope full`). Handlers are byte-identical; the writer-mode instructions text explicitly tells the agent to prefer the writer copy over any duplicate the full server still exposes (both call the same code path).

## Safety notes

- The vault path is bound to the server instance at startup. Tools cannot
  escape it.
- `second_brain_status` reuses the same redaction logic as `o2b export-config`.
- Brain writers (`brain_feedback`, `brain_apply_evidence`, `brain_note`,
  `brain_pinned_context`)
  go through atomic-rename writes so an interrupted call leaves either
  the prior or the new file, never a torn hybrid.
- MCP tools can declare lightweight output contracts; declared contracts are
  validated against `structuredContent` before the text mirror is emitted.
