MCP Setup
Overview
gitcode-mcp provides two MCP transport modes:
- stdio — single-client, local process. Recommended for editor integrations that spawn the server as a child process.
- HTTP/SSE — multi-client, shared cache. Recommended when multiple agents or clients need to query the same local cache.
Both modes serve the same MCP tools over the same JSON-RPC 2.0 protocol.
Stdio mode
Starting the server
gitcode-mcp --mcp
Or equivalently:
gitcode-mcp mcp serve --transport stdio
For MCP help without starting the server:
gitcode-mcp mcp --help
Client configuration (generic)
Configure your MCP client to launch:
{
"command": "gitcode-mcp",
"args": ["--mcp", "--cache-path", "/path/to/cache.db"]
}
Stdio mode uses stdin/stdout for JSON-RPC frames. stderr carries diagnostics.
Repo-local cache configuration
When the MCP client launches gitcode-mcp from inside a Git worktree, the server can use a repo-local cache without a per-client --cache-path. Bootstrap the worktree once:
gitcode-mcp repo init-local \
--repo example-owner/example-repo \
--owner example-owner \
--name example-repo
Then launch:
{
"command": "gitcode-mcp",
"args": ["--mcp"]
}
The command creates .gitcode/gitcode-mcp.yaml with cache_mode: repo-local, records the repository binding in <git-worktree>/.gitcode/mcp/cache.db, and ensures generated state is ignored:
.gitcode/mcp/
It does not sync data. Run gitcode-mcp sync --repo example-owner/example-repo ... separately when the cache should be populated.
Command-line --cache-path, GITCODE_MCP_CACHE_DIR, and global cache_path still override repo-local discovery.
HTTP/SSE mode
Starting the server
gitcode-mcp mcp serve --transport http-sse --bind 127.0.0.1:9020
Use a localhost bind address unless you explicitly intend to expose the server to other clients.
To use another fixed port:
gitcode-mcp mcp serve --transport http-sse --bind 127.0.0.1:9021
Endpoints
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Returns 200 if the server process is alive |
/ready |
GET | Returns 200 if the cache is readable and at least one repository is configured |
/sse |
GET | SSE endpoint for server-to-client events |
/message |
POST | JSON-RPC request endpoint |
Health check
curl http://127.0.0.1:9020/health
Expected: HTTP 200.
Readiness check
curl http://127.0.0.1:9020/ready
Returns a JSON object with ready boolean and optional code/message.
Expected readiness codes:
| Code | Meaning |
|---|---|
| (empty) | Ready |
cache_unreadable |
Cache database cannot be opened or read |
repo_unavailable |
No repositories configured |
locked_writer |
Writer lock contention |
Client configuration (generic HTTP/SSE)
Configure your MCP client with the server URL:
{
"transport": "sse",
"url": "http://127.0.0.1:9020"
}
MCP tool access
MCP tool access defaults to write, which exposes both read and write tools. This changes discovery only: every mutation still requires write_mode: "live" and passes the existing credential, provider, idempotency, audit, and cache-readiness gates.
Select a read-only MCP session explicitly:
mcp:
tools:
access: read
or:
GITCODE_MCP_TOOL_ACCESS=read gitcode-mcp --mcp
In read-only mode the server exposes cache/read/status tools and hides live/cache mutation tools from tools/list. A direct tools/call for a disabled mutation tool returns tool_disabled_by_policy before argument validation, credential resolution, network access, or cache mutation. Set access to write explicitly when overriding a read-only parent configuration.
Read-only Codex MCP example:
{
"command": "gitcode-mcp",
"args": ["--mcp"],
"env": {
"GITCODE_MCP_TOOL_ACCESS": "read"
}
}
Write-enabled Codex MCP example:
{
"command": "gitcode-mcp",
"args": ["--mcp"],
"env": {
"GITCODE_MCP_TOOL_ACCESS": "write"
}
}
Use separate config files or keyring accounts when different agents need different credentials:
{
"command": "gitcode-mcp",
"args": ["--mcp"],
"env": {
"GITCODE_MCP_CONFIG": "/path/to/gitcode-mcp-write.yaml",
"GITCODE_MCP_TOOL_ACCESS": "write",
"GITCODE_MCP_KEYRING_ACCOUNT": "codex-write"
}
}
The keyring account is non-secret metadata. The token remains in the OS keyring entry selected by credential.keyring_service and credential.keyring_account.
Zed stdio example for a repo-local cache:
{
"gitcode-mcp": {
"command": "gitcode-mcp",
"args": ["--mcp"],
"env": {
"GITCODE_MCP_TOOL_ACCESS": "read"
}
}
}
When credentials resolve, MCP startup selects the live provider by default for live lifecycle tools. Use --offline or --fixture only for deterministic fixture sessions. doctor reports the active tool_access and provider mode so agents can explain why write tools are or are not available.
MCP tools exposed
Tools are available in both transport modes. Read-only mode lists the cache/read/status subset; write mode lists all current tools:
| Tool | Description |
|---|---|
search_sources |
Hybrid source search by default; lexical results always participate, semantic chunks are grouped into source citations, and mode=full_text disables the embedding branch |
get_source |
Get a cached source record by stable id |
list_sources |
List cached sources with kind/status/limit/offset |
list_chunks |
List cached index chunks |
search_chunks |
Search cached index chunks by full-text/token query; not fuzzy or semantic |
get_snippet |
Get a cached chunk snippet |
stale_index_report |
Report missing or stale index state |
recent_changes |
List recently updated cached sources |
link_check |
Check cached source links for unresolved targets |
cache_status |
Report cache storage, WAL, count, and index-warning status |
source_backlinks |
List sources that link to the given id |
resolve_id |
Resolve a stable id or alias to its local record |
sync_status |
Check sync status for a source or the whole cache |
export_snapshot |
Export a deterministic snapshot |
diff_snapshot |
Diff two snapshots |
repo_status |
Report repository binding plus binary identity, cache schema compatibility, issue/comment counts, and issue-comment queue state |
maintenance_status |
Report sanitized daemon-managed cache, backfill frontier, content generation, and RAG coverage state |
maintenance_plan |
Build a deterministic, path-free plan for the selected MCP cache and requested refresh/RAG policy |
enable_cache_maintenance |
Apply an already rendered plan with write_mode=live and an idempotency key; machine-level installs/downloads return a CLI handoff |
repository_docs_policy |
Resolve the committed repository-document corpus policy at an exact local Git revision without fetching |
repository_docs_plan |
Plan bounded index cost and typed exclusions for one explicitly registered Git authority without embedding calls |
repository_docs_status |
Inspect metadata-only revision-set and vector coverage using opaque Git/worktree references |
repository_docs_search |
Search exact local Git blobs with bounded digest-verified citations; mode=fulltext requires no provider or index |
repository_docs_index |
Submit daemon-owned indexing for an exact opaque registration/source/generation selector; document text is never persisted |
sync_live |
Synchronize selected issue, issue-comment, pull-request, pull-request-comment, or wiki collections into the cache |
prepare_feedback |
Prepare and deduplicate a structured public-safe dogfood report without creating an issue |
submit_feedback |
Submit a prepared report to the configured sink through the audited write lifecycle |
create_issue |
Create a live issue through the audited write lifecycle |
add_issue_comment |
Add a live issue comment through the audited write lifecycle |
update_issue_comment |
Update a live issue comment through the audited write lifecycle |
update_issue |
Update live issue metadata through the audited write lifecycle |
create_pr |
Create a live pull request through the audited write lifecycle |
update_pr |
Update live pull request metadata through the audited write lifecycle |
list_milestones |
List live repository milestones and refresh cached milestone records |
list_push_remote_mirrors |
List live repository push mirrors and refresh credential-redacted cached records |
trigger_push_remote_mirror |
Trigger one configured push mirror through the audited write lifecycle |
wait_push_remote_mirror |
Poll sanitized mirror status until finished, failed, or timed out |
create_milestone |
Create a live milestone through the audited write lifecycle |
update_milestone |
Update live milestone metadata through the audited write lifecycle |
set_issue_milestone |
Assign a live issue milestone through the audited write lifecycle |
clear_issue_milestone |
Clear a live issue milestone through the audited write lifecycle |
add_pr_comment |
Add a live pull request comment through the audited write lifecycle |
add_pr_review_comment |
Create a live inline pull request review comment through the audited write lifecycle |
reply_pr_review_comment |
Reply inside a live pull request review discussion with list readback |
link_pr_issue |
Link a pull request to an issue through the GitCode relation API with fallback |
create_page |
Create a live wiki page through the audited write lifecycle |
update_page |
Update a live wiki page through the audited write lifecycle |
delete_page |
Delete a live wiki page through the audited write lifecycle |
add_label |
Add a label to a live issue through the audited write lifecycle |
index_repo |
Build or refresh the local cache index |
auth_status |
Report redacted credential presence and source metadata |
doctor |
Report structured server health diagnostics |
MCP write tools require write_mode: "live" and use the same service write path as CLI live writes: idempotency keys, provider confirmation, audit records, cache refresh, typed errors, and public-safe diagnostics. prepare_feedback is intentionally read-only and remains visible in read-only MCP sessions; submit_feedback is visible only in write-enabled sessions, requires write_mode: "live" plus a caller-provided idempotency key, and can write only to the configured sink repository. Exact fingerprint matches return the existing issue. With duplicate_policy: suggest, likely matches require review or duplicate_override: "create"; return_existing selects the strongest likely match without writing. repo_status identifies the running binary and cache together: it reports effective binary version/commit metadata, detected and expected cache schema versions, cached issue/comment counts, and the durable issue-comment queue summary. This makes an outdated binary, pending comment drain, and missing cached comments distinguishable without consulting the live API. sync_live exposes unambiguous issue_comments and pr_comments selectors. Its legacy comments selector follows the selected parent collection: issues + comments drains issue comments, pulls + comments syncs pull request comments, and selecting both parent kinds with the generic flag is rejected before any sync work. comments without a parent retains pull request comment compatibility. list_milestones is read-only and does not require write_mode; it refreshes cached milestone records from the live list response. create_issue requires title and accepts body, labels, optional milestone, and idempotency_key. update_issue accepts the same milestone selector or clear_milestone: true; the fields are mutually exclusive. Milestones are resolved and validated in the configured repository before issue mutation, then verified by issue readback. Successful and idempotently replayed receipts return the resolved stable/remote milestone identity or an explicit cleared marker. create_milestone requires title and due_on because GitCode rejects milestone creation without a due date. The dedicated set_issue_milestone and clear_issue_milestone tools remain available and use the same resolver/readback contract because GitCode can return milestone: null in the immediate issue PATCH response even when assignment succeeds. add_pr_review_comment requires number, body, path, and a 1-based current-side file line; the adapter derives GitCode's provider coordinates and requires path/line readback before success. The deprecated position input is not a diff-hunk offset and, if supplied, must equal line. Optional start_line must be at or before line, and end_line must equal line. list_pr_discussions distinguishes its presentation id from reply_discussion_id and reports replyable; use the provider reply id only when true. reply_pr_review_comment requires number, discussion_id, parent_comment_id, and body; synthetic ids are live-resolved when possible and otherwise return discussion_reply_unavailable before POST. Successful replies still validate the parent, avoid a matching duplicate, and require discussion readback. link_pr_issue defaults to strategy: "auto", which first calls the GitCode PR issue relation endpoint. If that endpoint is unsupported, it falls back to a deterministic PR-body marker plus Fixes #N. Use strategy: "description_fallback" to force the fallback behavior.
Repository binding diagnostics use the runtime context captured when the MCP server starts; they do not re-guess paths from the request process's current directory. repo_status returns the effective cache path, cache-path source, and selected configuration reference. An omitted repo_id is nothing_bound, while an unknown selected value is missing. For a missing binding the response preserves selected_repo_id, returns a bounded sorted available_bindings list, and includes suggested_repo_id only when the selected value exactly matches the repository name or alias of one configured binding. Callers must retry explicitly with that stable id; the server never silently reroutes repository-scoped operations. doctor reports the same recovery fields at the top level, emits the mismatch as one root-cause diagnostic, and skips derivative cache, sync, and index probes. If the binding registry itself cannot be read, the tool returns the typed cache/schema failure instead of misreporting a normal missing binding.
Issue read results make identity roles explicit. get_source, list_sources, recent_changes, and resolve_id return stable_source_id for cache links and issue_number for GitCode's repository-local write route; legacy id and remote_alias remain for compatibility. Issue-targeting MCP writes accept either number or issue_id. Use number only for the repository-local issue number. Use issue_id for a stable id such as ISSUE-76 or a known cached alias such as issue:76 or gitcode_issue_id:.... Resolution is cache-first. If both selectors are present they must identify the same issue, and a cached provider id accidentally supplied as number is rejected with an invalid_query hint before any remote write.
Operational error contract
Domain and local-operational failures use JSON-RPC code -32000, with a
stable category in the top-level message and a machine-readable error.data
object. Agents should branch on error.data.code or failure_class, not parse
the human message:
{
"code": "missing_repository_binding",
"failure_class": "missing_repository_binding",
"operation": "cache_status",
"repo_id": "example-owner/example-repo",
"message": "repository binding is not configured",
"remediation": "call repo_status ...; CLI fallback: gitcode-mcp doctor ..."
}
Known cache, repository-binding, local-service IPC, sync, write, and provider
diagnostics retain their typed codes. An unclassified failure is
internal_error; it is never mislabeled as sync_required. Cache corruption
and local-service connection errors return sanitized summaries rather than raw
database paths, socket addresses, or provider payloads. cache_status,
stale_index_report, service_status, service_jobs, and
service_job_status include their operation name, and repo-scoped tools include
the selected repo_id. Follow remediation for the MCP-first recovery and use
the stated CLI fallback when the MCP operation itself is unavailable.
Cache contention errors expose cache_ref, holder operation, repo_id,
started_at, and pid when known. They never expose the lock/cache path,
filesystem DSN, URL-style query parameters or fragments, or an arbitrary
lock-owner hint. cache_ref is an opaque correlation value derived from the
durable cache identity when available.
Before add_pr_review_comment performs a POST, it requires the parent PR-<number> record in the selected cache. A missing parent returns typed parent_pr_not_cached with an MCP-first targeted-sync remediation (sync_live with pulls=true and remote_alias=pr:N) plus the CLI fallback; no audit claim or provider write has occurred. Retry the review write with the same idempotency key after syncing pr:N.
For bounded discussion refresh, call sync_live with pr_comments: true and remote_alias: "pr:N". The PR must already be cached; the operation calls the per-PR comments adapter once and does not enumerate other cached pull requests. Exact selectors cannot be combined with collection bounds or daemon mode.
list_push_remote_mirrors is also read-only and requires only repo_id. It
removes destination URL user-info, query strings, and fragments before returning
or caching mirror records. trigger_push_remote_mirror requires
write_mode: "live" and a caller-provided idempotency_key; mirror_id may be
omitted only for a repository with exactly one configured mirror.
wait_push_remote_mirror accepts an optional RFC3339 after barrier and a
bounded timeout_seconds. Trigger and wait results contain no destination
field. See Push Mirror Operations.
Some CLI operations are intentionally not exposed through normal MCP write access. Credential management, raw escape hatches, destructive local cache maintenance, cache resets, and schema migrations must remain CLI-only unless a future capability registry entry documents a stricter MCP confirmation and safety contract.
Correlation IDs
HTTP/SSE requests carry an X-Request-ID header. If not provided by the client, the server generates one. All request logs include the correlation ID.
First MCP read
After syncing an offline fixture and indexing:
- Start the MCP server.
- Open
/sseand read the announced/message?session_id=...endpoint. - POST a
tools/callrequest forget_snippetwithrepo_id,source_id,line_start, andline_end. - Verify the SSE response contains the expected fixture snippet.
Example JSON-RPC request (HTTP/SSE):
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_snippet",
"arguments": {
"repo_id": "example-owner/example-repo",
"source_id": "ISSUE-42",
"line_start": 1,
"line_end": 3
}
}
}
Server lifecycle
- The HTTP/SSE server runs until the process receives SIGINT or SIGTERM.
- Sync, index, and write operations are explicit MCP tool calls or CLI commands; routine reads never trigger them automatically.
- Multiple MCP clients can read concurrently from the shared cache.
- Writer operations are serialized and require explicit live intent.