← All posts Engineering

MCP vs function calling: Practical architecture guide

MCP vs function calling: Practical architecture guide

The practical answer to MCP vs function calling is that you are choosing between two layers, not two interchangeable features. Function calling is the model-interface primitive: the model emits a structured request, usually JSON arguments, and your application or provider runs the tool. MCP is the integration protocol: tools are exposed by servers, discovered by clients, and reused across hosts.

Use direct function calling when you have a small set of app-owned tools, one main client, tight latency requirements, and simple ownership. Use MCP when tools need runtime discovery, multi-client reuse, separate credentials, independent deployment, or portability across model providers and agent hosts.

MCP Vs Function Calling: The Decision In One Table

| Decision factor | Direct function calling | MCP | |---|---|---| | Primary job | Let the model request a known tool with typed arguments | Expose tools, resources, and prompts through a standard server protocol | | Best fit | Few tools, one app, one orchestration loop | Many tools, multiple clients, shared integrations | | Discovery model | Usually defined by the app at design time | Tools can be listed at runtime with tools/list | | Execution boundary | Often in-process or inside the application backend | Separate server over stdio or Streamable HTTP | | Auth model | Inherits app credentials and policy | Can isolate credentials per MCP server, with optional OAuth-based authorization | | Latency profile | Lower overhead when local and app-owned | Adds a process or network hop | | Portability | Tied to the app and provider-specific tool API | Designed as a cross-host integration protocol | | Main risk | Tight coupling and duplicated integrations | More moving parts, server trust, auth, and tool-output risk |

The architectural mistake is treating MCP as a replacement for function calling. In most stacks, MCP tools still become tool choices that a model can select. The model usually does not speak MCP directly. A host, client, SDK, or model provider bridges MCP server tools into the model's tool-use interface.

What Function Calling Actually Solves

Function calling answers one narrow but critical question: how should a model express that it wants to use external functionality? OpenAI announced function calling on June 13, 2023 as a way to describe functions to models and receive JSON arguments. Current OpenAI docs frame function calling as giving models access to application-provided functionality and data.

In practice, you define tools in the model API request, often with JSON Schema. The model chooses a tool and returns arguments. Your application validates the arguments, executes the tool, sends the result back, and continues the loop. Anthropic's Claude docs make a similar distinction between client tools, which the application executes, and server tools, which Anthropic executes.

This is a good fit when your product owns the workflow. For example, an internal support assistant may need three tools: search tickets, fetch account status, and create a refund request. If those tools belong to one backend and one product surface, direct function calling keeps the system easier to reason about.

What MCP Actually Solves

MCP answers a different question: how should AI clients connect to external systems in a standard way? Anthropic introduced the Model Context Protocol on November 25, 2024 as an open standard for connecting AI assistants to systems where data lives, with the goal of replacing fragmented custom integrations.

An MCP server exposes capabilities. A client can ask for available tools with tools/list, call one with tools/call, and receive change notifications through notifications/tools/list_changed. The current spec version found in the brief is 2025-11-25, which includes changes around auth discovery, incremental scope consent, icons, tool-name guidance, and OAuth Client ID Metadata Documents.

MCP also defines deployment mechanics. The transports in the brief are stdio and Streamable HTTP. Streamable HTTP servers must validate Origin, and HTTP clients must include MCP-Protocol-Version. Those details matter because MCP is more than a schema format. It creates a process or network boundary around tools.

When Direct Function Calling Is The Right Choice

Choose direct function calling when the integration belongs to one application. The clearest case is an app-owned API that is already governed by the same backend, same auth layer, and same release process as the LLM feature.

Choose it when latency matters. Direct function calling can run inside your orchestration loop without adding an MCP server, discovery step, or remote hop. The brief notes practitioner skepticism that, for known app-owned APIs, manual direct integration may deliver better accuracy and performance than MCP.

Choose it when the tool surface is small and stable. If your assistant has five known actions and they rarely change, runtime discovery is not the hard problem. Good schema design, validation, policy checks, and observability inside your existing application probably matter more.

Choose it for prototypes that need speed and clarity. Descope frames function calling as better for simple prototypes, while MCP adds modularity and maintainability once the integration surface grows. That matches the practical engineering trade-off: avoid a protocol boundary until the boundary has a job.

When MCP Is The Right Choice

Choose MCP when integrations need to be shared. If the same GitHub, database, CRM, document store, or internal platform tools must be available to several assistants, several teams, or several model providers, MCP gives you a common server boundary instead of repeated function definitions in every app.

Choose MCP when tools should be added at runtime. The brief highlights a Hacker News practitioner theme: runtime extension is a core differentiator because tools can be added after the client is shipped. That is the practical value of tools/list and notifications/tools/list_changed.

Choose MCP when auth and deployment ownership need separation. MCP authorization is optional, but the spec's HTTP auth model is based on OAuth 2.1, protected resource metadata, authorization server metadata, OIDC discovery, and client registration. That is heavier than direct app credentials, but it gives you a place to isolate credential handling per tool server.

Choose MCP when cross-provider portability matters. OpenAI supports remote MCP servers and connectors as type: "mcp" tools in the Responses API, using server_url for remote MCP servers or connector_id for built-in connectors. Anthropic lists MCP connector as a server tool route for connecting remote MCP servers. The implementation details differ, but the integration boundary can survive provider changes better than provider-specific tool definitions alone.

Hybrid Patterns Are Normal

Many production systems will use both. Keep latency-sensitive, app-owned actions as direct function calls. Put shared external systems behind MCP servers. Then let the model host expose both kinds of tools through the provider's tool-use interface.

A practical split looks like this: account lookup, order mutation, and billing actions stay inside the product backend as direct function tools. Shared developer tools, document repositories, data warehouses, or internal knowledge systems move behind MCP servers. The first group optimizes for tight control. The second optimizes for reuse and independent ownership.

OpenAI's MCP support illustrates this bridge. A remote MCP server can be passed as a tool in the Responses API, but the authorization value is not stored by the Responses API and must be sent on every request. That means your application still owns request-time credential handling even when the tool integration is remote.

Security And Auth Trade-Offs

MCP can create cleaner boundaries, but it does not remove security work. OpenAI warns that remote MCP servers are third-party services, are not verified by OpenAI, and may access, send, receive data, and take actions. That warning should shape your vendor approval process and allowlist design.

The MCP authorization spec also forbids token passthrough. Servers must validate tokens intended for themselves and use separate upstream tokens when calling downstream APIs. The spec also states that access tokens must not be included in URI query strings. These are not optional implementation details if you are treating MCP as a production auth boundary.

Direct function calling has a different risk profile. It may inherit your application auth and logging, which is simpler, but it can also concentrate tool permissions inside one backend. The decision is not "secure versus insecure." It is whether you want policy enforcement inside the app boundary or at separately deployed tool servers.

Tool-output prompt injection remains a concern in both models. MCP expands the number of possible tool servers and outputs that may enter model context. Direct function calling reduces the number of integration parties, but tool output still needs sanitization, scoping, and policy checks before it affects actions.

Operational Checklist Before Choosing MCP

Before adopting MCP, answer six questions.

First, who owns each tool server? If no team owns uptime, schema changes, versioning, and incident response, MCP will turn integration reuse into shared ambiguity.

Second, how will tools be approved? Runtime discovery is useful only if clients know which servers and tools are allowed. Plan allowlists, review flows, and audit logs before exposing a large tool set.

Third, what is the credential model? Decide whether the server uses local credentials, user-delegated OAuth, service credentials, or a provider connector. For OpenAI remote MCP usage, remember that the provided authorization value must be sent on every request.

Fourth, what latency budget can the workflow tolerate? MCP over Streamable HTTP may add network time. MCP over stdio may add local process management. For actions inside a user-facing flow, measure this instead of assuming the overhead is acceptable.

Fifth, how will schemas change? The brief flags versioning as an open question. Tool names, argument schemas, and outputs become contracts between servers, clients, model prompts, and downstream systems.

Sixth, how many tools will the model see at once? The brief raises the risk that models may choose the wrong tool when many MCP tools are exposed. Use narrower tool sets, approval gates, or deferred loading where your host supports it.

Bottom-Line Recommendation

If you are building one assistant inside one product, start with function calling. You get a clear orchestration loop, lower overhead, direct validation, and fewer deployment parts.

If you are building a tool ecosystem for several assistants, clients, teams, or model providers, use MCP for the shared integrations. The extra protocol and auth work has a purpose when reuse, discovery, and separate ownership matter.

If both conditions are true, split the system by ownership and latency. Direct function calling is the right default for product-local actions. MCP is the right boundary for reusable tool servers. The best architecture is usually not one layer winning over the other. It is placing each layer where its trade-off is visible and worth paying.

Get started

Deploy your fleet.

Put a fleet of sandboxed agents to work on your own infrastructure, provisioned in seconds and watched live from one console.

Get started

Admin-provisioned · Self-host in one command · Your data never leaves your VM