Skip to content

MCP server

Khiip ships a Model Context Protocol server (khiip-mcp-server) that exposes the substrate’s core operations as MCP tools. Claude Desktop, Cursor, or any other MCP-aware client can connect over stdio and capture/recall through Khiip without writing any HTTP code.

Tools

ToolMaps to
capture_url(url, force_new=False)POST /api/v1/captures
recall(query, limit=10)GET /api/v1/recall
list_captures(source=None, limit=50, offset=0)GET /api/v1/captures
get_capture(capture_id, format="json")GET /api/v1/captures/{id}
refetch_capture(capture_id, dimension="extraction")POST /api/v1/captures/{id}/refetch
daemon_status()GET /health + GET /api/v1/meta

How it works

The MCP server is a thin HTTP proxy that connects to your running Khiip daemon at 127.0.0.1:8478 (configurable via the KHIIP_DAEMON_URL env var or [daemon] host/port in ~/.config/khiip/config.toml). It reads the Bearer auth token from ~/.config/khiip/auth.toml — the same file the CLI and Obsidian plugin use. The daemon must be running before MCP tool calls land.

Claude Desktop config

On macOS, edit ~/Library/Application Support/Claude/claude_desktop_config.json (analogous paths on other platforms):

{
"mcpServers": {
"khiip": {
"command": "khiip-mcp-server"
}
}
}

If khiip-mcp-server isn’t on Claude Desktop’s PATH (common when you installed with pip install -e inside a venv), point at the full path:

{
"mcpServers": {
"khiip": {
"command": "/Users/you/projects/khiip/.venv/bin/khiip-mcp-server"
}
}
}

Verify the wiring

Terminal window
# Start the daemon in one terminal
khiipd serve
# In another terminal, send an initialize ping to the MCP server
python -c "
import asyncio
from mcp.client.session import ClientSession
from mcp.client.stdio import stdio_client, StdioServerParameters
async def main():
params = StdioServerParameters(command='khiip-mcp-server', args=[])
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
for t in tools.tools:
print(t.name)
asyncio.run(main())
"

You should see all six tool names listed.