Odel
governed mcp gateway

governed mcp gateway

Local
@icohangar-opsTypeScriptMITUpdated Today

HTTP MCP gateway: principal on tools/call + SSE, allowlists, vault rotate, CHP gates.

Cubiczan Agent Platform

Identity, money, and evidence for agents that actually ship.

Three SKUs, one workspace. MCP clients keep a Bearer principal through tools/call and SSE. Spend cannot settle without a mandate and, over cap, a human second key. Board claims cannot seal without an agent, a CHP lock, and a hashed document.

Three SKUs: governed MCP gateway, spend mandate plane, CFO agent mesh

SKUPortRepoJob
Governed MCP Gateway:7474icohangar-ops/governed-mcp-gatewayPrincipal on every tool call and SSE frame. Claim→allowlist ∩ scope. Host-injected _meta (tenant / index / vault). Vaulted credential rotation. Schema token-tax ledger and pack / allow-by-need tools/list. Streamable HTTP multi-replica sessions (STATELESS / sticky / shared store).
Agent Spend & Mandate Plane:7475icohangar-ops/spend-mandate-planePropose → mandate → countersign → settle. Stripe by default; x402 is a rail.
Auditable CFO Agent Mesh:7476icohangar-ops/cfo-agent-meshClaim → agent → lock → document. ASC 842 / 606 / 718 engines. HMAC-chained evidence pack.

Shared primitives (packages/shared): CHP gate, HMAC ledger, HTTP/SSE helpers. Zero runtime npm dependencies. Stripe and x402 are rails — tests never call live networks.

Quickstart

npm install
npm test
npm run gateway   # :7474
npm run spend     # :7475
npm run cfo       # :7476

Demo Bearer keys (also in .env.example):

RoleKey
Gateway agentmcp_agt_payops_demo
Gateway humanmcp_human_controller_demo
Gateway research (no stripe.charge)mcp_agt_research_demo
Spend agentspend_agt_payops_demo
Spend humanspend_human_controller_demo
CFO agentcfo_agt_lease_demo
CFO humancfo_human_controller_demo

Regenerate the README cards from live local APIs:

npm run shots

1. Governed MCP Gateway

Production MCP drops identity. listTools runs on the request thread; tools/call and SSE run somewhere else. This gateway resolves a Bearer credential to a Principal, injects it on every JSON-RPC call, and repeats it on every SSE frame. Host-only tenant, index, and vaulted input names are bound on _meta.cubiczan.host — the model cannot invent them. Named vault inputs rotate in place — github_token stays github_token. Default tools/list is a session pack, not the full allowlist. Language-agnostic recipe: Principal-on-RPC cookbook (Spring, Ballerina, Python FastAPI). Host-injected _meta / pack-by-need: host-injected-meta.

Principal injected on tools/call

SSE repeats principal on every frame

Rotate github_token without a new input id

curl -sS -H "Authorization: Bearer mcp_agt_payops_demo" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"echo.ping","arguments":{"hello":"world"}}}' \
  http://127.0.0.1:7474/mcp
MethodPathWhat
POST/mcpJSON-RPC initialize, tools/list (default: session pack), tools/call
DELETE/mcpEnd a sticky/shared Mcp-Session-Id
GET/mcp/sse?once=1SSE notification with _meta.cubiczan.principal
GET/v1/context/taxSchema token-tax estate + session report
POST/v1/context/needAdmit allowlisted tools into the session pack
POST/v1/credentials/:name/rotateHuman-only vault rotate; old hash dies
POST/v1/credentials/verifyCheck a secret against the current hash

2. Agent Spend & Mandate Plane

Agents propose. Mandates authorize. A human countersigns when the amount is over the auto cap. The proposing agent cannot countersign itself. Settlement is a rail: Stripe meter event by default, x402 payment-required if you ask for it. No chain calls in this MVP.

Under-cap proposal auto-locks

Over-cap requires a human second key

Stripe meter vs x402 payment-required

curl -sS -H "Authorization: Bearer spend_agt_payops_demo" \
  -H "Content-Type: application/json" \
  -d '{"agent":"agt_payops","merchant":{"name":"Stripe","url":"https://stripe.com","country":"US"},"total":"12.00","rationale":"tool meter"}' \
  http://127.0.0.1:7475/v1/proposals
MethodPathWhat
POST/v1/mandatesOperator creates remaining-cents coverage
POST/v1/proposalsAgent propose; lane auto | approval | blocked
POST/v1/countersignHuman second key; agents are rejected
POST/v1/settle{ "rail": "stripe" } or "x402"

3. Auditable CFO Agent Mesh

A board claim is not done until it has an agent, a LOCKED CHP state, and at least one source document hash. Engines measure (ASC 842 lease rollforward, ASC 606 constrained POC, ASC 718 SBC). They do not decide facts of law. Token spend attaches as a source on the same HMAC-chained ledger.

Unsealed claim without documents

Sealed evidence pack

ASC 842 finance lease ends at 0.00

curl -sS -H "Authorization: Bearer cfo_agt_lease_demo" \
  -H "Content-Type: application/json" \
  -d '{"title":"AI spend is $12.00 this period","narrative":"Token ledger supports the board claim.","agentId":"agt_lease"}' \
  http://127.0.0.1:7476/v1/claims
MethodPathWhat
POST/v1/claimsOpen a claim
POST/v1/claims/:id/documentsAttach a named source; SHA-256 stored
POST/v1/claims/:id/lockHuman lock → LOCKED
POST/v1/engines/leaseASC 842 classification + rollforward
GET/v1/evidence/:idSeal; 400 if no documents or not locked

Specs

OpenSpec changes: ship-three-sku-platform, tools-list-token-tax, principal-on-rpc-cookbook, host-injected-meta, streamable-http-multi-replica.

Streamable HTTP on Kubernetes (sticky vs shared store vs fail-closed STATELESS): docs/streamable-http-multi-replica.md.

License

MIT