
At OpenCore Group, we've spent the past years helping teams move AI agents from impressive demos to systems they can trust in production. Almost every one of those projects hits the same wall. The model is capable, but it can't safely reach the tools and data it needs.
The Model Context Protocol (MCP) has become our default way to solve that. In this post, we share how we design, secure, and run production MCP servers, including the patterns that worked and the mistakes we learned from.
Why we standardized on MCP
MCP is an open standard, originally introduced by Anthropic, that defines how AI applications (client or hosts) connect to external capabilities through MCP servers. A server can expose three things:
- Tools, which are actions the model can take, like
create_ticketorquery_orders - Resources, which are read-only context, such as documents, records, or files.
- Prompts, which are reusable, parameterized templates.
Before MCP. our engagements often ended with custom function-calling glue built for one application. When a client wanted a second agent, or wanted to use the same integration from their IDE, we started over. With MCP, we build the integration once as a server, and every MCP-compatible client can use it.
MCP vs. function calling: how we explain it to clients
Function calling puts tool definitions inside each application. MCP moves them into independent servers with their own lifecycle, versioning, and access control. In practice, this gives our clients:
- Separation of ownership. Platform teams own servers, and product teams build agents.
- Reuse across internal agents, desktop assistants, IDEs, and customer-facing products.
- An auditable security boundary, because every tool call crosses a well-defined protocol layer.
The reference architecture we use
Most of our production deployments follow four layers:
- Agent host. This is the application running the LLM loop.
- MCP client. It manages connections to one or more servers.
- Domain-scoped MCP servers, such as billing, support, and analytics
- Backend systems, accessed with least-privilege credentials.
A lesson we learned the hard way: our early servers mirrored APIs one-to-one and exposed dozens of endpoints. Tool-selection accuracy suffered. We now design servers around business tasks, with a small number of well-described tools each.
A minimal MCP server, the way we start every project
We usually prototype with the official Typescript SDK:
npm instal @modelcontextprotocol/sdk zod
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "orders-server", version: "1.0.0" });
server.registerTool(
"get_order_status",
{
title: "Get order status,
description:
"Look up the current status of a customer order by order ID. " + "Use this when the user asks where their order is.",
inputSchema: { orderId: z.string().regex(/^ORD-\d{6}$/) },
},
async ({ orderId }) => {
const order = await fetchOrderFromApi(orderId);
return {
content: [{ type: "text", text: Order ${orderId} is ${order.status}.}],
};
}
);
await server.connect(new StdioServerTransport());
These are the three rules our engineers follow on every server:
- Write tool descriptions for the model, not for humans. The description is effectively a prompt, so say when to use the tool.
- Validate inputs strictly before anything reaches a backend.
- Keep outputs lean. Every extra token of JSON competes with the model's reasoning.
How we make MCP servers production-ready
Authentication and authorization
For remote servers, we implement the OAuth 2.1-based authorization flow defined in the MCP specification. We never ship shared API keys inside servers that act for users. Instead, we pass user identity through, so the agent can only do what that user could do.
Least privilege and human approval
Every tool we build is classified as read-only or destructive, and we use MCP tool annotations to signal the difference. Anything irreversible, such as deleting data, sending messages, or moving money, requires explicit human confirmation in the host.
Prompt injection defense
This is the risk we spend the most time on with clients. Tool output from untrusted sources (emails, tickets, web pages) can carry instructions aimed at the model. Our rules:
- Tool output is data, never instructions.
- No single agent session gets untrusted input, sensitive data access, and an outbound channel all at once.
- Third-party MCP servers are vetted and version-pinned, just like any other dependency.
Observability
We instrument every deployment with OpenTelemetry. Each agent turn is a trace, and each MCP tool call is a span with the tool name, redacted arguments, latency, and result size. When a client asks why the agent got slow or which tool keeps failing, we can answer in minutes instead of days.
Reliability
We set timeouts, retries, and per-user rate limits (agents can loop), and we write error messages the model can act on, such as "Order not found. Ask the user to confirm the ID." Remote servers run stateless over Streamable HTTP so they scale horizontally.
Versioning and evals
We treat tool schemas as public APIs. Every release runs through tool-selection evals in CI, which are scripted scenarios that check the agent picks the right tool with the right arguments. Renaming a parameter shouldn't be able to quietly break an agent.
Frequently asked questions
What is an MCP server? It's a service that exposes tools, resources, and prompts to AI applications through the Model Context Protocol, so agents can work with external systems in a standard way.
Is MCP only for Claude? No. MCP is an open standard supported by a growing range of AI platforms, IDEs, and agent frameworks.
Is MCP secure enough for enterprise use? Yes, when it's implemented carefully. That means OAuth-based authorization, least privilege, human approval for destructive actions, and prompt injection defenses. Those are the areas we focus on in every engagement.
Should we use stdio or HTTP transport? Use stdio for local, single-user tools. Use Streamable HTTP for shared, remote, production servers.
Work with OpenCore Group
MCP makes it possible for AI agents to do real work across your systems, but the protocol is the easy part. The value is in the engineering around it: tool design, security, observability, and testing.


