The PRD's first acceptance gate now holds: grep -RinE '\bx\.ai\b|grok' crates/ --include='*.rs' → 0 matches (exempt: NOTICE and third-party license archives, README provenance, and the required 'Based on Grok Build Open Source' attribution, now sourced from version_attribution.txt). Wire-visible renames (both sides in this repo, changed in lockstep): - Auth method id 'grok.com' → 'kimi-code' (AuthMethodKind::KimiCode). - Every x.ai/* and _x.ai/* ACP ext method and meta key → kigi/* / _kigi/* (~200 names; grokShell → kigiShell). Session-file replay keeps a read-side alias for the legacy '_x.ai/session/update' method so existing updates.jsonl histories load; writes emit only the new name (both directions test-pinned). - Agent types grok-build* → kigi* with a documented legacy-prefix alias at resolution time so persisted sessions keep resolving. - ToolNamespace/BuiltinAgentName GrokBuild* → Kigi* (wire snake_case kigi/kigi_concise/kigi_hashline; schema regenerated); grok_build implementation dirs renamed to kigi*. - x-grok-* headers → x-kigi-*, __GROK_* sentinels → __KIGI_*, themes grokday/groknight → kigiday/kiginight (old persisted values fall back to the default theme), web_fetch allowlist xAI hosts → kimi.com + moonshot platforms, changelog CDN → this repo, grok-build changelog archives deleted. - BYOK default endpoint removed: [endpoints] api_base_url is now truly optional with NO default — consumers fail fast with the flag name when unset (no silent x.ai egress). Mock harnesses inject it explicitly. - System-prompt identity fixed: 'released by xAI' → 'an unofficial community CLI for Kimi' (template + regenerated encrypted form). Also repaired pre-existing grok-era test debt found by the sweep: the stale trace_classify default-model pin, the grok-pager UA label test, pty-harness stale-binary reuse and non-hermetic moonshot routing (a PTY test could previously reach the real api.moonshot.cn), and the outdated oauth fixture scope key. Gates: §9 grep 0; fmt clean; workspace check/clippy 0/0 (-D warnings); FULL cargo test --workspace: 234 suites, 21,961 passed, 0 failed; deny advisories ok.
350 lines
14 KiB
Markdown
350 lines
14 KiB
Markdown
# MCP Servers
|
||
|
||
MCP (Model Context Protocol) servers extend Kigi with external tool integrations. They let Kigi interact with any service that implements the MCP standard.
|
||
|
||
---
|
||
|
||
## What Are MCP Servers?
|
||
|
||
An MCP server is a process that exposes tools to Kigi over a standardized protocol. When you configure an MCP server, its tools become available to the model alongside Kigi's built-in tools. The model can discover and call these tools during a session.
|
||
|
||
For example, a GitHub MCP server might expose tools like `create_issue`, `list_pull_requests`, and `search_code`. A database server might expose `query`, `list_tables`, and `describe_schema`.
|
||
|
||
See the [MCP specification](https://modelcontextprotocol.io) for protocol details.
|
||
|
||
---
|
||
|
||
## Configuration
|
||
|
||
MCP servers are configured in `~/.kigi/config.toml` under `[mcp_servers.<name>]` sections.
|
||
|
||
### stdio Transport (Local Process)
|
||
|
||
Kigi spawns a local process and communicates over stdin/stdout:
|
||
|
||
```toml
|
||
[mcp_servers.my-server]
|
||
command = "/path/to/server" # Server executable
|
||
args = ["--flag", "value"] # Command arguments
|
||
env = { API_KEY = "sk-..." } # Environment variables
|
||
enabled = true # Enable or disable the server (default: true)
|
||
startup_timeout_sec = 30 # Server startup timeout, seconds (default: 30)
|
||
tool_timeout_sec = 6000 # Per-tool-call timeout fallback, seconds (default: 6000)
|
||
tool_timeouts = { slow_op = 120 } # Per-tool timeout overrides, seconds
|
||
```
|
||
|
||
> **Global startup-timeout override:** instead of setting `startup_timeout_sec`
|
||
> per server, you can change the default for all servers via the `MCP_TIMEOUT`
|
||
> environment variable (milliseconds, compatible with Claude Code) or
|
||
> `KIGI_MCP_STARTUP_TIMEOUT_SECS` (seconds). A per-server `startup_timeout_sec`
|
||
> still takes precedence over both. Cold-start `npx`/`uvx` servers that download
|
||
> packages on first launch often need this; the default is 30s.
|
||
>
|
||
> **MCP tool-result size cap:** large MCP / `use_tool` results are truncated
|
||
> inline (full payload spilled under the session `mcp/` folder). Default is
|
||
> **20_000 bytes**. Override via:
|
||
>
|
||
> - env `KIGI_MAX_MCP_OUTPUT_BYTES` or `MAX_MCP_OUTPUT_BYTES` (bytes; Kigi-native
|
||
> wins if both set; Claude-style name, but we bound by **bytes** not tokens)
|
||
> - `config.toml` — user-level (`~/.kigi/config.toml`) **or repo-level**
|
||
> (`.kigi/config.toml` anywhere on the cwd → git-root chain; the deepest
|
||
> file wins, and the repo value applies only once the folder is trusted):
|
||
>
|
||
> ```toml
|
||
> [mcp]
|
||
> max_output_bytes = 40000
|
||
> ```
|
||
>
|
||
> Precedence: requirements.toml > env > repo `.kigi/config.toml` >
|
||
> user/managed config > default. Repo edits apply to running sessions in that
|
||
> directory via config hot-reload.
|
||
|
||
### HTTP/SSE Transport (Remote Server)
|
||
|
||
For remote MCP servers accessible over HTTP:
|
||
|
||
```toml
|
||
[mcp_servers.remote-api]
|
||
url = "https://mcp.example.com/api"
|
||
headers = { "Authorization" = "Bearer token" }
|
||
```
|
||
|
||
### Streamable HTTP with Session ID
|
||
|
||
```toml
|
||
[mcp_servers.my-streamable-server]
|
||
url = "https://mcp.example.com/api/mcp"
|
||
headers = { "x-mcp-session-id" = "{{session_id}}" }
|
||
```
|
||
|
||
---
|
||
|
||
## CLI Management
|
||
|
||
Manage MCP servers from the command line without editing config files:
|
||
|
||
```bash
|
||
# List configured MCP servers
|
||
kigi mcp list
|
||
kigi mcp list --json # Machine-readable output
|
||
|
||
# Add a stdio server. Everything after -- is the server command, so flags
|
||
# like -y reach the server instead of being parsed by kigi.
|
||
kigi mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /path/to/dir
|
||
|
||
# Add a stdio server with environment variables (-e is repeatable)
|
||
kigi mcp add postgres -e DATABASE_URL=postgres://localhost/mydb -- npx -y @modelcontextprotocol/server-postgres
|
||
|
||
# Add a remote HTTP server
|
||
kigi mcp add --transport http sentry https://mcp.sentry.dev/mcp
|
||
|
||
# Add a remote server with an authentication header (--header is repeatable)
|
||
kigi mcp add --transport http api https://mcp.example.com/mcp --header "Authorization: Bearer YOUR_TOKEN"
|
||
|
||
# Add a remote SSE server
|
||
kigi mcp add --transport sse linear https://mcp.linear.app/sse
|
||
|
||
# Remove a server
|
||
kigi mcp remove github
|
||
|
||
# Diagnose a server's configuration and connectivity
|
||
kigi mcp doctor # Check every configured server
|
||
kigi mcp doctor github # Check one server
|
||
kigi mcp doctor --json # Machine-readable output
|
||
```
|
||
|
||
The transport defaults to `stdio`; pass `--transport http` or `--transport sse` for remote servers.
|
||
|
||
By default `kigi mcp add` writes to `~/.kigi/config.toml` (`--scope user`). Use `--scope project` to write to `.kigi/config.toml` in the current directory instead, which can be committed and shared with your team (see [Project-Scoped MCP Servers](#project-scoped-mcp-servers)). Header and environment variable values are stored verbatim, so reference secrets as `${VAR}` instead of pasting them into a committed project config (see [Example Configurations](#example-configurations)). `kigi mcp list` shows servers from both scopes, marking project-scoped ones with `(project)`.
|
||
|
||
`kigi mcp remove` searches both scopes and exits 0 after removing the server. It exits 1 when the name is not found, or when the name is defined in both user and project scope — pass `--scope` to say which one to remove.
|
||
|
||
Breaking changes from earlier releases: `--env` now takes one `KEY=value` per flag (use `-e A=1 -e B=2`, not `--env A=1 B=2`), and server names may only contain letters, numbers, hyphens, and underscores.
|
||
|
||
---
|
||
|
||
## Project-Scoped MCP Servers
|
||
|
||
MCP servers can be configured per-project by placing a `.kigi/config.toml` in your repository:
|
||
|
||
```
|
||
my-project/
|
||
.kigi/
|
||
config.toml
|
||
src/
|
||
...
|
||
```
|
||
|
||
```toml
|
||
# .kigi/config.toml
|
||
[mcp_servers.linear]
|
||
url = "https://mcp.linear.app/mcp"
|
||
enabled = true
|
||
```
|
||
|
||
When a server exposes a native HTTP/SSE endpoint, prefer the `url` form over wrapping it in a stdio proxy such as `npx mcp-remote <url>`. Kigi handles HTTP/SSE and OAuth directly, so the native form avoids an extra subprocess per session. It also registers Kigi's own OAuth client with the provider.
|
||
|
||
Kigi walks from the current directory up to the git repo root, loading `.kigi/config.toml` at each level:
|
||
|
||
| Location | Scope | Priority |
|
||
|----------|-------|----------|
|
||
| `~/.kigi/config.toml` | All projects | Lowest |
|
||
| `<repo-root>/.kigi/config.toml` | This repository | Medium |
|
||
| `<cwd>/.kigi/config.toml` | Current directory | Highest |
|
||
|
||
If a project defines a server with the same name as a global one, the project version replaces it entirely (fields are not merged).
|
||
|
||
Project-scoped files contribute `[mcp_servers]`, `[plugins]`, and `[permission]` entries. Kigi reads most other config sections only from `~/.kigi/config.toml`.
|
||
|
||
---
|
||
|
||
## Tool Naming
|
||
|
||
MCP tools are namespaced with the server name to avoid collisions:
|
||
|
||
- Server `filesystem` with tool `read_file` becomes `filesystem__read_file`
|
||
- Server `github` with tool `create_issue` becomes `github__create_issue`
|
||
|
||
---
|
||
|
||
## Toggle Servers at Runtime
|
||
|
||
You can enable or disable MCP servers during a session without restarting Kigi.
|
||
|
||
### The /mcps Modal
|
||
|
||
Open the MCP servers modal in the TUI:
|
||
|
||
- Run `/mcps` as a slash command
|
||
- Or press `Ctrl+L` (non–VS Code family) and navigate to the MCP Servers tab; on VS Code family use `/plugins` or `/mcp` and open the MCP Servers tab
|
||
|
||
From the modal you can:
|
||
|
||
- See each server's source, enabled state, and tool count
|
||
- Enable or disable a server with `Space`
|
||
- Expand a server to view the tools it provides
|
||
- Refresh the list with `r` after you edit `config.toml`
|
||
- Authenticate an OAuth server with `i`
|
||
- Add a server with `a`, or remove one with `x`
|
||
|
||
### Tool Discovery
|
||
|
||
The model has access to two built-in tools for working with MCP servers:
|
||
|
||
- `search_tool` — Discover available integration tools across all enabled MCP servers. Use this to find tools by name or description.
|
||
- `use_tool` — Call an integration tool discovered via `search_tool`. Specify the fully-qualified tool name (e.g., `github__create_issue`).
|
||
|
||
---
|
||
|
||
## Compatibility
|
||
|
||
Kigi loads MCP server configurations from multiple sources for compatibility:
|
||
|
||
| Source | Format | Location | Configurable |
|
||
|--------|--------|----------|-------------|
|
||
| `config.toml` | Native Kigi config | `~/.kigi/config.toml`, `.kigi/config.toml` | Always on |
|
||
| `.claude.json` | Claude Code format | `~/.claude.json` | `[compat.claude] mcps` |
|
||
| `.cursor/mcp.json` | Cursor format | `~/.cursor/mcp.json`, `<project>/.cursor/mcp.json` | `[compat.cursor] mcps` |
|
||
| `.mcp.json` | MCP standard format | Project root (cwd to git root) | Loaded unless you have imported or dismissed the Claude import prompt (the import marker is set) |
|
||
|
||
All sources are merged in priority order: config.toml > Claude > Cursor > `.mcp.json`. Servers from higher-priority sources take precedence when names conflict.
|
||
|
||
The Claude and Cursor MCP sources are scanned by default. To disable scanning for a specific vendor, set `[compat.<vendor>] mcps = false` in `~/.kigi/config.toml` or the corresponding environment variable (`KIGI_CURSOR_MCPS_ENABLED`, `KIGI_CLAUDE_MCPS_ENABLED`). See [Configuration](05-configuration.md#harness-compatibility) for details. Use `kigi inspect` to see which MCP servers were loaded and their vendor origin (`[cursor]`, `[claude]`).
|
||
|
||
---
|
||
|
||
## MCP OAuth
|
||
|
||
For MCP servers that require OAuth authentication, Kigi handles the credential flow automatically. When an MCP server requests OAuth credentials, Kigi opens a browser-based authorization flow and stores the resulting tokens for future use.
|
||
|
||
---
|
||
|
||
## Example Configurations
|
||
|
||
Use the `url` form for hosted MCP servers and the `command` / `args` form for local stdio tools.
|
||
|
||
### Native HTTP (hosted services)
|
||
|
||
You must authenticate OAuth-based MCP servers before you can use them. Kigi stores the resulting tokens under `~/.kigi/mcp_credentials.json`. After you edit `config.toml`, press `r` in the `/mcps` modal to refresh the server list.
|
||
|
||
```toml
|
||
[mcp_servers.linear]
|
||
url = "https://mcp.linear.app/mcp"
|
||
enabled = true
|
||
|
||
[mcp_servers.sentry]
|
||
url = "https://mcp.sentry.dev/mcp"
|
||
enabled = true
|
||
|
||
[mcp_servers.mixpanel]
|
||
url = "https://mcp.mixpanel.com/mcp"
|
||
enabled = true
|
||
```
|
||
|
||
For internal or self-hosted servers that authenticate with a static bearer token rather than OAuth, set the `Authorization` header explicitly:
|
||
|
||
```toml
|
||
[mcp_servers.internal-tools]
|
||
url = "https://mcp.internal.example.com/mcp"
|
||
enabled = true
|
||
|
||
[mcp_servers.internal-tools.headers]
|
||
Authorization = "Bearer <token>"
|
||
```
|
||
|
||
To avoid putting secrets in the config file, reference an environment variable with `${VAR}` (or `${VAR:-default}`). Kigi expands string fields in `[mcp_servers.*]` — `url`, `command`, `args`, and the values in `env` and `headers` — at load time:
|
||
|
||
```toml
|
||
[mcp_servers.internal-tools]
|
||
url = "https://mcp.internal.example.com/mcp"
|
||
enabled = true
|
||
headers = { "Authorization" = "Bearer ${INTERNAL_MCP_TOKEN}" }
|
||
```
|
||
|
||
### Local stdio
|
||
|
||
Use stdio for tools that must run locally (filesystem access, local databases, in-house servers).
|
||
|
||
```toml
|
||
# Filesystem access scoped to a directory
|
||
[mcp_servers.filesystem]
|
||
command = "npx"
|
||
args = ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/directory"]
|
||
|
||
# Local Postgres
|
||
[mcp_servers.postgres]
|
||
command = "npx"
|
||
args = ["-y", "@modelcontextprotocol/server-postgres", "postgresql://user:pass@localhost/db"]
|
||
|
||
# Custom server with a longer startup timeout and tuned per-tool timeouts
|
||
[mcp_servers.my-tools]
|
||
command = "/usr/local/bin/my-mcp-server"
|
||
args = ["--config", "/etc/my-mcp.json"]
|
||
startup_timeout_sec = 30
|
||
tool_timeout_sec = 120
|
||
tool_timeouts = { slow_analysis = 300, quick_lookup = 10 }
|
||
```
|
||
|
||
On Windows, npm installs launchers like `npx`, `npm`, `pnpm`, and `yarn` as `.cmd` batch shims (there is no `npx.exe`). Kigi resolves a bare `command` such as `npx` to its real launcher path on `PATH` (honoring `PATHEXT`) before spawning, so these work without manually wrapping them in `cmd /c`. A `command` given as an absolute path or one containing a path separator is used as-is.
|
||
|
||
---
|
||
|
||
## Available MCP Servers
|
||
|
||
A partial list of MCP servers you can configure with the `url` or `command` forms shown above. Confirm the current endpoint or package name with each provider before use:
|
||
|
||
| Server | Transport | Endpoint / Package |
|
||
|--------|-----------|--------------------|
|
||
| Linear | HTTP (OAuth) | `https://mcp.linear.app/mcp` |
|
||
| Sentry | HTTP (OAuth) | `https://mcp.sentry.dev/mcp` |
|
||
| Mixpanel | HTTP (OAuth) | `https://mcp.mixpanel.com/mcp` |
|
||
| Filesystem | stdio | `@modelcontextprotocol/server-filesystem` |
|
||
| Git | stdio | `@modelcontextprotocol/server-git` |
|
||
| GitHub | stdio | `@modelcontextprotocol/server-github` |
|
||
| GitLab | stdio | `@modelcontextprotocol/server-gitlab` |
|
||
| PostgreSQL | stdio | `@modelcontextprotocol/server-postgres` |
|
||
| SQLite | stdio | `@modelcontextprotocol/server-sqlite` |
|
||
| Puppeteer | stdio | `@modelcontextprotocol/server-puppeteer` |
|
||
|
||
See the [MCP Server Registry](https://github.com/modelcontextprotocol/servers) for the full list of community servers and the [MCP specification](https://modelcontextprotocol.io) for protocol details.
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
### Server Not Starting
|
||
|
||
```bash
|
||
# Test the server command manually
|
||
npx -y @modelcontextprotocol/server-filesystem /path
|
||
|
||
# Increase startup timeout
|
||
# In config.toml:
|
||
[mcp_servers.filesystem]
|
||
startup_timeout_sec = 30
|
||
```
|
||
|
||
For stdio servers, Kigi captures the process's standard error to `~/.kigi/logs/mcp/<server>.stderr.log`, truncated on each launch. Check this file when a server starts but fails to handshake:
|
||
|
||
```bash
|
||
tail -f ~/.kigi/logs/mcp/filesystem.stderr.log
|
||
```
|
||
|
||
### Viewing Server Status
|
||
|
||
Use `kigi inspect` to see all loaded MCP servers and their sources:
|
||
|
||
```bash
|
||
kigi inspect # Human-readable
|
||
kigi inspect --json # Machine-readable
|
||
```
|
||
|
||
### Debug Logging
|
||
|
||
```bash
|
||
RUST_LOG=debug KIGI_LOG_FILE=/tmp/kigi.log kigi
|
||
tail -f /tmp/kigi.log
|
||
```
|
||
|
||
Look for log entries containing `mcp` to trace server startup, tool discovery, and tool call execution.
|