API — Endpoints#
Base URL defaults to http://localhost:443.
This Hub stores a catalog of manifests (agents/tools/mcp_servers), installs artifacts, and syncs MCP servers into MCP-Gateway. Mutating endpoints require an admin token if API_TOKEN is set.
Auth#
When API_TOKEN is configured in the Hub:
Authorization: Bearer <API_TOKEN>
Admin-only endpoints below are marked accordingly.
GET /health#
Check service health.
Query params
check_db(bool, optional): also checks DB connectivity.
200 Response
{ "status": "ok", "db": "ok" }
GET /catalog/search#
Hybrid search with filters (keyword/semantic/hybrid). Also handy for listing ingested items.
Query params
q(string, optional): text querytype(string, optional):agent|tool|mcp_servercapabilities(CSV, optional)frameworks(CSV, optional)providers(CSV, optional)mode(string, optional):keyword|semantic|hybrid(default:hybrid)limit(int, default:20)with_rag(bool, optional): include a brief fit explanation
200 Response (truncated)
{
"items": [
{
"id": "agent:pdf-summarizer@1.4.2",
"type": "agent",
"name": "PDF Summarizer",
"version": "1.4.2",
"summary": "...",
"capabilities": ["pdf", "summarize"],
"frameworks": ["langgraph"],
"providers": ["watsonx"],
"score_lexical": 0.8,
"score_semantic": 0.7,
"score_final": 0.79,
"fit_reason": "Matches 'summarize pdfs'..."
}
],
"total": 1
}
Useful scripts
# Lists all ingested entities as a table from the DB (falls back to API)
scripts/list_ingested.sh
# JSON output only
FORMAT=json scripts/list_ingested.sh
# Only MCP servers
TYPE=mcp_server scripts/list_ingested.sh
GET /catalog/entities/{id}#
Return full metadata for an entity (resolved from the ingested manifests).
Example
GET /catalog/entities/agent:pdf-summarizer@1.4.2
404 if not found.
POST /catalog/install (admin)#
Execute an install plan (artifacts/adapters) and best-effort MCP-Gateway registration when mcp_registration is present.
Body
{
"id": "mcp_server:hello-sse-server@0.1.0",
"target": "./apps/hello",
"manifest": { ... } // optional; if provided, it will be saved to DB
}
Notes
idmust be<type>:<slug>@<version>and match the manifest.-
If
manifestis provided inline: -
It is persisted as a catalog
Entity. mcp_registrationis saved on the entity (used later by sync).- A
matrix.lock.jsonis written undertarget. - Best-effort gateway registration is attempted; errors are recorded in results and
entity.gateway_error.
200 Response (truncated)
{
"plan": { "artifacts": [...], "adapters": [...], "mcp_registration": {...} },
"results": [
{"step":"git.checkout","ok":true,"elapsed_secs":1.12},
{"step":"adapters.write","ok":true,"extra":{"skipped":true}},
{"step":"gateway.register","ok":true,"extra":{}},
{"step":"lockfile.write","ok":true,"extra":{"path":"/path/to/matrix.lock.json"}}
],
"files_written": ["matrix.lock.json"],
"lockfile": { "version": 1, "entities": [ ... ] }
}
Remotes (catalog sources)#
These endpoints manage remote catalog indexes (each is an index.json URL). When no remotes are stored, the Hub seeds them from MATRIX_REMOTES (CSV or JSON array) the first time you call GET /remotes or POST /remotes/sync.
GET /remotes#
List configured remotes. If DB is empty, this call seeds from MATRIX_REMOTES.
200 Response
{
"items": [{"url":"https://raw.githubusercontent.com/agent-matrix/catalog/main/index.json"}],
"count": 1
}
POST /remotes (admin)#
Add a remote index URL.
Body
{ "url": "https://example.com/catalog/index.json" }
201 Response
{ "added": true, "url":"https://example.com/catalog/index.json", "total": 3 }
DELETE /remotes (admin)#
Remove a remote index URL.
Body
{ "url": "https://example.com/catalog/index.json" }
200 Response
{ "removed": true, "url":"https://example.com/catalog/index.json", "total": 2 }
Ingest & Sync#
POST /ingest (admin)#
Manually trigger ingestion for one or all remotes.
Body
{ "url": "https://raw.githubusercontent.com/agent-matrix/catalog/main/index.json" }
// or omit "url" to ingest all remotes
200 Response (truncated)
{
"results": [
{ "url": "https://.../index.json", "ok": true, "stats": { "...": "..." } }
]
}
POST /remotes/sync (admin)#
End-to-end sync:
- Ensure remotes exist (seed from
MATRIX_REMOTESif empty). - Ingest each remote.
- Register new MCP servers into MCP-Gateway (Tool → Resources → Prompts → Gateway).
200 Response
{
"seeded": false,
"ingested": ["https://raw.githubusercontent.com/agent-matrix/catalog/main/index.json"],
"errors": { "https://bad.example/index.json": "HTTP 404 ..." },
"synced": true,
"count": 1
}
Gateways (pending → registered)#
These endpoints help you see what’s ingested but not yet registered in MCP-Gateway, and clean them up if needed.
GET /gateways/pending (admin)#
List ingested MCP servers with gateway_registered_at IS NULL.
Query params
limit(int, default:100, max1000)offset(int, default:0)
200 Response
{
"items": [
{
"uid": "mcp_server:watsonx-agent@0.1.0",
"name": "Watsonx Chat Agent",
"version": "0.1.0",
"source_url": null,
"has_registration": true,
"server_url": "http://127.0.0.1:6288/sse",
"transport": "SSE",
"gateway_error": "Resource response missing numeric 'id'"
}
],
"count": 1
}
Tip: This is exactly what scripts/list_pending_gateways.sh displays.
DELETE /gateways/pending/{uid} (admin)#
Delete a pending mcp_server by UID (does nothing if it’s already registered).
200 Response
{ "removed": true, "uid": "mcp_server:code@0.1.0" }
404 is not used; if the row can’t be deleted you get:
{ "removed": false, "uid": "mcp_server:code@0.1.0", "reason": "not found|not an mcp_server|already registered" }
POST /gateways/pending/delete (admin)#
Bulk delete pending MCP servers.
Body
{
"uids": ["mcp_server:watsonx-agent@0.1.0", "mcp_server:code@0.1.0"],
"all": false,
"error_only": false
}
- Provide either
uidsor setall=true. - With
error_only=true, only entities withgateway_errorare deleted.
200 Response
{
"removed": ["mcp_server:code@0.1.0"],
"skipped": { "mcp_server:watsonx-agent@0.1.0": "already registered" },
"total_removed": 1
}
Scripts (helpers)#
-
scripts/list_ingested.shLists all ingestedmcp_serverrows from the DB (falls back to/gateways/pendingif DB is unavailable). Shows status:PENDINGvsREGISTERED. -
scripts/list_pending_gateways.shCallsGET /gateways/pendingand prints a table. Exits with non-zero if any pending exist (useful in CI). -
scripts/verify_token.shVerifies your Hub → Gateway auth and lists/serversand/gatewayson MCP-Gateway. -
examples/register_watsonx_local_via_hub.shPushes an inlinemcp_servermanifest to the Hub and triggers/remotes/sync(which registers the server into MCP-Gateway).
Behavior notes#
- Inline install parity: an inline
manifestinPOST /catalog/installis now persisted in the DB, includingmcp_registration. The same fields drive/remotes/sync. - Gateway registration flow (on sync):
Tool → Resources → Prompts → Gateway. SSE endpoints are normalized to/messages/when appropriate. - Error visibility: sync errors are recorded in
entity.gateway_errorand surfaced byGET /gateways/pending.
Optional: Gateway pass-throughs#
If you run the Gateway locally, use the Gateway’s own API (auth header from scripts/verify_token.sh):
GET /healthGET /serversGET /gatewaysPOST /gateways(register a federated server)
These are not Hub endpoints; they belong to MCP-Gateway.
Status codes#
200OK201Created (POST /remotes)400Bad request (invalid body or params)401Unauthorized (missing/invalid token when required)404Not found (for entity lookups; delete-pending returns a soft reason instead)409Conflict (idempotent creates may translate to OK upstream)500Internal server error
Environment#
API_TOKEN— enables admin protection on mutating routes.MATRIX_REMOTES— CSV or JSON array of index URLs; used to seed remotes when empty.DATA_DIR/DB_PATH— wherecatalog.sqliteis stored (deployment-specific).- Gateway auth used by the Hub (for sync):
MCP_GATEWAY_URL,JWT_SECRET_KEY,BASIC_AUTH_USERNAME,MCP_GATEWAY_TOKEN.