Model Context Protocol is how org-approved AI assistants (Claude Code, Copilot, Cursor and peers) get hands on your platform without screen-scraping or pasted kubeconfigs: you write one MCP server wrapping your platform's APIs, and every MCP-capable assistant your engineers use can query deployments, fetch service metadata, and — behind an approval gate — invoke golden-path actions.
Tier: Advanced · Hands-on time: ~2 hours
Pulumi's MCP server is the public reference for the pattern; this playbook builds yours, with read/write tiering and authz designed in from the first tool, not bolted on after the demo.
Skip MCP if only one bespoke internal app needs the integration — a direct API call is simpler. MCP pays off when multiple assistants/clients should share one governed integration point.
Pick 3 reads and 1 gated write. Classic starter set: get_service_info (catalog metadata, owner, on-call), get_deploy_status (recent deploys, versions, health), query_logs_or_metrics (bounded, read-only query passthrough), and scaffold_service or create_ephemeral_env as the single write — approval-gated. Resist tool sprawl: assistants pick tools by description, and ten vague tools confuse models where four sharp ones excel.
Design tool contracts for a model audience. Each tool gets: a description written to disambiguate ("use this for CURRENT deploy state, not history"), a tight input schema (enums for environment names, bounded time ranges, no free-form query strings where a structured filter works), and result shaping — return compact structured summaries, not 5MB JSON dumps that blow the assistant's context. Have AI draft the contracts, then edit descriptions like the product copy they are.
Implement reads with identity passthrough. The server authenticates the calling user (OAuth flow or per-user token) and calls platform APIs with that identity — so existing RBAC answers "can this user see prod logs?", not the MCP server's own privileges. Log every call: user, tool, arguments, result size, latency. Rate-limit per user from day one.
Implement the write as request-then-approve. The write tool does not execute — it files a validated request (pb-37's pipeline) and returns the request ID and approval link. A platform engineer (or the pipeline's policy check for sandbox tiers) approves; the assistant can poll status via a read tool. The assistant experience is still "I asked, it happened" — with a human between asking and happening for anything real.
Red-team the tool surface. Injection attempts via tool arguments ("env: prod; DROP TABLE"), data exfiltration via over-broad queries, description-abuse (does the model call the write tool when a read was wanted?), and confused-deputy checks (user A cannot fetch what their RBAC denies, no matter how the assistant phrases it). Also test the reverse direction: results returned to the assistant are untrusted-adjacent too — a log line containing "ignore previous instructions" must not steer the assistant into calling the write tool; document this residual risk and mitigate with result sanitization and the approval gate.
Package, distribute, and version. Ship client config snippets for your org's blessed assistants (Claude Code .mcp.json, Copilot/Cursor equivalents) via the golden-path template so onboarding is copy-paste. Version the server like an API (it is one): changelog, deprecation policy for tool signature changes, and an eval suite — canned assistant tasks ("what's deployed in staging for checkout?") that must produce correct tool calls — run in CI on every change.
An internal MCP server turns "every engineer pastes secrets and state into chat windows" into one governed, audited, identity-aware integration point — the platform team's answer to shadow AI integrations.
Every tool you expose is attack surface reachable by natural language from any connected assistant — scope reads tightly, gate writes with humans, and treat tool results as untrusted input to the model.