01 / Cross-org integration reliability
Your integration didn’t break. It started being wrong.
Every call succeeded. That’s why nothing caught it.
Flanj watches the calls your agents and services already make — agents most of all, since an agent reads a tool’s description to decide what to do. It catches the moment the other side’s contract moves, and carries evidence that organization can check against its own systems.
Out-of-band by design. The SDKs are Apache License 2.0; the collector is Elastic License 2.0. They run in your environment; no request or response body leaves it.
- Schema drift
- Tool description changed
- Agent picks another tool
- Missing webhooks
- Tool renamed or removed
- Perf. degradation
- Tool output drift
- Outages
- Scheduled downtime
- Tech support
02 / How it works
See what changed. Give both organizations the same context.
A / See what changed
The tool description changed. Your schema didn’t. Your agent started choosing differently and nothing anywhere logged an error.
This half works on its own, on day one, with nobody else’s permission.
One line to install, no source change. The SDK captures the request and response bodies of the calls your service makes and receives, and redacts sensitive fields inside your own process — before anything is written, stored or exported. The collector re-applies redaction, validates live traffic against the contract, and keeps a rolling window of redacted calls behind a UI on localhost.
Flow: an OpenAPI spec, published separately, becomes the baseline only if one exists and is current; live calls are compared against that baseline to produce a finding.
Flow: the tools/list response, answered by the server itself, is the baseline from the first call; live calls are compared against it to produce a finding.
REST drift detection needs a spec somebody published and kept accurate. MCP servers publish their contract on every single call — tools/list is the spec. So the collector has the baseline from the first call your agent makes, for every MCP server it touches, with nothing to configure.
Every tab below works. It is the collector’s own UI with sample data and fictional counterparties — nothing here leaves your environment; the thread is the only thing that crosses the boundary.
- REST Globex · api.globex.example — 1 contract drift finding on GET /v1/orders/{id} — 14 calls since 2026-09-20 16:42:08.
acme-prodThese calls were captured but not checked against any contract — the status above does not cover them.
REST providers 1
- api.hooli.exampleNo contract uploaded. 9 calls not checked.
MCP tool calls 1
MCP tool calls can't be validated when the tool declares no output schema. A tool call is checked against the output schema its server lists in tools/list, and these tools list none.
- MCPInitech MCPmcp.initech.examplesearch_orders declares no output schema. 86 calls not checked. Nothing on this server has been checked.
Not listed: single calls that were skipped for their own reason, such as a tool result marked as an error, or a call made before the server’s tools/list arrived. The Traffic row of each one says why.
Edges discovered from traffic — external only
| Counterparty | Status | Calls | First seen | Last seen |
|---|---|---|---|---|
| Globexapi.globex.example | 1204 | 2026-08-02 | 2026-09-21 · 2m ago | |
| Initech MCPMCPNewmcp.initech.example | self-reported· tools/list | 86 | 2026-09-17 | 2026-09-21 · 6m ago |
| Umbrellaapi.umbrella.example | checked | 57 | 2026-08-11 | 2026-09-21 · 3m ago |
| api.hooli.exampleNew | not checked | 9 | 2026-09-19 | 2026-09-21 · just now |
| Counterparty | Status | Calls | First seen | Last seen |
|---|---|---|---|---|
| Hoolihooks.hooli.example | checked | 312 | 2026-08-20 | 2026-09-21 · 1m ago |
Traffic recent captured calls — redacted at source
| Captured | Call | Counterparty | Status | Correlation | Contract |
|---|---|---|---|---|---|
| 09:41:07 | get /v1/orders/{id} | api.globex.example | 200 | req_8f2c… | drifted |
| 09:41:02 | tool search_orders | mcp.initech.example | ok | jr-1193 | not checked |
| 09:40:58 | post /v1/orders | api.globex.example | 201 | req_8f1a… | conforming |
| 09:40:51 | get /v1/inventory/{sku} | hooks.hooli.example | 200 | req_8f0d… | conforming |
| 09:40:47 | get /v2/shipments/{id} | api.umbrella.example | 200 | req_8ee9… | conforming |
| 09:40:44 | get /v1/customers/{id} | api.globex.example | 503 | req_8ef0… | conforming |
| 09:40:41 | get /v1/status | api.hooli.example | 200 | — | no contract |
| 09:40:39 | get /internal/health | svc-inventory | 200 | — | internal |
Your contract the API you publish — your inbound responses validated against it
MCP servers (1) each server publishes its own contract on tools/list — nothing to upload, nothing to remove
Provider contracts (2) the contracts your providers publish — your outbound calls validated against them
Threads state only — read and reply on the thread itself
Connect to Flanj this collector → app.flanj.io
Nothing leaves this collector until you click Connect. Local capture, detection and this UI work without it.
Appearance
Light by default. Dark is remembered on this browser only.
Agent access
Your agents can ask it too: the collector answers over MCP on localhost, so a coding agent can check what actually changed on a dependency before it writes against it — read-only, and over the same local surface as the UI above.
Capture is out-of-band: it never sits in the path of your response, each body is capped at 16 KiB, and when it cannot keep up it tells you we stopped collecting — never that your integration went down. No request or response body leaves your environment.
Where this stops, said out loud. Node is supported; Python is early, and MCP only. A REST provider needs a spec — paste a URL or upload one — and an MCP server needs none. Flanj does not judge what your agent should have chosen; that call is yours. What it tracks is what the tool promised, and what it promises now. Where nothing has been validated against a contract, the collector says exactly that rather than showing you a green light.
B / Give both organizations the same context
Seeing it is half the job. The change is in somebody else’s code.
This half needs a counterparty — the one part you cannot install.
A detection becomes a flag only when it carries something the other organization can check against their own systems: their request ids, their responses, their spec version. The flag opens a thread both teams read, holding the same evidence and the same history, and the other side reads and replies without installing anything.
Read from the other direction: a flag that lands on you carries your own request ids and your own responses, redacted, and scoped to the call the sender pointed at. You can check it against your own logs without taking anybody’s word for it.
Where there is nobody to flag — a provider that will not answer, or one you have no relationship with — the first half still stands on its own: you know what changed, and when.
03 / Live from drift.flanj.io
The same classifier, run in public, every day.
drift.flanj.io is not a statistic assembled for this page. It is this product’s own contract and diff code — the packages the collector runs against your traffic — pointed at a public set of MCP servers you will recognize, once a day, with every snapshot and every caveat published beside the result. The figures below are read from that page. Nothing here is remembered.
We measure how often contracts move, in the open, on a public set of MCP servers — and publish the caveats next to the number.
04 / Open source
The half that reads your traffic is yours.
Capture, redaction, detection and storage are open and run inside your own environment. That is the half that touches sensitive and regulated traffic, so it is the half you get to read, audit and self-host.
flanj-io/sdk
Supported · HTTP out + in, MCP client
An OpenTelemetry distribution for Node. Captures the request and response bodies of the HTTP calls your service makes and receives, and the tools/list and tools/call traffic of every MCP server your agent talks to. Redacts them in your process, and exports over OTLP.
flanj-io/sdk-py
Early · MCP client only
The Python SDK. Instruments an MCP client session: records the tools/list each MCP server hands your agent and the tools/call traffic that follows, redacts it in your process, and exports over OTLP. It captures MCP client calls, not HTTP.
flanj-io/collector
Required · both SDKs export to it
A single-binary OpenTelemetry Collector distribution. Re-applies redaction, validates live traffic against the provider's contract, keeps a rolling window of redacted calls, and serves a local UI on localhost. Deploy it with the Helm chart, or run the image with Docker.
Preferred · stateless fronts and one store pod
Step 1: Run the collector
Both SDKs export to a collector you run yourself, so it comes first: nothing works without one. The Helm chart is the preferred way to deploy it — one install gives you stateless front collectors and one store pod, where the UI and the rolling window live. The token is a secret you generate, not one Flanj issues: the store serves the contracts you upload to the fronts over an in-cluster port, and will not open that port without it.
From the collector README · Run it on Kubernetes — the README is the full setup, and the source of truth.
Install the charthelm install flanj oci://registry-1.docker.io/flanj/flanj-collector \ --namespace flanj --create-namespace \ --set specToken.value="$(openssl rand -hex 32)"Step 2: Add the SDK
Supported · HTTP out + in, MCP client
No source change — the preload patches
node:httpand instruments every MCP client your app constructs.NODE_OPTIONSis that preload, so your image’s command does not change either. The SDK runs in your workload’s pod, wherelocalhostis not the collector, so the patch names it. The chart answers at a fixed Service name — this line is the same on every cluster that ran the install above.node:http/node:https— and everything built on them (axios,got,node-fetch,superagent) — and, from@flanj/sdk0.4.0, globalfetch/undiciare captured (see What is captured).From the sdk README · Quick start and the sdk README · On Kubernetes — the README is the full setup, and the source of truth.
Installnpm install @flanj/sdkAdd to your containerenv: - name: FLANJ_OTLP_ENDPOINT value: http://flanj-collector.flanj:4318/v1/logs - name: NODE_OPTIONS value: "--require @flanj/sdk/register"Early · MCP client only
Needs
Python 3.10+— on an older interpreter,pip install flanjresolves to a placeholder package with noflanj.register, not this SDK. MCP client calls only — it does not capture HTTP. One line, and nothing else changes: make the import the first line of your program, before anything importsmcp. The SDK runs in your workload’s pod, wherelocalhostis not the collector, so the patch names it. The chart answers at a fixed Service name — this line is the same on every cluster that ran the install above.From the sdk-py README · Quick start and the sdk-py README · On Kubernetes — the README is the full setup, and the source of truth.
Installpip install flanjFirst line of your programimport flanj.register # noqa: F401Add to your containerenv: - name: FLANJ_OTLP_ENDPOINT value: http://flanj-collector.flanj:4318/v1/logsStep 3: Open the local UI
The UI is never a Service: it binds the store pod’s loopback, by design, and nothing the collector serves is reachable off-host. Port-forward to it, make a call, then open
http://localhost:5335— your calls are in Traffic, redacted. If5335is taken on your machine, forward15335:5335instead and openhttp://localhost:15335.From the collector README · Run it on Kubernetes — the README is the full setup, and the source of truth.
Port-forward the UIkubectl -n flanj port-forward sts/flanj-flanj-collector-store 5335:5335Step 4: Connect it to Flanj (optional)
The image and the chart already point at the hosted control plane, and the collector sends nothing until you press Connect. Open the local UI, Settings → Connect, and give it a collector name and a contact email — no token. The confirmation mail adds this collector to your workspace at app.flanj.io. Connect with the same email you sign in with there, or the collector lands in that person’s workspace instead.
From the collector README · Point your app at the collector — the README is the full setup, and the source of truth.
Step 1: Run the collector
Both SDKs export to a collector you run yourself, so it comes first: nothing works without one. The compose file is the collector’s own: it starts the collector and the small bridge that makes its UI reachable, and it pins the release it runs. Read it before you run it — it is short.
From the collector README · Run it with Docker — the README is the full setup, and the source of truth.
Download the compose file and bring it upcurl -fsSLO https://raw.githubusercontent.com/flanj-io/collector/main/docker-compose.yml docker compose up -dStep 2: Add the SDK
Supported · HTTP out + in, MCP client
No source change — the preload patches
node:httpand instruments every MCP client your app constructs. It exports tolocalhost:4318by default, which is the collector above, so there is nothing to point anywhere.node:http/node:https— and everything built on them (axios,got,node-fetch,superagent) — and, from@flanj/sdk0.4.0, globalfetch/undiciare captured (see What is captured).From the sdk README · Quick start — the README is the full setup, and the source of truth.
Installnpm install @flanj/sdkStart your appnode -r @flanj/sdk/register app.jsEarly · MCP client only
Needs
Python 3.10+— on an older interpreter,pip install flanjresolves to a placeholder package with noflanj.register, not this SDK. MCP client calls only — it does not capture HTTP. One line, and nothing else changes: make the import the first line of your program, before anything importsmcp. It exports tolocalhost:4318by default, which is the collector above, so there is nothing to point anywhere.From the sdk-py README · Quick start — the README is the full setup, and the source of truth.
Installpip install flanjFirst line of your programimport flanj.register # noqa: F401Step 3: Open the local UI
Nothing to run: the compose file already started the bridge, and publishes it on
127.0.0.1only — the UI has no credential, so staying on this machine is its access control. Make a call, then openhttp://localhost:5335— your calls are in Traffic, redacted.From the collector README · Run it with Docker — the README is the full setup, and the source of truth.
Step 4: Connect it to Flanj (optional)
The image and the chart already point at the hosted control plane, and the collector sends nothing until you press Connect. Open the local UI, Settings → Connect, and give it a collector name and a contact email — no token. The confirmation mail adds this collector to your workspace at app.flanj.io. Connect with the same email you sign in with there, or the collector lands in that person’s workspace instead.
From the collector README · Point your app at the collector — the README is the full setup, and the source of truth.
05 / Contact
Got a question?
Write it here and it lands in a mailbox we read. We answer by email.
Ask
Or emailhello@flanj.io