Integrations

stdio shim

Adoption is a one-line change in an existing MCP config: replace the server's command with kams shim -- <original command>.

Wrap a server

jsonc
{
  "mcpServers": {
    "filesystem": {
      "command": "kams",
      "args": [
        "shim", "--server", "filesystem", "--",
        "npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"
      ]
    }
  }
}

Everything after -- is the upstream command, launched as a child process. Kams relays stdin and stdout between the agent and that child, inspecting as it goes.

stdout is the wire

Kams logs exclusively to stderr. stdout carries nothing but MCP protocol bytes, because a single stray line there would corrupt the JSON-RPC stream.

If --server is omitted, the logical name defaults to the basename of the upstream binary. Naming it explicitly is worth doing — the name appears on every span, metric label, finding, and restriction.

What happens on the wire

text
agent stdin  ──▶ Kams ──▶ child stdin
agent stdout ◀── Kams ◀── child stdout
                  │
                  ├─ span per request/response pair
                  ├─ detectors on tools/list and tools/call
                  └─ OTLP to SigNoz

Original JSON bytes are forwarded unmodified unless Kams injects trace context into params._meta or applies a redaction. network.transport is reported as pipe.

Golden tests assert byte identity in observation-only mode across message ordering, Unicode, 200 KB payloads, and error responses.

First run, then pin

bash
# 1. run once so Kams records the definitions
kams shim --server filesystem -- npx -y @modelcontextprotocol/server-filesystem /tmp

# 2. review what it recorded
kams status

# 3. turn the recording into an assertion
kams pin filesystem

Until you pin, the baseline is provisional and drift is reported at reduced severity — Kams remembers what it saw, but nobody vouched for it. See Tool-definition integrity.

Flags

FlagDefaultEffect
--serverupstream binary nameLogical name on all telemetry
--lockkams.lockPinned definition store
--policypolicy.yamlRule file; missing file means permissive
--statekams-state.jsonShared restriction file
--otlp-endpointSigNoz localOTLP gRPC target
--log-levelwarningOr KAMS_LOG_LEVEL
--no-enforceoffObserve only; policy engine not built
--no-reflexoffPermissive policy, still honours SigNoz state
--no-integrityoffDisable the integrity detector
--no-egressoffDisable sensitive-data classification
--no-behaviouraloffDisable thrash / retry-storm / latency checks
--no-forwardoffDo not send findings to kamsd for enrichment
--no-telemetryoffPure relay; emits nothing
--kamsdhttp://127.0.0.1:8787/findingsEnrichment endpoint

`--no-telemetry` is the transparency harness

It reduces Kams to a byte relay with no spans, no detectors, and no policy. The golden wire tests run against it to prove the relay itself is faithful before any inspection is layered on.

Baseline persistence

The lockfile is written when a tools/list response is processed, not only at shutdown. A long-running session would otherwise hold a learned baseline in memory indefinitely and lose it on a crash.

If the file cannot be written, Kams prints to stderr and continues — a read-only working directory degrades integrity detection to in-memory only rather than stopping the agent.

Lifecycle

On shutdown, any request whose response never arrived has its span closed with kams.response.missing=true and an error status. Leaving them open would mean they are never exported and the calls vanish from the trace — the opposite of what an observability tool should do when something goes wrong.

Next: the same pipeline over streamable HTTP.