Appearance
Available MCPs Catalog API
The available MCPs catalog is a platform-curated list of known remote MCP servers. Authenticated users can browse and filter it; platform admins manage entries via mutations.
When a user selects a catalog entry from the UI, the frontend calls the existing POST /ai/agents/:agentId/mcp-servers endpoint with the optional availableMcpId, variantType, and credentials fields — the catalog entry is NOT provisioned through this endpoint directly.
All paths below are not under the /ai prefix — the catalog is a top-level resource.
Authentication Model
| Endpoint | Auth Required | Policy Required |
|---|---|---|
GET /available-mcps | JWT (@Auth()) | None — any valid session |
POST /available-mcps | JWT + platform.ai.available-mcp create | Platform Admin role |
PATCH /available-mcps/:id | JWT + platform.ai.available-mcp update | Platform Admin role |
DELETE /available-mcps/:id | JWT + platform.ai.available-mcp delete | Platform Admin role |
Requests without a valid Authorization: Bearer <jwt> header return 401. Authenticated users without the platform policy return 403.
GET /available-mcps
Returns all active catalog entries. Optionally filtered by tags (OR semantics).
Query Parameters
| Parameter | Type | Description |
|---|---|---|
tags | string[] | Optional. Filter entries by tags. Returns entries matching any of the provided tags (OR semantics). Example: ?tags[0]=crm&tags[1]=payments |
page | number | Optional. Pagination page (default: 1). |
limit | number | Optional. Page size (default: 20). |
sort | string | Optional. Sort field and direction. Example: sort[0][field]=createdAt&sort[0][direction]=desc |
Response — 200 OK
Returns an array of AvailableMcpDto objects. Returns [] (not 404) when no entries match.
json
[
{
"id": "019f3a...",
"name": "GitHub",
"description": "Connect to GitHub to manage repositories, issues, pull requests, and more.",
"logo": "/mcp-logos/github.svg",
"tags": ["dev-tools"],
"variants": [
{
"type": "apikey",
"url": "https://api.githubcopilot.com/mcp/",
"transportType": "http",
"credentialSchema": {
"type": "apikey",
"fields": [
{
"key": "apiKey",
"label": "GitHub Personal Access Token",
"type": "password",
"required": true,
"placeholder": "Enter your API key"
}
]
}
}
],
"isActive": true,
"createdAt": "2026-04-16T00:00:00.000Z",
"updatedAt": "2026-04-16T00:00:00.000Z"
}
]Inactive Entries
Entries with isActive: false (soft-deleted) are never returned by this endpoint.
POST /available-mcps
Creates a new catalog entry. Platform Admin only.
Request Body
json
{
"name": "My MCP",
"description": "A description of what this MCP does.",
"logo": "/mcp-logos/my-mcp.svg",
"tags": ["dev-tools"],
"variants": [
{
"type": "apikey",
"url": "https://api.example.com/mcp",
"transportType": "http",
"credentialSchema": {
"type": "apikey",
"fields": [
{
"key": "apiKey",
"label": "API Key",
"type": "password",
"required": true
}
]
}
}
]
}Validation Rules
name— non-empty, unique (conflict returns409)tags— at least one non-empty stringvariants— at least one variant required (422otherwise)apikeyvariant — must have at least one field incredentialSchema.fieldsfreeandoauthvariants —credentialSchema.fieldsmust be empty
Response — 201 Created
Returns the full AvailableMcpDto including the generated id.
PATCH /available-mcps/:id
Partially updates a catalog entry. All fields are optional. Platform Admin only.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | UUID v7 | The catalog entry ID |
Request Body
All fields are optional — only provided fields are updated.
json
{
"tags": ["crm", "productivity"],
"logo": "/mcp-logos/updated.svg"
}Response — 200 OK
Returns the full updated AvailableMcpDto.
Errors
404— Entry not found
DELETE /available-mcps/:id
Soft-deletes a catalog entry by setting isActive = false. Platform Admin only.
Hard delete is not supported — existing agent_mcp_servers rows referencing the entry via available_mcp_id would be orphaned. The ON DELETE SET NULL FK constraint handles the FK side, but the catalog record must remain for audit purposes.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | UUID v7 | The catalog entry ID |
Response — 200 OK
Returns the updated AvailableMcpDto with isActive: false.
Errors
404— Entry not found
Variant Schema (Discriminated Union)
Each variant in variants[] is a discriminated union on the type field:
type | Auth model | credentialSchema.fields |
|---|---|---|
free | No auth | Must be empty [] |
apikey | Static headers | Must have ≥1 field |
oauth | OAuth 2.0 / PKCE | Must be empty [] |
Credential Field Schema
For apikey variants, each field in credentialSchema.fields has:
| Property | Type | Description |
|---|---|---|
key | string | Unique key within the variant. Used as the credential map key. |
label | string | Display label shown in the UI. |
type | "text" | "password" | "header" | UI input type. password fields are masked. |
required | boolean | Whether the field is required when provisioning. |
placeholder | string? | Optional input placeholder text. |
helpText | string? | Optional helper text shown below the input. |
default | string? | Optional default value pre-filled in the UI. |
Tag Filter — OR Semantics
The tags query parameter uses OR semantics: an entry is returned if its tags array overlaps with any of the requested tags.
Example: GET /available-mcps?tags[0]=crm&tags[1]=payments
Returns entries tagged [crm], [payments], or [crm, payments]. All three qualify because at least one tag matches.
This is implemented using PostgreSQL's && array overlap operator with a GIN index on the tags column for performance.
Handoff: Adding a Catalog Entry to an Agent
To provision an AgentMcpServer row from a catalog entry, call the existing endpoint:
POST /ai/agents/:agentId/mcp-serversWith the optional catalog fields:
json
{
"name": "GitHub (my project)",
"url": "https://api.githubcopilot.com/mcp/",
"transportType": "http",
"availableMcpId": "019f3a...",
"variantType": "apikey",
"credentials": {
"apiKey": "ghp_xxxxxxxxxxxxx"
}
}The handler will:
- Load the catalog entry by
availableMcpId - Find the variant matching
variantType - Validate required credential fields (returns
422with missing field names if incomplete) - Map variant type →
McpAuthType:free → none,apikey → static_headers,oauth → oauth - Save the
AgentMcpServerwith theavailable_mcp_idFK set
For oauth variants, credentials can be empty — OAuth flow is initiated separately via POST /ai/agents/:agentId/mcp-servers/:serverId/oauth/initiate.
Seed Behavior
On every application bootstrap, AvailableMcpSeedLoader runs automatically and inserts the 23 curated entries if they do not yet exist.
| Property | Behavior |
|---|---|
| Natural key | name — entries are looked up by name before insert |
| Semantics | Insert-only — existing entries are skipped unchanged |
| Idempotent | Safe to run on every restart; count never exceeds 23 on repeat boots |
| Admin edits preserved | Tags, logo, and variant edits made via the API are never overwritten by the seed |
The seed covers: GitHub, Supabase, Postman, Context7, Stripe, Slack, Notion, HubSpot, Linear, Jira, Confluence, Airtable, Google Sheets, Google Calendar, Datadog, Sentry, Vercel, Netlify, Twilio, Zapier, Firecrawl, Browserbase, Semrush.
Note: A 24th entry slot is reserved pending product confirmation. It is intentionally absent from the seed to avoid a placeholder entry.