DMC-12 Mark Miller Subaru / dmc-12 guide
endpoint live · DMC-12 v0.6 · 11 tools

Partner onboarding

Partner access is granted, not self-served. You email us, we provision an Auth0 machine-to-machine client and seed your agent row, and you're live the same day. Here's the whole flow and the credential bundle you'll receive.

1. Email Ben

Onboarding starts with an email to benr@mmsubaru.com (or mm_reports@mmsubaru.com, subject [mm-inv-mcp onboarding] <your org>). Include your legal entity, a named technical contact, your use case, and the scopes you need. Triage takes about 10 minutes; total turnaround from triage to live is typically under an hour.

2. The credential bundle

We deliver these values over a secure channel (1Password time-bounded share or Bitwarden Send — never plain email or Slack).

FieldValue
Auth0 tenantmmbrain-prod.us.auth0.com
Token endpointhttps://mmbrain-prod.us.auth0.com/oauth/token
Grant typeclient_credentials
Audiencemm-inventory-mcp
Signing algRS256
Token TTL3600 s (1 hour)
client_id / client_secretunique per partner — delivered securely
Your sub at the service<client_id>@clients
A2A endpoint/a2a/
Two JWKS — don't confuse them Auth0 JWKS (mmbrain-prod.us.auth0.com/.well-known/jwks.json) verifies the access tokens Auth0 issues. The service JWKS (/.well-known/jwks.json) verifies the Agent Card signature. You consume both, for different things.

3. Mint a token

A2A_BEARER=$(curl -s -X POST https://mmbrain-prod.us.auth0.com/oauth/token \
  -H 'content-type: application/json' \
  -d '{
    "client_id":     "<your client_id>",
    "client_secret": "<your client_secret>",
    "audience":      "mm-inventory-mcp",
    "grant_type":    "client_credentials"
  }' | jq -r .access_token)

Auth0 returns a standard client-credentials token response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6…",   // the RS256 JWT — send as Bearer
  "expires_in": 3600,                                  // seconds; re-mint before this elapses
  "token_type": "Bearer",
  "scope": "inventory:read quote:write reservation:write deal:handoff pricing:read"
}
FieldTypeDescription
access_tokenstringThe RS256 JWT. Send as Authorization: Bearer <access_token> on every /a2a/ call.
expires_inintLifetime in seconds (3600). Cache and re-mint before it lapses.
token_typestringAlways Bearer.
scopestringSpace-delimited granted scopes. Your effective set at call time is this ∩ your agent row (see §5).

Cache the token ~55 minutes and re-mint before expiry. Minting on every request will get you rate-limited at Auth0.

4. Call a tool

curl -X POST …/a2a/ \
  -H "Authorization: Bearer $A2A_BEARER" \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc": "2.0", "id": 1, "method": "tools/call",
    "params": { "name": "search_inventory",
                "arguments": { "query": "2024 Outback AWD under 35k", "limit": 5 } }
  }'

The dry-run that completes onboarding is exactly this call: you mint a token and hit search_inventory; we confirm your trace_id in the audit log and flip your agent row to active = true.

5. The scopes we issue you

The default partner bundle is five scopes. We grant the minimum that covers your use case; tell us during triage if you need less.

ScopeUnlocksPII?
inventory:readsearch_inventory, get_vehicle_by_vin, list_inventory, check_availabilityno
quote:writerequest_quoteno (opaque buyer_ref)
reservation:writecreate_reservation, release_reservation, get_reservation_statusno (opaque customer_ref)
deal:handoffinitiate_deal_handoffyes — name, phone, email
pricing:readget_pricing_disclosure (+ OTD on quotes)no
Effective scope = DB row ∩ JWT grant Your permissions at call time are the intersection of the scopes seeded on your agent row and the scopes present in the token you minted. A token requested with only inventory:read cannot reserve, even if your row grants reservation:write. Mint tokens with exactly the scopes the session needs. An empty intersection returns NOT_AUTHORIZED.
quote:negotiate is not issued at MM The negotiation scope is only meaningful on negotiation-enabled deployments. MM runs with negotiation off, so it is not part of the bundle and the four negotiation tools are not registered.

6. Rate limits & audit

BudgetDefaultCeiling (on request)
Requests / minute (burst)60600
Reservations / day5100
Audit retention90 days365 days (with agreement)

Rate-limit denials come back in the envelope as RATE_LIMITED (retryable), not as a JSON-RPC error. Every response carries _metadata.trace_idlog it; it is the only way we can correlate a complaint against the 90-day audit trail. Quote your trace_id and any error_id in incident email.

Backoff on RATE_LIMITED Treat RATE_LIMITED as retryable: exponential backoff with jitter (e.g. ~1s, 2s, 4s … capped, plus a random fraction) and a sane max-attempt ceiling — don't hot-loop. Stay under your per-minute burst rather than relying on retries. Note the reservation budget is separate from the rate limit: create_reservation charges your daily reservation budget, and a same-UTC-day release_reservation refunds that slot — so a held-then-released VIN within the day costs nothing against the budget. See the error taxonomy for which codes are retryable.

7. Lifecycle

Reference material Spec source: github.com/mm-open/dmc-12 · served spec: dmc12.ai/specification/SPEC.md · schemas: dmc12.ai/schemas/{capability}.json.
copied