Public
Like
mcp-registry-subregistry-api
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
I want to create an MCP Subregistry API using the following tech stack:
- GET /v0/servers — List all servers with pagination
- GET /v0/servers/{serverName} — Get the latest version of a server (URL-encoded)
- GET /v0/servers/{serverName}/versions — List all versions of a server
- GET /v0/servers/{serverName}/versions/{version} — Get a specific version (both parameters URL-encoded)
- Read operations: No authentication required
- Write operations: Namespace-scoped bearer token issued via official auth exchanges Content Typek
All requests and responses use application/json
The canonical OpenAPI contract now mirrors the upstream 2025-09-29 MCP registry spec. The faith.tools subregistry layers optional features on top:
- Extended query parameters on
GET /v0/servers
:search
— simple LIKE-based token search (subregistry only)updatedSince
,version
— enable incremental syncs (documented outside the base spec)
- Auth token exchange endpoints (not part of the upstream spec):
- POST /v0/auth/github-at
- POST /v0/auth/github-oidc
- POST /v0/auth/dns
- POST /v0/auth/http
- POST /v0/auth/oidc
- Observability/admin:
- GET /metrics — Prometheus metrics endpoint exporting registry counters (publish/update/auth exchange) and uptime
- GET /v0/health — Enhanced status payload with uptime, metrics summary, and timestamp
- Marketplace metadata:
- Publisher-provided
_meta
may includemarketplaceIcon
- Registry-managed
_meta.io.modelcontextprotocol.registry/official.marketplaceIcon
stores cached blob references
- Publisher-provided
Clients should treat these additions as optional subregistry features.
List endpoints use cursor-based pagination for efficient, stable results.
- Initial request: Omit the cursor parameter
- Subsequent requests: Use the nextCursor value from the previous response
- End of results: When nextCursor is null or empty, there are no more results
Important: Always treat cursors as opaque strings. Never manually construct or modify cursor values.
- Val Town compatibility: We proxy every statement through
sqlite.execute(...)
, matching the Val Town SQLite migration guidance. Schema bumps create new_poc_vN
tables instead of runningALTER TABLE
, and the Drizzle sqlite-proxy adapter is just a typed wrapper around the same helper shown in the Val Town Drizzle ORM docs. - Schema highlights (
server_versions_poc_v2
): Core fields store canonical server metadata (server_name
,version
, timestamps, status), whilesearch_text
plus supporting indices power LIKE filtering. Optional columns cache blob icon references and MCP capability flags as JSON strings for future expansion. Seebackend/database/migrations.ts
for the full definition. - Query behavior: All writes validate against the SDK Zod schemas, recompute
is_latest
, and derive search tokens before persisting. Reads enforce the same schemas, use cursor-based pagination (base64url ofupdatedAt
,serverNameLower
,version
), and currently treat blob columns as placeholders until the blob ingestion plan lands.
- Validate the Open API spec is 100% up to date with upstream 2025-09-29 release
- Create database tables that meet the Open API spec using Val.Town SQLite/Blobs and the Zod types in
npm:mcp-registry-spec-sdk
- Create Hono endpoints (additional integration tests pending)
- Wire marketplaceIcon ingestion into publish/update flows
- Implement official auth exchanges (GitHub/DNS/HTTP/OIDC) and namespace enforcement
- Enforce package ownership, remote URL, registry allowlist, and
_meta
constraints during publish/update - Add
/metrics
endpoint and enhanced health checks, then update README/testing guidance
- Publish a new server via POST /v0/publish and confirm the response validates against the SDK schema.
- Publish a server with a remote/data-URL
marketplaceIcon
and verifyblobIconKey/blobIconMime
plus the cached pointer in_meta
. - Fetch GET /v0/servers/{serverName} to verify the latest version flag (
is_latest
) is set correctly. - List versions with GET /v0/servers/{serverName}/versions and ensure ordering by
published_at
+id
. - Page through GET /v0/servers with and without
cursor
, confirmingnextCursor
progression. - Exercise search by passing tokenized
search
terms and verifying LIKE-based filtering onsearch_text
. - Update an existing version via PUT /v0/servers/{serverName}/versions/{version} and confirm derived fields recompute, while timestamps behave as expected.
- Update a version that already has a cached icon and ensure the blob rotates (old key deleted, new key present).
- Invoke GET /v0/health and confirm uptimeSeconds/timestamp/metrics keys reflect recent activity.
- Scrape GET /metrics and validate Prometheus exposition format includes publish/update/auth counters and uptime gauge.
- Running
deno check main.ts
locally requires allowing remote imports (deno check --allow-import main.ts
) to satisfy Val Town SDK dependencies.
Hey, I'm Cam Pak. Let me know how I can make this better for you.