Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Built-in MCP (Model Context Protocol) client that connects to external MCP servers, discovers their tools, and registers them as native Kheish tools. Supports stdio and HTTP transports with automatic reconnection, security filtering, and zero-config tool injection.
.claude/skills/graniet-native-mcp/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 145% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 201% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 151% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 55% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 161% | 0% |
This skill is repo-local and stays inactive until explicitly activated.
When the original instructions refer to legacy tool names, use these Kheish mappings:
terminal => bashweb_extract => web_fetch, plus web_search when discovery is neededsearch_files => grep_search and glob_searchbrowser_* tools require a browser-capable surfaced tool or MCP; if none is available, use the closest available surface and say so explicitlyWhen the instructions mention local helper files, resolve them from ${KHEISH_SKILL_DIR}.
Kheish has a built-in MCP client in the daemon. It connects to MCP servers at daemon startup, discovers their tools, and surfaces them as first-class runtime tools when the current session is allowed to see them.
Use this whenever you want to:
For ad-hoc, one-off MCP tool calls from the terminal without configuring anything, see the mcporter skill instead.
pip install mcp. If not installed, MCP support is silently disabled.npx-based MCP servers (most community servers)uvx-based MCP servers (Python-based servers)Install the MCP SDK:
bashpip install mcp # or, if using uv: uv pip install mcp
Create an MCP config file for the daemon:
toml[mcp_servers.time] command = "uvx" args = ["mcp-server-time"]
Start the daemon with that config:
bashkheish-daemon serve --mcp-config ./mcp-config.toml
On startup the daemon will:
mcp__time__*Verify the result with:
bashkheish-daemon runtime get
Each entry under mcp_servers is a server name mapped to its config. There are two transport types: stdio (command-based) and HTTP (url-based).
yamlmcp_servers: server_name: command: "npx" # (required) executable to run args: ["-y", "pkg-name"] # (optional) command arguments, default: [] env: # (optional) environment variables for the subprocess SOME_API_KEY: "value" timeout: 120 # (optional) per-tool-call timeout in seconds, default: 120 connect_timeout: 60 # (optional) initial connection timeout in seconds, default: 60
yamlmcp_servers: server_name: url: "https://my-server.example.com/mcp" # (required) server URL headers: # (optional) HTTP headers Authorization: "Bearer <api_token>" timeout: 180 # (optional) per-tool-call timeout in seconds, default: 120 connect_timeout: 60 # (optional) initial connection timeout in seconds, default: 60
| Option | Type | Default | Description | |-------------------|--------|---------|---------------------------------------------------| | command | string | -- | Executable to run (stdio transport, required) | | args | list | [] | Arguments passed to the command | | env | dict | {} | Extra environment variables for the subprocess | | url | string | -- | Server URL (HTTP transport, required) | | headers | dict | {} | HTTP headers sent with every request | | timeout | int | 120 | Per-tool-call timeout in seconds | | connect_timeout | int | 60 | Timeout for initial connection and discovery |
Note: A server config must have either command (stdio) or url (HTTP), not both.
When Kheish starts, discover_mcp_tools() is called during tool initialization:
mcp_servers from ~/.kheish/config.yamllist_tools() to discover available toolsMCP tools are registered with the naming pattern:
mcp_{server_name}_{tool_name}Hyphens and dots in names are replaced with underscores for LLM API compatibility.
Examples:
filesystem, tool read_file → mcp_filesystem_read_filegithub, tool list-issues → mcp_github_list_issuesmy-api, tool fetch.data → mcp_my_api_fetch_dataAfter discovery, MCP tools are made available to Kheish runtime profiles, but the effective session/persona capability scope can still filter individual servers or tools. Do not assume every conversation sees the full MCP surface.
discover_mcp_tools() is idempotent -- calling it multiple times only connects to servers that aren't already connected. Failed servers are retried on subsequent calls.
The most common transport. Kheish launches the MCP server as a subprocess and communicates over stdin/stdout.
yamlmcp_servers: filesystem: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
The subprocess inherits a filtered environment (see Security section below) plus any variables you specify in env.
For remote or shared MCP servers. Requires the mcp package to include HTTP client support (mcp.client.streamable_http).
yamlmcp_servers: remote_api: url: "https://mcp.example.com/mcp" headers: Authorization: "Bearer <api_token>"
If HTTP support is not available in your installed mcp version, the server will fail with an ImportError and other servers will continue normally.
For stdio servers, Kheish does NOT pass your full shell environment to MCP subprocesses. Only safe baseline variables are inherited:
PATH, HOME, USER, LANG, LC_ALL, TERM, SHELL, TMPDIRXDG_* variablesAll other environment variables (API keys, tokens, secrets) are excluded unless you explicitly add them via the env config key. This prevents accidental credential leakage to untrusted MCP servers.
yamlmcp_servers: github: command: "npx" args: ["-y", "@modelcontextprotocol/server-github"] env: # Only this token is passed to the subprocess GITHUB_PERSONAL_ACCESS_TOKEN: "<github_personal_access_token>"
If an MCP tool call fails, any credential-like patterns in the error message are automatically redacted before being shown to the LLM. This covers:
sk-...)token=, key=, API_KEY=, password=, secret= patternsThe mcp Python package is not installed. Install it:
bashpip install mcp
No mcp_servers key in ~/.kheish/config.yaml, or it's empty. Add at least one server.
Common causes:
command binary isn't on PATH. Ensure npx, uvx, or the relevant command is installed.-y in args to auto-install.connect_timeout.Your mcp package version doesn't include HTTP client support. Upgrade:
bashpip install --upgrade mcp
mcp_servers (not mcp or servers)mcp_{server}_{tool} -- look for that patternThe client retries up to 5 times with exponential backoff (1s, 2s, 4s, 8s, 16s, capped at 60s). If the server is fundamentally unreachable, it gives up after 5 attempts. Check the server process and network connectivity.
yamlmcp_servers: time: command: "uvx" args: ["mcp-server-time"]
Registers tools like mcp_time_get_current_time.
yamlmcp_servers: filesystem: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/documents"] timeout: 30
Registers tools like mcp_filesystem_read_file, mcp_filesystem_write_file, mcp_filesystem_list_directory.
yamlmcp_servers: github: command: "npx" args: ["-y", "@modelcontextprotocol/server-github"] env: GITHUB_PERSONAL_ACCESS_TOKEN: "<github_personal_access_token>" timeout: 60
Registers tools like mcp_github_list_issues, mcp_github_create_pull_request, etc.
yamlmcp_servers: company_api: url: "https://mcp.mycompany.com/v1/mcp" headers: Authorization: "Bearer <api_token>" X-Team-Id: "engineering" timeout: 180 connect_timeout: 30
yamlmcp_servers: time: command: "uvx" args: ["mcp-server-time"] filesystem: command: "npx" args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] github: command: "npx" args: ["-y", "@modelcontextprotocol/server-github"] env: GITHUB_PERSONAL_ACCESS_TOKEN: "<github_personal_access_token>" company_api: url: "https://mcp.internal.company.com/mcp" headers: Authorization: "Bearer <api_token>" timeout: 300
All tools from all servers are registered and available simultaneously. Each server's tools are prefixed with its name to avoid collisions.
Kheish supports MCP's sampling/createMessage capability — MCP servers can request LLM completions through the agent during tool execution. This enables agent-in-the-loop workflows (data analysis, content generation, decision-making).
Sampling is enabled by default. Configure per server:
yamlmcp_servers: my_server: command: "npx" args: ["-y", "my-mcp-server"] sampling: enabled: true # default: true model: "gemini-3-flash" # model override (optional) max_tokens_cap: 4096 # max tokens per request timeout: 30 # LLM call timeout (seconds) max_rpm: 10 # max requests per minute allowed_models: [] # model whitelist (empty = all) max_tool_rounds: 5 # tool loop limit (0 = disable) log_level: "info" # audit verbosity
Servers can also include tools in sampling requests for multi-turn tool-augmented workflows. The max_tool_rounds config prevents infinite tool loops. Per-server audit metrics (requests, errors, tokens, tool use count) are tracked via get_mcp_status().
Disable sampling for untrusted servers with sampling: { enabled: false }.
{"result": "..."} or {"error": "..."}mcporter -- you can use both simultaneously| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 9,417 | 12,045 | +28% | 1 | 1 | 0% | 1,777 | 4,358 | +145% | 0 | 0 | — |
case-02 | fail→pass | 7,408 | 4,415 | -40% | 1 | 1 | 0% | 1,415 | 4,263 | +201% | 0 | 0 | — |
case-03 | fail→pass | 10,149 | 5,868 | -42% | 1 | 1 | 0% | 1,826 | 4,577 | +151% | 0 | 0 | — |
case-04 | fail→pass | 14,151 | 2,235 | -84% | 1 | 1 | 0% | 2,425 | 3,749 | +55% | 0 | 0 | — |
case-05 | fail→pass | 8,724 | 2,409 | -72% | 1 | 1 | 0% | 1,474 | 3,854 | +161% | 0 | 0 | — |
case-10 | pass→pass | 15,030 | 2,232 | -85% | 1 | 1 | 0% | 1,314 | 3,712 | +182% | 0 | 0 | — |
case-06 | pass→pass | 12,393 | 3,817 | -69% | 1 | 1 | 0% | 2,140 | 4,004 | +87% | 0 | 0 | — |
case-07 | fail→pass | 13,798 | 3,648 | -74% | 1 | 1 | 0% | 2,166 | 3,955 | +83% | 0 | 0 | — |
case-08 | fail→pass | 12,650 | 1,464 | -88% | 1 | 1 | 0% | 2,306 | 3,589 | +56% | 0 | 0 | — |
case-09 | fail→pass | 8,309 | 1,638 | -80% | 1 | 1 | 0% | 1,497 | 3,563 | +138% | 0 | 0 | — |
case-11 | pass→pass | 7,541 | 2,731 | -64% | 1 | 1 | 0% | 1,173 | 3,764 | +221% | 0 | 0 | — |
case-12 | fail→pass | 10,312 | 3,083 | -70% | 1 | 1 | 0% | 1,901 | 3,803 | +100% | 0 | 0 | — |
case-13 | fail→pass | 12,183 | 2,423 | -80% | 1 | 1 | 0% | 2,165 | 3,772 | +74% | 0 | 0 | — |
case-14 | pass→pass | 11,736 | 1,761 | -85% | 1 | 1 | 0% | 1,936 | 3,634 | +88% | 0 | 0 | — |
case-15 | fail→pass | 12,583 | 1,493 | -88% | 1 | 1 | 0% | 2,145 | 3,590 | +67% | 0 | 0 | — |
case-16 | pass→pass | 13,458 | 3,089 | -77% | 1 | 1 | 0% | 2,476 | 3,913 | +58% | 0 | 0 | — |
case-17 | pass→pass | 3,813 | 2,264 | -41% | 1 | 1 | 0% | 803 | 3,858 | +380% | 0 | 0 | — |
case-18 | fail→pass | 10,862 | 2,554 | -76% | 1 | 1 | 0% | 1,722 | 3,838 | +123% | 0 | 0 | — |
case-19 | pass→pass | 6,695 | 1,645 | -75% | 1 | 1 | 0% | 1,230 | 3,551 | +189% | 0 | 0 | — |
case-20 | fail→pass | 14,784 | 1,033 | -93% | 1 | 1 | 0% | 2,748 | 3,471 | +26% | 0 | 0 | — |
case-21 | fail→fail | 11,969 | 2,938 | -75% | 1 | 1 | 0% | 2,125 | 3,858 | +82% | 0 | 0 | — |
case-22 | fail→fail | 7,191 | 3,452 | -52% | 1 | 1 | 0% | 1,431 | 3,950 | +176% | 0 | 0 | — |
case-23 | fail→pass | 12,411 | 5,144 | -59% | 1 | 1 | 0% | 1,997 | 4,272 | +114% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +61 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.