{"slug":"mcp-plain-terms","title":"MCP in Plain Terms: What Changes When the Agent Grows Up","description":"AI agents now search, chain, and summarize on their own. Here's what that means for DevOps, CloudOps, and SecOps teams building MCP tools.","date":"2025-09-13","author":"Elaph Hilful","thumbnail":"/placeholder.svg","tags":["MCP","AI Agents","DevOps","Platform Engineering","Automation","SecOps"],"category":"Platform Engineering","featured":true,"readTime":5,"htmlContent":"<p>The agent grew up. Our servers should too.</p>\n<p>MCP is how AI agents plug into our systems. What changed this year is simple: the agent now does more of the work itself, so what we build on our side has to change.</p>\n<h2>The Shift: From Hand-Holding to Self-Service</h2>\n<div class=\"mermaid\">graph LR\n    subgraph Before[\"Before: Hand Everything Over\"]\n        A1[Agent] --&gt; B1[All Tools Loaded]\n        B1 --&gt; C1[Manual Chaining]\n        C1 --&gt; D1[Full Output Dump]\n    end\n\n    subgraph After[\"After: Agent Fetches What It Needs\"]\n        A2[Agent] --&gt; B2[Search for Tool]\n        B2 --&gt; C2[Auto-Chain Calls]\n        C2 --&gt; D2[Summary Only]\n    end\n</div>\n<p>The agent used to be handed everything at once. Now it fetches what it needs and chains the calls itself.</p>\n<h3>What the Agent Now Does Itself</h3>\n<ul>\n<li><strong>Searches for the tool it needs</strong> instead of holding all of them in memory</li>\n<li><strong>Writes a small script</strong> to run several tools in a row, in a safe sandbox</li>\n<li><strong>Sends back only the final answer</strong>, not every intermediate step</li>\n</ul>\n<h3>What's Left to Us</h3>\n<ul>\n<li><strong>Decide which jobs</strong> the agent can do at all</li>\n<li><strong>Name them clearly</strong> so it picks the right one</li>\n<li><strong>Control who is allowed</strong> to run each one</li>\n</ul>\n<p>The point: don't just expose every API call as a tool. Offer the common jobs as single tools, the way an SDK offers shortcut methods. That's where the value is now.</p>\n<h2>What This Means for Ops Teams</h2>\n<p>DevOps, CloudOps, SecOps, SaaSOps — most of our work is already a fixed sequence of steps across several systems. That's exactly what should become a single tool.</p>\n<div class=\"mermaid\">graph TD\n    subgraph Tool[\"One Tool: triage_service\"]\n        A[Agent calls triage_service] --&gt; B[Pull recent deploys]\n        B --&gt; C[Fetch error logs]\n        C --&gt; D[Gather traces]\n        D --&gt; E[Check alerts]\n        E --&gt; F[Container health]\n        F --&gt; G[Return summary]\n    end\n</div>\n<p>A runbook turned into one tool call. The steps and the order live in the tool, not in the agent's head.</p>\n<h3>The Tool Catalog</h3>\n<table>\n<thead>\n<tr>\n<th>Team</th>\n<th>Tool</th>\n<th>What It Does Behind the Scenes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>DevOps</strong></td>\n<td><code>triage_service</code></td>\n<td>Pulls recent deploys, errors, traces, alerts and container health — returns one summary</td>\n</tr>\n<tr>\n<td><strong>DevOps</strong></td>\n<td><code>promote_release</code></td>\n<td>Checks the pipeline, ships the new version, watches health, rolls back if it fails</td>\n</tr>\n<tr>\n<td><strong>CloudOps</strong></td>\n<td><code>find_cost_hotspots</code></td>\n<td>Cost data, untagged resources and idle capacity, mapped to the team that owns them</td>\n</tr>\n<tr>\n<td><strong>SecOps</strong></td>\n<td><code>review_access</code></td>\n<td>Shows a role, its permissions, when they were last used, and what looks unusual</td>\n</tr>\n<tr>\n<td><strong>SecOps</strong></td>\n<td><code>collect_audit_evidence</code></td>\n<td>Gathers config snapshots, log retention proof and approvals for one control</td>\n</tr>\n<tr>\n<td><strong>SaaSOps</strong></td>\n<td><code>offboard_person</code></td>\n<td>Disables the account, kills sessions and reclaims paid seats across every SaaS app</td>\n</tr>\n</tbody>\n</table>\n<h3>Why This Is Safer, Not Riskier</h3>\n<p>The correct order lives in the tool, so the agent cannot invent its own version of a runbook. Fewer half-finished changes, and a clean record of who ran what.</p>\n<h2>How to Start, Safely</h2>\n<p>Start with things that cannot break anything, then earn the right to add the ones that can.</p>\n<div class=\"mermaid\">graph LR\n    A[Read-Only Tools] --&gt;|Build trust| B[Permission Tools]\n    B --&gt;|Prove safety| C[Change Tools]\n\n    A1[\"list_services&lt;br&gt;get_logs&lt;br&gt;show_metrics\"] --&gt; A\n    B1[\"review_access&lt;br&gt;audit_config&lt;br&gt;check_compliance\"] --&gt; B\n    C1[\"promote_release&lt;br&gt;offboard_person&lt;br&gt;scale_service\"] --&gt; C\n</div>\n<p>Read-only first, permissions next, changes last.</p>\n<h2>Rules for Every Tool We Ship</h2>\n<table>\n<thead>\n<tr>\n<th>Rule</th>\n<th>Why</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Safe to run twice</strong></td>\n<td>Agents retry. Running a tool again must not create a second thing.</td>\n</tr>\n<tr>\n<td><strong>Show before you change</strong></td>\n<td>A preview call lists what would change. Approval is a separate step.</td>\n</tr>\n<tr>\n<td><strong>Short answers</strong></td>\n<td>Return a summary, not a huge dump. Big outputs get truncated or ignored.</td>\n</tr>\n<tr>\n<td><strong>Clear failures</strong></td>\n<td>Say which step failed and what is safe to do next.</td>\n</tr>\n<tr>\n<td><strong>Narrow permissions</strong></td>\n<td>One set of permissions per group of tools, not one key for everything.</td>\n</tr>\n<tr>\n<td><strong>Logged and redacted</strong></td>\n<td>Record who called what. Strip secrets and patient data at the edge.</td>\n</tr>\n</tbody>\n</table>\n<h3>Idempotency Example</h3>\n<pre role=\"region\" aria-label=\"python code block\"><code class=\"hljs language-python\" tabindex=\"0\"><span class=\"hljs-comment\"># Bad: Creates duplicate on retry</span>\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">create_user</span>(<span class=\"hljs-params\">name: <span class=\"hljs-built_in\">str</span></span>) -&gt; <span class=\"hljs-built_in\">dict</span>:\n    <span class=\"hljs-keyword\">return</span> db.insert({<span class=\"hljs-string\">\"name\"</span>: name})\n\n<span class=\"hljs-comment\"># Good: Safe to run twice</span>\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">ensure_user</span>(<span class=\"hljs-params\">name: <span class=\"hljs-built_in\">str</span></span>) -&gt; <span class=\"hljs-built_in\">dict</span>:\n    existing = db.find_one({<span class=\"hljs-string\">\"name\"</span>: name})\n    <span class=\"hljs-keyword\">if</span> existing:\n        <span class=\"hljs-keyword\">return</span> {<span class=\"hljs-string\">\"status\"</span>: <span class=\"hljs-string\">\"exists\"</span>, <span class=\"hljs-string\">\"user\"</span>: existing}\n    <span class=\"hljs-keyword\">return</span> {<span class=\"hljs-string\">\"status\"</span>: <span class=\"hljs-string\">\"created\"</span>, <span class=\"hljs-string\">\"user\"</span>: db.insert({<span class=\"hljs-string\">\"name\"</span>: name})}\n</code></pre>\n<h3>Preview-Before-Change Pattern</h3>\n<pre role=\"region\" aria-label=\"python code block\"><code class=\"hljs language-python\" tabindex=\"0\"><span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">promote_release</span>(<span class=\"hljs-params\">service: <span class=\"hljs-built_in\">str</span>, version: <span class=\"hljs-built_in\">str</span>, preview: <span class=\"hljs-built_in\">bool</span> = <span class=\"hljs-literal\">True</span></span>) -&gt; <span class=\"hljs-built_in\">dict</span>:\n    changes = calculate_changes(service, version)\n\n    <span class=\"hljs-keyword\">if</span> preview:\n        <span class=\"hljs-keyword\">return</span> {\n            <span class=\"hljs-string\">\"action\"</span>: <span class=\"hljs-string\">\"preview\"</span>,\n            <span class=\"hljs-string\">\"would_update\"</span>: changes[<span class=\"hljs-string\">\"pods\"</span>],\n            <span class=\"hljs-string\">\"rollback_available\"</span>: <span class=\"hljs-literal\">True</span>\n        }\n\n    <span class=\"hljs-comment\"># Actual promotion requires explicit preview=False</span>\n    <span class=\"hljs-keyword\">return</span> execute_promotion(service, version)\n</code></pre>\n<h2>The Architecture</h2>\n<div class=\"mermaid\">flowchart TD\n    Agent[AI Agent] --&gt; MCP[MCP Gateway]\n    MCP --&gt; Auth{Auth &amp; Permissions}\n    Auth --&gt;|Allowed| Router[Tool Router]\n    Auth --&gt;|Denied| Reject[Reject + Log]\n\n    Router --&gt; DevOps[DevOps Tools]\n    Router --&gt; CloudOps[CloudOps Tools]\n    Router --&gt; SecOps[SecOps Tools]\n\n    DevOps --&gt; K8s[Kubernetes]\n    DevOps --&gt; CI[CI/CD Pipeline]\n    CloudOps --&gt; AWS[AWS/Azure/GCP]\n    SecOps --&gt; IAM[IAM Systems]\n    SecOps --&gt; SIEM[SIEM/Logs]\n\n    subgraph Audit\n        Log[Audit Log]\n        Redact[PII Redaction]\n    end\n\n    Router --&gt; Audit\n</div>\n<h2>The Takeaway</h2>\n<p>Let the agent handle finding and chaining tools. We decide:</p>\n<ol>\n<li><strong>Which jobs exist</strong> — the runbooks worth automating</li>\n<li><strong>What they cost to run</strong> — rate limits, approval gates, resource bounds</li>\n<li><strong>Who is allowed to run them</strong> — RBAC at the tool level, not the API level</li>\n</ol>\n<p>The agent got smarter. Our job isn't to give it more power — it's to give it the right power, safely packaged, clearly named, and properly logged.</p>\n<h2>Resources</h2>\n<ul>\n<li><a href=\"https://modelcontextprotocol.io/\">Model Context Protocol Specification</a></li>\n<li><a href=\"https://github.com/modelcontextprotocol/servers\">MCP Server Examples</a></li>\n<li><a href=\"/blog/ai-agent-kubectl-bouncer\">Building Secure AI Agent Tools</a></li>\n</ul>"}