Skip to main content

Production evidence — 2026-08-19

This page is a secret-free handoff derived from real production requests. JWTs, client secrets, gateway keys, session identifiers, and full Secret objects are not retained. [REDACTED ...] marks removed credential material. JSON-RPC request IDs are documentation labels; response bodies otherwise preserve the observed protocol/status data, with long tool schemas reduced to names.

Evidence provenance​

EventTime (America/Chicago)Result
Cutover annotation2026-08-19 14:14:03 CDTRecorded on AIRS deployment
Transition matrix2026-08-19 14:19:18 CDTPass
Final matrix after restarts2026-08-19 15:02:23 CDTPass
Final matrix after source retirement2026-08-19 15:14:07 CDTPass
Fresh documentation probes2026-08-19 15:57 CDTPass

Original evidence is private, mode 0600, under the operator's local state directory. It contains only selected claims, status codes, tool names, and epochs—no encoded tokens or secrets.

Production deployments during the fresh probe:

WorkloadReadyImmutable image
clippy-chat2/2sha-fe3b2a2... + digest sha256:3b9104b4...
clippy-mcp1/1sha-fe3b2a2... + digest sha256:4b57c11d...
agent-gateway-mcp2/2digest sha256:02750150...

Real token response (sanitized)​

Request:

POST https://auth.dev.cdot.io/realms/truffles/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=clippy-mcp-client&client_secret=[REDACTED CLIENT SECRET]

Observed response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"access_token": "[REDACTED JWT]",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "mcp.invoke"
}

Selected claims observed during the final matrix:

{
"iss": "https://auth.dev.cdot.io/realms/truffles",
"aud": ["clippy", "stack-clippy"],
"azp": "clippy-mcp-client",
"scope": "mcp.invoke",
"portkey_oid": "80f1e8db-1efe-49a7-a45b-b45cade4d861",
"portkey_workspace": "ws-produc-985697"
}

The selected claims are routing/authorization metadata, not the credential itself.

Real initialize request and response​

Request:

POST https://mcp-airs.cdot.io/ws-produc-985697/clippy/mcp
x-portkey-api-key: [REDACTED JWT]
X-Auth-Token: Bearer [REDACTED JWT]
Content-Type: application/json
Accept: application/json, text/event-stream

