# Custom MCP Servers

Connect any MCP-compatible server to the Responses API. The AI model discovers tools from your server at request time and can call them during the conversation.

## Two Ways to Connect

### 1. Inline (Per-Request)

Pass the MCP server URL directly in the `tools` array. No setup required — the server is contacted once for this request, its tools are discovered, and the AI can use them.


```json
{
  "model": "gpt-5",
  "inputs": [{ "role": "user", "content": "What's the weather in Zurich?" }],
  "tools": [
    {
      "type": "mcp",
      "server_label": "weather",
      "server_url": "https://weather-mcp.example.com/sse",
      "headers": {
        "X-API-Key": "your-api-key"
      }
    }
  ]
}
```

### 2. Saved Configuration (Reusable)

Save the server once via the MCP Configurations API, then reference it by ID. Credentials are encrypted at rest.

**Step 1 — Save the configuration:**


```bash
curl -X POST https://api.aitronos.com/v1/mcp-configurations \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Company CRM",
    "organization_id": "org_abc123",
    "server_url": "https://crm-mcp.example.com/sse",
    "transport_type": "sse",
    "auth_type": "bearer_token",
    "credentials": { "token": "sk-crm-secret-key" }
  }'
```

Response includes the `id` (e.g., `mcp_a1b2c3d4...`).

**Step 2 — Reference in requests:**


```json
{
  "model": "gpt-5",
  "inputs": [{ "role": "user", "content": "Show my recent deals" }],
  "tools": [
    {
      "type": "mcp",
      "server_label": "crm",
      "configuration_id": "mcp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
    }
  ]
}
```

## Tool Schema

Each MCP tool in the `tools` array requires:

| Field | Type | Required | Description |
|  --- | --- | --- | --- |
| `type` | `"mcp"` | Yes | Must be `"mcp"` |
| `server_label` | `string` | Yes | Unique label for this server within the request (alphanumeric + underscore, max 64 chars) |
| `server_url` | `string` | One of these | Direct URL to MCP server (`https://...`) |
| `configuration_id` | `string` | required | Reference to a saved MCP configuration (`mcp_...`) |
| `authorization` | `string` | No | Authorization header value (e.g., `"Bearer sk-..."`) — only with `server_url` |
| `headers` | `object` | No | Additional HTTP headers to send to the MCP server — only with `server_url` |
| `allowed_tools` | `string[]` | No | Restrict which tools from this server the AI can use. Omit to allow all. |


You must provide exactly one of `server_url` or `configuration_id`, not both.

## How It Works


```
Request with MCP tool
        │
        ▼
┌─────────────────────────┐
│ 1. Connect to MCP server│
│ 2. List available tools │  (10s timeout)
│ 3. Add to AI's toolset  │
└────────────┬────────────┘
             ▼
┌─────────────────────────┐
│ AI generates response   │
│ May call MCP tools      │──▶ MCP Server executes tool
│ Receives tool results   │◀── Returns result
│ Continues response      │
└─────────────────────────┘
```

1. Before generating a response, the API connects to your MCP server and calls `tools/list` to discover available tools.
2. The discovered tools are added to the AI model's available tools alongside any other tools (functions, connectors, web search).
3. If the AI decides to use an MCP tool, the API calls your server's `tools/call` endpoint and feeds the result back to the model.


Tool names are automatically prefixed with `reqmcp_{server_label}__` to avoid collisions between multiple servers.

## Multiple Servers

You can connect multiple MCP servers in a single request:


```json
{
  "model": "gpt-5",
  "inputs": [{ "role": "user", "content": "Draft an email about our latest GitHub issues" }],
  "tools": [
    {
      "type": "mcp",
      "server_label": "github",
      "server_url": "https://github-mcp.example.com/sse",
      "authorization": "Bearer ghp_xxxx"
    },
    {
      "type": "mcp",
      "server_label": "email",
      "configuration_id": "mcp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
    }
  ]
}
```

## Mixing Tool Types

MCP tools work alongside other tool types in the same request:


```json
{
  "model": "gpt-5",
  "inputs": [{ "role": "user", "content": "Search the web for MCP servers, then check our CRM for related contacts" }],
  "system_tools": {
    "web_search": { "mode": "auto" }
  },
  "tools": [
    {
      "type": "mcp",
      "server_label": "crm",
      "configuration_id": "mcp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
    },
    {
      "type": "function",
      "name": "format_report",
      "description": "Format data into a report",
      "parameters": {
        "type": "object",
        "properties": {
          "data": { "type": "string" },
          "format": { "type": "string", "enum": ["markdown", "html"] }
        }
      }
    }
  ]
}
```

## Filtering Tools

Use `allowed_tools` to restrict which tools from a server the AI can access:


```json
{
  "type": "mcp",
  "server_label": "github",
  "server_url": "https://github-mcp.example.com/sse",
  "allowed_tools": ["list_issues", "get_issue", "search_code"]
}
```

This is useful when a server exposes many tools but you only want the AI to use a specific subset.

## Authentication Options

### No Auth


```json
{
  "type": "mcp",
  "server_label": "public_data",
  "server_url": "https://public-mcp.example.com/sse"
}
```

