> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parallel.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Tools

> Give the Responses API a remote MCP server to call while it researches

Pass the OpenAI `mcp` tool to let the model call tools on a remote MCP server alongside its
web research. Parallel connects to the server, lists its tools, and calls them when they are
useful for the question. Each call is reported as an `mcp_call` output item, in the same
shape OpenAI returns it.

Use an `mcp` tool for a server you run or a provider your organization already licenses. For
Data Connectors Parallel manages, use [`data_sources`](/resources/data-connectors#responses-api)
instead.

## Add a server

<CodeGroup>
  ```bash cURL theme={"system"}
  curl https://api.parallel.ai/v1/responses \
    -H "Authorization: Bearer $PARALLEL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "parallel",
      "input": "What transport protocols does the MCP Python SDK support?",
      "tools": [
        {
          "type": "mcp",
          "server_label": "deepwiki",
          "server_url": "https://mcp.deepwiki.com/mcp",
          "require_approval": "never"
        }
      ]
    }'
  ```

  ```python Python theme={"system"}
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["PARALLEL_API_KEY"],
      base_url="https://api.parallel.ai/v1",
  )

  response = client.responses.create(
      model="parallel",
      input="What transport protocols does the MCP Python SDK support?",
      tools=[
          {
              "type": "mcp",
              "server_label": "deepwiki",
              "server_url": "https://mcp.deepwiki.com/mcp",
              "require_approval": "never",
          }
      ],
  )

  print(response.output_text)
  ```

  ```typescript TypeScript theme={"system"}
  import OpenAI from "openai";

  const client = new OpenAI({
    apiKey: process.env.PARALLEL_API_KEY,
    baseURL: "https://api.parallel.ai/v1",
  });

  const response = await client.responses.create({
    model: "parallel",
    input: "What transport protocols does the MCP Python SDK support?",
    tools: [
      {
        type: "mcp",
        server_label: "deepwiki",
        server_url: "https://mcp.deepwiki.com/mcp",
        require_approval: "never",
      },
    ],
  });

  console.log(response.output_text);
  ```
</CodeGroup>

| Field              | Type               | Description                                                                                                                                                 |
| ------------------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`             | `"mcp"`            | Required.                                                                                                                                                   |
| `server_label`     | `string`           | Required. A name for the server, reported as `server_label` on its `mcp_call` items. Must not be blank or match a connector named in `data_sources`.        |
| `server_url`       | `string`           | Required. URL of the MCP server.                                                                                                                            |
| `require_approval` | `"never"`          | Required. Parallel runs tool calls without an approval step, so this must be set to `"never"`. Omitting it, which OpenAI treats as `"always"`, is rejected. |
| `headers`          | `{string: string}` | Optional. HTTP headers sent on every request to the server, such as an API key.                                                                             |
| `authorization`    | `string`           | Optional. An OAuth access token, sent as `Authorization: Bearer <token>`.                                                                                   |
| `allowed_tools`    | `string[]`         | Optional. Names of the tools the model may call. Omit to allow every tool on the server.                                                                    |

`server_description` is accepted and ignored. Parallel does not run the OAuth flow for you;
obtain a token separately and pass it as `authorization` or in `headers`:

```json theme={"system"}
{
  "type": "mcp",
  "server_label": "crm",
  "server_url": "https://mcp.example.com/mcp",
  "require_approval": "never",
  "headers": { "X-Api-Key": "YOUR_PROVIDER_KEY" },
  "allowed_tools": ["search_accounts", "get_account"]
}
```

A request may carry up to 10 `mcp` tools, but fewer usually gives better answers. MCP tools
work on every `reasoning.effort` tier, and can be combined with a
[`web_search` tool](/responses-api/features/web-search-tool) and with `data_sources`.

### Restrictions

* Only servers using the Streamable HTTP transport are supported, and only their tools: MCP
  resources and prompts are not used.
* `require_approval` must be `"never"`. There is no approval round trip, so the response
  never contains `mcp_approval_request` items.
* `connector_id` (OpenAI connectors), `tunnel_id`, and `defer_loading` are not supported and
  are rejected when set, including `defer_loading: false`.
* `allowed_tools` must be a list of tool names. An empty list and the filter-object form
  (`{"read_only": true}`) are rejected.
* Connection and tool-listing errors are not reported yet. If a server can't be reached or
  its tools can't be listed, the request completes on web research and any other servers,
  with no `mcp_call` items for that server. `allowed_tools` names that match no tool on the
  server are also ignored without an error, so if none match, that server is never called.

Rejected tools return a `400` with the reason; see
[OpenAI Responses Compatibility](/responses-api/openai-compatibility#rejected).

## Read tool calls

A completed response contains one `mcp_call` item per tool call the model made, for your
`mcp` tools and for the connectors you named in `data_sources`:

```json theme={"system"}
{
  "id": "mcp_resp_a0fa0e42-fa1b-4bf0-ae62-baca311fd5b6_0",
  "type": "mcp_call",
  "server_label": "deepwiki",
  "name": "ask_question",
  "arguments": "{\"repoName\": \"modelcontextprotocol/python-sdk\", \"question\": \"Which transports does the SDK support?\"}",
  "output": "The SDK supports three transports: stdio, SSE, and Streamable HTTP...",
  "error": null,
  "status": "completed"
}
```

| Field          | Meaning                                                                                                          |
| -------------- | ---------------------------------------------------------------------------------------------------------------- |
| `server_label` | The server called: your tool's `server_label`, or the connector name from `data_sources`.                        |
| `name`         | The tool called.                                                                                                 |
| `arguments`    | The tool input, as a JSON-encoded string.                                                                        |
| `output`       | The text the tool returned, or `null` if the call failed.                                                        |
| `error`        | Why the call failed, or `null` if it succeeded.                                                                  |
| `status`       | `completed` or `failed`. A call is `failed` when the server returned a tool error or the call could not be made. |

The model decides when a tool is useful, so a server may be called several times or not at
all. A failed call does not fail the response. Calls to Index Partners are not reported.

Read `output` by item `type` rather than by position. `mcp_call` items follow the
`web_search_call` items and precede the `message` item in a non-streaming response, but
follow the `message` item in a streamed one.

<CodeGroup>
  ```python Python theme={"system"}
  for item in response.output:
      if item.type == "mcp_call":
          result = item.output if item.status == "completed" else item.error
          print(f"{item.server_label}.{item.name}({item.arguments}) -> {result}")
  ```

  ```typescript TypeScript theme={"system"}
  for (const item of response.output) {
    if (item.type === "mcp_call") {
      const result = item.status === "completed" ? item.output : item.error;
      console.log(`${item.server_label}.${item.name}(${item.arguments}) -> ${result}`);
    }
  }
  ```
</CodeGroup>

The response echoes your `mcp` tools on `tools` with credentials removed: `headers` and
`authorization` are `null`, and any query string on `server_url` is replaced with `***`.

With [streaming](/responses-api/features/streaming-events) enabled, tool calls are reported
once research finishes, after the answer's text delta, as `response.output_item.added`,
`response.mcp_call.completed` or `response.mcp_call.failed`, and `response.output_item.done`
for each call. The `response.mcp_call.in_progress`, `response.mcp_call_arguments.*`, and
`response.mcp_list_tools.*` events are not sent.
