Build an Insurance Agency Operations MCP Server for Quoting & CRM Workflows
Inspired by SUPERAGENT 3.0 (August 11, 2026), the AI business partner for insurance agencies, this dispatch builds agency-ops-mcp, a FastMCP TypeScript server exposing read-only quote data, policy and CRM lookup, and compliance status to agents. Write tools for quote generation and policy updates are gated behind OAuth scopes plus a human approval gate, and every action is written to an append-only audit trail.
Deepak Bagada
Founder & Editor-in-Chief
- SUPERAGENT 3.0 on August 11, 2026 positioned AI as an insurance agency business partner, and agency-ops-mcp turns the quoting + CRM pattern into a reusable FastMCP server.
- Read tools for quotes, policies, CRM contacts, and compliance status are always available to authenticated agents.
- Write tools — generate_quote and update_policy — require OAuth scopes plus a human approval gate and return approval intents, never completion states.
- Compliance status is surfaced read-only to every agent so no model ever changes a compliance flag without a human.
- Audit logging, audience validation, and credential isolation protect carrier data across every read and write.
By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.
On August 11, 2026, SUPERAGENT 3.0 landed and reframed what an AI assistant is for an insurance agency. Rather than a chat copilot that answers questions, SUPERAGENT 3.0 positions itself as an AI business partner that can run quoting, CRM, and follow-up workflows on the agency's behalf. For a vertical as regulated and data-dense as insurance, that framing matters because the value is real — agencies drown in carrier portals, rate sheets, and renewal follow-ups — and the risk is equally real. A misfired policy update or an unapproved quote can mean a compliance violation, an E&O claim, or a carrier relationship burned over a single weekend.
The engineering answer is the one every regulated vertical is converging on: reads wide open, writes gated. This dispatch builds that answer. You will implement agency-ops-mcp, a FastMCP TypeScript server that exposes read-only quote data, policy and CRM lookup, and compliance status to agents, with human-approval-gated write tools for quote generation and policy updates. Read tools are always available to authenticated agents; write tools return approval intents, never completion states; and every action lands in an append-only audit trail. Keep the MCP directory open while you build — a server like this is the canonical agency-ops entry.
What SUPERAGENT 3.0 changed for agencies
The August 11, 2026 release of SUPERAGENT 3.0 was a statement about agency operations, not chat. The product's pitch is an AI business partner that owns workflows end to end: it can size a prospect's risk profile, pull rates from carriers, build a quote, update the CRM, and follow up on renewals — the exact list of tasks that used to keep an agency principal working past 7 p.m. For independent agencies the appeal is arithmetic. Every hour an agent spends orchestrating carrier quotes is an hour not spent on the relationships that actually retain clients. The latest-ai-news coverage of the launch kept repeating one line: agencies do not have an AI problem, they have an operations problem, and the AI finally fits into the operations.
The catch is that insurance is regulated, quoted prices are binding once bound, and policy records are legal artifacts. SUPERAGENT 3.0's own rollout stressed approvals around quoting; any agency that wires its own tools has to build the same guardrails, because a carrier will not care which AI drafted the bad quote. That is precisely the pattern agency-ops-mcp encodes: quote data, policy records, CRM contacts, and compliance status are read-only to agents, while generating a quote or updating a policy is a write that requires OAuth scopes plus a human approval gate. The workflows library carries a companion template for approval-gated quote pipelines if you want the orchestration layer to match.
Architecture
Every request forks at one point: read or write? Reads hit the quoting, policy, CRM, and compliance APIs directly. Writes pass through a scope check and a human approval gate that live outside the model. Every leg reports to the same append-only audit trail, so the server's behavior is explainable after the fact and defensible in a compliance review.
flowchart TD
A[MCP client agent] -->|Bearer token + scopes| B[agency-ops-mcp FastMCP server]
B --> C{Read or write tool?}
C -->|read| D[Read dispatcher]
D --> E[Quote data lookup]
D --> F[Policy lookup]
D --> G[CRM contact search]
D --> H[Compliance status]
B -->|write| I{Scope token present?}
I -->|no| J[403 missing write scope]
I -->|yes| K{Human approval gate}
K -->|rejected| L[Audit: write blocked]
K -->|approved| M[Write executor]
M --> N[generate_quote -> rating engine]
M --> O[update_policy -> policy system]
N --> P[Append-only audit trail]
O --> P
E --> P
F --> P
G --> P
H --> P
The TypeScript implementation
The server uses @modelcontextprotocol/sdk with McpServer and zod, and every tool is registered through registerTool. Read and write tools are registered in separate methods, so the boundary is structural, not just documented.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
type AgentContext = {
principalId: string;
scopes: string[];
};
export class AgencyOpsMcp {
private server: McpServer;
private quotes: QuotesApi;
private policies: PoliciesApi;
private crm: CrmApi;
private compliance: ComplianceApi;
private audit: AuditTrail;
private approvals: ApprovalService;
constructor() {
this.quotes = new QuotesApi();
this.policies = new PoliciesApi();
this.crm = new CrmApi();
this.compliance = new ComplianceApi();
this.audit = new AuditTrail();
this.approvals = new ApprovalService();
this.server = new McpServer({ name: "agency-ops-mcp", version: "1.0.0" });
this.registerReadTools();
this.registerWriteTools();
}
private registerReadTools() {
this.server.registerTool(
"get_quote",
"Return a quote by ID with coverage, premium, and status. Read-only quote data.",
{ quoteId: z.string().describe("Quote identifier") },
async ({ quoteId }, extra) => {
const ctx = this.contextFrom(extra);
this.audit.log(ctx.principalId, "get_quote", { quoteId }, "read");
return this.quotes.get(quoteId);
}
);
this.server.registerTool(
"list_quotes",
"List quotes for an account or prospect with status and premium totals.",
{
accountId: z.string().describe("Account identifier"),
limit: z.number().int().min(1).max(50).default(20)
},
async ({ accountId, limit }, extra) => {
const ctx = this.contextFrom(extra);
this.audit.log(ctx.principalId, "list_quotes", { accountId }, "read");
return this.quotes.forAccount(accountId, limit);
}
);
this.server.registerTool(
"get_policy",
"Return policy details, endorsements, and renewal date. Read-only policy lookup.",
{ policyId: z.string().describe("Policy identifier") },
async ({ policyId }, extra) => {
const ctx = this.contextFrom(extra);
this.audit.log(ctx.principalId, "get_policy", { policyId }, "read");
return this.policies.get(policyId);
}
);
this.server.registerTool(
"search_contacts",
"Search CRM contacts and accounts. Returns matched records read-only.",
{
query: z.string().describe("Name, email, or account search"),
maxResults: z.number().int().min(1).max(25).default(10)
},
async ({ query, maxResults }, extra) => {
const ctx = this.contextFrom(extra);
this.audit.log(ctx.principalId, "search_contacts", { query }, "read");
return this.crm.search(query, maxResults);
}
);
this.server.registerTool(
"get_compliance_status",
"Return compliance status for a policy, agency, or carrier filing. Read-only; never mutates compliance state.",
{
entityId: z.string().describe("Policy, agency, or filing identifier"),
entityType: z.enum(["policy", "agency", "filing"]).default("policy")
},
async ({ entityId, entityType }, extra) => {
const ctx = this.contextFrom(extra);
this.audit.log(ctx.principalId, "get_compliance_status", { entityId }, "read");
return this.compliance.status(entityId, entityType);
}
);
}
private registerWriteTools() {
this.server.registerTool(
"generate_quote",
"PROPOSE generating a quote for an account from coverage inputs. Requires quote:write scope AND human approval; the quote is not bound until approved.",
{
accountId: z.string().describe("Account to quote"),
coverages: z.array(z.object({
line: z.string().describe("Coverage line, e.g. general liability"),
limit: z.number().int().describe("Coverage limit in USD")
})).describe("Coverage selections"),
carrierId: z.string().optional().describe("Preferred carrier, if any")
},
async ({ accountId, coverages, carrierId }, extra) => {
const ctx = this.contextFrom(extra);
if (!ctx.scopes.includes("quote:write")) {
throw new Error("Missing quote:write scope");
}
this.audit.log(ctx.principalId, "generate_quote", { accountId }, "write-proposed", "high");
return this.approvals.createIntent("generate_quote", ctx.principalId, { accountId, coverages, carrierId });
}
);
this.server.registerTool(
"update_policy",
"PROPOSE updating a policy record (endorsement, billing contact, effective date). Requires policy:write scope plus approval.",
{
policyId: z.string().describe("Policy identifier"),
changes: z.array(z.object({
field: z.string(),
value: z.string()
})).describe("Field changes to apply")
},
async ({ policyId, changes }, extra) => {
const ctx = this.contextFrom(extra);
if (!ctx.scopes.includes("policy:write")) {
throw new Error("Missing policy:write scope");
}
this.audit.log(ctx.principalId, "update_policy", { policyId }, "write-proposed", "high");
return this.approvals.createIntent("update_policy", ctx.principalId, { policyId, changes });
}
);
}
private contextFrom(extra: any): AgentContext {
return decodeAndValidateToken(extra?.session?.auth?.token);
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
}
}
The design decisions are the same three that carry any regulated-vertical MCP server. Write tools return approval intents, never completion states — a model can prepare a quote but never bind one. Every write re-checks scopes on the resolved token at runtime, so a config block cannot overstate authority. And the audit trail records the proposal before execution, so a blocked attempt is as visible as an executed one.
inputSchema
The schemas below are the JSON Schema the client registers, generated from the zod definitions above. Write schemas carry exactly the fields a reviewer needs — coverage lines for a quote, a change list for a policy update — because an approval gate is only as good as the context it shows the approver.
{
"get_quote": {
"type": "object",
"properties": { "quoteId": { "type": "string" } },
"required": ["quoteId"],
"additionalProperties": false
},
"generate_quote": {
"type": "object",
"properties": {
"accountId": { "type": "string" },
"coverages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"line": { "type": "string" },
"limit": { "type": "integer" }
},
"required": ["line", "limit"]
}
},
"carrierId": { "type": "string" }
},
"required": ["accountId", "coverages"],
"additionalProperties": false
},
"update_policy": {
"type": "object",
"properties": {
"policyId": { "type": "string" },
"changes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"field": { "type": "string" },
"value": { "type": "string" }
},
"required": ["field", "value"]
}
}
},
"required": ["policyId", "changes"],
"additionalProperties": false
}
}
mcpServers config
Connect any MCP client with this block. The oauth entry requests the scope set at handshake; a read-only service-desk agent should request only the read scopes so it is never handed a write path it can exercise.
{
"mcpServers": {
"agency-ops": {
"command": "node",
"args": ["dist/index.js"],
"env": {
"AOP_AUTH_URL": "https://auth.example.com",
"AOP_AUDIENCE": "api.agency.example.com",
"AOP_LOG_LEVEL": "info"
},
"oauth": {
"authorization_url": "https://auth.example.com/authorize",
"token_url": "https://auth.example.com/oauth/token",
"scopes": ["quote:read", "policy:read", "crm:read", "compliance:read", "quote:write", "policy:write"],
"audience": "api.agency.example.com"
}
}
}
}
OAuth 2.0 security
The read-write boundary in agency-ops-mcp is enforced through OAuth scopes, and it must hold at three layers. Authorization: the access token's aud claim must match api.agency.example.com, and tokens minted for carrier or vendor APIs are rejected before dispatch. Audience validation: the authorization server issues tokens only for the agency operations audience, so a token from another SaaS cannot be replayed here. Scopes: the write dispatcher checks the token's scopes on every call — quote:write in the config block means nothing if the token does not carry it. Credential isolation: the server holds the agent's token and the carrier's service account separately, never forwarding one identity's credential to the other provider, and carrier calls use short-lived service tokens with the narrowest scope each operation needs. PKCE is required for public clients, and because quote generation and policy updates are legally consequential, token revocation is immediate and audit-logged.
Retry rules
Retry policy in an insurance context is a correctness question as much as an availability one. Reads (quote, policy, CRM, compliance): retry up to three times with exponential backoff (base 200 ms, factor 2, jitter 25%) on 429 and 503; all 4xx are terminal. Write-intent creation: one retry after one second on 5xx only; intents are idempotent via intent ID, so replays return the existing record instead of stacking proposals. Approval submission: zero automatic retries — a timeout leaves the intent pending and an agency principal reconciles it manually. Executing a quote generation or policy update the gate already accepted: retry at most twice on 408 and 503, always replaying the same idempotency key so a timed-out call cannot double-bind. Timeouts: reads at 10 seconds, intent staging at 15 seconds, execution at 30 seconds; anything over budget is logged as a high-severity audit event.
Frequently Asked Questions
What does read-only quote data buy an agency agent?
An agent with quote:read can answer "what is the status of this quote?", compare premiums across carriers, and prep customer-facing summaries without touching a single record. The entire service-desk workload becomes queryable by agents, with zero mutation risk.
Why gate quote generation behind human approval?
A generated quote becomes a binding, legally relevant document the agency is accountable for. Getting the coverage lines wrong, or binding a price the principal never reviewed, is an E&O exposure. The agent proposes; a human binds.
How is compliance status handled?
Compliance status is exposed through a read-only tool that returns policy state, licensing, and filing status to any authenticated agent. There is deliberately no write tool that changes compliance state in v1 — the safest write tool for compliance is the one that does not exist.
Which write tools should ship in the first version?
Exactly two: generate_quote and update_policy, each requiring the scope that matches its blast radius (quote:write and policy:write). Every additional write tool should earn its place by answering a question a human approving it can understand in under a minute.
Can a downstream carrier ever see an agent's credentials?
No. Credential isolation means the server keeps agent tokens and carrier service accounts in separate credential stores and never forwards one identity's credential to the other provider. Carriers see only short-lived service tokens scoped to the narrowest operation.
Closing thoughts
SUPERAGENT 3.0's August 11, 2026 launch made the case that the AI business partner for an insurance agency is an operations tool, not a chat toy. agency-ops-mcp is the engineering side of that case: read-only quote, policy, CRM, and compliance data always available to agents, write tools for quote generation and policy updates locked behind OAuth scopes and a human approval gate, and an append-only audit trail underneath it all. An agency gets an agent that answers faster, prepares more, and never binds anything alone. Build the boundary first, and let the agency partners inside it.
Enjoyed this breakdown? Get our morning dispatch in your inbox.
Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.
Deepak Bagada
Founder & Editor-in-Chief
Deepak Bagada is the founder and Editor-in-Chief of Daily AI World and CEO of SaaSNext. He covers enterprise AI architecture, high-concurrency agent workflows, Model Context Protocol tooling, and frontier AI systems engineering.
Build a Research-Agent Citation-Integrity Workflow with AI-Paper Forensics
Next Story →Ahrefs Letaido: The Agent Workspace That Owns the Marketing Grind
Related Intelligence Analysis
Stop the Burnout: Building an AI Employee Retention Monitor Guide
Build an AI Employee Retention Monitor with FastMCP in Python. Aggregate non-invasive workload telemetries, predict burnout scores, and prevent regretted turnover.
Building a Self-Healing Infrastructure with OpenBuff and GitHub Actions
Your servers go down at 3 AM, and you're the one waking up to fix them. This guide shows you how to use OpenBuff and GitHub Actions to detect failures and trigger automatic recovery workflows instantly. Stop manual resta...
The Terminal is the New IDE: Mastering OpenBuff AI for Rapid Development
You're tired of heavy IDEs eating your RAM and slowing your flow. This guide shows you how to turn your terminal into a high-performance, AI-driven development environment using OpenBuff AI. Stop context switching and st...