Build a Support Copilot That Loads the Runbook Before It Calls a Tool A developer built a support copilot that separates instruction bundles from tool authorization, loading runbooks only when relevant and keeping permission decisions in code rather than in the model. The workflow classifies messages, selects an allowed runbook, and produces an escalation packet for human resolution, emphasizing that natural-language messages are untrusted input. An AI support demo can look finished after it answers one question and calls one API. The production tension appears later: the model has instructions, tools, customer messages, and credentials in the same context—but nobody can clearly say which part authorizes what. That is not just an AI problem. It is a systems-design problem hiding behind natural language. A reliable support copilot needs at least two separate layers: Reusable instruction bundles—often called skills—fit the first layer. MCP can fit the second by exposing tools through a common protocol. They are complementary, not interchangeable. This tutorial builds a small workflow that selects a support runbook, loads it only when relevant, permits read-only diagnostics, and produces an escalation packet for a human. The goal is not autonomous support. It is faster investigation without quietly transferring operational authority to a model. A support request should move through this sequence: visitor message ↓ normalize and classify ↓ select an allowed runbook ↓ load its full instructions ↓ request approved diagnostic tools ↓ apply policy outside the model ↓ return evidence, unknowns, and a proposed next step ↓ human resolves, replies, or escalates The model may propose a tool call. It does not decide whether it has permission to make that call. This distinction matters more than whether the instruction file is branded as a skill, prompt, playbook, or procedure. Natural-language messages are untrusted input, not operating instructions. Normalize them before putting them near a model or a tool registry. js import { z } from "zod"; export const SupportCase = z.object { id: z.string .uuid , message: z.string .min 1 .max 4 000 , category: z.enum "availability", "authentication", "billing", "how to", "unknown" , appVersion: z.string .max 80 .optional , accountRef: z.string .max 120 .optional , receivedAt: z.string .datetime } ; export type SupportCase = z.infer