MCP Concepts Explained: Tools, Resources, and Prompts
A developer-friendly explainer of the Model Context Protocol — tools, resources, prompts, and how MCP connects AI applications to external systems.
Published on • September 9, 2026
AI Assistant

MCP Concepts Explained: Tools, Resources, and Prompts
MCP is the USB-C port for AI applications. It provides a standardized way to connect Claude, ChatGPT, VS Code Copilot, and Cursor to data sources, tools, and workflows. Build once, integrate everywhere.
Architecture: Host, Client, Server
MCP follows a client-server architecture with three participants:
| Participant | Role |
|---|---|
| MCP Host | The AI application (Claude Desktop, VS Code) that coordinates clients |
| MCP Client | Component that maintains a connection to an MCP server |
| MCP Server | Program that provides context to clients |
MCP Host (AI Application)
├── MCP Client 1 ──→ Server A (Filesystem)
├── MCP Client 2 ──→ Server B (Database)
└── MCP Client 3 ──→ Server C (Sentry)
Two layers:
- Data Layer — JSON-RPC 2.0 for client-server communication
- Transport Layer — stdio for local, Streamable HTTP for remote
Three Primitives, Three Control Models
The key insight: MCP defines three primitives with different control models.
Tools (Model-Controlled)
Functions the LLM calls to take actions. The model discovers and invokes tools automatically.
{
"name": "get_weather",
"description": "Get current weather for a location",
"inputSchema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name"}
},
"required": ["location"]
}
}
The flow: Client sends tools/list → LLM selects a tool → Client sends tools/call → Server returns result.
Resources (Application-Controlled)
Data the host application loads into the model’s context. Identified by URI:
{
"uri": "file:///project/src/main.rs",
"name": "main.rs",
"description": "Primary application entry point",
"mimeType": "text/x-rust"
}
Common URI schemes: https://, file://, git://, custom schemes.
Prompts (User-Controlled)
Reusable templates users invoke by name — slash commands, menu entries.
{
"name": "code_review",
"description": "Analyze code quality and suggest improvements",
"arguments": [
{"name": "code", "description": "The code to review", "required": true}
]
}
Building an MCP Server in Python (15 Lines)
from mcp.server import MCPServer
mcp = MCPServer("Demo")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
"""Greet someone by name."""
return f"Hello, {name}!"
No JSON Schema needed — type hints are the schema. The SDK handles protocol handling, serialization, and validation automatically.
MCP Client in 10 Lines
import asyncio
from mcp import Client
async def main():
async with Client("http://localhost:8000/mcp") as client:
result = await client.call_tool("add", {"a": 1, "b": 2})
print(result.structured_content) # {'result': 3}
asyncio.run(main())
TypeScript Server
import { McpServer } from '@modelcontextprotocol/server';
import { serveStdio } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';
serveStdio(() => {
const server = new McpServer({ name: 'weather', version: '1.0.0' });
server.registerTool(
'get-forecast',
{
description: 'Get weather forecast for a city',
inputSchema: z.object({ city: z.string() })
},
async ({ city }) => ({
content: [{ type: 'text', text: `Sunny in ${city} all week.` }]
})
);
return server;
});
Client Primitives
MCP also defines primitives that clients expose:
- Elicitation — Servers can request additional info from users (confirmation, form input)
- Logging — Servers send log messages to clients
Real-Time Notifications
MCP supports push updates without polling:
notifications/tools/list_changed— Available tools changednotifications/resources/list_changed— Available resources changednotifications/resources/updated— A specific resource changed
Clients subscribe via subscriptions/listen with filters.
Security Essentials
- Servers MUST validate all tool inputs and implement access controls
- Clients SHOULD prompt for user confirmation on sensitive operations
- Human-in-the-loop is recommended for trust and safety
- Rate limit invocations to prevent abuse
The Takeaway
MCP gives you three primitives with clean separation of concerns: Tools let the model act, Resources give the model context, Prompts let users drive. The Python and TypeScript SDKs handle all protocol complexity — write functions with type hints, and the SDK does the rest.
💡 Install the MCP Python SDK with
uv add "mcp[cli]"and scaffold a server in seconds.