Insurance Claims Assistant
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Insurance Claims AssistantAnalyze this accident report and classify the severity"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Insurance Claims Assistant
A remote MCP server for automated car insurance claim processing, built with TypeScript and the Anthropic Claude API. It runs over stdio or Streamable HTTP with bearer token auth, and is deployed on Render.
I built this after a year working on Guidewire ClaimCenter at AXA France, where I integrated the EDI broker flows (506/508/509) for automated claim opening and modification. The business logic here mirrors what I dealt with there (entity extraction, severity triage, broker notifications), but implemented with LLMs instead of static rules.
The core of it is a two-model validation pipeline: a fast model classifies, a stronger model reviews and can overrule it before anything ships.
What it does
Three tools, chained together:
Raw claim text
↓ analyze_claim_report
Structured ClaimData
↓ classify_claim_severity
Severity + judge verdict
↓ generate_broker_notification
Formal broker notificationRelated MCP server: Claim Pilot MCP Server
Remote server
The server is deployed on Render and reachable over Streamable HTTP:
Resource | Value |
Status page | |
MCP endpoint |
|
Health check |
|
Auth |
|
This is a portfolio project running as a technical demo. It has no real users, and the token is not public because every tool call spends my Anthropic credit. To try the tools, run the server locally with your own API key (see Setup).
On Render's free plan the service sleeps after 15 minutes without traffic. The first request after that wakes it up, which takes 30 to 60 seconds.
MCP Inspector connected to the deployed server over Streamable HTTP, with the initialize, tools/list and tools/call messages in the protocol log:

