Platform-Agent Bridge

mcp.astrasync.ai/mcp

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

Nine tools on one MCP server: identity registration (register_agent, request_registration, poll_registration), doc search (search_docs), verify-access (verify_agent), and commerce (list_merchants, discover_catalog, start_checkout, confirm_purchase). The four commerce tools are documented below; identity + 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_merchants

Discovery surface. Returns AstraSync-registered merchants that opted into platform-agent discoverability. No authentication required.

{
  "merchants": [
    {
      "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"
    }
  ]
}

Finding the merchant's MCP endpoint: the response does not surface mcpUrlas 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" },
      "availability": "in_stock",
      "protocol": "acp",
      "raw": { /* merchant's native shape, untouched */ }
    }
  ],
  "fetchedAt": "2026-05-15T10:00:00.000Z",
  "cached": false,
  "tier": "verified"
}

The rawfield on each SKU is the merchant's native protocol shape, preserved verbatim. Drop down to it when the canonical fields elide something protocol-specific.

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.

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 toolPurposeActionWhen fired
discover_catalogshoppingshopping.searchCatalog browse, merchant filtering, SKU search.
start_checkoutshoppingshopping.purchaseCart → checkout transition (intent mandate issued).
confirm_purchaseshoppingshopping.purchaseFinal purchase confirmation (same purpose — checkout-create and checkout-confirm are two phases of one shopping intent).
verify_agentidentitycaller-suppliedVerify-access check (allowed/denied + trust score). Pass an optional purpose (bare category; defaults to identity) and a required dotted-verb action.
list_merchantsdiscoverydiscovery.readBridge-discoverable merchant listing.
search_docsdiscoverydiscovery.readDocs / FAQ search.

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
shoppingshopping.search, shopping.purchaseCatalog browse/search; checkout create + confirm (one purchase intent)
identityidentity.verify, identity.lookupTrust/score verification; identity resolution
discoverydiscovery.readMerchant listing, docs search
datadata.read, data.write, data.deleteGeneric 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
  • allowedActions is required (min 1) — the evaluator is fail-closed on actions. categories is 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 the data category.

Structured denial shape

When start_checkout or confirm_purchasedenies 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

dimensionExample reason
agent.missingNo _meta.astrasync provided (transactional tools only)
agent.lookupagentId provided but not registered with AstraSync
agent.statusAgent deactivated or revoked
pdlss.purposeMerchant policy doesn't allow commerce.checkout.create for this agent
pdlss.limitsCart total exceeds the agent's autonomous threshold
pdlss.scopeMerchant URL outside the agent's allowed scope list
counterparty.allowlistMerchant requires allowlist + caller not on it
counterparty.trustCaller's trust score below merchant's floor
attestation.typePayment-mandate type not accepted by merchant
endpoint.deactivatedMerchant endpoint deactivated
upstream.validation_failedPlatform reached but rejected the request as invalid — fix the input, then retry
upstream.auth_failedPlatform rejected the bridge credentials (authentication)
upstream.access_deniedPlatform reached but denied access for this call (authorization)
upstream.unexpected_statusPlatform returned an unexpected 4xx — inspect the body before retrying
system.platform_unreachableMCP 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.