How to connect an MCP-capable IDE or agent to KnowCode, and how to wrap the REST API as LLM function-calling tools for frameworks that cannot use MCP. The canonical agent retrieval policy is the MCP contract — thresholds, verbosity rules, and token budgets live there so every agent behaves the same way; don't hard-code separate values per client.
Agents retrieve focused repository context before building a large prompt. The low-token workflow:
- Agent receives a user query.
- Agent calls
knowcode_retrievewithaction="query"andverbosity="minimal". - KnowCode returns compact
context_text,sufficiency_score, and token count. - Agent answers locally when the configured threshold is met
(
sufficiency_threshold, default 0.8). - Agent escalates budget or verbosity only when minimal context is not enough.
- KnowCode installed (with the
mcpextra:pip install "knowcode[mcp]"). - A built knowledge store and index:
knowcode build .
knowcode doctor --store . --mcpThe server resolves its repository root from, in order: an explicit
--store, the CLAUDE_PROJECT_DIR environment variable, then the process
working directory. Claude Code does not document the working directory it
spawns a stdio server with and its own guidance is to resolve
project-relative paths from CLAUDE_PROJECT_DIR, so do not rely on
--store . — omit --store and let the env var win.
That makes one registration serve every repository:
claude mcp add knowcode --scope user -- knowcode mcp-serverWhich is equivalent to:
{
"mcpServers": {
"knowcode": {
"command": "knowcode",
"args": ["mcp-server"]
}
}
}Pin a single repository instead by passing an absolute --store:
{
"mcpServers": {
"knowcode": {
"command": "/absolute/path/to/repository/.venv/bin/knowcode",
"args": ["mcp-server", "--store", "/absolute/path/to/repository"]
}
}
}A server launched with uvx --from <checkout>[mcp] does not pick up edits
in the checkout: uv resolves that requirement onto a cached tool environment
(~/.local/share/uv/tools/knowcode) and reuses it indefinitely for a path
source, and --refresh does not rebuild it. The server will happily run
month-old code against a fresh store with no signal of the drift
(BL-32). Two launch shapes avoid the trap:
- The repository's own venv, which always executes the working tree:
bin/knowcode-mcp.sh mcp-server --store /absolute/path/to/repository. - A reinstall after each pull — the cache clean is load-bearing,
--forcealone reinstalls from the cached wheel and reproduces the staleness:uv cache clean knowcode && uv tool install --force --python 3.11 '<checkout>[mcp]'.
Drift is no longer silent, though (BL-32, fixed):
every generation manifest names the code that built it, knowcode doctor
fails a Builder drift check when the running code disagrees with the store,
and the server prints a one-line warning banner at startup. The launch shapes
above remain the cure; the check is what tells you that you need it.
Restart the IDE or agent host after changing its MCP config. On macOS, if
the stdio server is not spawned correctly from a GUI client, the wrapper
script bin/knowcode-mcp.sh works around provenance checks.
The server starts whether or not artifacts exist, so an agent in a
repository KnowCode has never seen can build them itself: call
knowcode_lifecycle with action="build", then poll knowcode_inspect
action="job_status". No terminal step is required.
Tools are named mcp__knowcode__<tool>. Because the surface is split by
concern, retrieval can be allowlisted without also allowing builds:
{
"permissions": {
"allow": ["mcp__knowcode__knowcode_retrieve", "mcp__knowcode__knowcode_inspect"]
}
}knowcode_lifecycle declares anthropic/requiresUserInteraction, so every
build is confirmed even if the server is otherwise allowlisted. A build
sends repository chunk text to the configured embedding provider and consumes
quota, so this is deliberate.
Lifecycle actions return a job_id immediately rather than blocking, because
indexing costs one embedding round-trip per file with no cross-file batching
or concurrency — a few hundred files is minutes, a few thousand is tens of
minutes. Claude Code's stdio idle timeout defaults to 30 minutes
(CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT), which a synchronous build could
exceed. Polling is cheap and read-only.
The server exposes three consolidated tools; an action selects the
capability. The canonical policy, token budgets, and escalation ladder live in
the MCP contract.
| Tool | Actions |
|---|---|
knowcode_retrieve |
query (primary), search, context, trace, semantic_search |
knowcode_lifecycle |
build, index, export |
knowcode_inspect |
job_status, doctor, freshness, quality, stats, preflight, history, telemetry |
Call knowcode_retrieve with action="query" first for ordinary repository
questions; use the rest for focused follow-up.
Deliberately excluded: telemetry deletion, daemon/host control
(server, mcp-server, install), and ask — inside an agent the model
should consume retrieved context rather than pay a second LLM.
The five original flat tools remain available for one release via
--legacy-tools (off by default).
Put only a pointer plus the compact rule in agent-specific config files:
When repository context is needed, follow docs/mcp-contract.md.
Start with knowcode_retrieve action=query, verbosity=minimal, and the smallest
budget that fits the task. Escalate to standard or verbose only when the minimal
context is insufficient. Use the configured sufficiency_threshold from
aimodels.yaml to decide whether to answer from local context.knowcode doctor --store . --mcpThe MCP handshake check spawns the server, lists tools, and calls the primary tool, so a green result proves the surface really answers.
Then ask the agent a repository question such as “Where is the retrieval
orchestration implemented?” Expected: the agent calls knowcode_retrieve
with action="query" and verbosity="minimal" first, answers locally when
sufficiency_score meets the threshold, and escalates only if
insufficient. A manual test plan with expected sufficiency scores per
question is in tests/test_mcp_workflow.md.
Target baselines to aim for (actuals depend on your codebase and queries):
70%+ of queries with sufficiency_score ≥ 0.8, and a 50%+ reduction in
external LLM token usage. Monitor knowcode telemetry show against these
targets.
MCP server not available. Check the command path, that --store is an
absolute path, and that the IDE was restarted. Run the server directly to
see errors: knowcode mcp-server --store .
Knowledge store not found. Call knowcode_lifecycle action="build"
(or run knowcode build .) and poll job_status until it succeeds. Note
that a current build publishes the graph as knowledge.db inside
knowcode_index/generations/; the flat knowcode_knowledge.json is a legacy
export written only with export_json. Both layouts count as ready, so do
not expect the JSON to exist.
Semantic retrieval fallback. Rebuild the index (knowcode index .) and
confirm embedding keys from aimodels.yaml are present in the agent's
environment.
Stale results (is_stale: true). Run knowcode build . to refresh
store and index together; with the server running, POST /api/v1/reload.
Context still too small. Follow the ladder in the
MCP contract: increase breadth while staying in
minimal, then standard for implementation detail, then verbose for
evidence. Don't make diagnostic the default.
- The MCP server runs locally over stdio; it never exposes a port.
knowcode_knowledge.jsonandknowcode_index/contain repository-derived data — treat them like your source.- Embedding providers receive chunk text during indexing, depending on your configured provider.
- Store API keys in environment variables, not committed files.
For custom agent frameworks that cannot use MCP, translate KnowCode's REST
API into native LLM tools: the FastAPI server publishes its schema at
/openapi.json, which you map to tool definitions.
- Start the server:
knowcode server --port 8000— the spec is served athttp://127.0.0.1:8000/openapi.json. - Translate endpoints to tools. Frameworks like LangChain's
RequestsToolkitor LlamaIndex'sOpenAPIToolSpecautomate this; by hand:
import requests
openapi_spec = requests.get("http://127.0.0.1:8000/openapi.json").json()
tools = [
{
"type": "function",
"function": {
"name": "query_context",
"description": "Execute semantic search and return relevant code chunks with context.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"task_type": {"type": "string",
"enum": ["explain", "debug", "extend", "review", "locate", "general"]}
},
"required": ["query"]
}
}
}
# ... repeat for the endpoints below
]- Execute tool calls by hitting the corresponding HTTP endpoint and feeding the response back as the tool result message.
The highest-value endpoints to expose as tools:
| Tool | Endpoint | Role |
|---|---|---|
query_context |
POST /api/v1/context/query |
Primary discovery — natural-language semantic search |
search |
GET /api/v1/search?q= |
Exact symbol lookup |
get_context |
GET /api/v1/context?target= |
Deep dive on a discovered entity |
trace_calls |
GET /api/v1/trace_calls/{entity_id} |
Caller/callee dependency mapping |
The full endpoint reference, including rate limits, is in REST API.