The question is mis-posed, and knowing why is most of the answer. A REST API is how programs call a system. MCP is how an AI application discovers and calls a system's capabilities on behalf of a user, and it is almost always implemented on top of the same API. The two are not competitors; one is a transport and resource model, the other is a contract for a model-driven caller: typed tools the model can list at runtime, results it can read and recover from, OAuth authorisation bound to the person, and confirmation hooks the client can honour.
So the practical rule is: if a program is the caller, with fixed logic you wrote, use the API. If a model is the caller, choosing actions at runtime for a person, use MCP, and let it wrap the API. Where you are building the agent yourself with the Claude or OpenAI APIs, you can do either, and the trade-off is who writes and maintains the glue.
The misconception
The phrase MCP vs API suggests a replacement, and the protocol invites the reading because it looks like an API: an HTTPS endpoint, JSON, a list of callable operations. Underneath, it is JSON-RPC 2.0 over Streamable HTTP, which is to say it is an HTTP API with a fixed message shape. What it standardises is not how to reach a system but how an AI application asks a system what it can do, how it calls those things with a model choosing the arguments, how errors are handed back so the model can self-correct, and how the person behind the model is authorised. A REST API standardises none of that, because it never needed to: its callers were programs whose authors read the documentation once.
Every serious MCP server for a business system is a layer over that system's existing service layer or API. The question is therefore not which to build, since you need the API either way, but which to hand to an agent.
What an API gives an agent, and what it does not
Give a model a REST API and it can use it, with help. The help is the problem. Someone has to turn the endpoints into function definitions the model can see, in the format the model provider expects; Claude's and OpenAI's function-calling formats are similar but not identical. Someone has to write the loop that takes the model's chosen function, calls the endpoint with the right credentials, and feeds the response back. Someone has to decide how errors reach the model, because a 422 with a validation body is not something a model reads well unless it is converted. And someone has to solve authorisation, because an API key in the agent's environment makes every action look like the same service account, not the person asking.
None of that is hard for one system and one agent, which is why it was the state of the art before the protocol. It scales badly. Each pairing of an agent product and a business system is bespoke, the definitions drift from the API, and there is no way for a user of Claude or ChatGPT to connect a system themselves. The API remains excellent at what it was built for: high-volume, program-to-program calls, bulk operations, webhooks, and integrations where the logic is fixed and the caller is code.
What MCP adds
The protocol answers each of those gaps with a rule that every client implements once. Discovery: tools/list returns the tools with names, descriptions and JSON Schemas at runtime, so the agent product needs no prior knowledge and the list can change as apps are installed or roles change. Invocation: tools/call carries a name and arguments; the result carries content the model reads, optional structured content, and an isError flag that tells the model to correct and retry rather than give up. Authorisation: OAuth 2.1 with the token bound to the server and to the person, so the tool list and every call can be scoped to who is asking. Consent: annotations let a server say a tool is read-only, destructive or idempotent, and clients use them to decide when to confirm; a server can also return an input-required result to ask the person a question mid-call. Here is one call and its reply, as a client sends and receives them.
{
"jsonrpc": "2.0",
"id": 12,
"method": "tools/call",
"params": {
"name": "recordPayment",
"arguments": {
"invoice_id": "9f1c2a6e-4b8d-4c1a-9e2f-2d7a1b6c5e10",
"amount": 4850,
"payment_date": "2026-09-18",
"payment_reference": "BACS 41877"
}
}
}
{
"jsonrpc": "2.0",
"id": 12,
"result": {
"content": [
{ "type": "text", "text": "Payment recorded against INV-1057. Amount paid 4850.00 of 4850.00; status is now paid." }
],
"structuredContent": {
"invoice_id": "9f1c2a6e-4b8d-4c1a-9e2f-2d7a1b6c5e10",
"number": "INV-1057",
"amount_paid": 4850,
"status": "paid"
},
"isError": false
}
}A tools/call request and result for a Sois payment tool. The same operation over the REST API would need a function definition written for the model provider, a loop to relay the call, and a decision about how to present the response; here the client already knows how to do all three.
There is a cost. The protocol is younger than REST and still moving: the 2026-07-28 revision removed protocol-level sessions and changed how servers ask clients for input, and clients are required to fall back for servers on the previous revision. Tool lists consume context, so large servers need deferred loading or tool search on the client side. And a model-driven caller is slower and less predictable than a program, which is precisely why you would not use it for a nightly sync.
When each is right
| Situation | Use | Reason |
|---|---|---|
| A person's agent in Claude, ChatGPT, Cursor or VS Code needs to act in the system | MCP | The client already implements discovery, OAuth and confirmation; the user connects with a URL and a sign-in, and acts as themselves. |
| A nightly sync, a bulk import, a report feed | API | Fixed logic, high volume, no model in the loop; a program is the right caller and REST is built for it. |
| Events out of the system (payment received, stock low) | API and webhooks | MCP has no outbound event model beyond change notifications a client subscribes to; webhooks are the standard. |
| You are building your own agent with the Claude or OpenAI API and the system has an MCP server | MCP, through the provider's connector | Both APIs accept a remote MCP server directly; you avoid writing and maintaining function definitions and the relay loop. |
| You are building your own agent and the system has only a REST API | API, via function calling | Write the function definitions and the loop; consider putting an MCP server in front if more than one agent product will need it. |
| Deep research or company-knowledge features in ChatGPT | MCP, read-only | ChatGPT's search and fetch conventions are defined over MCP; a REST API cannot be plugged in. |
| A caller with no agent at all, such as a form or a script that wants an outcome | A plain-language endpoint | Neither: hand a sentence to a hosted agent and receive the result; Sois offers this as its Chat Agent Gateway. |
The column that decides is the caller. A model choosing at runtime for a person wants MCP; a program with fixed logic wants the API; both may exist over the same service layer.
How the major agent products consume each today
The provider APIs settle the comparison for anyone building their own agent, because both now accept an MCP server as a first-class tool alongside ordinary function calling. On the Claude side, custom connectors in the web and desktop apps and Cowork take a server URL and complete OAuth in the app; Claude Code adds a server with one command; and the Messages API's MCP connector (beta, behind the mcp-client-2025-11-20 header) takes an mcp_servers entry and an mcp_toolset, supports tool calls only, and expects you to supply the access token. On the OpenAI side, ChatGPT's developer mode connects a remote server with OAuth or no authentication and asks for confirmation on write actions by default; the Responses API takes a tool of type mcp with a server_url, a require_approval setting and an optional allowed_tools list, returns mcp_list_tools and mcp_call items, and works with Streamable HTTP or the older SSE transport.
Ordinary function calling remains available in both APIs, and it is the path for a REST-only system: you define the functions, you call the API, you return the results. The difference is entirely in who maintains the bridge. With MCP the system's owner maintains one server and every client benefits; with function calling each agent builder maintains their own definitions against the API.
The pattern that works: API underneath, MCP on top
The systems that get this right expose both and route them through the same permission layer. Sois is one implementation of the pattern. The workspace has a service layer that every screen uses. Its MCP server publishes that layer as tools at one URL, filtered by the caller's role and checked again on every call, with OAuth for connectors and a bearer token for scripts. The same workspace accepts plain-language requests at a separate endpoint for callers with no agent, where the workspace's own agent does the reasoning and replies by webhook or polling. And for the outbound direction, its own agent can call external MCP servers through a gateway, under the same allow, ask and deny governance.
Nothing in that design requires choosing. The API serves programs, the MCP server serves models, the gateway serves callers with neither, and one permission model governs all three. When someone asks which to build, the honest answer is that the API is a given and the MCP server is the thing that makes the system usable by the agents people already have.
Questions people ask
Is MCP just a wrapper around a REST API?
Usually it is implemented as one, and that is the point. The wrapper adds what a model-driven caller needs and REST does not define: runtime discovery, typed tools, readable errors, per-user OAuth and confirmation hints.
Can I use function calling instead of MCP?
Yes, in both the Claude and OpenAI APIs, and for a system with only a REST API it is the path. You write and maintain the function definitions and the relay loop; an MCP server moves that work to the system's owner and makes it reusable by every client.
Is MCP slower or more expensive than calling the API directly?
The protocol adds little; the model does. A model-driven caller costs tokens for the tool list and reasoning and is less predictable than fixed code, which is why bulk and scheduled work belongs on the API.
Does MCP handle events and webhooks?
Not in the way REST integrations do. The protocol has change notifications a client can subscribe to, but for events leaving a business system to other services, webhooks over the API remain the standard.
- Model Context Protocol specification (2026-07-28) the base protocol, tools, transports, authorisation and the changelog against the previous revision
- Claude API documentation: MCP connector mcp_servers, mcp_toolset, tools-only support and the token requirement
- OpenAI documentation: connectors and MCP in the Responses API the mcp tool type, approval flow, output items and supported transports
- Sois documentation: MCP server, Chat Agent Gateway and MCP Gateway the three routes into and out of a workspace under one permission model
This article is reviewed when the products it describes change. Next scheduled review: 4 December 2026.
