Browse the public MCP connector directory, register workspace-owned MCP servers, and call tools on connected servers.
Three surfaces work together:
| Surface | Endpoints | Purpose |
|---|---|---|
| Public directory | /mcps, /mcps/{slug} | Discover featured connectors (Linear, Slack, GitHub, …) |
| Workspace registrations | /mcp-servers | Register custom MCP server URLs for your workspace |
| Tool proxy | /mcps/{slug}/tools | List and invoke tools after OAuth or API-key connect |
Connecting (OAuth, API keys) uses POST /credentials with provider: "mcp" (requires credentials:write). This page covers directory browsing, workspace CRUD, discovery, and tool calls.
See REST overview — response format.
→ Browsing & connecting: CLI and web app workflows
→ Using connector tools — belt mcp tools and agent tool setup
Public directory
No API key required.
List MCP servers
GET /mcps or POST /mcps/list
Returns approved store listings sorted by rank. Accepts standard cursor-list parameters (cursor, limit, filters, sort, search) on POST.
Response (PublicMCPServerDTO):
| Field | Description |
|---|---|
id | Server ID |
slug | Short identifier (used in URLs and belt mcp connect {slug}) |
name | Stable identifier (often matches slug) |
title | Display name; falls back to name when empty |
description | Short summary |
icon_url | Server icon |
category | developer, productivity, data, communication, ai, or other |
server_url | MCP endpoint URL |
auth_type | oauth, api_key, or none |
default_scopes | OAuth scopes requested on connect |
documentation_url | Vendor docs link |
namespace | Publisher namespace |
is_featured, rank | Store placement |
installs, uses | Usage counters |
connection_status | connected when you or your workspace have a connected MCP credential for this server_url. Omitted otherwise. The match compares server_url with the credential's account_identifier. |
Send an API key or session on list and get calls to receive connection_status. Unauthenticated directory requests omit it.
1curl "https://api.inference.sh/mcps?limit=20"Get by slug
GET /mcps/{slug}
Returns one public listing. Responds 404 when the slug is not in the directory.
1curl https://api.inference.sh/mcps/linearDiscover server metadata
GET /mcps/discover?url={url}
Proxy for MCP remote discovery. Use this from custom UIs when browser CORS blocks direct fetches to /.well-known/mcp-server-card or OAuth metadata endpoints.
No API key required. The API tries, in order:
GET {origin}/.well-known/mcp-server-card(MCP server card)- OAuth protected-resource metadata on the URL
Returns the JSON document with Cache-Control: public, max-age=300. Responds 404 when neither document is found.
| Query | Required | Description |
|---|---|---|
url | Yes | http or https URL (typically a bare origin like https://mcp.example.com) |
1curl "https://api.inference.sh/mcps/discover?url=https://mcp.example.com"The same resolution runs automatically when you connect via CLI, the web app, or POST /credentials with a bare server_url origin.
Workspace MCP server registrations
Manage servers your workspace publishes or connects privately. Requires API key scopes credentials:read (list, get) and credentials:write (create, update, delete).
List workspace servers
GET /mcp-servers or POST /mcp-servers/list
Cursor-paginated list of MCP servers owned by the authenticated workspace. Same pagination shape as Skills. Returns MCPServerDTO objects (see below).
Get workspace server
GET /mcp-servers/{id}
Returns MCPServerDTO for one registration.
MCPServerDTO fields
| Field | Description |
|---|---|
id | Server ID |
user_id, team_id, visibility | Ownership and sharing |
slug | URL-safe identifier |
name | Stable identifier (often matches slug) |
title | Display name; falls back to name when empty |
description, icon_url | Listing metadata |
server_url | MCP endpoint URL |
auth_type | oauth, api_key, or none |
oauth_client_id | BYOK OAuth client ID when set |
default_scopes | OAuth scopes to request on connect |
headers | Static HTTP headers your workspace admins set on this registration. The platform sends them on every MCP request for this server_url (for example Azure DevOps X-MCP-Toolsets, X-MCP-Readonly). Non-secret only — never put tokens here. |
setup | Optional MCPServerSetup hints from the public directory for this server's host (see below). Omitted when the directory has no setup row for the host. |
documentation_url | Vendor docs link |
connection_status | connected when you or your workspace have a connected MCP credential for this server_url. Omitted otherwise. The match compares server_url with the credential's account_identifier. |
connection_scope | When connection_status is connected, who owns that login: user, team, org, or platform. Omitted when not connected. |
credentials | The credential the server declares it needs, same shape as an app's credentials: ([{slug, scopes, capabilities, …}], written as a map keyed by slug or a list). Each slug must name an auth provider your workspace can connect: a catalog slug, your team's own scheme, or an MCP server's provider such as <server-slug>-mcp. When set, connection_status means the caller has a connected login for that slug, and tool calls send that login's token (or API key, per the slug's auth method) instead of a server-specific MCP login. Empty for servers that still sign in the MCP-specific way. |
credential_slug | The first declared slug, for linking to the vault entry (/credentials/{slug}). Empty when the server declares nothing. |
List and get responses set connection_status and connection_scope from your MCP credentials, so a connect/disconnect UI does not need to merge GET /credentials/configs.
setup (MCPServerSetup)
Directory maintainers store setup metadata per MCP host (not per workspace registration). When you list or get a workspace server whose server_url shares a host with a directory entry, the API attaches that host's setup object so connect UIs can show vendor-specific guidance without hard-coding servers in the app.
| Field | Description |
|---|---|
resource_app_id | Application ID at the server's authorization server. Organizations need this before they can approve access (for Microsoft Entra: the application ID a tenant uses when creating a service principal). |
recommended_headers | Least-privilege static headers the vendor documents (same validation rules as workspace headers). The web app offers these as presets in the headers editor; GET /credentials/mcp/app also returns recommended_headers for MCP connect flows. |
Python types: MCPServerSetup on MCPServerDTO in inferencesh.types (inferencesh ≥ v0.14.3).
Create workspace server
POST /mcp-servers
Register a custom MCP server URL. The API enriches missing fields from the remote server card and OAuth discovery metadata, then declares the server's sign-in the way connect does: it creates or reuses the auth provider for the server's URL and sets credentials from what discovery found. A body that already sends credentials keeps them. A server that cannot be reached saves with no provider; set credentials later with update or refresh.
Body (common fields):
| Field | Required | Description |
|---|---|---|
server_url | Yes | MCP endpoint or bare origin (resolved via discovery when needed) |
name | No | Stable name (defaults from server card or hostname) |
title | No | Display title |
slug | No | URL-safe identifier (auto-generated from name when omitted) |
description | No | Short summary (max 200 characters; a description discovered from the server is clipped to the limit when the server is registered) |
auth_type | No | oauth (default), api_key, or none |
oauth_client_id | No | OAuth client ID when you bring your own client |
default_scopes | No | OAuth scopes to request |
headers | No | Static, non-secret HTTP headers on every MCP request (for example X-MCP-Toolsets, X-MCP-Readonly). At most 16 headers; values up to 1024 characters. Cannot override auth or MCP transport headers (Authorization, Mcp-*, and similar). |
credentials | No | The credential the server needs, as a map keyed by slug ({"aikido-mcp": {"scopes": ["issues:read"]}}) or a list of entries. Usually omitted on create, since discovery declares it. Validated like an app's credentials:, and each slug must name a provider your workspace can connect (see credentials on MCPServerDTO above). On update, a present value replaces the declaration and [] clears it. |
documentation_url | No | Link to vendor docs |
visibility | No | team (default) or public — team keeps the registration in your workspace; public lists it in the MCP directory |
Response: MCPServerCreateResponse:
| Field | Description |
|---|---|
id, slug, name, … | Created MCPServerDTO |
discovery | Optional hints for the connect UI (ready_to_connect, needs_credentials, cross_domain, cross_domain_issuer) |
Errors:
| HTTP | Code | Cause |
|---|---|---|
409 | already_exists | Duplicate slug within the workspace |
400 | validation_error | Invalid field values (credentials, headers, slug, …); detail names the field |
400 | invalid_request | A credentials slug names no provider; detail names it and adds leave the credential slug empty to set up sign-in from the server |
400 | create_failed | Any other discovery or input failure (for example a missing server_url), with the error text in detail |
402 / 403 | entitlement or refusal | Connector limit reached on your plan, a missing scope, or no manage_vault |
1curl -X POST https://api.inference.sh/mcp-servers \2 -H "Authorization: Bearer inf_your_key" \3 -H "Content-Type: application/json" \4 -d '{5 "server_url": "https://mcp.example.com",6 "name": "Example MCP",7 "visibility": "team"8 }'Register vs connect: Creating a server only registers its URL and who can see it. It does not share your OAuth login. Each person connects their own account afterward — see Browsing & connecting — custom MCP servers.
After create, connect with POST /credentials (provider: "mcp", metadata.server_url) or belt mcp connect — see Browsing & connecting.
Update workspace server
PUT /mcp-servers/{id}
Send only fields to change. Same field names as create.
For headers:
| Request body | Effect |
|---|---|
| Field omitted | Stored headers stay as they are |
"headers": { … } | Replaces the whole set (validated) |
"headers": {} | Clears all static headers |
Errors: the same codes as create (validation_error, invalid_request, refusals, 404 for an unknown server). Other failures answer 400 update_failed with the error text in detail. Nothing is saved when validation fails.
Update workspace server visibility
POST /mcp-servers/{id}/visibility
Changes who can see a workspace registration (not who can use your connection): your workspace only, or the public MCP directory. Requires credentials:write and the workspace manage_vault capability (same as create and update). Public servers get a store listing without sharing anyone's OAuth login — only the server registration is shared.
1{2 "visibility": "public"3}| Value | Description |
|---|---|
team | Only your workspace (default) |
public | Listed in the MCP directory; others can connect with their own credentials |
Response: Updated MCPServerDTO.
1curl -X POST "https://api.inference.sh/mcp-servers/mcp_abc123/visibility" \2 -H "Authorization: Bearer inf_your_key" \3 -H "Content-Type: application/json" \4 -d '{"visibility":"public"}'You can still set visibility on create; this endpoint updates an existing registration.
Refresh workspace server metadata
POST /mcp-servers/{id}/refresh
Re-runs MCP server card and OAuth discovery against the stored server_url, then persists updated fields. Requires credentials:write.
Use this when a registration has stale metadata — for example a hostname used as the display name, or an incorrect auth_type from before automatic discovery was wired in. The same enrichment logic runs on create; refresh applies it again without recreating the server.
CLI equivalent: belt mcp refresh <slug> (resolves the public directory slug to the server ID).
Response: same shape as Create workspace server: updated MCPServerDTO plus optional discovery hints.
Errors: the same codes as create (validation_error, invalid_request, refusals, 404 for an unknown server). Other discovery or save failures answer 400 refresh_failed with the error text in detail.
1curl -X POST "https://api.inference.sh/mcp-servers/mcp_abc123/refresh" \2 -H "Authorization: Bearer inf_your_key"Delete workspace server
DELETE /mcp-servers/{id}
Returns { "deleted": true }.
List and call tools
Requires authentication and an active credential for the server (credentials:read to list, credentials:write to call).
You must connect first — GET /mcps/{slug}/tools returns 400 mcp_error with not connected to {name} when no credential exists for that server's URL.
List tools
GET /mcps/{slug}/tools
Returns an array of MCP tool definitions:
| Field | Description |
|---|---|
name | Tool identifier |
title | Display title (optional) |
description | What the tool does |
inputSchema | JSON Schema for arguments. Per MCP (SEP-1613), schemas without "$schema" use the 2020-12 dialect; an explicit "$schema" (including draft-07) is respected. |
outputSchema | JSON Schema for results (optional) |
annotations | Optional MCP hints (title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint). Values come from the connected MCP server as returned by tools/list. |
1curl https://api.inference.sh/mcps/linear/tools \2 -H "Authorization: Bearer inf_your_key"Call tool
POST /mcps/{slug}/tools/{tool}
Body — JSON object of tool arguments (empty object when the tool takes no input).
Success — MCP tool result (content blocks and structured output). When the remote tool declares an MCP Apps page (SEP-1865), the response may also include:
| Field | Description |
|---|---|
ui.resource_uri | Resource URI from the tool's _meta.ui |
ui.html | Fetched HTML document (text/html;profile=mcp-app) |
ui.csp | Content-Security-Policy for the sandboxed iframe |
ui.prefers_border | When true, hosts may draw a border around the page |
ui.domain | Optional postMessage domain hint |
ui.page_hash | When the HTML is stored once in mcp_ui_pages, the inline ui.html is omitted and this SHA-256 key names the page (see Stored MCP Apps pages) |
Recorded runs (GET /mcp-tool-calls/{id}) keep the same ui payload (or ui.page_hash plus a fetch) so permalinks can reopen the page with the stored input and output. Nested tool calls from the page go back through the MCP proxy on the same connection — by directory slug when one exists, or by credential_id when it does not (see below).
Tool-level error — HTTP 200 with { "error": true, "content": "..." } when the remote server reports isError.
Connection errors — 400 not_connected or 502 mcp_error when the credential is missing or the remote call fails.
1curl -X POST https://api.inference.sh/mcps/linear/tools/list_issues \2 -H "Authorization: Bearer inf_your_key" \3 -H "Content-Type: application/json" \4 -d '{"teamId": "TEAM-123", "limit": 10}'Call tool by connection (credential_id)
POST /mcp-credentials/{credential_id}/tools/{tool}
Same request body, scopes (credentials:write), audit row, usage policy, and response shape as Call tool. Use this when the MCP server is not in the public directory (no resolvable /mcps/{slug}) but you have a connected MCP credential — for example an MCP Apps page in chat that must proxy follow-up tools/call on the same connection.
The caller must be allowed to use that connection: their own, their workspace's, their org's, or a platform-wide MCP credential. A teammate's personal connection is never used directly; the API substitutes the caller's own connection to the same server_url when possible, or responds 403 when they must connect their own account.
1curl -X POST "https://api.inference.sh/mcp-credentials/cred_abc123/tools/list_issues" \2 -H "Authorization: Bearer inf_your_key" \3 -H "Content-Type: application/json" \4 -d '{"limit": 10}'Read MCP Apps resource by connection
POST /mcp-credentials/{credential_id}/resources/read
Proxies MCP resources/read to the server behind the credential. Only ui:// URIs are accepted (MCP Apps pages and their parts). Requires credentials:read. The body matches MCPResourceReadRequest:
1{ "uri": "ui://vendor.example/widget.html" }Responses follow MCP resources/read (contents array). Total payload size is capped at 2 MiB, the same limit as tool-result UI fetch. Blocked servers are rejected under the same usage policy as tool calls (even though no tool-call row is written). Unknown credentials, non-MCP credentials, and unreachable connections respond 404 with a generic not-found message so credential IDs cannot be probed.
Stored MCP Apps pages
Large MCP Apps HTML is stored once under a content hash (SHA-256 over HTML plus framing metadata). Tool-call records and chat widgets reference the page with ui.page_hash instead of repeating ui.html.
Get stored page
GET /mcp-ui-pages/{hash}
Returns MCPUIPageDTO (html, csp, prefers_border, domain, created_at). Requires credentials:read. You may read a page only when you can see at least one MCP tool-call record that rendered with that hash; otherwise the API responds 404 (same response for unknown hashes, so hashes cannot be enumerated). Responses are cacheable (Cache-Control: private, max-age=31536000, immutable) because a hash always names the same document.
Chat embeds that already carry inline HTML do not need this route; it is for permalinks, audit views, and clients that received only page_hash on the tool call.
JavaScript SDK
1import { inference } from '@inferencesh/sdk';23const client = inference({ apiKey: process.env.INFERENCE_API_KEY });45// Public directory6const directory = await client.mcpServers.list({ limit: 20 });7const linear = await client.mcpServers.get('linear');89// Team-owned registrations10const owned = await client.mcpServers.listOwned();11const created = await client.mcpServers.create({12 server_url: 'https://mcp.example.com',13 name: 'Example MCP',14});1516// Tools (requires connect first)17const tools = await client.mcpServers.listTools('linear');18const result = await client.mcpServers.callTool('linear', 'list_issues', { limit: 10 });MCP tool call history
GET /mcp-tool-calls (cursor-paginated) returns MCPToolCallDTO records for connector tool invocations. Requires credentials:read.
When a remote tool declares an MCP Apps page in _meta.ui.resourceUri, the platform fetches that ui:// resource at call time (up to 2 MiB), stores the document in mcp_ui_pages, and attaches a reference on the record:
| Field | Description |
|---|---|
ui.resource_uri | The ui:// URI from the tool definition or result |
ui.html | Fetched HTML when the record was written before hash storage, or on live responses before persistence |
ui.page_hash | Content hash when the HTML is stored once; fetch with GET /mcp-ui-pages/{hash} |
ui.csp, ui.domain, ui.prefers_border | Framing hints from the resource _meta.ui block |
Chat and audit clients use this to render connector widgets the same way an MCP host would after tools/call. Follow-up tool calls and resources/read from the page use POST /mcp-credentials/{credential_id}/tools/{tool} and POST /mcp-credentials/{credential_id}/resources/read when no directory slug applies. See inference shell as an MCP server — MCP Apps.
Related APIs
| Need | Endpoint / guide |
|---|---|
| OAuth connect and disconnect | POST /credentials with provider: "mcp" — Browsing & connecting |
| Tool call audit history | GET /mcp-tool-calls (same credentials:read scope) |
| Add tools to agents | Connector tools |
| CLI workflows | Browsing & connecting |