Skip to main content
Glama

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.


Related MCP server: Offramp MCP Server

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 -->

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides AI assistants with access to 30+ validated financial independence calculation functions, eliminating hallucinations by ensuring accurate calculations for retirement planning, CoastFI, investment returns, and other FI metrics.
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides retirement planning computations for AI agents, including Monte Carlo simulations, tax burden modeling across all US states, Social Security claiming optimization, and cost-of-living comparisons.
    7 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Connects AI assistants to the NowCapital.ca retirement planning API for Canadian retirement simulations, enabling calculations of sustainable spending, tax-optimized projections, and Monte Carlo risk analysis.
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Provides 77 deterministic financial calculators, live market data, and a meta-advisor that chains tools into prioritized plans from plain-language descriptions.
    77
    6
    MIT