Using the MCP Tool to Connect External Services in the OpenAI Responses API

The Model Context Protocol (MCP) tool lets the OpenAI Responses API invoke external services—such as custom search engines, databases, or internal APIs—by forwarding tool calls to an MCP server you host, then injecting the returned JSON back into the model's reasoning flow.

The openai/openai-cookbook repository provides production-ready examples demonstrating how to bridge the Responses API with external data sources using the MCP tool. This integration pattern allows models to access real-time information from vector stores, enterprise databases, or proprietary search indexes without hardcoding credentials or logic into your client application.

How the MCP Tool Works in the Responses API

When you include an MCP tool in a responses.create call, the OpenAI service treats it like any other function tool. The key difference is that execution happens on your infrastructure rather than inside OpenAI's environment.

The flow follows this architecture:

  1. Your client sends a request to responses.create with a tools array containing an entry where "type": "mcp"
  2. The model decides to call the tool and emits a tool-call message
  3. The Responses service forwards the call via HTTP POST to your MCP server's SSE endpoint
  4. Your server executes the registered Python function (e.g., search or fetch) and returns JSON
  5. The model receives the result and continues reasoning, potentially making additional calls

This pattern is implemented in the Deep Research example within the cookbook, where the model uses an MCP server to query a vector store before generating citations.

Setting Up an MCP Server for the Responses API

To enable MCP tool calls, you must run a compatible server that exposes your custom logic through standardized tool definitions. The cookbook uses the FastMCP framework to handle protocol details.

Registering Tools with FastMCP

In examples/deep_research_api/how_to_build_a_deep_research_mcp_server/main.py, the server registers two tools using the @mcp.tool() decorator:

from fastmcp import FastMCP
from openai import OpenAI

openai_client = OpenAI(api_key="YOUR_KEY")
VECTOR_STORE_ID = "vs_123"

def create_server():
    mcp = FastMCP(
        name="Sample Deep Research MCP Server",
        instructions="Use `search` to find relevant docs then `fetch` to retrieve full content."
    )
    
    @mcp.tool()
    async def search(query: str):
        resp = openai_client.vector_stores.search(
            vector_store_id=VECTOR_STORE_ID, 
            query=query
        )
        return {
            "results": [
                {
                    "id": r.file_id, 
                    "title": r.filename, 
                    "text": r.content[0].text[:200]
                } for r in resp.data
            ]
        }

    @mcp.tool()
    async def fetch(id: str):
        file = openai_client.vector_stores.files.content(
            vector_store_id=VECTOR_STORE_ID, 
            file_id=id
        )
        meta = openai_client.vector_stores.files.retrieve(
            vector_store_id=VECTOR_STORE_ID, 
            file_id=id
        )
        return {
            "id": id, 
            "title": meta.filename, 
            "text": "\n".join(c.text for c in file.data)
        }
    
    return mcp

Each @mcp.tool() decorated function becomes available to the model. The function signatures define the JSON schema that the model will use when generating tool calls.

Exposing the Server via SSE Transport

The Responses API communicates with MCP servers using Server-Sent Events (SSE) over HTTP. You must start the server with the SSE transport enabled and bind it to an accessible host:

if __name__ == "__main__":
    server = create_server()
    server.run(transport="sse", host="0.0.0.0", port=8000)

According to the README in examples/deep_research_api/how_to_build_a_deep_research_mcp_server/README.md, the server listens on http://0.0.0.0:8000/sse/ and expects POST requests for tool invocations.

Configuring the MCP Tool in Your Responses Request

To connect your MCP server to the Responses API, add a tool definition with "type": "mcp" to the tools array in your responses.create call. The configuration requires the server_url pointing to your SSE endpoint and a server_label for identification:

import os
from openai import OpenAI

client = OpenAI()

system_message = """You are a researcher. Use the internal file lookup tool to search 
and fetch documents from our vector store before answering."""

response = client.responses.create(
    model="o3-deep-research-2025-06-26",
    input=[
        {
            "role": "developer", 
            "content": [{"type": "input_text", "text": system_message}]
        },
        {
            "role": "user", 
            "content": [{"type": "input_text", "text": "Research the economic impact of semaglutide."}]
        }
    ],
    reasoning={"summary": "auto"},
    tools=[
        {"type": "web_search_preview"},
        {
            "type": "mcp",
            "server_label": "internal_file_lookup",
            "server_url": "http://localhost:8000/sse/",
            "require_approval": "never"
        }
    ]
)

print(response.output)

The require_approval parameter controls whether the user must manually approve each tool invocation. Setting it to "never" allows autonomous operation, suitable for trusted internal tools.

The Deep Research implementation demonstrates how to combine the MCP tool with OpenAI's vector store search capabilities. This pattern lets models retrieve proprietary documents that are not accessible via public web search.

The MCP Server Implementation

As shown in examples/deep_research_api/how_to_build_a_deep_research_mcp_server/main.py, the server wraps the Vector Stores API. The search tool performs semantic lookup, while the fetch tool retrieves full document content. This two-step approach minimizes token usage by fetching only the specific documents the model needs.

Invoking the MCP Tool from the Client

When the model receives a research query, it automatically calls the search tool with relevant keywords. The MCP server returns document metadata, and if the model needs deeper context, it calls fetch with the specific document ID. All results flow back into the model's context window as JSON content, allowing it to cite sources accurately.

Advanced Pattern: Databricks MCP Integration

For enterprise scenarios, the cookbook includes a supply chain copilot example in examples/mcp/building-a-supply-chain-copilot-with-agent-sdk-and-databricks-mcp/main.py. This implementation exposes Databricks Vector Search and Unity Catalog functions as MCP tools:

@function_tool
async def vector_search(query: str):
    ws, token, base = await _ctx()
    url = f"{base}/api/2.0/mcp/vector-search/{CATALOG}/{SCHEMA}"
    async with httpx.AsyncClient(timeout=30.0) as client:
        r = await client.post(
            url, 
            json={"query": query}, 
            headers={"Authorization": f"Bearer {token}"}
        )
        r.raise_for_status()
        return r.json()

@function_tool
async def uc_function(name: str, params: dict):
    ws, token, base = await _ctx()
    url = f"{base}/api/2.0/mcp/functions/{FUNCTIONS_PATH}"
    async with httpx.AsyncClient(timeout=30.0) as client:
        r = await client.post(
            url, 
            json={"function": name, "params": params},
            headers={"Authorization": f"Bearer {token}"}
        )
        r.raise_for_status()
        return r.json()

This pattern allows the Responses API to query enterprise data lakes and execute custom SQL functions through the same MCP interface, extending the model's capabilities to internal business systems.

Summary

  • The MCP tool enables the Responses API to call external services through a standardized protocol, bridging the gap between the model and your infrastructure.
  • Server setup requires defining tools with @mcp.tool() and exposing them via SSE transport on an HTTP endpoint, as demonstrated in examples/deep_research_api/how_to_build_a_deep_research_mcp_server/main.py.
  • Client configuration involves adding a JSON object with "type": "mcp", server_url, and server_label to the tools array in responses.create.
  • Execution flow is automatic: the model generates the tool call, the Responses service forwards it to your server, and the JSON result returns to the model's context.
  • Enterprise patterns can wrap existing APIs (like Databricks Vector Search) behind MCP endpoints to give models secure access to proprietary data.

Frequently Asked Questions

What transport protocol does the MCP tool use?

The MCP tool uses Server-Sent Events (SSE) over HTTP. Your MCP server must expose an SSE endpoint (typically at /sse/) that the OpenAI Responses service can reach via POST requests. The cookbook examples use FastMCP's run(transport="sse") configuration to handle protocol compliance automatically.

How does authentication work with MCP servers?

Authentication is handled between your client and your MCP server directly. The OpenAI service forwards the tool call but does not manage credentials for your infrastructure. In the Databricks example, the server obtains OAuth tokens using the Databricks SDK and passes them in HTTP headers, keeping secrets within your security perimeter.

Can I use multiple MCP servers in one Responses API call?

Yes. The tools array accepts multiple MCP tool entries, each pointing to different server_url endpoints. You can combine internal file lookup, external database queries, and web search in a single request by including multiple objects with "type": "mcp" and distinct server_label values.

What is the difference between MCP tools and standard function tools?

Standard function tools execute within your client code after the model returns a tool-call message; you handle the API call and send results back in a follow-up request. MCP tools delegate execution to a remote MCP server; the OpenAI service forwards the call and returns the result automatically, reducing client-side complexity and enabling stateless integrations with external services.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →