-
Notifications
You must be signed in to change notification settings - Fork 0
1.12 MCP Integration Guide
New in v1.0.0-rc.2. ClioDeck speaks the Model Context Protocol in both directions:
- Client side — Brainstorm can call tools exposed by external MCP servers you configure.
- Server side — ClioDeck exposes your indexed corpus to Claude Desktop, Claude Code, or any other MCP client.
Both surfaces are opt-in. The MCP server is inactive by default.
ClioDeck's Brainstorm mode can drive any MCP server (stdio or SSE transport) the user configures. The tools that server exposes become callable by the LLM during a Brainstorm turn (provider must advertise capabilities.tools).
Settings → MCP Clients (MCPClientsSection):
- Click Add client.
- Fill in:
-
Name — a short identifier (no spaces; this becomes part of the namespaced tool name
<name>__<tool>). -
Transport —
stdio(spawn a subprocess) orsse(connect to an HTTP endpoint). - For
stdio: Command and Args (space-separated). - For
sse: URL.
-
Name — a short identifier (no spaces; this becomes part of the namespaced tool name
- Save. ClioDeck spawns the subprocess (or opens the SSE stream) and runs the MCP handshake.
Each client exposes a typed state, not a connected: bool:
| State | Meaning |
|---|---|
unconfigured |
Configured but not yet started. |
spawning |
Subprocess started; transport handshake in progress. |
handshaking |
Transport up; MCP initialize round-trip in progress. |
ready |
Tools listed, available to Brainstorm. |
degraded |
Operational but partially impaired. |
failed |
Last error captured in lastError. |
stopped |
Explicitly stopped by the user. |
The UI reflects the state in real time. A crashed client is auto-retried once, without any user action required — but this isn't invisible in the UI: the client transitions through degraded (shown with the same red/danger color as failed, raw state text) for the ~500ms retry window (backend/integrations/mcp-clients/manager.ts), then either recovers to ready or, on a second failure, moves to failed with a manual retry button. What's automatic is the retry attempt, not its visibility.
Partial success is first-class: if 3 clients out of 5 are ready and 2 are failed, Brainstorm uses the 3 and shows a badge for the missing 2.
In a Brainstorm turn (fusion-chat-service.ts), the engine assembles a catalog of tools by iterating ready clients:
namespaced name = <clientName>__<bareToolName>
description = [<clientName>] <description>
parameters = the tool's JSON Schema (from its inputSchema)
When the LLM emits a tool call, the engine strips the namespace prefix and routes the call to the right client via mcpClientsService.callTool(clientName, bareTool, args).
Before the catalog reaches the model, Brainstorm applies a read/write opt-in filter: a pure heuristic (backend/integrations/mcp-clients/tool-classifier.ts) classifies each bare tool name as 'read' (auto-enabled — search_/get_/list_/find_/fetch_/… prefixes, plus ping/health/version) or 'write' (opt-in — everything else, including any unrecognised verb). All 9 of ClioDeck's own built-in tools classify as read. The user's per-tool choices are surfaced in a banner above the Brainstorm chat input and persist across restarts — see Brainstorm Mode Guide. Passing no enabledTools at all (any caller other than Brainstorm) preserves the legacy behaviour of every ready tool being available.
ClioDeck ships an MCP server binary (bin/cliodeck-mcp) that exposes the workspace's indexed corpus + a handful of public-archive connectors as MCP tools. It is off by default — loadMCPConfig refuses to start unless the workspace's config.json has the server enabled.
Settings → MCP Server (MCPServerSection):
- Tick the Enable checkbox. The status badge flips between
onandoff. - (Optional) Change the server name. Default: the workspace folder name.
- The section displays the resolved Binary path (read-only); the resolution depends on whether you're running a packaged build or
npm start. Copy it from the UI — you'll paste it into your MCP client config. - Pick a client tab (Claude Desktop, Claude Code CLI, or Generic MCP (stdio)) and copy the generated snippet.
Every call into the server is appended to .cliodeck/mcp-access.jsonl as a typed MCPAccessEvent (kind, tool name, timestamp, input, summary of output). Open the file directly with any text editor to audit which client called what, when (a dedicated viewer is on the RC3 roadmap).
All tools return JSON-friendly content. topK defaults to 10 and is bounded between 1 and 200. Content is truncated to 4,000 characters per chunk (2,000 for Gallica/HAL snippets) to keep responses bounded.
| Tool | Purpose | Required input | Optional input |
|---|---|---|---|
search_documents |
Lexical search across PDF chunks (full text). |
query (string) |
year, author, topK
|
search_obsidian |
BM25 search across your Obsidian vault (FTS5). |
query (string) |
topK |
search_tropy |
Case-insensitive search over Tropy primary sources. |
query (string) |
topK |
search_zotero |
Lookup over bibliography (title / author / bibtex key). |
query (string) |
year, topK
|
graph_neighbors |
Citations out, citations in, similarity neighbors for a document. |
documentId (string) |
topK |
entity_context |
NER-extracted mentions of a named entity across the corpus. |
entity (string) |
topK |
search_gallica |
SRU search against the BnF's Gallica catalogue. No key required. |
query (string) |
dateFrom, dateTo, docType, topK
|
search_hal |
Solr search against the HAL open-archive (CCSD). No key required. |
query (string) |
dateFrom, dateTo, docType, topK
|
search_europeana |
Search Europeana (~50M items). Requires a free API key. |
query (string) |
mediaType (IMAGE/TEXT/VIDEO/SOUND/3D), topK
|
The Europeana key is read at call time from the EUROPEANA_API_KEY environment variable. When ClioDeck spawns the MCP server itself, the key is propagated automatically from secureStorage. When a third-party MCP client spawns the server, you need to set the env var in your client config — see the snippets below.
The Settings → MCP Server section generates ready-to-paste snippets for three common clients. Copy them from the UI for the live binary path; what follows is the shape.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent on your OS, and merge:
{
"mcpServers": {
"cliodeck": {
"command": "/absolute/path/to/cliodeck-mcp",
"args": ["/absolute/path/to/your/workspace"]
}
}
}The exact command path is shown in Settings → MCP Server → Binary path — copy it from there. In dev it resolves to <repo>/bin/cliodeck-mcp; in a packaged build it sits under Electron's resources/bin/cliodeck-mcp.
To enable Europeana from Claude Desktop, add an env block to the snippet:
{
"mcpServers": {
"cliodeck": {
"command": "...",
"args": ["..."],
"env": {
"EUROPEANA_API_KEY": "your-wskey-here"
}
}
}
}Restart Claude Desktop after editing.
From a terminal:
claude mcp add cliodeck -- /path/to/cliodeck-mcp /absolute/path/to/your/workspaceTo pass EUROPEANA_API_KEY, prefix the command with env:
claude mcp add cliodeck -- env EUROPEANA_API_KEY=your-key /path/to/cliodeck-mcp /absolute/path/to/your/workspaceAny MCP client that supports stdio can spawn the binary directly:
/path/to/cliodeck-mcp /absolute/path/to/your/workspaceThe first positional argument is always the workspace root (the folder that contains .cliodeck/).
- Server inactive by default. No data leaves the workspace until you flip the toggle.
- Per-workspace scope. The binary is bound to one workspace root passed on the command line; it cannot see other projects.
-
Auditable. Every call is appended to
.cliodeck/mcp-access.jsonlas a typed event. There is no renderer-side viewer for it yet (see the note above) — open the file directly to audit it. - Revocable. Toggling the server off invalidates running connections; restarting the client is required to re-connect.
-
No secrets on disk. API keys (Europeana) live in Electron's
safeStorage, never inconfig.json.
For external MCP clients you wire into ClioDeck, the same source-inspection pipeline that runs on PDFs and Tropy chunks (backend/security/source-inspector.ts) is applied to tool results before they enter the LLM prompt.
⚠️ Real bug, verified against code: an in-flight tool call itself is safe across a project switch —MCPClientsService.callTool()(mcp-clients-service.ts) never re-readsthis.workspaceRootmid-call, it just delegates to whichever manager instance was already in scope when the call started. But the audit log it's recorded to can still be misattributed: every manager'sonEventclosure callsthis.writeAuditLog(e), which readsthis.auditLogStream— the current field value — not a reference captured when that manager was created.loadProject()'sunload()step callsmanager.stopAll()before opening the new project's audit stream, butstop()(manager.ts) only awaitedhandle.close(), so an in-flight tool call's audit event could land in the new project'smcp-access.jsonl. Fixed in RC4 — the audit stream is captured when the manager is created, so it can never write to another project's trail.
- Brainstorm Mode Guide — how MCP tools are dispatched inside the agent loop.
- Archive Connectors Guide — the three archive tools in detail.
-
Obsidian Vault Guide — the source behind
search_obsidian.