mcp-annuities-server

mcp-annuities-server

Enables retrieval of annuity client data, payout calculations, and portfolio analysis, with prompt templates for generating client reviews, summaries, and reports.

Category
Visit Server

README

MCP Annuities Server

Consolidated & fixed from MCP-Example-main + mcp-prompt-templates-main For: VS Code + Claude Code on WSL/Ubuntu

šŸ“„ Open README.html in a browser for the full documentation with embedded architecture diagrams.


What Was Fixed

Issue in original repos Fix applied
Hardcoded C:\Users\Bijut\Desktop\typesdk.md Path(__file__).parent — cross-platform
Windows paths + uv in desktop config WSL-friendly .venv/bin/python absolute paths
Two separate repos Merged into one: 5 tools + 1 resource + 3 prompts
Low-level Server class (verbose) FastMCP @mcp.tool / @mcp.resource / @mcp.prompt
No automated test test_client.py — full end-to-end, no IDE needed
realpath resolves symlink to system Python Use $(pwd)/.venv/bin/python in claude mcp add

Key rule applied: tool count kept to 5. Too many tools breaks LLM tool-selection reliability.


Project Structure

mcp-annuities-server/
ā”œā”€ā”€ CLAUDE.md
ā”œā”€ā”€ README.md                    ← this file
ā”œā”€ā”€ README.html                  ← full docs with diagrams (open in browser)
ā”œā”€ā”€ requirements.txt
ā”œā”€ā”€ server.py                    ← MCP server (5 tools + 1 resource + 3 prompts)
ā”œā”€ā”€ test_client.py               ← standalone end-to-end test
ā”œā”€ā”€ claude_desktop_config.example.json
ā”œā”€ā”€ .vscode/
│   └── mcp.json
ā”œā”€ā”€ data/
│   ā”œā”€ā”€ annuities.csv            ← 500-row dataset
│   └── generate_data.py
└── templates/
    ā”œā”€ā”€ annuity_review/          ← config.yaml + template.md
    ā”œā”€ā”€ client_summary/
    └── portfolio_report/

Setup

cd ~/mcp-annuities-server
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python data/generate_data.py

Full Lifecycle — How a Request Flows

[1] User terminal (VS Code / WSL)
     │  Natural-language request typed
     ā–¼
[2] Claude Code reasoning (Sonnet / Opus)
     │  Matches request to tool schema
     │  Produces tool_use block: {name, arguments}
     ā–¼
[3] MCP stdio handshake
     │  JSON-RPC 2.0 sent over child process stdin
     │  Server lives in .venv/bin/python subprocess
     ā–¼
[4] FastMCP dispatch + validation
     │  Validates args against JSON Schema (from type hints)
     │  Routes to the matching @mcp.tool() function
     ā–¼
[5] Tool execution
     │  get_client: reads annuities.csv, returns matching row
     │  calculate_payout: amortization math, no data lookup
     ā–¼
[6] data/annuities.csv
     │  500 rows, 15 columns, all values stored as strings
     │
     └──► Result serialized → stdout → layers 4→3→2→1 → user

Tool chaining (your session)

When you said "calculate the payout for this client", Claude Code chained two tools without any orchestrator script:

"Calculate the payout..."
    → Call 1: get_client("CLIENT_0001")         [retrieves record]
    → Model extracts current_account_value + rate [type-converts strings]
    → Call 2: calculate_payout(principal, rate, term) [math]
    → Final answer combining both results

This is the live minimal version of Domain 1's agentic loop.


Layer-by-Layer Explanations

Layer 1 — User terminal

The terminal is just the I/O surface. All orchestration (deciding which tool to call, building JSON-RPC, managing the subprocess) happens inside the claude process, not in bash. Auth: use Claude Pro login (not API key) to avoid extra billing. The ANTHROPIC_API_KEY env var set for your Python lab scripts causes the "both auth methods" warning in Claude Code.

Layer 2 — Claude Code reasoning

Tool selection is pure pattern matching against schema descriptions. "look up CLIENT_0001" matches get_client because its description says "Retrieve full annuity contract details for one client by ID". A vague description causes wrong picks — this is the "tool boundary design" Domain 2 exam concept. The model emits a tool_use block, Claude Code intercepts it, sends to layer 3, and waits for the result before writing the final answer.