### Bearer Token (inline)


```json
{
  "type": "mcp",
  "server_label": "private_api",
  "server_url": "https://api-mcp.example.com/sse",
  "authorization": "Bearer sk-your-secret-key"
}
```

### API Key via Headers (inline)


```json
{
  "type": "mcp",
  "server_label": "service",
  "server_url": "https://service-mcp.example.com/sse",
  "headers": {
    "X-API-Key": "your-api-key"
  }
}
```

### Saved Configuration (encrypted)

For production use, save credentials via the MCP Configurations API. Credentials are encrypted at rest and never returned in API responses.


```json
{
  "type": "mcp",
  "server_label": "production_service",
  "configuration_id": "mcp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
}
```

## MCP Configurations API

Manage saved MCP server configurations for your organization.

### Create Configuration


```
POST /v1/mcp-configurations
```


```json
{
  "name": "My CRM Server",
  "organization_id": "org_abc123",
  "server_url": "https://crm-mcp.example.com/sse",
  "transport_type": "sse",
  "auth_type": "bearer_token",
  "credentials": { "token": "sk-secret" },
  "tool_configuration": {
    "allowed_tools": ["search_contacts", "create_note"]
  }
}
```

| Field | Type | Required | Description |
|  --- | --- | --- | --- |
| `name` | `string` | Yes | Display name (max 255 chars) |
| `organization_id` | `string` | Yes | Organization this config belongs to |
| `server_url` | `string` | Yes | HTTPS URL to MCP server |
| `transport_type` | `string` | Yes | `"sse"` or `"streamable_http"` |
| `auth_type` | `string` | Yes | `"none"`, `"api_key"`, `"bearer_token"`, or `"oauth"` |
| `credentials` | `object` | No | Authentication credentials (encrypted at rest) |
| `tool_configuration` | `object` | No | Tool filtering config (e.g., `{"allowed_tools": [...]}`) |


### List Configurations


```
GET /v1/mcp-configurations?organization_id=org_abc123
```

### Test Connection


```
POST /v1/mcp-configurations/{id}/test
```

Returns connection status and list of discovered tools.

### Update / Delete


```
PUT /v1/mcp-configurations/{id}
DELETE /v1/mcp-configurations/{id}
```

## Building an MCP Server

Your MCP server must implement the [Model Context Protocol](https://modelcontextprotocol.io/) specification. At minimum:

1. **`tools/list`** — Return the list of available tools with their names, descriptions, and input schemas.
2. **`tools/call`** — Execute a tool with the given arguments and return the result.


### Transport

The API connects to your server via **Streamable HTTP** — it sends JSON-RPC 2.0 POST requests directly to your server URL. Your server must accept `POST` requests with `Content-Type: application/json` and return JSON-RPC responses.

The API tries these endpoint paths in order: `/mcp`, `/sse`, then the root URL. If your `server_url` already ends with `/mcp` or `/sse`, it is used directly.

### Example Server (Python)


```python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("My Tools")

@mcp.tool()
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    # Your implementation here
    return f"Weather in {city}: 22C, sunny"

@mcp.tool()
def search_database(query: str, limit: int = 10) -> list[dict]:
    """Search the internal database."""
    # Your implementation here
    return [{"id": 1, "name": "Result 1"}]

if __name__ == "__main__":
    mcp.run(transport="streamable-http")
```

### Example Server (TypeScript)


```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";

const server = new McpServer({ name: "My Tools", version: "1.0.0" });

server.tool("get_weather", { city: { type: "string" } }, async ({ city }) => {
  return { content: [{ type: "text", text: `Weather in ${city}: 22C, sunny` }] };
});

// Serve via Streamable HTTP on port 3000
const transport = new StreamableHTTPServerTransport("/mcp");
await server.connect(transport);
```

## Limits and Timeouts

| Limit | Value |
|  --- | --- |
| Tool discovery timeout | 10 seconds |
| Tool execution timeout | 30 seconds |
| Max MCP servers per request | No hard limit (but more servers = more latency) |
| `server_label` max length | 64 characters |
| `server_label` allowed chars | `a-z`, `A-Z`, `0-9`, `_` |


## Troubleshooting

### Server Not Responding

If tool discovery times out (10s), the MCP tools are silently skipped and the AI responds without them. Check:

- Server is reachable from the internet
- URL points to the correct SSE/HTTP endpoint
- TLS certificate is valid


### Tools Not Appearing

If the AI doesn't use your MCP tools:

- Verify `tools/list` returns tools with clear descriptions
- Check that `allowed_tools` isn't filtering them out
- Ensure tool input schemas are valid JSON Schema


### Authentication Errors

If using a saved configuration:

- Test the connection via `POST /v1/mcp-configurations/{id}/test`
- Re-save credentials if they've been rotated


**Related:**

- [Create Model Response](/docs/api-reference/responses/create) — Full Responses API reference
- [Function Calling](/docs/documentation/core-concepts/function-calling) — Custom function tools
- [Personal Connectors](/docs/documentation/personal-connectors/overview) — Pre-built integrations (GitHub, Google, etc.)