{"jsonrpc":"2.0","id":"docs-init","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"ai-security-handoff","version":"1.0"}}}

Observed response:

HTTP/1.1 200 OK
Content-Type: text/event-stream

event: message
data: {"jsonrpc":"2.0","id":"docs-init","result":{"protocolVersion":"2025-03-26","capabilities":{"experimental":{},"prompts":{"listChanged":false},"resources":{"subscribe":false,"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"clippy-tools","version":"1.28.1"}}}

Real tools/list request and response​

Request body:

{"jsonrpc":"2.0","id":"docs-tools","method":"tools/list","params":{}}

Observed response was HTTP 200 with full MCP schemas. Reduced only to exact tool names:

{
"jsonrpc": "2.0",
"id": "docs-tools",
"result": {
"tools": [
"get_current_datetime",
"get_weather",
"get_daily_news",
"web_search",
"get_mlb_scores",
"polymarket_bets",
"scm_config"
]
}
}

Real safe tool request and response​

Request body:

{"jsonrpc":"2.0","id":"docs-call","method":"tools/call","params":{"name":"get_current_datetime","arguments":{}}}

Observed response:

HTTP/1.1 200 OK
Content-Type: text/event-stream

event: message
data: {"jsonrpc":"2.0","id":"docs-call","result":{"content":[{"type":"text","text":"{\n \"date\": \"2026-08-19\",\n \"time\": \"15:57\",\n \"weekday\": \"Wednesday\",\n \"timezone\": \"America/Chicago\",\n \"utc_offset\": \"-0500\"\n}"}],"isError":false}}

Real denial responses​

Missing both headers:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{"error":"unauthorized","error_description":"Authentication required to access this resource"}

Valid Clippy credentials sent to the wrong workspace route:

POST https://mcp-airs.cdot.io/wrong-workspace/clippy/mcp
x-portkey-api-key: [REDACTED JWT]
X-Auth-Token: Bearer [REDACTED JWT]

HTTP/1.1 403 Forbidden
{"error":"forbidden","error_description":"You do not have access to this resource"}

Final authorization matrix​

All values below are from the final post-retirement evidence.

ProbeHTTPInterpretation
inference200Inference client retained access
agent_gateway200Agent Gateway initialize/list succeeded
clippy200Clippy initialize/list succeeded
isolated_agent_to_clippy401Fresh Agent token rejected by Clippy
isolated_clippy_to_agent401Fresh Clippy token rejected by Agent Gateway
distinct_agent_gateway200Separate gateway and identity credentials accepted
distinct_clippy200Separate gateway and identity credentials accepted
missing_agent401No credentials rejected
missing_clippy401No credentials rejected
missing_gateway_agent401Gateway layer required
missing_gateway_clippy401Gateway layer required
missing_identity_agent401Per-server identity required
missing_identity_clippy401Per-server identity required
wrong_gateway_agent401Malformed gateway credential rejected
malformed_token401Malformed identity rejected
wrong_audience401Wrong signed audience rejected
wrong_scope401Token lacking mcp.invoke rejected
wrong_workspace403Workspace isolation enforced
clippy_safe_call200Real get_current_datetime execution succeeded
inference_to_agent401Inference identity cannot invoke Agent MCP
inference_to_clippy401Inference identity cannot invoke Clippy MCP
agent_to_clippy500Cached gateway validation; upstream Clippy still rejected
clippy_to_agent500Cached gateway validation; upstream Agent still rejected
agent_to_inference403Agent identity cannot invoke inference
clippy_to_inference403Clippy identity cannot invoke inference
post_restart_agent200Agent Gateway ready after restart
post_restart_clippy200Clippy ready after restart

Why two cross-server probes show 500​

AIRS 2.15 can reuse a token-global validation-cache result after the same token was accepted on its correct registration. In the cached cross-server probes, AIRS forwarded the wrong identity; the destination MCP server independently returned 401; AIRS exposed that upstream denial as 500. This is fail-closed, not authorization success. Fresh isolated tokens returned direct 401, proving registration isolation without the cache interaction.

Reviewers should accept 500 only for this specifically identified cached cross-server case, and only while server logs/evidence prove upstream 401. All other authorization negatives must return 401 or 403.

Exact post-restart tool parity​

Agent Gateway:

agent_list, delivery_ack, delivery_nak, inbox_pull, message_search, message_send,
session_heartbeat, task_publish, task_update, thread_get, topic_subscribe, topic_unsubscribe

Clippy:

get_current_datetime, get_daily_news, get_mlb_scores, get_weather, polymarket_bets,
scm_config, web_search

Both arrays matched their pre-restart baselines exactly.

Client retirement proof​

The following source clients were disabled in agent-mesh only after destination credentials, config, protocol mappers, client roles/scopes, and all six required realm-management direct and scope roles matched in truffles, then the old 900-second token lifetime expired:

ag-0090212860eec4eabff8cf9f0ab19852
ag-560d2489a782793f222c1024973143db
ag-c7f40b285da4d06578d6935f4311fe7e
ag-f378d91646c512c141f341c4d20e24a8
agent-gateway-provisioner
airs-gw-m2m
dubs-god-airs-gw
openclaw-airs-gw

The post-retirement final matrix then repeated with the same pass result.

Secret placement​

These results prove request authorization, not secret-store ownership. Placement was settled separately on 2026-08-22: Clippy Chat and AI Security Academy are separate stacks, so Clippy's application, Postgres, and MCP secrets moved to the dedicated Clippy Chat vault, and the clippy-mcp-client Secret continues to reconcile from the realm-scoped Truffles vault.

Forgejo issue #22, which tracked moving that credential into AI Security Academy - Runtime, was closed as invalid — it required exactly the coupling this boundary forbids. The evidence above predates that change and is unaffected by it: no issuer, audience, client, scope, or workspace value moved.