Connecting a client
For Claude Code, in a project .mcp.json:
{
"mcpServers": {
"insurance-claims": {
"type": "http",
"url": "https://insurance-claims-mcp.onrender.com/mcp",
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}Or from the command line:
claude mcp add --transport http insurance-claims https://insurance-claims-mcp.onrender.com/mcp --header "Authorization: Bearer <token>"With MCP Inspector, run npx @modelcontextprotocol/inspector, add a server with the Streamable HTTP transport and the endpoint URL, then open its Settings and add a custom header named Authorization with the value Bearer <token>. The value must start with Bearer followed by a space. Without a valid header the server answers 401, and the Inspector falls back to an OAuth flow that this server does not implement (it fails on /register).
The same configuration works against a local server on http://localhost:3000/mcp.
The judge
Classification runs through two models.
Claude Haiku takes the structured claim and returns a severity plus a confidence score and its reasoning. Claude Sonnet then receives the same claim data alongside Haiku's answer, and returns a verdict:
{
"approved": false,
"feedback": "Injuries confirmed in the report, AUTO_PROCESS is not applicable",
"finalSeverity": "URGENT_ESCALATION"
}Sonnet doesn't ask Haiku to retry. It overrides directly, and finalSeverity is what the pipeline uses downstream. The judge always has the last word.
The reason this pattern is here and not somewhere cheaper: in claims processing, a misclassification isn't a cosmetic error. An URGENT_ESCALATION claim with injuries routed to AUTO_PROCESS means someone waits longer for assistance. Haiku is cheap enough to run on every claim; Sonnet costs more but only runs once, as a gate.
analyze_claim_report
Takes raw accident report text and returns structured JSON: vehicles, parties, damages, circumstances, witnesses.
Uses an Agent Skill pattern: the extraction prompt lives in its own module (skills/claim-extraction.skill.ts) rather than being inlined in the tool.
classify_claim_severity
Classifies a claim as AUTO_PROCESS, REVIEW_NEEDED, or URGENT_ESCALATION.
generate_broker_notification
Generates a formal notification letter for the broker, with the required actions based on the severity classification.
This one sends MCP progress notifications (1/3, 2/3, 3/3) so the client can display real-time status.
Architecture
src/
├── index.ts Entry point, stdio transport
├── http.ts Entry point, Streamable HTTP + bearer auth
├── server.ts createServer(), tool registration
├── status-page.ts Public status page served on /
├── tools/
│ ├── analyze-claim.ts
│ ├── classify-claim.ts
│ └── generate-notification.ts
├── skills/
│ └── claim-extraction.skill.ts Reusable prompt template
├── judge/
│ └── classification-judge.ts Sonnet validates Haiku
├── utils/
│ ├── anthropic-client.ts Shared SDK instance + model config
│ ├── logger.ts stderr logging
│ └── progress.ts Progress callback type
└── types/
├── claim.types.ts
└── claim.schemas.ts Zod schemas for tool inputsA few decisions worth explaining
Logging goes to stderr, not stdout. MCP servers using stdio transport reserve stdout for JSON-RPC messages. A stray console.log corrupts the protocol and the client drops the connection. Everything logs to stderr instead.
Haiku everywhere except the judge. Extraction, classification, and notification generation all run on Haiku. Sonnet only runs as the validator. On a real claim volume, that cost difference matters.
Progress notifications are optional. The server only sends them when the client provides a progress token, and sends them on the stream of the request in progress. No client should crash because it didn't ask for progress updates.
Zod for input validation. The MCP SDK uses Zod schemas to validate tool inputs at the server boundary, before any business logic runs. ClaimData and ClassificationResult have full schemas, so an incomplete or malformed object is rejected before any Claude call. It also gives typed handler arguments for free.
Stateless HTTP transport. Each POST /mcp creates a fresh server and transport, handles the request, then disposes of them. No session lives in memory, so nothing is lost when Render puts the service to sleep or restarts it. The tools carry no state between calls anyway.
A static bearer token, not OAuth. The MCP spec recommends OAuth 2.1 for remote servers with many users. This one has a single user, so a static token read from an environment variable is the proportionate choice. OAuth would be the next step for a multi-user setup. The server refuses to start without a token of at least 32 characters, so a configuration mistake cannot expose an open endpoint.
Dependency updates through Dependabot. Dependabot checks the npm packages and the Docker base image every week, and only proposes versions published at least 14 days earlier. Security fixes skip that delay. Since every push to main redeploys on Render, a Dependabot pull request is built and tested locally (npm run build, npm run test:progress) before it is merged.
Constant-time token comparison. The token check uses crypto.timingSafeEqual instead of ===. A regular string comparison stops at the first different character, which in theory lets an attacker guess the token by measuring response times.
Setup
Requires Node.js 18+ (developed and tested on Node.js 24) and an Anthropic API key.
git clone https://github.com/youssefmkb/insurance-claims-assistant
cd insurance-claims-assistant
npm install
cp .env.example .env # add your API key and an auth token
npm run buildGenerate an auth token for the HTTP transport:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Run the server over stdio, for clients that launch it themselves:
node dist/index.jsOr over Streamable HTTP (listens on PORT, default 3000):
npm run start:httpTest it with MCP Inspector:
npx @modelcontextprotocol/inspector node dist/index.jsRun the full chain with progress notifications:
npm run test:progress # stdio
npm run test:progress -- --url http://localhost:3000/mcp # HTTP, token read from .envDocker
docker build -t insurance-claims-mcp .
docker run --rm --env-file .env -p 3000:3000 insurance-claims-mcpThe image is built in two stages, so only the compiled JavaScript and production dependencies ship. It runs as a non-root user, with tini as init process for clean shutdowns. Secrets are injected when the container starts and never copied into the image.
Screenshots
Tools exposed by the server:

Entity extraction from a raw accident report:

Classification with the judge verdict:

Broker notification, with progress updates visible bottom right:

Stack
Node.js, TypeScript, @modelcontextprotocol/sdk 1.x, Anthropic SDK (Haiku + Sonnet), Zod, Express, Docker. Transports: stdio and Streamable HTTP. Deployed on Render.
V2 ideas
Things I'd add if this went further:
Actual email delivery. Right now the notification is generated but not sent. Hooking up SendGrid or Nodemailer would close the loop.
Persistence. Claims are stateless today. A database would let you track a claim across its lifecycle instead of processing each call in isolation.
MCP sampling. Let the server request completions from the client's model rather than calling the API directly.
Author
Youssef Mokhbi · github.com/youssefmkb · LinkedIn
Available Tools
3 toolsanalyze_claim_reportB
Extrait les entités structurées d'un constat de sinistre automobile : véhicules, parties, dommages et circonstances. Retourne un objet ClaimData structuré.
| Name | Required | Description | Default |
|---|---|---|---|
| claimId | Yes | Identifiant unique du sinistre | |
| rawText | Yes | Texte brut du constat amiable |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It mentions a structured return object but does not describe side effects, error behavior, reliability, permissions, or whether it is read-only; significant behavioral context is missing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no wasted words; the purpose and return type are front-loaded and immediately clear. The description is appropriately sized for the amount of information it chooses to convey.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description gives the extraction target and return type, but with no annotations and no output schema, it should say more about the structure of ClaimData and any input assumptions or limitations. It is adequate but leaves clear gaps for correct invocation in ambiguous cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are fully documented in the schema. The description adds no parameter-level syntax or format details beyond what the schema already provides, making the baseline of 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Extrait') and resource ('constat de sinistre automobile') and enumerates the extracted entity types, making the operation concrete. It does not explicitly distinguish itself from siblings like classify_claim_severity, but the extraction purpose is clear enough to infer the difference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus alternatives, no prerequisites, and no exclusions. The description implies usage from the input nature but leaves all routing decisions to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
classify_claim_severityB
Classifie la sévérité d'un sinistre automobile en AUTO_PROCESS, REVIEW_NEEDED ou URGENT_ESCALATION. Utilise un LLM-as-judge (Sonnet valide Haiku) pour garantir la fiabilité.
| Name | Required | Description | Default |
|---|---|---|---|
| claimData | Yes | Objet ClaimData retourné par analyze_claim_report |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions an LLM-as-judge validation process (Sonnet validates Haiku) for reliability, but it does not clarify whether the operation is read-only, whether it has side effects, what permissions are required, latency, cost, or failure behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with no wasted wording. The primary purpose and output categories are front-loaded before the secondary reliability note.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The input schema is rich and fully described, and the description lists the possible output labels. However, with no output schema and no annotations, it does not fully describe the return structure, side effects, or invocation context needed for a complex classification tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents the single claimData parameter and its nested fields thoroughly. The description adds no additional parameter semantics beyond the schema baseline, which is appropriate for a 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: classifying the severity of an automobile claim. It also names the exact output categories, making the tool's purpose immediately clear. It does not explicitly distinguish itself from sibling tools such as analyze_claim_report, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains what the tool does but gives no guidance on when to use it versus analyze_claim_report or generate_broker_notification. There are no prerequisites, exclusions, or contextual triggers for invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_broker_notificationA
Génère une notification courtier formelle suite à la classification d'un sinistre automobile. Inclut les détails du sinistre, la décision de traitement et les actions requises.
| Name | Required | Description | Default |
|---|---|---|---|
| claimData | Yes | Objet ClaimData retourné par analyze_claim_report | |
| classification | Yes | Objet ClassificationResult retourné par classify_claim_severity |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of revealing behavioral traits. It clarifies that the output notification is comprehensive, including 'détails du sinistre, la décision de traitement et les actions requises', giving the agent insight into the complexity and content of the generated document.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The two sentences are highly efficient. The first sentence serves as a high-level purpose statement, and the second details the required contents of the resulting notification.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Because this tool generates a complex document with no defined output schema, the description is crucial. It is complete enough for the agent to know that the resulting artifact is a formal, actionable notification rather than a simple data summary.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Since schema coverage is 100%, the baseline is high. The description doesn't need to explain the nested fields, but it contextualizes the two required inputs (`claimData` and `classification`) as the foundational data sources for the final notification.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: generating a formal broker notification after a claim classification. While the tool's name implies the action, the description specifically defines the resource being generated (a formal notification).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description strongly implies the use case by referencing the required steps: 'suite à la classification d'un sinistre automobile' (following the classification of an automobile claim). The schema descriptions further link this tool to the output of 'analyze_claim_report' and 'classify_claim_severity'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v1.0.0- First observed
analyze_claim_report - First observed
classify_claim_severity - First observed
generate_broker_notification
TDQS
Scored across 3 tools
The tools represent three distinct, sequential steps in the claims processing pipeline: data extraction, severity classification, and communication generation. There is no functional overlap or ambiguity among the tools.
All tools adhere to a highly consistent snake_case naming convention where the function is preceded by a verb describing its specific action. The style is uniform across all three tools.
For a specialized 'Claims Assistant' focusing on the initial triage process, three well-scoped tools are appropriate. Each tool provides a necessary, non-trivial step in the workflow without being excessive.
While the tools cover the initial linear path of extraction, classification, and notification, they have notable missing operations. The set lacks functionality for retrieving existing claim details, modifying classification outcomes, or handling broader policy lifecycle management.
Maintenance
Related MCP Connectors
Hosted MCP for denial, prior auth, reimbursement, workflow validation, batch scoring, and feedback.
MCP server for VC pitch-deck scoring, thesis-fit matching, and deal-flow management.
Hybrid human + AI expertise for faster, trusted answers and decisions via MCP Server.
MCP server for medicaid-intelligence
Related MCP Servers
- AlicenseAqualityBmaintenanceMCP server for healthcare claims workflow scoring, validation, and feedback, supporting denial risk, prior authorization, and reimbursement assessment.824 PyPIMIT
- AlicenseNot gradedqualityDmaintenanceMCP server for insurance claim pilot tools, providing policy search, claim lookup, and fraud score calculation.MIT

clichefactory-mcpofficial
AlicenseNot gradedqualityDmaintenanceMCP server for ClicheFactory, enabling structured data extraction from documents such as PDFs, images, and office files via AI assistants.36 PyPIMIT- FlicenseNot gradedqualityBmaintenanceMCP server that reviews insurance claims against policy documents, providing coverage decisions, policy clause retrieval, claim history lookup, coverage rule checks, and fraud risk scoring via four tools.-