The io.github.icohangar-ops/governed-mcp-gateway is an HTTP MCP control plane with a default port 7474. It acts as an MCP gateway that applies governance around traffic, making principals apply to both tools/call requests and SSE frames, rather than exposing a tool catalog.
๐ ๏ธ Key Features
HTTP MCP control plane (default port 7474)
Principal enforced on every tools/call
Principal enforced on every SSE frame
Uses allowlists
Supports vault rotate
Includes CHP gates
๐ Use Cases
Gate and govern MCP tool calls and streamed updates over HTTP
Use cases involving production authentication where workloads move across threads/workers
Environments needing allowlist-based access control
โก Developer Benefits
Centralized governance for tools/call and SSE traffic
Operational control via CHP gates
Credential/secret lifecycle support via vault rotate
โ ๏ธ Limitations
Described as a control plane, explicitly not a tool catalog.
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.
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
bash
npm install
npm test
npm run gateway # :7474
npm run spend # :7475
npm run cfo # :7476
Demo Bearer keys (also in .env.example):
Role
Key
Gateway agent
mcp_agt_payops_demo
Gateway human
mcp_human_controller_demo
Gateway research (no stripe.charge)
mcp_agt_research_demo
Spend agent
spend_agt_payops_demo
Spend human
spend_human_controller_demo
CFO agent
cfo_agt_lease_demo
CFO human
cfo_human_controller_demo
Regenerate the README cards from live local APIs:
bash
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. Named vault inputs rotate in place โ github_token stays github_token.
Local SSE notification with _meta.cubiczan.principal (not the Vercel path)
GET
/v1/context/tax
Schema token-tax estate + session report
POST
/v1/context/need
Admit allowlisted tools into the session pack
POST
/v1/credentials/:name/rotate
Human-only vault rotate; old hash dies
POST
/v1/credentials/verify
Check a secret against the current hash
Glama remote connector
Glama can health-check a stateless Streamable HTTP remote at https://$VERCEL_URL/mcp with Bearer auth. This is the hosted HTTPS path. Stdio (npm run mcp / Dockerfile CMD) remains the Glama Docker build path.
Vercel project settings (import this GitHub repo; do not invent a hostname):
Setting
Value
Root Directory
. (repository root โ vercel.json + api/)
Framework Preset
Other (vercel.json sets "framework": null)
Fluid Compute
On ("fluid": true)
Node.js
20 or later
Install Command
npm ci && npm run build (vercel.json already sets this)
Build Command
npm run build (esbuild โ dist/web.mjs; do not run tsc)
Output Directory
public (empty static dir for the Other preset; Fluid still serves /api)
npm run build runs scripts/build-vercel.mjs (esbuild). That emits dist/web.mjs. api/index.mjs imports that compiled file โ it does not load TypeScript via runtime tsx. Demo allowlist and oversized-schema seed are inlined in that bundle so Fluid does not open test/fixtures/ (the function only includes dist/**). The Other preset still expects a static output folder after a custom buildCommand; public/ is that folder (outputDirectory: "public"). If the Vercel dashboard still has a Build Command of tsc, clear it or set it to npm run build so TS5097 does not come back. Dashboard overrides are not required if vercel.json is honored.
Environment variables (Vercel Project โ Settings โ Environment Variables). Rotate the demo values before a public URL:
Name
Local demo
Role
GATEWAY_AGENT_KEY
mcp_agt_payops_demo
Glama connector Bearer (PayOps allowlist)
GATEWAY_HUMAN_KEY
mcp_human_controller_demo
Vault / locks
GATEWAY_RESEARCH_KEY
mcp_agt_research_demo
Research allowlist (no stripe.charge)
SPEND_PLANE_URL
unset
Optional hook to :7475
Glama connector fields after deploy (replace $VERCEL_URL with the deployment host Vercel prints):
initialize does not mint Mcp-Session-Id. Pass params.pack / params.need on the same tools/list when you need more than the session pack. GET /mcp is 405 (no sticky SSE on the remote).
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.
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
bash
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