Layer 3 — MCP stdio handshake

Server.py is spawned ONCE as a child process at session start (not per call). Three pipes wired: stdin (requests in), stdout (results out), stderr (logs — never corrupts the protocol). JSON-RPC 2.0, newline- delimited. The ✘ Failed to connect happened because realpath resolved the venv symlink to /usr/bin/python3.12 (no mcp package) — $(pwd)/ .venv/bin/python keeps the venv path and the handshake succeeds.

Layer 4 — FastMCP dispatch + validation

FastMCP's event loop reads each JSON-RPC line, dispatches on method: tools/call, validates arguments against the auto-generated JSON Schema (from type hints) before calling Python, serializes the return value into a text content block, and writes the response to stdout. No print() allowed in server.py — it would corrupt the stream.

Layer 5 — Tool execution

get_client: linear scan of CSV, returns matching dict (all strings). calculate_payout: amortization formula with zero-rate edge-case handler and explicit input validation (returns structured error, not exception). Both are pure functions with no side effects — safe for an LLM to call.

Layer 6 — data/annuities.csv

500 rows, 15 columns (client_id, dob, age, product_type, premium_amount, crediting_rate_pct, term_years, monthly_payment, surrender_charge_pct, rider, risk_profile, state, payment_frequency, contract_start_date, current_account_value). IMPORTANT: csv.DictReader returns ALL values as strings — tools doing math must cast with float()/int(). Pydantic models with typed fields do this automatically (Domain 4 connection).


Step-by-Step: Wire into Claude Code

# 1. Standalone test (proves server logic, no AI)
.venv/bin/python test_client.py

# 2. MCP Inspector (visual debugging)
npx @modelcontextprotocol/inspector .venv/bin/python server.py

# 3. Register with Claude Code
claude mcp remove annuities-server  # if exists
claude mcp add annuities-server -- "$(pwd)/.venv/bin/python" server.py
claude mcp list
# → annuities-server: .../.venv/bin/python server.py - āœ” Connected

# 4. Fix auth (if showing Opus / API billing)
claude /logout
# → choose claude.ai YES, API key NO

# 5. Launch and test
claude
/mcp
"Use the annuities-server to look up CLIENT_0001"

Tool / Resource / Prompt Reference

Tools (5)

Tool Purpose Key args
get_client Look up one client client_id
search_clients Filter portfolio product_type, risk_profile, state, limit
portfolio_summary Aggregate stats group_by
calculate_payout Amortized payout principal, annual_rate_pct, term_years
calculate_percentage Utility math value, percentage

Resource

URI Content
annuities://dataset Raw CSV of all 500 rows

Prompts

Prompt Purpose Args
annuity_review Suitability assessment client_id
client_summary Client letter client_id
portfolio_report Executive report group_by

CCAF Exam Domain Mapping

What you built Exam concept Domain
@mcp.tool() with type hints Tool schema design D2
stdio subprocess transport Local MCP deployment D2
claude mcp add with venv path MCP client configuration D2
5-tool limit Tool boundary / reasoning overload D2
@mcp.resource() Resources vs tools distinction D2
YAML + @mcp.prompt() MCP prompt templates D2
get_client → calculate_payout chaining Implicit task decomposition D1
CLAUDE.md at project root CLAUDE.md hierarchy D3
String CSV → Pydantic coercion Structured output enforcement D4
JSON-RPC id correlation Context / multi-turn state D5

Quick Reference

# Golden path
cd ~/mcp-annuities-server && source .venv/bin/activate
python test_client.py        # sanity check
claude mcp list              # āœ” Connected
claude                       # launch
/mcp                         # verify
"Use annuities-server to look up CLIENT_0001"

# Fix ✘ Failed to connect
claude mcp remove annuities-server
claude mcp add annuities-server -- "$(pwd)/.venv/bin/python" server.py

# Fix Opus / API billing instead of Pro
claude /logout → claude.ai YES → API key NO

<-- See all tables with row Last updated: 2026-06-13 -->

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured