MCP and Connectors: The Universal Standard
On this page
MCP and Connectors: The Universal Standard
The Model Context Protocol (MCP) is an open standard that lets models interact with external services through a unified protocol. OpenAI Connectors implement this standard to link models directly to third-party tools within the Responses API.
The Problem MCP Solves
The core issue is the multiplication of integrations: connecting N models to M services requires N×M custom integrations, each written and maintained separately. Every new service forces you to repeat the work for every application, and every API change risks breaking multiple integrations.
MCP turns this product into a sum: the service exposes its capabilities once using the protocol, and any compatible client consumes them. This is the same logic behind printer drivers or the Language Server Protocol (LSP) in code editors—standardization doesn’t make integrations more powerful; it makes them economically sustainable.
# Before MCP: manual integration for every service
tools = [
# Function for Slack
{"type": "function", "name": "slack_send_message", ...},
{"type": "function", "name": "slack_read_channel", ...},
# Function for Jira
{"type": "function", "name": "jira_create_ticket", ...},
{"type": "function", "name": "jira_list_tickets", ...},
# Function for Google Drive
{"type": "function", "name": "gdrive_list_files", ...},
# ... dozens of functions to maintain
]
With MCP, each service exposes its capabilities via a standard protocol, and the model consumes them directly.
MCP Architecture
The protocol defines three concepts:
- MCP Server: A service that exposes tools, resources, and prompts
- MCP Client: The system that consumes the server’s capabilities
- Transport: The communication channel between client and server
# An MCP server exposes:
# - Tools: Actions the model can execute
# - Resources: Data the model can read
# - Prompts: Predefined prompt templates
Using OpenAI Connectors
Connectors are MCP servers that are already hosted and maintained: you declare them, authenticate, and consume. This is the natural entry point—there’s no need to write an MCP server to talk to a common service that someone has already connected.
from openai import OpenAI
client = OpenAI()
# Conceptual example: connector to an external service
response = client.responses.create(
model="gpt-5.6-terra",
input="Create a Jira ticket for the homepage bug",
tools=[
{
"type": "mcp",
"server_label": "jira",
"server_url": "https://mcp.your-server.com/jira",
"require_approval": "always"
}
]
)
The require_approval parameter controls human validation:
"always": Every action requires approval"never": Automatic execution
Creating an MCP Server in Python
Writing your own server becomes worthwhile as soon as an internal service needs to be reachable by multiple applications. The logic is the same as for an internal API: you write it once, cleanly, with its own access rules—and every application benefits without reinventing the integration layer.
from mcp.server import Server
from mcp.types import Tool, TextContent
import json
server = Server("my-crm")
@server.tool()
async def search_client(term: str, field: str = "name") -> str:
"""Search for a client in the internal CRM.
Args:
term: The search term (name, email, or ID)
field: The field to search in (name, email, id)
"""
# Your business logic
results = await crm_database.search(term, field=field)
return json.dumps([{
"id": r.id,
"name": r.name,
"email": r.email,
"company": r.company
} for r in results])
@server.tool()
async def create_opportunity(
client_id: str,
title: str,
amount: float,
probability: int
) -> str:
"""Create a sales opportunity in the CRM.
Args:
client_id: Client identifier
title: Opportunity title
amount: Estimated amount in euros
probability: Probability of closing (0-100)
"""
opp = await crm_database.create_opportunity(
client_id=client_id,
title=title,
amount=amount,
probability=probability
)
return json.dumps({"id": opp.id, "status": "created"})
Exposing MCP Resources
MCP distinguishes between tools, which do something, and resources, which provide something to read. This distinction matters because it defines risk: a resource is consulted without side effects, while a tool can modify the state of the world. Approval controls naturally focus on the latter.
@server.resource("crm://pipeline")
async def sales_pipeline() -> str:
"""Current state of the sales pipeline."""
pipeline = await crm_database.get_pipeline()
return json.dumps({
"total_opportunities": pipeline.count,
"total_value": pipeline.total_value,
"by_stage": {
"prospecting": pipeline.prospecting,
"qualification": pipeline.qualification,
"proposal": pipeline.proposal,
"negotiation": pipeline.negotiation,
"closing": pipeline.closing
}
})
@server.resource("crm://client/{client_id}")
async def client_profile(client_id: str) -> str:
"""Complete profile of a client."""
client = await crm_database.get_client(client_id)
return json.dumps({
"name": client.name,
"email": client.email,
"purchase_history": client.purchases,
"satisfaction_score": client.nps
})
Connecting an MCP Server to the Responses API
# MCP connector configuration in the API call
response = client.responses.create(
model="gpt-5.6-terra",
input="What is the status of our sales pipeline? "
"Create an opportunity for client CLI-789: "
"cloud migration, 50000 euros, 70% probability.",
tools=[
{
"type": "mcp",
"server_label": "internal-crm",
"server_url": "https://mcp.internal.example.com/crm",
"require_approval": "never"
}
]
)
Pattern: Multi-Connector Hub
This is where the standard truly shines: multiple servers declared side by side, with the model composing across them—reading a ticket here, searching for a client there, writing a response elsewhere. Without a common protocol, this same flow would require three specific integrations and their ongoing maintenance.
response = client.responses.create(
model="gpt-5.6-terra",
input="Check open Jira tickets, send a summary to Slack, "
"and update the Notion dashboard",
tools=[
{
"type": "mcp",
"server_label": "jira",
"server_url": "https://mcp.example.com/jira",
"require_approval": "always"
},
{
"type": "mcp",
"server_label": "slack",
"server_url": "https://mcp.example.com/slack",
"require_approval": "always"
},
{
"type": "mcp",
"server_label": "notion",
"server_url": "https://mcp.example.com/notion",
"require_approval": "always"
}
]
)
Security and Authentication
# MCP servers handle authentication via headers
# or tokens in the configuration URL
# Best practice: always use require_approval for write actions
tools = [
{
"type": "mcp",
"server_label": "crm",
"server_url": "https://mcp.example.com/crm",
"require_approval": "always", # Human validation
"allowed_tools": ["search_client", "client_profile"], # Restrict tools
}
]
Key Takeaways
- MCP is an open standard for connecting models to external services
- OpenAI Connectors integrate MCP directly into the Responses API
- Build your own MCP servers to expose internal services
- Use
require_approvalto control human validation - Connect multiple MCP servers in a single call for cross-functional workflows