MCP (Model Context Protocol) — One Standard to Connect AI to All Your Company's Tools
MCP (Model Context Protocol) is an open standard for communication between AI applications and external tools and data — published by Anthropic in November 2024 and adopted within months by OpenAI, Google DeepMind and Microsoft. It solves the N×M problem: instead of building a separate integration between every AI application and every tool (4 apps × 4 tools = 16 integrations), you build one adapter per side (4 + 4 = 8). If your tools need to serve multiple AI applications (Claude, ChatGPT, Cursor, your own agent) — MCP is the right choice. If you are building a single application with a handful of functions — plain function calling is enough, and MCP would be over-engineering.
The complete guide to MCP: what problem the protocol solves, how the host–client–server architecture works, how it differs from function calling and OpenAPI, how to build your own MCP server in Python and TypeScript, which ready-made servers to plug into your business tools, and how to secure the deployment against tool poisoning.
Your company has an AI agent in customer support, an assistant in Slack and a copilot for the sales team. Each of them needs access to the CRM, the database and the calendar. Without a standard you write nine integrations — and when the CRM changes its API, you patch three applications at once. That exact pain is what MCP was created to remove.
The adoption numbers speak for themselves: over 5,800 public MCP servers in the registry, ~97 million SDK downloads per month and backing from the four biggest AI players. In 2026 MCP stopped being a curiosity — it became an architectural decision every company deploying agents has to consider. This article explains how the protocol works, when to use it and how to deploy it safely.
What problem does MCP solve?
/// THE N×M PROBLEM AND HOW MCP SOLVES IT
Without MCP: 16 integrations. With MCP: 8 adapters.
4 × 4 = 16 separate integrations
Before MCP, every AI-to-tool integration was bespoke. LangChain had its "tools", OpenAI had its "functions", every framework had its own definition format and its own error handling. The result: a fragmented ecosystem, non-portable integrations, and every new AI application in the company starting from zero.
MCP standardises three things:
- Tool discovery — the AI application asks the server "what can you do?" and receives a list of tools with descriptions and parameter schemas; nothing is hardcoded
- Invocation — one request and response format (JSON-RPC 2.0) regardless of whether the tool is a database, an API or a file system
- Context — beyond tools, a server can expose resources (files, records) and prompt templates that the AI application fetches in a unified way
The analogy that stuck: MCP is USB-C for AI. A laptop manufacturer does not build a separate port for every device — one standard serves them all. In the same way, an AI application with an MCP client can use any MCP server, no matter who wrote it.
How MCP works — host, client, server
The MCP architecture has three roles:
| Role | What it does | Example |
|---|---|---|
| Host | The AI application the user talks to | Claude Desktop, Cursor, your agent |
| MCP client | Host component — maintains a 1:1 connection with a server | Built into the host, you do not write it |
| MCP server | Exposes tools, resources and prompts for one system | Postgres server, Slack server, your own |
An MCP server exposes three kinds of objects (the primitives):
- Tools — functions the model can call: "find a customer in the CRM", "send a message", "run a SQL query"; the equivalent of function calling
- Resources — read-only data the host can pull into context: a file, a database record, a document; like GET in REST
- Prompts — ready-made prompt templates with parameters that the server recommends for its tools; used less often, but valuable in complex systems
Communication runs over JSON-RPC 2.0 on one of two transports:
| Transport | How it works | When to use |
|---|---|---|
| stdio | The host launches the server as a local process, communicating via stdin/stdout | Local tools: file system, local database, CLI — 90% of cases |
| Streamable HTTP | The server runs remotely as an HTTP endpoint, supports streaming and multiple clients | A server shared by a team, SaaS, production |
The practical rule: build and test on stdio, switch to Streamable HTTP only when more than one person or machine needs the server. Note: the older SSE transport was removed from the spec in March 2025 in favour of Streamable HTTP — if a tutorial shows SSE, it is outdated.
This is what connecting MCP servers to Claude Desktop looks like — a single config file:
{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/company/documents"] }, "postgres": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://readonly_user:password@localhost/crm"] } }}
After restarting the app, Claude sees both servers' tools and decides on its own when to use them. Note the "readonly_user" — that is not an accident; we will come back to it in the security section.
MCP vs function calling vs OpenAPI — which to choose?
This is the most common question and the biggest source of confusion. All three approaches solve the same problem — the model picks an action, the runtime executes it — but at different levels:
| Criterion | Function calling | OpenAPI tools | MCP |
|---|---|---|---|
| What it is | A model vendor's API feature | Auto-generating tools from a REST spec | An open discovery and invocation protocol |
| Scope | One application | Existing HTTP APIs | Many apps × many tools |
| Tool discovery | None — defined in code | From the OAS 3.1 spec | Dynamic — the runtime asks the server |
| Portability | Low (vendor format) | Medium | High — any MCP host |
| Implementation cost | Lowest | Low with an existing API | Medium — you run a server |
| Best for | One app, a few functions, low latency | Governed corporate REST APIs | An ecosystem of many agents and tools |
The decision in three questions:
- 1.Building a single application with at most a dozen functions? Function calling — simplest, fastest, no extra infrastructure (I covered this in the article on tool calling in production)
- 2.Have a mature REST API with an OpenAPI spec you want to expose to agents? OpenAPI tools — do not build an MCP server just to wrap an existing API that only one application consumes
- 3.More than one AI application needs the same tools — or you want to tap into the ecosystem of ready-made servers? MCP — the cost of running a server pays off with the second client
An important nuance: these approaches are not mutually exclusive. An MCP host still uses the model's function calling under the hood — MCP standardises the layer above: where tools come from and how they are discovered.
How to build your own MCP server in Python
The fastest route is FastMCP — a high-level SDK where a tool is a decorated function. Example: a server giving an agent access to the company order database:
from fastmcp import FastMCPimport osimport psycopg2mcp = FastMCP("orders-server")def get_db(): return psycopg2.connect( host="localhost", dbname="shop", user="readonly_agent", password=os.environ["DB_PASS"] )@mcp.tool()def find_order(order_id: str) -> dict: """Returns the status, amount and date of an order by its number.""" with get_db() as conn, conn.cursor() as cur: cur.execute( "SELECT status, total, created_at FROM orders WHERE id = %s", (order_id,) ) row = cur.fetchone() if row is None: return {"error": "Order not found: " + order_id} return {"status": row[0], "total": float(row[1]), "created_at": str(row[2])}@mcp.tool()def orders_summary(days: int = 7) -> dict: """Summary of orders from the last N days: count and total revenue.""" if days < 1 or days > 90: return {"error": "days must be in the range 1-90"} with get_db() as conn, conn.cursor() as cur: cur.execute( "SELECT count(*), coalesce(sum(total),0) FROM orders " "WHERE created_at > now() - make_interval(days := %s)", (days,) ) count, total = cur.fetchone() return {"orders": count, "revenue": float(total), "period_days": days}if __name__ == "__main__": mcp.run()Three things that make a real difference here:- **Docstrings are part of the product** — they are how the model learns when to use a tool; write them like instructions for a new employee, not like comments for a programmer- **Range validation in code** — the model will eventually pass days=10000; the server must reject it, not execute it- **The readonly_agent account** — permissions are enforced by the database, not the prompt; even a successful prompt injection cannot run an UPDATE through an account that only has SELECT
Testing before connecting an agent: "npx @modelcontextprotocol/inspector python orders_mcp_server.py" opens the MCP Inspector web interface, where you can call every tool manually and see the raw responses. It is the Postman of MCP — use it before every integration.
An MCP server in TypeScript
For JS/TS teams, the official SDK looks like this — a warehouse stock server:
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: "inventory", version: "1.0.0" });server.tool( "check_stock", "Checks the stock level of a product by SKU. Returns quantity and location.", { sku: z.string().regex(/^[A-Z0-9-]{4,20}$/) }, async ({ sku }) => { const res = await fetch("https://api.company.com/v1/stock/" + sku, { headers: { Authorization: "Bearer " + process.env.WMS_TOKEN } }); if (!res.ok) { return { content: [{ type: "text", text: "Product not found: " + sku }] }; } const data = await res.json(); return { content: [{ type: "text", text: JSON.stringify(data) }] }; });const transport = new StdioServerTransport();await server.connect(transport);
Differences from Python: parameter validation is done by Zod (the regex schema on SKU rejects junk input before it touches your API), and logs must go to console.error — stdout is owned by the protocol and any console.log will break the connection. Language choice: Python/FastMCP for fast iteration and ML integrations, TypeScript for long-lived services where the type safety pays off.
Ready-made MCP servers for business tools
Before writing your own server, check the registry — most popular systems already have one:
- Data and databases: PostgreSQL, MongoDB, SQLite, Redis — queries with access control at the database-role level
- Communication: Slack (reading channels, sending messages), Gmail, Microsoft Teams
- Documents: Google Drive, Notion, Confluence, file system restricted to specified directories
- Developer: GitHub (issues, PRs, code review), GitLab, Sentry, Docker
- Business: Stripe (payments and invoices), HubSpot, Salesforce, Linear, Jira
- Web: Brave Search, Puppeteer/Playwright (browser automation), Firecrawl (scraping)
The decision rule: take a ready-made server when it covers your use case completely and comes from a trusted source (the official vendor or the modelcontextprotocol repository). Write your own when you need business logic (e.g. "find customers at churn risk"), aggregation of several systems into one tool, or hard permission constraints that a generic server does not enforce.
MCP security — a new attack surface
/// SECURITY RISKS OF THE MCP ECOSYSTEM
4 main MCP attacks — and 3 defense rules
MCP adds a class of risk to AI applications that plain function calling did not have — because tools now come from external sources. This directly extends the topics from the prompt injection article (#39):
- Tool poisoning — an attacker plants malicious instructions in a tool description; the model reads and follows them while the user never sees them, because the UI shows only the tool name
- Rug pull — a server that passed your audit quietly changes its tool definitions in a later version; trust from installation day does not last forever
- Confused deputy — the MCP server acts with broader privileges than the user invoking it; one OAuth misconfiguration and the agent does things the user is not allowed to do
- Credential leakage — MCP configuration files contain API keys and passwords; tool poisoning can instruct the agent to read and exfiltrate them (CVE-2025-6514 demonstrated OAuth token interception via a malicious authorisation endpoint)
Defense rules for deployment:
- 1.Allowlist instead of blocklist — the host denies tool invocations by default; you approve individually the ones the agent actually needs
- 2.Pin server versions — after the audit, freeze the version (exact package hash, not "latest"); an update means re-reviewing tool definitions
- 3.Least privilege at the source system level — read-only database accounts, scoped API keys, OAuth with minimal scopes; permissions are enforced by the system, not the prompt
- 4.Trusted server sources only — official vendor repositories; an MCP server from a random GitHub repo carries the same risk as installing an unknown npm package with access to your CRM
- 5.HTTPS everywhere — a significant share of audited MCP servers use plaintext HTTP, exposing tokens to interception; no TLS exceptions in production
- 6.Human-in-the-loop for irreversible actions — sending, paying and deleting require human confirmation, exactly as in the defense layers from article #39
Deploying MCP in your company — where to start
- 1.Inventory your AI applications and tools: how many hosts (Claude, Cursor, your own agents) and how many systems to connect — if the result is 1×N, stay with function calling
- 2.Start with ready-made servers in read-only mode: filesystem on a designated directory and Postgres on a readonly account — zero code, immediate value
- 3.Test every server in MCP Inspector before connecting it to a host
- 4.Write your first own server for one business process with 2–4 tools — do not build a "server for everything" on day one
- 5.Treat docstrings and tool descriptions like prompts: test whether the model picks the right tool and iterate on the wording
- 6.Validate parameters in server code (ranges, regex, types) — the model will eventually pass an absurd value
- 7.Keep all credentials in environment variables or a vault — never in a config committed to the repo
- 8.Set a tool allowlist on the host and pin server versions
- 9.Log every tool invocation (who, what, with which parameters, result) — audit and debugging in one
- 10.Move to Streamable HTTP with OAuth only when the server must be shared — local stdio is safer by default
Key takeaways
MCP solves a real problem — the N×M integration explosion — and has rare industry-wide consensus behind it: Anthropic, OpenAI, Google and Microsoft. Choose it when more than one AI application uses the same tools; for a single application, stay with function calling. Getting started is cheap: ready-made servers connect in an hour, your own takes 1–3 days with FastMCP. Take security seriously from day one: a tool allowlist, version pinning, least privilege on source-system accounts and trusted server sources only — because an MCP server is a new attack vector carrying your systems' permissions.
---
I help companies design and deploy tool architecture for AI agents — from the function calling vs MCP decision, through building custom MCP servers with proper permissions, to secure production deployment with monitoring. Get in touch — I start with a free 30-minute analysis of your use case.
/// RELATED_RECORDS
How AI Reads Invoices from Email and Enters Them into ERP
AI can automatically read an invoice from an email attachment — PDF, scan, or phone photo — and enter the data directly into an ERP system without any manual retyping. Full automation of cost invoice processing: from the mailbox to accounting.
Where to Start with AI Implementation in Your Company
AI implementation starts not with choosing a tool, but with identifying one repetitive process that wastes the most human time. Learn step by step how to select, map, and automate that process.
How to Build a Company Internal Knowledge Base with AI (RAG in Practice)
An internal knowledge base built on RAG lets you create your own company chatbot that answers only from your company's documents — not the model's guesses. Safe, up-to-date, precise AI with full control over your data.
Signal received?
Terminate
Silence
Initiate protocol. Establish connection. Let's build something loud.
