What is the Model Context Protocol?
The Model Context Protocol (MCP) is an open-source standard created by Anthropic to solve a fundamental problem: how to allow an LLM to access external tools, data, and contexts in a secure and standardised way? Before MCP, every AI application had to implement its own proprietary integrations for each tool.
MCP defines a JSON-RPC 2.0 protocol between two actors:
- MCP Client: the AI application (Claude Desktop, Claude Code, your custom application)
- MCP Server: a process exposing capabilities (tools, resources, prompts) through the standardised protocol
Communication happens via stdin/stdout (local processes) or HTTP+SSE (remote servers).
MCP Primitives
- Tools: functions the LLM can call (e.g.
kubectl_get_pods,terraform_plan). The LLM decides when to invoke them based on context. - Resources: static or dynamic data exposed as context (e.g. file contents, SQL query result)
- Prompts: parameterised prompt templates the user can activate
- Sampling: the server can ask the client to make an LLM inference (recursive agents)
MCP vs Classic Function Calling
Function calling (OpenAI, Anthropic) already allows LLMs to call functions. MCP adds two further advantages:
- Standardisation: an MCP server works with any compatible client (Claude, Cursor, your custom app) without modification
- Dynamic discovery: the client discovers available tools at runtime via
tools/list, without static configuration
Building an MCP Server for AWS CLI
Here is a minimal MCP server in TypeScript that exposes AWS commands as tools accessible by an LLM:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
const server = new Server(
{ name: "aws-devops-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "list_ecs_services",
description: "List ECS services in a cluster",
inputSchema: {
type: "object",
properties: {
cluster: { type: "string", description: "ECS cluster name" },
region: { type: "string", description: "AWS region", default: "eu-west-1" },
},
required: ["cluster"],
},
},
{
name: "get_cloudwatch_logs",
description: "Retrieve CloudWatch logs from a log group",
inputSchema: {
type: "object",
properties: {
logGroupName: { type: "string" },
minutes: { type: "number", default: 15 },
},
required: ["logGroupName"],
},
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "list_ecs_services") {
const { stdout } = await execAsync(
`aws ecs list-services --cluster ${args.cluster} --region ${args.region || "eu-west-1"} --output json`
);
return { content: [{ type: "text", text: stdout }] };
}
if (name === "get_cloudwatch_logs") {
const startTime = Date.now() - (args.minutes || 15) * 60 * 1000;
const { stdout } = await execAsync(
`aws logs filter-log-events --log-group-name "${args.logGroupName}" --start-time ${startTime} --output json`
);
return { content: [{ type: "text", text: stdout }] };
}
throw new Error(`Unknown tool: ${name}`);
});
const transport = new StdioServerTransport();
server.connect(transport);
MCP Server for Kubernetes
// kubectl wrapped as MCP tool
{
name: "kubectl_get",
description: "Run kubectl get on a namespace and resource",
inputSchema: {
type: "object",
properties: {
resource: { type: "string", description: "Resource type (pods, services, deployments)" },
namespace: { type: "string", default: "default" },
selector: { type: "string", description: "Optional label selector" },
},
required: ["resource"],
},
}
// Handler
const { stdout } = await execAsync(
`kubectl get ${args.resource} -n ${args.namespace} ${args.selector ? '-l ' + args.selector : ''} -o json`
);
Claude Desktop Integration
To connect your MCP server to Claude Desktop, add it to the configuration:
// ~/.config/claude/claude_desktop_config.json
{
"mcpServers": {
"aws-devops": {
"command": "node",
"args": ["/opt/mcp-servers/aws-devops/dist/index.js"],
"env": {
"AWS_PROFILE": "production",
"AWS_DEFAULT_REGION": "eu-west-1"
}
},
"kubernetes": {
"command": "node",
"args": ["/opt/mcp-servers/kubernetes/dist/index.js"],
"env": {
"KUBECONFIG": "/home/user/.kube/config"
}
}
}
}
MCP Server for GitHub
The official GitHub MCP server (github.com/github/github-mcp-server) exposes GitHub operations as MCP tools:
list_pull_requests: list PRs for a repositorycreate_issue: create a GitHub issueget_file_contents: read file contents from a repositorysearch_code: search code across the organisation
Security Considerations
MCP servers have access to powerful tools — rigorous validation is essential:
- Input validation: validate all arguments before executing shell commands (command injection)
- Principle of least privilege: the MCP server should have only the minimum permissions required
- Sandboxing: run the MCP server in a container with limited capabilities
- Audit log: log all tool invocations with the user's identity
- Command allowlist: do not expose a generic
exec_commandtool — define specific tools with validation
Production Deployment of an MCP Server
For an MCP server used by a team, deploy it as an HTTP service with SSE transport:
// MCP server with HTTP/SSE transport
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import express from "express";
const app = express();
const transports = new Map();
app.get("/mcp", (req, res) => {
const transport = new SSEServerTransport("/mcp/message", res);
transports.set(transport.sessionId, transport);
server.connect(transport);
});
app.post("/mcp/message", (req, res) => {
const transport = transports.get(req.query.sessionId);
transport?.handlePostMessage(req, res);
});
app.listen(3000);
MCP Ecosystem
In 2026, the MCP ecosystem has several hundred open-source servers:
- Databases: PostgreSQL, MySQL, Redis, MongoDB
- Cloud: AWS, GCP, Azure, Terraform, Pulumi
- DevOps: GitHub, GitLab, Jira, PagerDuty, Datadog
- Productivity: Slack, Notion, Google Drive, Gmail
- Observability: Grafana, Prometheus, OpenSearch
Conclusion
MCP is becoming the universal standard for connecting LLMs to enterprise tools. Its simplicity (JSON-RPC over stdio or HTTP) and its explicit security model (the LLM can only do what an MCP tool authorises) make it a solid foundation for building reliable AI agents in DevOps contexts. The key to success: define tools with clear interfaces and rigorous validation rather than exposing generic unbounded tools.
