Claude Code, Cursor, Cline, Continue, Codex, or a custom stdio runtime writes JSON-RPC frames.
Connect any MCP client through Clavenar.
Point native streamable-HTTP clients directly at the proxy's /mcp surface. For clients that only launch stdio MCP servers, run clavenarctl mcp-bridge: it reads newline-delimited JSON-RPC on stdin/stdout, forwards each frame over mTLS, and preserves the client protocol version end to end.
Use an inline Claude Code, Cursor, Cline, Continue, Codex, native HTTP, or generic stdio config.
mcpServers
Configure
Choose local or prod
Local dev uses the dev proxy and generated certs. Production uses enrolled agents and SVIDs.
--url
Run
Start the bridge
Restart the client or drive the bridge manually with initialize and tools/list frames.
tools/list
Verify
Check proof rows
Match the proxy correlation id to the ledger row, then verify the hash chain.
/verify
Six stdio clients, one bridge command.
The client-specific part is the config file shape. The command and arguments stay the same: run clavenarctl mcp-bridge, pass the proxy URL and client certs, then set --client-hint so logs identify the caller.
Use .mcp.json or the global Claude config.
Project-scoped config keeps the Clavenar server tied to one repository. The same shape is emitted by claude mcp add.
{
"mcpServers": {
"clavenar": {
"command": "/usr/local/bin/clavenarctl",
"args": [
"mcp-bridge",
"--url", "https://localhost:19443",
"--cert", "/home/you/clavenar/certs-dev/client.crt",
"--key", "/home/you/clavenar/certs-dev/client.key",
"--ca", "/home/you/clavenar/certs-dev/ca.crt",
"--client-hint", "claude-code"
]
}
}
}
Use the Claude-style JSON shape.
Cursor reads ~/.cursor/mcp.json globally or <workspace>/.cursor/mcp.json per project. Saving the file can trigger tool rediscovery.
{
"mcpServers": {
"clavenar": {
"command": "/usr/local/bin/clavenarctl",
"args": [
"mcp-bridge",
"--url", "https://localhost:19443",
"--cert", "/Users/you/clavenar/certs-dev/client.crt",
"--key", "/Users/you/clavenar/certs-dev/client.key",
"--ca", "/Users/you/clavenar/certs-dev/ca.crt",
"--client-hint", "cursor"
]
}
}
}
Keep disabled false and approvals explicit.
Cline stores MCP config in VS Code extension storage. Leave autoApprove empty unless you intentionally want editor-side pre-approval for safe tools.
{
"mcpServers": {
"clavenar": {
"command": "clavenarctl",
"args": [
"mcp-bridge",
"--url", "https://localhost:19443",
"--cert", "/Users/you/clavenar/certs-dev/client.crt",
"--key", "/Users/you/clavenar/certs-dev/client.key",
"--ca", "/Users/you/clavenar/certs-dev/ca.crt",
"--client-hint", "cline"
],
"disabled": false,
"autoApprove": []
}
}
}
Use an array plus an explicit stdio transport.
Continue's stable config uses mcpServers as an array. Older versions may still call the key experimental.modelContextProtocolServers.
{
"mcpServers": [
{
"name": "clavenar",
"transport": {
"type": "stdio",
"command": "clavenarctl",
"args": [
"mcp-bridge",
"--url", "https://localhost:19443",
"--cert", "/Users/you/clavenar/certs-dev/client.crt",
"--key", "/Users/you/clavenar/certs-dev/client.key",
"--ca", "/Users/you/clavenar/certs-dev/ca.crt",
"--client-hint", "continue"
]
}
}
]
}
Use TOML, not JSON.
Codex reads MCP servers from ~/.codex/config.toml. Each server is its own [mcp_servers.<name>] table.
[mcp_servers.clavenar] command = "clavenarctl" args = [ "mcp-bridge", "--url", "https://localhost:19443", "--cert", "/Users/you/clavenar/certs-dev/client.crt", "--key", "/Users/you/clavenar/certs-dev/client.key", "--ca", "/Users/you/clavenar/certs-dev/ca.crt", "--client-hint", "codex", ]
Drive the bridge as a subprocess.
Any client that writes MCP JSON-RPC over stdin and reads stdout can use the bridge. Notifications do not produce responses.
Full recipe on GitHubclavenarctl mcp-bridge \
--url https://localhost:19443 \
--cert ./certs-dev/client.crt \
--key ./certs-dev/client.key \
--ca ./certs-dev/ca.crt \
--client-hint generic <<'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
EOF
Skip the bridge when the client supports streamable HTTP.
Point the client directly at /mcp over mTLS. With proxy streaming enabled, upstream SSE responses relay chunk by chunk; the stdio bridge buffers that leg.
{
"name": "clavenar",
"transport": {
"type": "streamable-http",
"url": "https://proxy.clavenar.local:8086/mcp",
"tls": {
"cert": "/etc/clavenar/agents/client.crt",
"key": "/etc/clavenar/agents/client.key",
"ca": "/etc/clavenar/ca.crt"
}
}
}
Know where the file lives before debugging the bridge.
Most failures are config-path, reload, or process-environment issues. This matrix keeps those client differences visible beside the shared Clavenar command.
| Client | Config path | Shape | Scope | Reload | Verify |
|---|---|---|---|---|---|
| Claude Code | ~/.claude.json or .mcp.json |
JSON map under mcpServers |
Global or project | Restart session or run claude mcp list |
claude mcp list |
| Cursor | ~/.cursor/mcp.json or .cursor/mcp.json |
JSON map under mcpServers |
Global or workspace | Open Settings → MCP; restart if stale process remains | Green dot in MCP panel |
| Cline | cline_mcp_settings.json in VS Code global storage |
JSON map with disabled and autoApprove |
VS Code profile | Use Cline settings UI or reload VS Code window | Ask Cline to list Clavenar tools |
| Continue.dev | ~/.continue/config.json |
JSON array with transport.type |
User profile | Next chat turn or extension reload | Ask Continue what Clavenar tools it sees |
| Codex CLI | ~/.codex/config.toml |
TOML table [mcp_servers.clavenar] |
User profile | Restart the CLI session | codex --tools |
| Generic stdio | Client-owned subprocess config | Command + args array | Runtime-specific | Restart subprocess | Send initialize then tools/list |
| Native HTTP MCP | Client-owned HTTP MCP server config | Streamable HTTP URL + TLS material | Runtime-specific | Reconnect HTTP MCP server | Client calls tools/list against /mcp |
The shim changes transport, not policy semantics.
Stdio clients still reach the same proxy, policy engine, HIL queue, ledger, and upstream tools as native HTTP clients. The bridge only translates process stdio into mTLS HTTP requests.
mcp-bridge
Reads newline-delimited stdin/stdout, preserves notifications, and attaches the client hint.
/mcp
The proxy authenticates the cert-derived agent id and checks that Vault credentials exist.
Green calls pass, Red calls deny before upstream, and Yellow calls park until an operator decides.
Every decision writes a hash-chained row that can be replayed by correlation id and verified.
Local dev and production use the same client config shape.
Only the proxy URL, certificate source, and credential enrollment path change. Keep the client recipe stable and swap the environment-specific values.
Use generated dev certs against https://localhost:19443.
The stdio bridge expects a Clavenar proxy /mcp endpoint. clavenar-lite is useful for SDK/local policy experiments; MCP clients should use the dev proxy unless a lite build explicitly exposes the same MCP surface.
cd repos/clavenar-proxy
./scripts/gen_certs.sh --env dev
export CLAVENAR_PROXY_URL="https://localhost:19443"
export CLAVENAR_CERT="$PWD/certs-dev/client.crt"
export CLAVENAR_KEY="$PWD/certs-dev/client.key"
export CLAVENAR_CA="$PWD/certs-dev/ca.crt"
curl -H 'X-Vault-Token: root' -X POST \
http://localhost:18200/v1/secret/data/agents/agent-001 \
-d '{"data":{"api_key":"stub-key"}}'
Use enrolled agents, short-lived SVIDs, and production Vault credentials.
Production configs should point at the deployed proxy hostname and use certs issued by clavenar-identity. Keep certificate verification enabled outside a dev certificate rotation.
export CLAVENAR_PROXY_URL="https://proxy.clavenar.local:8086" clavenarctl agents create coding-agent clavenarctl agents svid coding-agent \ --out-cert /etc/clavenar/agents/client.crt \ --out-key /etc/clavenar/agents/client.key vault kv put secret/agents/coding-agent \ api_key="$UPSTREAM_TOOL_TOKEN"
Prove the client path before handing it to an agent.
Run the bridge manually once with the same URL and certs your client will use. If initialize and tools/list work here, remaining failures are almost always client config path, reload, or process PATH issues.
Set shared bridge values.
export CLAVENAR_PROXY_URL="https://localhost:19443" export CLAVENAR_CERT="./certs-dev/client.crt" export CLAVENAR_KEY="./certs-dev/client.key" export CLAVENAR_CA="./certs-dev/ca.crt" export CLAVENAR_AGENT_ID="agent-001"
Send initialize and tools/list.
clavenarctl mcp-bridge \
--url "$CLAVENAR_PROXY_URL" \
--cert "$CLAVENAR_CERT" \
--key "$CLAVENAR_KEY" \
--ca "$CLAVENAR_CA" \
--client-hint generic <<'EOF'
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
EOF
Check the ledger and chain.
curl -s "http://localhost:18083/audit/$CLAVENAR_AGENT_ID" \
| jq '.[0] | {agent_id, method, correlation_id, verdict}'
curl -s http://localhost:18083/verify
The bridge writes one JSON-RPC response for initialize and one for tools/list. The notifications/initialized frame writes no stdout response. The ledger row's agent_id matches the certificate identity and /verify returns {"valid":true}.
Decode failures by layer.
Start with process spawn, then mTLS, then Vault credentials, then upstream tool visibility. The bridge logs to stderr; some clients hide stderr unless debug mode is enabled.
| Symptom | Likely layer | Fix |
|---|---|---|
| Client cannot find or spawn the server | Config path or process PATH | Use the compatibility matrix path, make clavenarctl executable, or switch command to an absolute path. |
| Bridge exits immediately with JSON parse errors | Client-to-bridge stdio | Ensure the client writes one complete JSON-RPC frame per newline. Notifications may omit id; requests need one. |
clavenar proxy 401 or native HTTP TLS failure |
mTLS ingress | Confirm --cert, --key, and --ca point to the pair signed by the proxy CA. Verify locally with openssl verify. |
clavenar proxy 403 or unknown agent_id |
Vault credential gate | Add the Vault entry keyed by the agent id from the cert's SPIFFE URI or CN. The proxy only needs to know credentials exist. |
| Server connects but no tools are visible | Upstream MCP server | Run the manual bridge session and inspect tools/list. If it is empty there too, debug the upstream server behind Clavenar. |
| Yellow-tier call appears stuck | HIL decision path | Open the operator queue, decide the pending request, then replay the correlation id. For stdio clients, expect the response only after the proxy resolves the parked call. |
| Config changed but behavior did not | Client reload | Restart the IDE or CLI session. Cursor may leave old bridge processes running; kill stale clavenarctl mcp-bridge processes before retrying. |