Platform-Agent Bridge (mcp.astrasync.ai)
One MCP endpoint that lets every platform agent transact with every AstraSync-registered merchant.
One MCP endpoint that lets every platform agent (Claude, ChatGPT, Gemini, Cursor) transact with every AstraSync-registered merchant. The bridge handles protocol normalisation (ACP / AP2 / UCP / x402), forwards the inbound agent's AstraSync identity to the merchant's policy engine, and surfaces structured denials when PDLSS boundaries don't allow a request.
Bridge is transport, merchant is policy. The bridge does not enforce its own trust floor on transactional tools. Every call triggers verify-access against the merchant's endpoint with the inbound agent's credentials forwarded — the merchant decides what to accept. Agents the merchant would happily transact with directly are never blocked at the bridge layer.
No direct merchant HTTP checkout, no CSRF handshake. The bridge is a discovery +
identity-handshake layer: start_checkout and confirm_purchase call AstraSync's own
verify-access and mint a scoped session — they do not POST to your merchant checkout
endpoint. So merchants do not need to expose a CSRF token to the bridge or special-case CSRF
for bridge-mediated flows; CSRF protection on your own checkout routes is unaffected. (Direct
merchant checkout forwarding is a separate, not-yet-shipped capability — when it lands, any CSRF
handshake will be handled by the bridge, never by the agent.)
Tool surface
One MCP server exposes identity registration, doc search, verify-access, in-chat approval and
onboarding cards, and commerce. The full tool list below is generated from the server's own
registry (the same source as /.well-known/mcp.json and /skill.md):
| Tool | What it does |
|---|---|
| register_agent | Register an agent identity with AstraSync credentials (API key, email + password, or a signed keypair). |
| request_registration | Keyless registration: lodge a request under the owner's email for the owner to approve. No credential enters the agent's context. |
| poll_registration | Read a pending registration's state; returns the ASTRA-ID once the owner approves. |
| verify_agent | Run verify-access for an agent against an endpoint: identity, trust and PDLSS scope in one decision. |
| search_docs | Search the AstraSync documentation. |
| review_pending_approvals | Open the in-chat approvals panel so the owner can approve pending registrations. |
| start_onboarding | Open the in-chat onboarding card (account, identity verification, payment instrument). |
| manage_payment_instruments | Open the in-chat panel for the owner's saved payment instruments. |
| list_endpoints | List AstraSync-registered endpoints (merchants and service APIs) and pick an ASTRAE-ID. The commerce entry point. |
| describe_endpoint | Read a service endpoint's route contract (for endpoints with no product catalog, such as banking or data APIs). |
| invoke_endpoint | Call a service endpoint's route (API) or registered tool (MCP server) with verified identity. A call the owner asked to approve (over the spend limit, or an action, time, scope or sub-agent rule set to Ask me) is held for the owner's approval card. |
| discover_catalog | Browse a merchant's catalog; verified callers see the tier their identity unlocks. |
| start_checkout | Open a checkout session for chosen items; returns sessionId, intent mandate and required scopes. |
| confirm_purchase | Complete a checkout by sessionId (no payment token). A purchase the owner asked to approve (over the autonomous limit, or another rule set to Ask me) is held and this call shows the owner's approval card. |
| poll_step_up | Read the outcome of a held purchase or endpoint call after the owner decides in the approval card: approved, denied, expired or consumed (with settlement or invocation outcome). Read-only. |
The commerce flow is five steps:
list_endpoints→ pick an endpoint'sastraeIddiscover_catalog({ astraeId })→ pick SKUsstart_checkout({ astraeId, items, jurisdiction })→ receive asessionIdconfirm_purchase({ sessionId })→ complete the purchase. You supply no payment token. A purchase above the agent's autonomous limit is held: this call renders the owner's approval card and moves no money.poll_step_up({ approvalId })→ read the owner's decision on a held purchase
Service endpoints with no product catalog (banking, data APIs, MCP servers) are listed by
list_endpoints too; use describe_endpoint to read an endpoint's contract and invoke_endpoint
to call it with verified identity instead of steps 2–4. An api endpoint publishes path rules and
takes invoke_endpoint({ astraeId, path, method, body? }). An mcp_server endpoint publishes
tool rules and takes invoke_endpoint({ astraeId, tool, arguments }): only tools with a rule
can be called, the purpose and action come from the rule, and the bridge runs a real MCP session
with the server (see MCP integration — tool rules). The commerce tools are documented below; identity and
verify tools follow standard MCP conventions — see /docs/agent-access for
those.
register_agent
Thin wrapper over the verification-gateway SDK's AstraSync.register(). Pass any of the SDK's
auth modes — { apiKey } (owner step-up email), { email, password } (synchronous active),
{ apiKey, privateKey } (synchronous signed) — plus the standard RegisterOptions (name, pdlss,
model, framework, protocols). Returns SDK's RegisterResult verbatim:
{ status: "active", agent } or { status: "pending_approval", requestId, pollUrl }.
No-creds calls return a structured guidance envelope (registrationUrl, steps[]) mirroring the
same shape the SDK's verify path emits for unauthenticated callers.
poll_registration
Thin wrapper over AstraSync.pollRegistration(requestId). Returns
{ state: "pending" | "approved" | "denied" | "expired", astraId?, agent?, reason? }. Use the
requestId returned by register_agent. The skill defines two polling patterns: conversational
agents poll once on user-confirmation; autonomous agents poll every 5–10s with a 5-minute
timeout.
list_endpoints
Discovery surface and the commerce entry point. Returns AstraSync-registered endpoints
(merchants and service APIs) that opted into platform-agent discoverability. Optional filters:
query, jurisdiction, surface (e.g. website for storefronts, api for service/banking
endpoints). No authentication required.
{
"endpoints": [
{
"astraeId": "ASTRAE-shop42",
"name": "ExampleShop",
"surface": "website",
"jurisdictions": ["AU", "NZ"],
"supportedProtocols": ["acp", "ap2"],
"skillUrl": "https://shop.example/mcp/skill.md",
"catalogUrl": "https://shop.example/api/catalog"
}
],
"count": 1
}Finding the merchant's MCP endpoint: the response does not surface mcpUrl as a first-class
field today. Agents needing to reach the merchant's MCP server should fetch the skillUrl above
and read the endpoints.mcp field from the returned skill document. A first-class mcpUrl on
the merchant entry is on the roadmap; in the interim, fetch-the-skill is the supported path.
discover_catalog
Fetches the merchant's registered catalogUrl (not /.well-known/*, which gateways skip-path
and always return the public view). Forwards inbound _meta.astrasync credentials so tiered
catalogs serve the correct tier. Anonymous responses are cached; verified callers always bypass
cache.
Canonical catalog shape:
{
"merchantAstraeId": "ASTRAE-shop42",
"name": "ExampleShop",
"supportedProtocols": ["acp", "ap2"],
"skus": [
{
"id": "sku-001",
"title": "Widget",
"description": "Best-in-class widget",
"price": { "amount": "25.00", "currency": "USD" },
"rrp": { "amount": "32.00", "currency": "USD" },
"availability": "in_stock",
"stockLevel": 12,
"imageUrl": "https://shop.example/images/sku-001.png",
"protocol": "acp",
"raw": { /* merchant's native shape, untouched */ }
}
],
"fetchedAt": "2026-05-15T10:00:00.000Z",
"cached": false,
"tier": "verified"
}The raw field on each SKU is the merchant's native protocol shape, preserved verbatim. Drop
down to it when the canonical fields elide something protocol-specific.
imageUrl, rrp and stockLevel appear only when the merchant sends them. The merchant's
catalog provides sku, name, price, optionally sale_price and sale_price_effective_date,
rrp, in_stock and image_url (see the
merchant catalog fields). price and
sale_price follow the ACP product feed and Google Merchant Center: price is the regular price,
sale_price the price charged while the sale runs (sale_price_effective_date is
"<ISO start>/<ISO end>"), and both accept the "59.99 USD" string form. Inside the sale window
the canonical price is the sale price, rrp is the regular price, and start_checkout charges
the sale price; a sale that isn't lower, is in another currency or has a malformed date range is
ignored. imageUrl is kept only when it is an absolute HTTPS URL; images must be PNG, JPEG or
WebP (no SVG), square, 1000×1000 recommended, at most 2 MB. rrp is kept only when it is above
price, is display-only, and is never used to price a checkout.
The catalogue card. On hosts that render MCP Apps (claude.ai web and Claude Desktop),
discover_catalog also returns AstraSync's catalogue card: one tile per product with its image,
name, price (RRP struck through when discounted), stock and a Buy button. Buy runs
start_checkout through the user's connector and asks the model to confirm, so the purchase goes
through the same approval and confirm_purchase flow. The card never takes payment details.
Product images in the card load through AstraSync's image proxy
(/catalog-img/:astraeId?u=<image URL>), which serves only images on the merchant's catalog host
or listed in its catalog; the merchant's server sees AstraSync, not the viewer.
Merchants can test their catalog against these rules with Check catalog on the endpoint's
page in the dashboard (POST /api/endpoints/:id/catalog-check).
start_checkout
Initiates a checkout against a merchant. Calls verify-access with
purpose: "shopping.purchase" against the merchant's endpoint. Returns a sessionId + intent
mandate on grant; a structured denial otherwise.
{
"success": true,
"sessionId": "cks_…",
"merchantAstraeId": "ASTRAE-shop42",
"intentMandate": {
"agentId": "ASTRA-XYZ…",
"merchant": "ASTRAE-shop42",
"items": [{ "sku": "sku-001", "quantity": 2 }],
"totalValue": 50,
"currency": "USD",
"issuedAt": "...",
"expiresAt": "..."
},
"requiredScopes": ["shopping.purchase"],
"tokenLifetime": 1800000,
"accessLevel": "standard"
}confirm_purchase
Completes a session. Re-validates trust + scope against the merchant via verify-access with
purpose: "shopping.purchase" (same canonical purpose token as start_checkout —
checkout-create and checkout-confirm are two phases of one shopping intent), plus the
commerce-pipeline's payment-mandate checks server-side.
{
"success": true,
"verificationResult": {
"identityVerified": true,
"policyAllowed": true,
"accessLevel": "standard",
"recommendation": "grant",
"correlationId": "cor_…"
},
"txHash": "astrasync-placeholder:cor_…",
"txHashKind": "astrasync-correlation-placeholder",
"receiptUrl": "https://astrasync.ai/receipts/cor_…",
"merchantAstraeId": "ASTRAE-shop42",
"items": ["..."],
"totalValue": 50,
"currency": "USD"
}txHash is a placeholder until v2. The txHashKind: "astrasync-correlation-placeholder"
discriminator tells you not to verify it on a public blockchain. Use receiptUrl for
confirmation today. Blockchain commit lands in a separate v2 PR.
poll_step_up
When confirm_purchase holds a purchase for the owner, it returns an approvalId and renders the
approval card. After the owner decides in the card, poll_step_up({ approvalId }) reads the
outcome: approved, denied, expired or consumed (a consumed approval also carries
settlementOutcome — whether money moved, plus the order id). Read-only: the agent never makes
the decision.
Purpose tokens the bridge emits
When the bridge calls verify-access on your behalf (Path B), it passes a canonical PDLSS
purpose token. The vocabulary stays disjoint from transport tokens (no mcp_invoke) and reuses
the existing PDLSS shopping / identity / discovery namespaces — so your endpoint's PDLSS scope
allowlist doesn't have to grow a new sub-namespace just to support bridge traffic.
When declaring an agent's allowedActions or scope.resources, MCP traffic uses
<method>:<toolName> action encoding and mcp:tool/<name> resource encoding — see
Declaring allowedActions and scope.resources for MCP traffic
on the agent-access docs for the worked example.
| Bridge tool | Purpose | Action | When fired |
|---|---|---|---|
discover_catalog | shopping | shopping.search | Catalog browse, merchant filtering, SKU search. |
start_checkout | shopping | shopping.purchase | Cart → checkout transition (intent mandate issued). |
confirm_purchase | shopping | shopping.purchase | Final purchase confirmation (same purpose — checkout-create and checkout-confirm are two phases of one shopping intent). |
verify_agent | identity | caller-supplied | Verify-access check (allowed/denied — the agent never sees its own trust score). Pass an optional purpose (bare category; defaults to identity) and a required dotted-verb action. |
list_endpoints | discovery | discovery.read | Bridge-discoverable endpoint listing. |
search_docs | discovery | discovery.read | Docs / FAQ search. |
Acting proof (round 29.1). A valued purchase settles only when the bridge can prove the caller may act as the agent: the agent belongs to the signed-in AstraSync connector user, the owner approved it with a passkey, or the agent passed a runtime challenge. Anything else (an anonymous connection, or a user naming someone else's agent) is held for the agent owner's passkey approval and never settles on its own. A checkout opened by a signed-in user can only be confirmed by that user.
Path B merchants: route allowedPurposes take the bare category nouns; agents enumerate the
dotted actions in their allowedActions. If an agent declares shopping.purchase but not
shopping.search, it gets a successful start_checkout but a denied discover_catalog —
declare the granularity that fits.
| Purpose category (bare noun) | Actions (dotted verbs) | Covers |
|---|---|---|
| shopping | shopping.search, shopping.purchase | Catalog browse/search; checkout create + confirm (one purchase intent) |
| identity | identity.verify, identity.lookup | Trust/score verification; identity resolution |
| discovery | discovery.read | Merchant listing, docs search |
| data | data.read, data.write, data.delete | Generic API access — the fallback pair for unmapped routes (data.execute is reserved) |
| custom (e.g. trading, accounting) | trading.execute, accounting.read, … | Any bare noun + dotted verbs under it — first-class, not second-class |
allowedActionsis required (min 1) — the evaluator is fail-closed on actions.categoriesis derived from the dotted-action prefixes; supply extras only to widen.- MCP tool names (
list_products) are valid enumerated actions; they derive no category, so add an explicit one if all your actions are dotless. - Transport verbs (GET/POST) never travel as actions — HTTP senders map them through the pinned table (GET → data.read, POST/PUT/PATCH → data.write, DELETE → data.delete).
- Retired gen-1 tokens (
read_data,write_data,execute_action) are rejected at registration — use thedatacategory.
Structured denial shape
When start_checkout or confirm_purchase denies a request, the response uses the same envelope
as the platform's verify-access route (so a single parser handles bridge + direct verify-access
responses interchangeably).
{
"success": true,
"access": {
"allowed": false,
"reason": "Caller did not present an AstraSync agent identity",
"failures": [
{
"code": "agent_missing",
"message": "No _meta.astrasync.agentId provided.",
"dimension": "agent.missing"
}
],
"requiresStepUp": false,
"requiresApproval": false
},
"recommendation": "deny",
"recommendationReasons": ["..."],
"correlationId": "cor_..."
}The failures[].dimension field is the literal string to switch on for error handlers.
Vocabulary below.
Deny propagation today: when a Path B merchant's PDLSS denies a bridge request, the bridge
propagates the merchant's deny verbatim as a JSON-RPC error. There is no anonymous step-down
behaviour today — agents whose PDLSS scope conflicts with merchant policy see the merchant's
deny shape directly. Anonymous step-down (bridge re-fetching the restricted-tier catalog and
returning it with a tier: "stepped_down" indicator) is on the roadmap as a later-round bridge
enhancement.
failures[].dimension vocabulary
| dimension | Example reason |
|---|---|
agent.missing | No _meta.astrasync provided (transactional tools only) |
agent.lookup | agentId provided but not registered with AstraSync |
agent.status | Agent deactivated or revoked |
pdlss.purpose | Merchant policy doesn't allow commerce.checkout.create for this agent |
pdlss.limits | Cart total exceeds the agent's autonomous threshold |
pdlss.scope | Merchant URL outside the agent's allowed scope list |
counterparty.allowlist | Merchant requires allowlist + caller not on it |
counterparty.trust | Caller's trust score below merchant's floor |
attestation.type | Payment-mandate type not accepted by merchant |
endpoint.deactivated | Merchant endpoint deactivated |
upstream.validation_failed | Platform reached but rejected the request as invalid — fix the input, then retry |
upstream.auth_failed | Platform rejected the bridge credentials (authentication) |
upstream.access_denied | Platform reached but denied access for this call (authorization) |
upstream.unexpected_status | Platform returned an unexpected 4xx — inspect the body before retrying |
system.platform_unreachable | MCP bridge couldn't reach the AstraSync platform (5xx/network/DNS/timeout — retry, and check ASTRASYNC_API_URL uses the canonical apex form https://astrasync.ai/api) |
Discovery + skill
- Discovery doc:
https://mcp.astrasync.ai/.well-known/mcp.json - Anthropic Skill:
https://mcp.astrasync.ai/skill.md
The skill markdown covers two tracks: tool-capable agents (the default modern chat surface) call
register_agent on the MCP server directly, with conversational or autonomous polling patterns;
tool-less chat agents are advised to switch to a client with tool access. All 10 tools — identity
registration, agent lookup, doc search, verify-access, and commerce — live on the single /mcp
surface.
Opt your endpoint into the bridge. In your AstraSync dashboard under
Endpoints → [your endpoint] → Platform-Agent Bridge, set Discoverability: Discoverable
and register a Catalog URL (gateway-evaluated path for tiered content; not
/.well-known/*). Optionally add a Skill URL pointing at your own merchant-specific MCP
server or Anthropic Skill.

