Web apps publish a manifest of structured, permissioned actions. AI agents discover, validate, and call those actions through MCP — instead of clicking around UIs that were designed for humans.
AgentBridge v0.4.0 is live on npm under the @marmarlabs scope
(published via npm Trusted Publishing with SLSA build provenance).
The v0.4.0 line ships the opt-in Streamable HTTP MCP transport,
adopter quickstart, manifest-pattern catalogue, and OpenAPI
regression fixtures. See
docs/releases/v0.4.0.md for the full
release notes.
v0.5.0 (Signed manifests) is in design — design-first PR
landing now, no runtime change yet. Publishers will be able to
sign their /.well-known/agentbridge.json with a key set served
at /.well-known/agentbridge-keys.json; agents and the MCP
server will verify the manifest offline before trusting any
action. Verification is additive — confirmation gate, origin
pinning, target-origin allowlist, audit redaction, stdio stdout
hygiene, and HTTP transport auth/origin checks all continue to
enforce on top. See
docs/designs/signed-manifests.md
and
docs/adr/0002-signed-manifests.md
for the design and decision record. Tracking issue:
#31.
The v0.4.0 line shipped:
- An opt-in Streamable HTTP MCP transport with static
bearer-token auth, exact-origin allowlist, and loopback-by-
default bind. stdio remains the default for local desktop
clients — nothing about the existing stdio behavior changes.
HTTP is opt-in via
AGENTBRIDGE_TRANSPORT=httpand fails closed on missing token, missing Origin allowlist for public bind, or token-in-query-string. Design: docs/designs/http-mcp-transport-auth.md; ADR: docs/adr/0001-http-mcp-transport.md. - An adopter quickstart (docs/adopter-quickstart.md) and manifest-pattern catalogue (docs/manifest-patterns.md) for existing-app onboarding.
- OpenAPI converter regression fixtures (examples/openapi-regression) pinning stable mapping behavior.
No published v0.x release alone is v1.0 production readiness; each is a step toward it. The HTTP transport is experimental in v0.4.0.
npm install @marmarlabs/agentbridge-sdk @marmarlabs/agentbridge-core
npx @marmarlabs/agentbridge-cli scan http://localhost:3000
npx @marmarlabs/agentbridge-mcp-serverAgentBridge is usable today for local development, app prototyping, manifest authoring, scanner workflows, OpenAPI import, and MCP experiments. It is not yet production security infrastructure — signed manifests (v0.5.0, in design), OAuth scope enforcement, and distributed audit storage are roadmap items (see docs/roadmap.md). Destructive demo actions remain simulated.
For release notes, see docs/releases/v0.4.0.md for the latest shipped release, docs/releases/v0.3.0.md for the production-foundations release, docs/releases/v0.2.2.md for the Codex onboarding release, docs/releases/v0.2.1.md for the docs cleanup patch, and docs/releases/v0.2.0.md for the first public release.
- Why agent-native interfaces matter
- What is AgentBridge?
- How it works
- Architecture
- The confirmation flow
- Quick start
- Project layout
- Packages and apps
- The CLI
- OpenAPI import
- Manifest spec
- Demo walkthrough
- Wire it to an MCP client
- Manifest schema reference
- MCP tools reference
- Security model
- Testing
- Documentation
- Roadmap
- Contributing
- License
Today's web is built around the assumption that a human will be there — clicking, scrolling, reading visual hierarchy, dismissing modals, recovering from confusing error states. When an AI agent has to operate that same surface, it ends up driving a browser blindly:
- Inferring intent from button labels and DOM structure
- Guessing at element selectors that change between deploys
- Hoping confirmation dialogs don't appear unexpectedly
- Praying that nothing visual changes mid-flow
The result is brittle, slow, and unsafe. There's no reliable way for an agent — or its operator — to reason about what an action will do before it happens.
Apps shouldn't force agents to operate a UI built for human eyes. Apps should publish what they actually do — semantically, with types, with risk metadata, with clear confirmation requirements — so agents can reason about actions before invoking them.
AgentBridge is a manifest format + SDK + MCP server that lets any web app expose its operations to AI agents safely.
The core unit is a manifest served at a well-known URL:
https://your-app.com/.well-known/agentbridge.json
The manifest declares every action the app supports, with:
| Field | Purpose |
|---|---|
name, title, description |
Semantic identity an agent can reason about |
inputSchema (JSON Schema) |
Validate inputs before invocation |
outputSchema (JSON Schema) |
Tell agents what to expect back |
risk: low | medium | high |
Triage which actions need human-in-the-loop |
requiresConfirmation: bool |
Force an explicit approval step |
humanReadableSummaryTemplate |
Generate natural-language confirmation prompts |
permissions[] |
Document required scopes |
examples[] |
Teach agents the correct call shape |
An MCP server bridges any AgentBridge-enabled site to MCP-speaking agents (OpenAI Codex, Claude Desktop, Cursor, custom MCP clients) with enforcement built in: risky actions never execute without explicit confirmationApproved: true, every call is audited, and outbound requests are pinned to the manifest's origin.
flowchart LR
A["🧑 Human user"] --> B["Web app UI<br/>orders.acme.com"]
C["🤖 AI agent"] --> D["MCP client<br/>Codex / Claude Desktop / Cursor / custom"]
D <--> E["AgentBridge<br/>MCP server"]
E -->|fetch manifest| F["/.well-known/<br/>agentbridge.json"]
E -->|invoke action| G["/api/agentbridge/<br/>actions/:name"]
F --> B
G --> B
E --> H[("Audit log")]
style A fill:#dbeafe,stroke:#2563eb
style C fill:#fee2e2,stroke:#dc2626
style E fill:#fef3c7,stroke:#d97706
style H fill:#f3f4f6,stroke:#6b7280
The same web app serves two audiences:
- Humans see the visual UI, click around, and get rich layout
- Agents see the manifest, validate inputs, and invoke structured actions
Both flows share the same backend logic. Both write to the same audit log. The only difference is whether the caller is a browser or a programmatic agent.
flowchart TB
subgraph workspace["agentbridge/ (npm workspace)"]
direction TB
subgraph packages["packages/"]
CORE["📦 agentbridge-core<br/><i>schemas, types,<br/>validation, audit</i>"]
SDK["📦 agentbridge-sdk<br/><i>defineAgentAction,<br/>manifest builder</i>"]
SCAN["📦 agentbridge-scanner<br/><i>readiness scoring,<br/>structured checks</i>"]
OAPI["📦 agentbridge-openapi<br/><i>OpenAPI 3.x →<br/>manifest converter</i>"]
CLI["📦 agentbridge-cli<br/><i>scan, validate, init,<br/>generate, mcp-config</i>"]
end
subgraph apps["apps/"]
DEMO["🛒 demo-app (:3000)<br/><i>Fake order management.<br/>Serves manifest + actions.</i>"]
STUDIO["🎛 studio (:3001)<br/><i>Developer dashboard.<br/>Scan, exercise, audit.</i>"]
MCP["🔌 mcp-server (stdio)<br/><i>Tools, resources, prompts.<br/>Confirmation tokens + idempotency.</i>"]
end
DATA[("📁 data/<br/>audit · confirmations · idempotency")]
end
SDK --> CORE
SCAN --> CORE
OAPI --> CORE
CLI --> CORE
CLI --> SCAN
CLI --> OAPI
DEMO --> SDK
DEMO --> CORE
STUDIO --> SCAN
STUDIO --> CORE
MCP --> SCAN
MCP --> CORE
DEMO -.writes.-> DATA
STUDIO -.writes.-> DATA
MCP -.writes.-> DATA
STUDIO -.reads.-> DATA
DEMO -.reads.-> DATA
style CORE fill:#dbeafe,stroke:#2563eb
style SDK fill:#dbeafe,stroke:#2563eb
style SCAN fill:#dbeafe,stroke:#2563eb
style OAPI fill:#dbeafe,stroke:#2563eb
style CLI fill:#dbeafe,stroke:#2563eb
style DEMO fill:#dcfce7,stroke:#16a34a
style STUDIO fill:#dcfce7,stroke:#16a34a
style MCP fill:#fef3c7,stroke:#d97706
style DATA fill:#f3f4f6,stroke:#6b7280
This is the heart of the safety story. Risky actions never execute on a single agent call — they require a deliberate, two-step approval.
sequenceDiagram
autonumber
participant Agent as 🤖 Agent
participant MCP as MCP Server
participant App as Web App
participant Audit as Audit Log
Agent->>MCP: call_action(execute_refund_order, input)
MCP->>App: GET /.well-known/agentbridge.json
App-->>MCP: manifest (action.risk = "high")
MCP->>MCP: validate input vs JSON Schema
Note over MCP: risk=high & no confirmationApproved
MCP->>Audit: status: confirmation_required
MCP-->>Agent: { status: "confirmationRequired",<br/>summary: "EXECUTE refund draft xyz",<br/>hint: "re-call with confirmationApproved: true" }
Note over Agent: Agent presents the<br/>summary to a human
Agent->>MCP: call_action(..., confirmationApproved: true)
MCP->>MCP: re-validate, re-fetch manifest
Note over MCP: confirmation cleared ✓
MCP->>App: POST /api/agentbridge/actions/execute_refund_order
App-->>MCP: { simulated: true, simulatedTransactionId: "..." }
MCP->>Audit: status: completed, confirmationApproved: true
MCP-->>Agent: { status: "ok", result: { ... } }
The Studio dashboard enforces the same gate visually — the operator must type CONFIRM in a modal before any medium- or high-risk action runs.
git clone https://github.com/marmar9615-cloud/agentbridge-protocol.git
cd agentbridge-protocol
npm install # pulls Next.js, MCP SDK, Zod, etc.
npm test # all suites should pass
npm run dev # demo on :3000, Studio on :3001Then open:
- Demo app: http://localhost:3000 (the human surface)
- Manifest: http://localhost:3000/.well-known/agentbridge.json
- Studio: http://localhost:3001 (the dev dashboard)
To run the MCP server (stdio) for an MCP client:
npm run dev:mcpRequirements: Node 20+, npm 10+. CI runs on Node 20.x and 22.x.
agentbridge-protocol/
├── packages/
│ ├── core/ # 📦 schemas, types, validation, audit
│ ├── sdk/ # 📦 defineAgentAction, manifest builder
│ ├── scanner/ # 📦 readiness scoring + structured checks
│ ├── openapi/ # 📦 OpenAPI 3.x → AgentBridge manifest converter
│ └── cli/ # 📦 @marmarlabs/agentbridge-cli — scan, validate, init, generate
├── apps/
│ ├── demo-app/ # 🛒 Next.js order-management demo (port 3000)
│ ├── studio/ # 🎛 Next.js dashboard (port 3001)
│ └── mcp-server/ # 🔌 stdio MCP server: tools + resources + prompts
├── spec/
│ ├── agentbridge-manifest.schema.json # JSON Schema for the manifest
│ ├── agentbridge-manifest.v0.1.md # human-readable spec
│ └── examples/ # 3 example manifests
├── examples/ # nextjs-basic · openapi-store · mcp-client-config · codex-config · codex-plugin
├── docs/ # quickstart, mcp-client-setup, codex-setup, openapi-import, roadmap
├── data/ # 📁 local audit/confirmations/idempotency (gitignored)
├── .github/workflows/ # CI
├── AGENTS.md # model-neutral working notes for AI coding agents
├── CLAUDE.md # deeper Claude-Code-specific working notes
├── CONTRIBUTING.md / SECURITY.md / CODE_OF_CONDUCT.md / CHANGELOG.md
├── README.md
└── LICENSE # Apache 2.0
The shared contract. Everything depends on this.
import {
AgentBridgeManifestSchema,
validateManifest,
isRiskyAction,
summarizeAction,
createAuditEvent,
appendAuditEvent,
} from "@marmarlabs/agentbridge-core";
const result = validateManifest(rawJson);
if (result.ok) {
for (const action of result.manifest.actions) {
if (isRiskyAction(action)) {
console.log("Needs confirmation:", action.name);
}
}
}Key exports:
- Zod schemas for the manifest, actions, resources, permissions, audit events
validateManifest(json)—{ ok, manifest }or{ ok: false, errors[] }isRiskyAction(action)— boolean confirmation gatesummarizeAction(action, input)— fillshumanReadableSummaryTemplatewith{{key}}placeholderscreateAuditEvent,appendAuditEvent,readAuditEvents— JSON-file audit log with PII redaction (stripsauthorization,cookie,password,token,secretrecursively)
The author's interface. Define actions ergonomically with Zod, get JSON Schema for free.
import { defineAgentAction, createAgentBridgeManifest, z } from "@marmarlabs/agentbridge-sdk";
const refundAction = defineAgentAction({
name: "draft_refund_order",
title: "Draft a refund",
description: "Creates a refund draft. Not executed until confirmed via execute_refund_order.",
method: "POST",
endpoint: "/api/agentbridge/actions/draft_refund_order",
risk: "medium",
requiresConfirmation: true,
inputSchema: z.object({
orderId: z.string().min(1),
reason: z.string().min(3),
amount: z.number().positive(),
}),
outputSchema: z.object({
draftId: z.string(),
summary: z.string(),
}),
humanReadableSummaryTemplate:
"Draft a refund of ${{amount}} on order {{orderId}} (reason: {{reason}})",
examples: [
{
description: "Partial refund for a damaged item",
input: { orderId: "ORD-1001", reason: "Damaged on arrival", amount: 24 },
},
],
});
export const manifest = createAgentBridgeManifest({
name: "Acme Order Manager",
version: "1.0.0",
baseUrl: "https://acme.com",
contact: "platform@acme.com",
actions: [refundAction /* ... */],
});The SDK converts Zod → JSON Schema (via zod-to-json-schema) automatically, so you get one source of truth for both runtime validation and the published manifest.
Audit any URL for agent readiness. Returns a 0–100 score plus actionable recommendations.
import { scanUrl } from "@marmarlabs/agentbridge-scanner";
const report = await scanUrl("http://localhost:3000");
// {
// score: 100,
// manifestFound: true,
// validManifest: true,
// actionCount: 5,
// riskyActionCount: 3,
// missingConfirmationCount: 0,
// issues: [],
// recommendations: [],
// }Scoring rubric:
| Issue | Deduction |
|---|---|
| No manifest at all | → score 0 |
| Manifest invalid against schema | → score 10 |
| No actions declared | −30 |
Missing contact field |
−5 |
| Per action: short/missing description | −3 |
| Per action: no examples | −2 |
Per action: no humanReadableSummaryTemplate |
−2 |
Per action: no outputSchema |
−2 |
Per high-risk action without requiresConfirmation |
−15 |
Per medium-risk action without requiresConfirmation |
−7 |
Optionally runs a Playwright probe (probe: true) to fall back on visible buttons/forms when no manifest exists yet — useful for "what would an agent see if there were no manifest?" baselines.
A toy order-management Next.js app exposing 5 actions of escalating risk:
| Action | Risk | Confirmation |
|---|---|---|
list_orders |
low | none |
get_order |
low | none |
draft_refund_order |
medium | required |
add_internal_note |
medium | required |
execute_refund_order |
high | required |
The demo intentionally simulates destructive actions — execute_refund_order mutates an in-memory store and returns { simulated: true, simulatedTransactionId: "..." }. No real payment processor is touched anywhere in this codebase.
A developer dashboard at :3001 for inspecting and exercising any AgentBridge surface:
- Scan — fetch + score + recommend
- Manifest — pretty-printed JSON viewer
- Actions — list with risk pills, click-through to detail
- Action detail — auto-generated form from
inputSchema, "Try it" button, confirmation modal for risky actions - Audit log — cross-source view (demo / studio / mcp)
A Model Context Protocol server speaking stdio. Exposes 5 tools, 4 resources, and 4 prompts to AI agents (see MCP tools reference below). Enforces the confirmation gate, origin pinning, URL allowlist, confirmation tokens, and idempotency keys before any outbound call.
OpenAPI 3.x → AgentBridge manifest converter. Used by the CLI; can also be imported directly. Resolves $refs, infers risk from method, merges path/query/body params into the action's inputSchema. See docs/openapi-import.md for limits.
The agentbridge command. See The CLI below.
# From the repo root, no install needed:
npm run dev:cli -- scan http://localhost:3000
# After installing the published package, or via npx without install:
npx @marmarlabs/agentbridge-cli scan http://localhost:3000| Command | What it does |
|---|---|
agentbridge scan <url> |
Score the URL's AgentBridge readiness. Readable terminal output; --json for machine output. |
agentbridge validate <file-or-url> |
Validate a manifest from disk or a URL against the schema. --json. |
agentbridge init |
Scaffold an agentbridge.config.ts and a starter /.well-known/agentbridge.json. --force to overwrite, --format json for JSON config. |
agentbridge generate openapi <src> |
Generate a draft manifest from an OpenAPI 3.x doc. --out PATH, --base-url URL, --json. |
agentbridge mcp-config |
Print copy-pasteable MCP client configs for OpenAI Codex (CLI + config.toml), Claude Desktop, Cursor, and any other MCP-compatible client. |
agentbridge version |
Print CLI version. |
Example: take an existing OpenAPI document and turn it into a draft manifest in one shot:
npx @marmarlabs/agentbridge-cli generate openapi ./your-api.openapi.json \
--base-url https://api.acme.com \
--out ./public/.well-known/agentbridge.jsonSee docs/openapi-import.md for the full guide.
The CLI's generate openapi command and the @marmarlabs/agentbridge-openapi package
turn an existing OpenAPI 3.x document into a draft AgentBridge manifest.
| OpenAPI method | Risk inferred | requiresConfirmation |
|---|---|---|
GET / HEAD |
low | false |
POST / PUT / PATCH |
medium | true |
DELETE |
high | true |
The generator walks every operation, uses operationId (snake-cased) as the
action name, merges path/query params and request body into the action's
inputSchema.properties, and resolves $refs against components.schemas.
Review every action after generation — heuristics aren't a substitute for intent. See the example and docs/openapi-import.md.
The manifest format is a stable, versioned spec — not just whatever
@marmarlabs/agentbridge-core happens to validate.
| Artifact | Path |
|---|---|
| Human-readable spec | spec/agentbridge-manifest.v0.1.md |
| JSON Schema (Draft 2020-12) | spec/agentbridge-manifest.schema.json |
| Examples | spec/examples/ — minimal, e-commerce, support tickets |
The example manifests are validated by tests, so they stay in sync with the
schema as it evolves. Add a new example by dropping a JSON file into
spec/examples/ and the test in packages/core/src/tests/spec-examples.test.ts
will pick it up automatically.
-
Boot it up.
npm run dev
-
Browse as a human. Visit http://localhost:3000/orders. Click into an order. Notice this is a normal-looking app.
-
Inspect the manifest. Visit http://localhost:3000/.well-known/agentbridge.json (or the pretty viewer at
/manifest). The same five operations a human can perform are declared as structured actions an agent can call. -
Switch to Studio. Visit http://localhost:3001. Hit Scan. You should see a perfect or near-perfect score, with all 5 actions and their risk levels.
-
Run a low-risk action. Open
list_ordersfrom the Actions list. The form has a single optionalstatusenum. Submit — runs immediately, returns the order list. -
Run a risky action. Open
add_internal_note. Fill inorderId: ORD-1001and a note. Click Review & confirm. The modal blocks until you typeCONFIRM. Then it runs. Refresh the order detail page in the demo — the note is there. -
See the audit trail. Visit
/auditin either app. Both invocations appear, with the source (studiohere), the input, and timestamps. -
Try refusing. Try to invoke
execute_refund_orderfrom the MCP server withoutconfirmationApproved:echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}} {"jsonrpc":"2.0","method":"notifications/initialized"} {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"call_action","arguments":{"url":"http://localhost:3000","actionName":"execute_refund_order","input":{"draftId":"x","confirmationText":"CONFIRM"}}}}' \ | npm run dev:mcp 2>/dev/null
You'll get back
{ "status": "confirmationRequired", "summary": "EXECUTE refund draft x (irreversible in real life)", ... }— the action endpoint is not called.
The AgentBridge MCP server speaks stdio. Same launcher
(npx -y @marmarlabs/agentbridge-mcp-server) works in every
MCP-compatible client below — only the surrounding config syntax
differs. For everything beyond the snippets below see
docs/mcp-client-setup.md and (for Codex
specifically) docs/codex-setup.md.
- OpenAI Codex — CLI (
codex mcp add) or~/.codex/config.toml. See docs/codex-setup.md. - Claude Desktop — JSON config under
~/Library/Application Support/Claude/. - Cursor — Settings → MCP, same JSON shape as Claude Desktop.
- Custom or other MCP clients — anything that can launch a stdio MCP server runs the same
npx -y @marmarlabs/agentbridge-mcp-serverentry.
npx @marmarlabs/agentbridge-cli mcp-config prints copy-pasteable
snippets for all of the above.
codex mcp add agentbridge -- npx -y @marmarlabs/agentbridge-mcp-serverVerify with /mcp inside Codex. Walkthrough, project-scoped config,
and troubleshooting are in docs/codex-setup.md.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"agentbridge": {
"command": "npx",
"args": ["-y", "@marmarlabs/agentbridge-mcp-server"]
}
}
}Restart Claude Desktop. You should see agentbridge show up in the tools panel with 5 tools available.
Settings → MCP → Add server. Same command/args shape as Claude
Desktop. Or paste:
{
"mcpServers": {
"agentbridge": {
"command": "npx",
"args": ["-y", "@marmarlabs/agentbridge-mcp-server"]
}
}
}The dialogue below uses Claude Desktop, but the same flow works with Codex, Cursor, or any other MCP-compatible client — only the surrounding chrome differs.
You: What can the app at http://localhost:3000 do?
Agent: (uses
discover_manifest) It's a Demo Order Manager v0.1.0 with 5 actions: list_orders (low risk), get_order (low), draft_refund_order (medium, needs confirmation), execute_refund_order (high, needs confirmation), and add_internal_note (medium, needs confirmation).You: Refund order ORD-1001 for $24 because the customer reported damage.
Agent: (uses
call_actionfordraft_refund_order) I've drafted the refund. Draft iddraft_xxx. To execute it, I need explicit approval — should I proceed?You: Yes, go ahead.
Agent: (uses
call_actionforexecute_refund_orderwithconfirmationApproved: true) Done. Simulated transactionsim_tx_yyy. Order ORD-1001 is now inrefundedstatus.
A complete example manifest:
{
"name": "Demo Order Manager",
"description": "A fake order management app exposing structured AgentBridge actions for AI agents.",
"version": "0.1.0",
"baseUrl": "http://localhost:3000",
"contact": "demo@agentbridge.local",
"auth": { "type": "none", "description": "Demo only — no auth." },
"resources": [
{
"name": "orders",
"description": "Customer orders with items, status, notes, and refund history.",
"url": "/orders"
}
],
"actions": [
{
"name": "execute_refund_order",
"title": "Execute a drafted refund",
"description": "Executes a previously drafted refund. SIMULATED.",
"method": "POST",
"endpoint": "/api/agentbridge/actions/execute_refund_order",
"risk": "high",
"requiresConfirmation": true,
"inputSchema": {
"type": "object",
"required": ["draftId", "confirmationText"],
"properties": {
"draftId": { "type": "string", "minLength": 1 },
"confirmationText": { "type": "string", "minLength": 1 }
}
},
"outputSchema": {
"type": "object",
"properties": {
"simulated": { "const": true },
"simulatedTransactionId": { "type": "string" }
}
},
"permissions": [],
"examples": [
{
"description": "Execute the refund draft after confirmation",
"input": { "draftId": "draft_xxx", "confirmationText": "CONFIRM" }
}
],
"humanReadableSummaryTemplate": "EXECUTE refund draft {{draftId}} (irreversible in real life)"
}
],
"generatedAt": "2026-04-27T02:05:06.203Z"
}Top-level fields: name, description, version, baseUrl, resources[], actions[], auth, contact, generatedAt.
Action fields: name, title, description, inputSchema (JSON Schema), outputSchema (JSON Schema), method, endpoint, risk (low | medium | high), requiresConfirmation, permissions[], examples[], humanReadableSummaryTemplate.
The MCP server exposes 5 tools, 4 resources, and 4 prompts. All accept a target url (the origin of an AgentBridge-enabled app).
| Tool | Purpose |
|---|---|
discover_manifest |
Fetch + summarize a manifest. Use first to understand what an app supports. |
scan_agent_readiness |
Run the full scanner; returns 0–100 score, structured checks[], grouped recommendations. |
list_actions |
Compact list of actions with name, title, risk, confirmation flag, permissions. |
call_action |
Invoke an action. Risky actions return confirmationRequired plus a confirmationToken; the second call must include confirmationApproved: true AND the same token. Optional idempotencyKey replays prior results. |
get_audit_log |
Read recent audit events; filter by url. |
URIs the agent can fetch directly:
| URI | What it returns |
|---|---|
agentbridge://manifest?url=<encoded> |
The validated manifest at the given URL. |
agentbridge://readiness?url=<encoded> |
Full scanner report (score, checks, recommendations). |
agentbridge://audit-log?url=<encoded>&limit=N |
Recent audit events, optionally filtered. |
agentbridge://spec/manifest-v0.1 |
Bundled human-readable manifest spec (markdown). |
Reusable agent prompts:
| Prompt | Use case |
|---|---|
scan_app_for_agent_readiness |
Audit + write up findings for an AgentBridge surface. |
generate_manifest_from_api |
Turn an OpenAPI doc or API description into a draft manifest. |
explain_action_confirmation |
Translate an action for a human reviewer about to approve it. |
review_manifest_for_security |
Safety-focused review of an existing manifest. |
A repeat call with the same idempotencyKey and same input returns the
cached result without re-invoking the upstream endpoint. A repeat with the
same key and different input is rejected as a conflict.
This is an MVP — but security is not an afterthought, because the entire value of the project is letting agents act safely.
| Control | Where it lives | What it does |
|---|---|---|
| URL allowlist | mcp-server/src/safety.ts, scanner/src/scanner.ts |
Loopback only by default. Production-recommended: set AGENTBRIDGE_ALLOWED_TARGET_ORIGINS to a comma-separated list of exact origins. Broad escape hatch: AGENTBRIDGE_ALLOW_REMOTE=true (with a one-time stderr warning). |
| Configurable bounds | mcp-server/src/config.ts |
AGENTBRIDGE_ACTION_TIMEOUT_MS, AGENTBRIDGE_MAX_RESPONSE_BYTES, AGENTBRIDGE_CONFIRMATION_TTL_SECONDS — out-of-range values are clamped with a stderr warning. See docs/security-configuration.md. |
| Stdout hygiene | apps/mcp-server/src/tests/stdio-hygiene.test.ts |
Stdout carries only JSON-RPC. Warnings/diagnostics go to stderr. Verified by an MCP subprocess test. |
| Origin pinning | mcp-server/src/safety.ts:assertSameOrigin |
Action endpoints must share origin with manifest.baseUrl. A poisoned manifest cannot redirect calls elsewhere. |
| Confirmation gate | mcp-server/src/tools.ts:callAction, studio/api/call/route.ts |
Risky actions return confirmationRequired unless caller passes confirmationApproved: true. |
| Confirmation tokens | mcp-server/src/confirmations.ts |
Tokens are bound to (url, actionName, hash(input)), single-use, expire in 5 minutes. Reuse with different input is rejected. |
| Idempotency keys | mcp-server/src/idempotency.ts |
Optional per-call key replays prior result; same key + different input is a conflict. |
| Outbound timeout + size cap | mcp-server/src/tools.ts |
10s timeout on action calls; 1MB response body cap. |
| Schema validation | mcp-server/src/tools.ts (Ajv), SDK (Zod) |
Inputs validated against the action's JSON Schema before any upstream call. |
| Audit redaction | core/src/audit.ts:redact |
Strips authorization, cookie, password, token, secret, api_key recursively before persisting. |
| Simulated destructive actions | demo-app/lib/orders.ts |
No real payment processor is wired anywhere. All "destructive" demo actions return { simulated: true, ... }. |
| Bounded audit log | core/src/audit.ts |
Capped at 500 most recent events; atomic write (tmp + rename) to prevent corruption. |
- Real OAuth/bearer auth on the MCP server and on action endpoints
- Per-action RBAC and tenant isolation
- Signed manifests so agents can verify the publisher
- Policy engine integration (OPA / Cedar) for action-level allow/deny
- Rate limiting and cost accounting
- Distributed audit storage (the MVP uses a local JSON file)
| Threat | Mitigation today | Long-term mitigation |
|---|---|---|
| Agent misclicks a destructive action | Confirmation gate + risk metadata | Same + signed policy contracts |
| Poisoned manifest redirects calls to attacker host | Origin pinning to baseUrl |
Same + signed manifests + cert pinning |
| SSRF via attacker-supplied URL | Loopback-only by default | Same + outbound-host allowlist per agent |
| Audit log leaks secrets | Recursive redaction of common keys | Same + structured logging w/ tagged sensitive fields |
| Agent DOS's the upstream app | (none today) | Per-tool rate limiting + cost accounting |
npm test # all suites
npm run typecheck # per-package tsc --noEmit
npm run build # tsup build for publishable packages
npm run pack:dry-run # validate published-tarball contentsCoverage:
packages/core— manifest validation, risk classification, summary template rendering, audit log persistence + redaction, spec example validation.packages/scanner— scoring, structured checks, URL allowlist enforcement, cross-origin baseUrl, destructive-method detection.packages/openapi— OpenAPI parsing, risk inference, name normalization, $ref resolution, full fixture conversion.packages/cli— arg parsing, exit codes, validate/init/generate behaviour, file system side effects.apps/mcp-server— confirmation gate, token issuance + binding + single-use, idempotency replay + conflict, origin pinning, JSON Schema validation, low-risk pass-through.
CI runs npm install, typecheck, all tests, and Next.js builds on Node 20.x and 22.x — see .github/workflows/ci.yml.
| Doc | What it covers |
|---|---|
| docs/quickstart.md | Five-minute walkthrough from clone to running stack. |
| docs/codex-setup.md | Hooking AgentBridge MCP into OpenAI Codex (CLI + config.toml + project-scoped). |
| docs/mcp-client-setup.md | Hooking AgentBridge MCP into Codex, Claude Desktop, Cursor, custom clients. |
| docs/openapi-import.md | Generating manifests from OpenAPI 3.x. |
| docs/v1-readiness.md | The v1.0.0 readiness checklist — what "production-ready" means and where we stand. |
| docs/production-readiness.md | Practical "what is AgentBridge safe for today?" assessment plus a pre-flight checklist. |
| docs/threat-model.md | Full threat catalogue with current mitigations and v1.0 targets. |
| docs/security-configuration.md | Every env var the MCP server honors, with defaults, ranges, and recipes. |
| docs/trusted-publishing.md | npm Trusted Publishing plan and the draft release-publish.yml workflow. |
| docs/designs/http-mcp-transport-auth.md | v0.4.0 HTTP MCP transport + auth design. |
| docs/adr/0001-http-mcp-transport.md | ADR for adding the opt-in HTTP MCP transport. |
| docs/designs/signed-manifests.md | v0.5.0 signed-manifest design (in progress). |
| docs/adr/0002-signed-manifests.md | ADR for adding optional signed AgentBridge manifests. |
| docs/roadmap.md | What's shipped, what's next. |
| spec/agentbridge-manifest.v0.1.md | The manifest specification. |
| AGENTS.md | Short, model-neutral working notes for any AI coding agent (Codex, Claude, Cursor, custom). |
| CLAUDE.md | Deeper Claude-Code-specific working notes for this repo. |
| CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md | Community + reporting. |
| CHANGELOG.md | Per-release notes. |
Near-term, in rough priority order:
- Signed manifests (v0.5.0, in design). A published manifest carries an inline publisher signature (Ed25519 by default, RFC 8785 canonicalization) an agent can verify offline against the publisher's key set at
/.well-known/agentbridge-keys.json. Optional in v0.5.0; mandatory at v1.0 after a documented migration. Design: docs/designs/signed-manifests.md. ADR: docs/adr/0002-signed-manifests.md. Tracking: #31. - Standardized risk taxonomy. Move from
low | medium | highto a richer model:read,write-self,write-others,financial,irreversible. Lets agents reason about action consequences more precisely. - Policy primitives. First-class support for cost caps, rate limits, business-hours gating, and N-of-M approver workflows declared in the manifest.
- HTTP MCP transport. Stdio works for desktop clients; hosted/centralized agents need an authenticated HTTP transport. Implemented as opt-in in v0.4.0 behind
AGENTBRIDGE_TRANSPORT=httpwith bearer-token auth, exact-origin allowlist, and loopback-by-default bind. Design: docs/designs/http-mcp-transport-auth.md. Recipe: examples/http-client-config. - Cross-app workflows. Let an agent compose actions from multiple AgentBridge surfaces with consistent confirmation semantics across them.
- Browser fallback + auto-generation. When a site doesn't publish a manifest, run a Playwright probe and generate a starter manifest from visible buttons and forms — give app teams a one-click on-ramp.
- Manifest registry. Optional public index of manifests so agents can discover what surfaces exist for a given task ("find me an app that can refund a Stripe charge").
This is a prototype, and the most valuable contributions are about the interface contract between agents and apps — not the demo Next.js plumbing.
High-leverage places to start:
packages/core/src/schemas.ts— the manifest schema is the entire contract. Field additions, deprecations, and tightening live here.packages/scanner/src/score.ts— the readiness rubric. What does a "good" agent-ready app look like? Should missing examples cost more than missing output schemas?apps/mcp-server/src/tools.ts— the enforcement surface. The confirmation gate and origin pinning are critical paths.
Please open an issue before starting on any PR larger than a small fix, so we can align on direction.
Apache License 2.0 — see LICENSE.
Built as an MVP exploration of the agent-native interface layer for the web.
If this resonates, open an issue and let's talk.