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
CEO, SaaSNext
- 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
CEO, SaaSNext
Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.
Microsoft's Read-Write Agent Shift: When AI Tools Move from Reading to Acting
Next Story →Ahrefs Letaido: The Agent Workspace That Owns the Marketing Grind
Related Intelligence Analysis
Vercel AI SDK Tool Calling React: 5 Steps (2026)
Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...
Fact-Density vs. Word Count: The New SEO for 2026
Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...
NVIDIA Audex vs Qwen3.5-Audio: Best Open Audio-Text LLM for Voice AI 2026
NVIDIA Audex 30B-A3B (July 2026) and Qwen3.5-35B-A3B are the two leading open audio-text LLMs. Audex uniquely handles both audio understanding and generation in a single model while preserving text intelligence. Qwen3.5-...