[requires: nothing — public]
A2AWire ships connector products — Spend Guard is #001 — and each one needs
a home on the web. The URL rule is one sentence, and it is a directive, not
a preference: connector URLs name the connector, never the platform.
Connectors are apps; platforms (Muse, Grok) are app stores. An app store
name in an app's URL ages badly — the day Spend Guard ships on Grok, a
/muse/ URL stops describing anything.
This tutorial is the developer's map of that structure: the canonical URLs, the legacy redirect that keeps every published link alive, and the registry-driven wiring that makes connector #002 a data change instead of a routing project.
The canonical URLs#
| URL | What lives there |
|---|---|
https://a2awire.com/connectors/ | The portfolio index: one card per connector product |
https://a2awire.com/connectors/spend-guard/ | Connector #001's deep-dive page: setup steps, the verbatim setup prompt, REST and MCP doors |
https://a2awire.com/mcp/connectors/spend-guard/http | The connector's MCP endpoint (streamable HTTP, scoped to its own tools) |
https://a2awire.com/api/v1/connectors/spend-guard/bootstrap.sh | The reviewable bootstrap script for agents with no account |
Trailing-slash forms are canonical. Both pages are real prerendered content pages — their own title, description, canonical URL, and JSON-LD — not SPA shells, and they are not excluded from the sitemap.
The legacy /muse/ redirect#
Spend Guard's page originally lived at /muse/ (platform-named), and the
Muse directory submission — under review at the time of the move — links
that form. Every published link stays valid:
- Production 301s
/museand any/muse/...path to/connectors/spend-guard/at the CloudFront edge (cloudfront-functions/spa-edge.js), before trailing-slash canonicalization and before the prerendered-prefix logic — so/musewith no slash is one hop, not two. The querystring is preserved. - The React router carries a client-side
<Navigate to="/connectors/spend-guard/" replace />fallback for themusepath, covering local dev and hydration edge cases. - No
/musestatic shell is ever emitted: the prerender prefix list has nomuseentry, which is itself pinned by test.
A 301 (permanent) is the SEO-honest answer: the old URL's equity moves to the new one, and agents that cached the old link get one redirect, not a 404 or a soft relink.
The portfolio page is registry-driven#
/connectors/ renders entirely from frontend/src/lib/connectorsRegistry.ts
— the frontend-canonical registry of connector products. A registry entry
carries:
slug— matches theNNN-<slug>packet directory underconnectors/in the repo (connectors/001-spend-guard/:SUBMISSION.md,PROMPT.md,PROMPT-GROK.md).name,tagline(max 90 characters),icon— the card.status— exactly one global product status:live,directory-pending, orplanned("Live", "In directory review", "Coming soon").platforms— where the connector is reachable:muse,grok,generic-mcp("Any MCP client" — any streamable-HTTP MCP client via BYO-server settings).platformNotes— per-platform caveats, rendered as notes on the card, never as the status.href/promptHref/sortIndex— the deep-dive route, where the copy-paste setup prompt lives, and card order.
The status-honesty rule is the subtle one: Spend Guard is live as a
product while its Muse directory listing is still under review — that
review is a platformNotes.muse caveat ("Live as a custom connector; the
Muse directory listing is under review."), not a downgraded status. One
badge says what the product is; notes say what each platform's
process is doing.
Reachability is a platform list, not a platform name#
The platforms field is how a connector says where it can be used without
naming any platform in its URL. Today's set:
muse— Muse, as a custom connector (the three-step setup on the connector's page).grok— Grok, through grok.com's custom-connector flow (bring your own MCP server).generic-mcp— any streamable-HTTP MCP client (Claude, Cursor, ...) via BYO-server settings.
Spend Guard ships on all three, which is exactly the case the URL rule protects: a page named after one app store would undersell a product that lives in three.
Why the registry is frontend-canonical#
The registry lives in frontend/src/lib/connectorsRegistry.ts rather than
reading the repo-root connectors/ packets directly, because
cross-importing that directory is not viable in the Vite build. The
agreement is enforced from the other side instead:
tests/lib/connectorsRegistry.test.ts reads connectors/ on disk
(with fs) and fails when the registry and the packets drift — the
submission must exist, the names must match, the tagline must respect its
cap, the icon asset must be real. The data source and the drift test live
on opposite sides of the build boundary on purpose; neither side can
silently win.
What "prerendered" buys these pages#
Both /connectors/ and /connectors/<slug>/ are emitted as static HTML
at build time with their own <title>, meta description, canonical URL,
and JSON-LD — the portfolio page ships CollectionPage and
BreadcrumbList structured data, the deep-dive pages their own. Three
lists must agree for that to keep working, and tests pin the agreement:
lib/prerenderRoutes.ts— theconnectorstop-level prefix plus the nesting rule that prerenders every/connectors/<slug>/.cloudfront-functions/spa-edge.js— the same prefix mirrored, so the edge serves the prerendered HTML instead of the SPA shell.- The sitemap — connector routes are deliberately not excluded, so
/connectors/spend-guard/is a discoverable, canonical URL for crawlers and agents alike.
For an agent or a crawler the practical difference: a GET on
/connectors/spend-guard/ returns the real content page immediately —
no JavaScript bootstrap, no client-side route resolution.
Connector #002 is one entry plus one page#
The wiring is deliberately boring. The routing half of connector #002 is:
- One registry entry in
connectorsRegistry.ts. - One
connectors/002-<slug>/packet (submission + platform prompts).
No portfolio-page surgery, because /connectors/ maps over the registry —
the new card appears from the entry alone. No prerender surgery, because
lib/prerenderRoutes.ts prerenders every /connectors/<slug>/ via its
nesting rule (the same pattern as /content/<slug>/), emitting
/connectors/<slug>/index.html. No edge surgery, because
spa-edge.js mirrors the single top-level connectors prefix — a
three-list agreement (prerender prefixes, the edge function, and the
sitemap) that tests keep in lockstep. No sitemap surgery, because connector
routes are not on the exclusion list.
What connector #002 does still cost: its deep-dive page. App.tsx routes
each deep dive explicitly — today's entry is the literal path
connectors/spend-guard bound to that connector's own page component, not a
connectors/:slug dynamic route — so a second connector adds one page
component and one route entry under the same connectors prefix. The prefix
is what the three lists agree on; the page behind each slug is still
hand-authored. Budget one page, not a routing project.
Two drift tests hold the structure honest:
tests/lib/connectorsRegistry.test.ts reads connectors/ on disk and
fails if the registry and the packets disagree (the NNN-<slug> directory
must exist, the name must appear in the submission, the tagline must be
within the cap, the icon asset must exist), and
tests/seo/prerender-routes.test.ts pins the prerender/edge/mirror
agreement — including that /muse stays absent from the prefix list.
One disambiguation for backend readers#
/api/v1/connectors on the backend is a different, unrelated surface: the
foundry's write-only secret store (POST /api/v1/connectors stores an
LLM provider key, returns an opaque connector_id for manifests). It
shares the word, not the URL space — the public connector products live
under /connectors/ on the site and /mcp/connectors/{slug}/http on the
MCP rail, and neither is the foundry's keyed API.
Next Steps#
- Spending Guardrails for a Muse Agent (Spend Guard) — connector #001 in full: the tool semantics, REST and MCP examples, and the live validation script.
- Connecting via MCP — the general MCP endpoints, of which each connector's scoped endpoint is a sibling.
- Discovering A2AWire with agent.json — the machine-readable discovery document, the other half of how agents and clients find these surfaces.