# cf-integration
`cf-integration` manages ContextForge Docker stacks and runs probes, load tests,
live gateway checks, and official MCP conformance. Routed traffic uses one of
two lanes:
- `builtin`: the Python dataplane in `cf-controlplane`.
- `external`: the Rust `cf-dataplane`.
`/servers/{virtual_host_id}/mcp` routes to the external dataplane. Raw `/mcp`
and control-plane UI/API traffic route to `cf-controlplane`; there is no
fallback between them.
## Install
```bash
cargo binstall cf-integration
# or
cargo install cf-integration --locked
```
Use `cargo run --` before a command when running this checkout. Runtime use
requires Docker Compose v2, Git, and Node.js 22.7.5 or newer. Rust 1.97 is
needed only to compile the CLI or a local dataplane image.
Published images are the default. Set `CF_DATAPLANE_REF` to build and test a
local dataplane ref.
## Selection
Routed commands accept `--lane builtin|external`; `external` is the default.
Conformance and protocol-only live tests also accept `fixture-direct`.
`stack down` accepts `all`. No command accepts the old `--topology` option.
Commands that exercise MCP accept `--protocol-version modern|legacy`:
- `modern`: current per-request, stateless MCP.
- `legacy`: current initialization-based MCP.
The CLI deliberately does not expose dated wire revisions. Defaults may be set
with `CF_MCP_LANE` and `MCP_PROTOCOL_VERSION`.
Add the global `--standalone` flag to run the external lane without any control
plane. Standalone mode starts Redis, the Rust dataplane, nginx, and the required
test fixture. It generates an ephemeral RSA key, obtains a test token from the
dataplane's local tool endpoint, validates it through the dataplane's loopback
JWKS endpoint, and publishes a fresh config through the dataplane serializer.
Redis therefore always contains the schema understood by the image under test.
Standalone commands also work from an installed binary without control-plane
checkouts or generated control-plane secrets.
Routes and tool schemas are discovered from every catalog page of the running
fixture, including the selected protocol era's diagnostic tools and prompts.
Use `cf-integration <command> --help` for the complete interface.
## Stack
Use a persistent stack for manual testing:
```bash
cf-integration stack up --lane builtin --protocol-version modern
cf-integration stack up --lane external --protocol-version legacy --fresh
cf-integration stack up --lane external --protocol-version legacy --standalone
cf-integration stack status --lane external --standalone
cf-integration stack logs --lane external --standalone
cf-integration stack logs --lane external --standalone dataplane nginx
cf-integration stack config --lane external --standalone
cf-integration stack down --lane external --standalone
cf-integration stack down --lane all
cf-integration stack down --lane all --volumes
```
`up --fresh` and `down --volumes` remove the selected stack's volumes.
ClickStack has an independent lifecycle and is intentionally left running by
all stack and managed-test cleanup.
## Probe
Probe authentication, protocol lifecycle, backend identity, catalog selection,
and a safe routed tool call:
```bash
cf-integration probe --lane builtin --protocol-version modern
cf-integration probe --lane external --protocol-version legacy
cf-integration probe --lane external --protocol-version legacy --standalone
```
For standalone external runs, the known catalog comes from the mocked Redis
snapshot because the Rust dataplane intentionally does not implement fan-out
`tools/list`.
## Load
```bash
# Compare both lanes for two minutes
cf-integration load --lane builtin --protocol-version legacy \
--users 10 --spawn-rate 2 --run-time 2m
cf-integration load --lane external --protocol-version legacy \
--users 10 --spawn-rate 2 --run-time 2m
# Isolate the external dataplane and mocked Redis
cf-integration load --lane external --protocol-version legacy --standalone \
--users 10 --spawn-rate 2 --run-time 2m
# Include telemetry when diagnostic value matters more than benchmark purity
cf-integration load --lane external --protocol-version modern --standalone \
--observability --users 10 --spawn-rate 2 --run-time 2m
```
`--smoke` selects a short workload. Durations accept ordered positive `h`, `m`,
and `s` groups such as `2m30s`. Defaults are `100` users, `10` users/s, and
`5m`, overridable with `LOCUST_USERS`, `LOCUST_SPAWN_RATE`, and
`LOCUST_RUN_TIME`. Observability is opt-in for load tests to avoid skew.
## Live gateway checks
Groups are `mcp`, `rbac`, `protocol`, and `all` (default):
```bash
cf-integration live --lane builtin --protocol-version legacy --group all
cf-integration live --lane external --protocol-version modern --group all
cf-integration live --lane fixture-direct --protocol-version legacy --group protocol
```
Routed runs execute the upstream control-plane live suites. `live --standalone`
is unsupported because these suites require the control plane. Use
`cf-integration probe --lane external --standalone` for isolated authentication,
protocol, and routed tool-call checks.
## Conformance
`run` executes the pinned official MCP suite and compares results with checked-in
baselines. With no selectors it runs all three lanes with a modern client
against legacy and modern fixtures.
```bash
cf-integration conformance run
cf-integration conformance run \
--lane fixture-direct --lane builtin --lane external \
--client-era legacy --client-era modern \
--server-era legacy --server-era modern
cf-integration conformance run --lane external --standalone \
--client-era modern --server-era modern
cf-integration conformance run --lane external --standalone \
--client-era modern --server-era modern --bless
```
`--client-era` and `--server-era` accept `legacy`, `modern`, or `dual`.
`--bless` replaces only the selected baselines and only after every selected
run succeeds. `--standalone` permits the external lane only.
Ctrl-C finishes cleanup for the active run, skips the remaining matrix entries,
and leaves baselines unchanged.
Regenerate Markdown from existing results without running tests:
```bash
cf-integration conformance report
cf-integration conformance report \
--results-dir .integration/conformance --output-dir reports/conformance
```
## Debug
```bash
cf-integration debug inspect --lane external \
--protocol-version modern --method tools/list
cf-integration debug inspect --lane builtin \
--protocol-version legacy --server-id <virtual-server-id>
cf-integration debug token --kind scoped
cf-integration debug token --kind scoped --server-id <virtual-server-id>
cf-integration debug token --kind admin
# Issue a token from an already-running standalone external stack
cf-integration debug token --kind scoped --standalone
```
`inspect` uses the official MCP Inspector. Control-plane tokens are revoked when
the workflow owns them; caller-supplied `MCPGATEWAY_BEARER_TOKEN` values are
never revoked.
## Observability and artifacts
ClickStack starts by default for stack, probe, live, conformance, and Inspector
workflows. Open the no-login HyperDX UI at <http://127.0.0.1:3000>. Logs open by
default; for metrics use **Chart Explorer**, choose the **Metrics** source and a
metric such as `http.server.request.duration`, then run the query. Allow at
least 60 seconds of traffic for multiple 30-second cumulative exports.
Telemetry storage is ephemeral inside ClickStack.
Load reports are written below `CF_INTEGRATION_DIR/reports/load`, conformance
results below `CF_INTEGRATION_DIR/conformance`, and comparison Markdown below
`reports/conformance`. Copy [`.env.example`](.env.example) for the complete
configuration list. Process environment values override `.env`.