Connect Claude Code to Semlith
How to connect Claude Code to Semlith over MCP, the command or file that adds it, and how to check the connection works.
${SEMLITH_BIN} where the binary goes, the path which semlith prints. Set up your agent client explains it and the HTTP form.Claude Code — claude mcp add, or a committed .mcp.json in the project
root. Its scopes are local, user and project, defaulting to local, so
--scope user makes one registration cover every directory. --transport http
points it at the running daemon; in the subprocess form the -- matters,
because Claude Code reads anything starting with a dash as its own flag. The
JSON below is the project file, which is committed on purpose, so semlith never
writes it.
{
"mcpServers": {
"semlith": {
"type": "http",
"url": "http://127.0.0.1:7365/mcp",
"headers": { "Authorization": "Bearer ${SEMLITH_AGENT_KEY}" }
}
}
}claude mcp add --scope user --transport http semlith http://127.0.0.1:7365/mcp --header "Authorization: Bearer ${SEMLITH_AGENT_KEY}"Or as a subprocess, which needs no key. To replace an existing entry, remove it
first: remove takes the same scope flag, and without one it deletes from
whichever scope it finds the name in.
claude mcp remove --scope user semlithclaude mcp add --scope user semlith -- "${SEMLITH_BIN}" mcpsemlith setup also writes two hook entries into ~/.claude/settings.json. The
PreToolUse one fires before a Bash grep, rg, find, cat, sed -n, head, tail
or awk, a Read, a Grep or a Glob inside a folder semlith indexes, and adds
one line naming a semlith call that answers the same question
(semlith_search {query: …}, semlith_impact {name: …}, semlith_read {target: …}, semlith_files {tree: true}). It stays quiet outside indexed folders, on
commands that search nothing, and after three lines in a session. The
PostToolUse one records that a session has called semlith. Both sit beside any
other hooks, and semlith setup --no-hooks removes both and leaves the rest of
the file as it was.
The default mode never blocks. semlith setup --hook-mode gate refuses raw
lookups until the session has made one semlith call, at most twice, then only
nudges; --hook-mode hard always refuses grep, rg and find in an indexed
folder. --strict is kept as the name for gate.
Gate exists because, on code, an agent with Grep reaches for Grep. On 50
held-out code questions with Opus 5.5, no wording of the instructions, tool
descriptions or soft hook moved it (0 to 5 of 50 sessions called semlith). Under
gate, about 45 of 50 did, with two more correct answers and about 12 % more
cost per session (bench/scorecard/README.md). It stays opt-in. On documents it
is the other way round: 127 of 127 sessions called semlith unforced (#189).
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|Read|Grep|Glob",
"hooks": [{ "type": "command", "command": "${SEMLITH_BIN} hook" }]
}
],
"PostToolUse": [
{
"matcher": "mcp__.*semlith.*",
"hooks": [{ "type": "command", "command": "${SEMLITH_BIN} hook" }]
}
]
}
}It also links the semlith Agent Skill into the directory Claude Code reads user skills from:
semlithIt sets "alwaysLoad": true on the user-scope server entry in ~/.claude.json,
so the semlith tools are in context from the first turn rather than behind
ToolSearch. claude mcp add has no flag for it, so the entry is upgraded in
place, backed up beside itself first. Other clients load an MCP server’s tools
when they connect and need no equivalent.
It writes a read-only research subagent, ~/.claude/agents/semlith-explorer.md,
whose tools are the semlith tools plus a bounded Read for files semlith does
not index, and which Claude chooses over Explore for code research in an
indexed folder. semlith setup --no-agents removes it.
semlith doctor reports a missing alwaysLoad, the hook’s mode, the research
agent, and a per-project disable: disabledMcpServers or
disabledMcpjsonServers naming semlith for the directory you run it from, which
the client’s /mcp toggle writes and which makes the server silently absent
there. semlith doctor --fix clears that one entry for the current directory and
leaves the rest of ~/.claude.json as it was. Only --fix touches it; setup
never does, because the disable was your choice in that project.