MCP Servers & Tools
Declare MCP servers once and let Soubi generate the tool glue each harness needs.
Declare MCP servers once and Soubi writes each harness's native configuration. Portable tools keep their execute functions and are exposed through generated server or plugin code.
Declaring MCP servers
Add mcpServers to plugin.config.ts (or default-export a record/array from an mcp.ts file):
import { defineConfig } from "soubi";
export default defineConfig({
id: "diff-river",
mcpServers: {
// stdio server
linear: {
command: "npx",
args: ["-y", "linear-mcp"],
env: { LINEAR_API_KEY: "…" },
},
// remote / http server
github: { transport: "http", url: "https://api.githubcopilot.com/mcp/" },
},
});These are emitted natively per target:
| Harness | Emitted to |
|---|---|
| Claude Code | .mcp.json (mcpServers) |
| Codex CLI | .mcp.json (direct server map) |
| Gemini CLI | gemini-extension.json (mcpServers) |
| OpenCode | opencode.json (mcp, as local/remote) |
| Cursor | plugin-root mcp.json (mcpServers) |
| GitHub Copilot | .vscode/mcp.json (servers) |
| Windsurf | mcp_config.json (mcpServers) |
| Pi | dropped with a warning — no native MCP client |
| Hermes Agent | mcp-config-fragment.yaml for global config |
| Kiro CLI | .kiro/settings/mcp.json (mcpServers) |
| Amp | .amp/settings.json (amp.mcpServers) |
| Factory Droid | plugin-root mcp.json (mcpServers) |
| OMP | dropped with a warning — no native MCP client |
| Devin CLI | plugin-root mcp_config.json (mcpServers) |
| Kimi Code CLI | kimi.plugin.json (mcpServers) |
| Qoder CLI | .mcp.json (mcpServers) |
| Kilo Code CLI | kilo.json (mcp, as local/remote) |
| MastraCode | .mastracode/mcp.json (mcpServers) |
| Grok CLI | plugin-root .mcp.json (mcpServers) |
| Antigravity | plugin-root mcp_config.json (mcpServers) |
| Maki | mcp.toml ([mcp.<name>]) |
| Herdr | dropped with a warning — Herdr is not an MCP client |
Tools become a generated MCP server
Custom tools (tools.ts) carry a real execute function. Because a live function can't be serialized into a config file, Soubi:
- bundles the module and its imports into a self-contained
mcp/tools.mjs, - generates
mcp/tools-server.mjs, a small Node MCP stdio server that imports the bundle and dispatchestools/callto yourexecute, - registers that server in the target's MCP config as
<plugin-id>-tools.
MCP-capable harnesses launch that generated server. Pi, OMP, and Amp register tools through generated TypeScript extensions/plugins; Hermes uses its native Python plugin API, and Maki uses its native Lua plugin API. Herdr explicitly drops model-callable tools because its actions are user-invoked multiplexer controls. Run a tool locally to test:
pnpm soubi tools ./my-plugin --call diff-stats --args '{"base":"main"}'Keep execute portable
The generated server runs directly with the installed Node runtime. Package imports are bundled at build time, but harness-specific globals are not portable; prefer Node APIs and ordinary package dependencies.
Install-time merge
soubi install merges id-keyed MCP config for Claude, OpenCode, Cursor, Qoder, Kilo, MastraCode, Amp, Kiro, and Droid rather than overwriting it, so hand-added servers survive installs and upgrades. Identical entries can be shared by plugins; a differing entry is an actionable install conflict and is never overwritten. Reinstall refuses user-edited generated values, and uninstall preserves pre-existing, shared, and edited keys while reporting a preserved count. Malformed state aborts without rewrite; reinstall legacy installs for the same harnesses before uninstalling. Hermes is the exception: because its MCP configuration is global YAML, Soubi emits an explicit merge fragment and never overwrites ~/.hermes/config.yaml. See the CLI reference.