The Model Context Protocol (MCP) is an open standard for connecting AI assistants to tools and data. One MCP server for your ops tooling can serve every MCP-capable assistant your engineers use.
1. Start small and read-only
Good first tools for an ops team:
| Tool | Returns |
|---|---|
service_health(service) | Status, last deploy, open incidents |
recent_errors(service, minutes) | Top error messages with counts |
search_runbooks(query) | Titles and links of matching runbooks |
No restarts, no deletes, no config changes in version one.
2. The server
pip install "mcp[cli]" httpx
# ops_mcp.py
from mcp.server.fastmcp import FastMCP
import httpx, os
mcp = FastMCP("ops-tools")
API = os.environ["OPS_API_URL"]
TOKEN = os.environ["OPS_API_TOKEN"] # read-only token
@mcp.tool()
async def service_health(service: str) -> dict:
"""Current health of ONE service: status, last deployment time and open incidents.
Use when the user asks whether a named service is up or degraded."""
async with httpx.AsyncClient(timeout=10) as c:
r = await c.get(f"{API}/services/{service}/health", headers={"Authorization": f"Bearer {TOKEN}"})
r.raise_for_status()
return r.json()
@mcp.tool()
async def recent_errors(service: str, minutes: int = 30) -> list[dict]:
"""Top 20 distinct error messages for a service in the last N minutes (max 240), with counts."""
minutes = max(1, min(minutes, 240))
async with httpx.AsyncClient(timeout=20) as c:
r = await c.get(f"{API}/services/{service}/errors", params={"minutes": minutes, "limit": 20},
headers={"Authorization": f"Bearer {TOKEN}"})
r.raise_for_status()
return r.json()
if __name__ == "__main__":
mcp.run() # stdio transport by default
The docstrings become the tool descriptions the model reads. Write them like instructions: what it does, when to use it, limits.
3. Test it
mcp dev ops_mcp.py # opens the MCP Inspector to call tools by hand
Then register it in your MCP client following that client's documentation (each one has a config file or command for adding a stdio server, passing the environment variables).
4. Guardrails
- Read-only credentials for the backing APIs. The server can't do more than its token allows.
- Clamp parameters (time ranges, limits) in code, as above.
- Strip secrets and personal data from results before returning them.
- Log every tool call with the user, arguments and result size.
- For a shared remote server (HTTP transport), require authentication and authorise per user.
5. Adding write actions later
If you add actions such as "restart pod", make them narrow (one service, one action), require the client's human approval step, rate-limit them, and keep them in a separate server or toolset that only on-call engineers enable.
Tip
Treat tool output as untrusted input to the model: an error message or log line can contain text like "ignore previous instructions". See the prompt injection checklist before connecting tools that read customer-provided content.