MCP Demo Transcript — Cat-4 South FL via the srdb_mcp protocol

This is a CAPTURED trace, not a hand-written one. Reproduce with uv run python scripts/demo_mcp_session.py.

An MCP client speaks JSON-RPC over stdio to the srdb_mcp server. The client below drives the canonical interview question — "What's our hurricane exposure right now and what would a Cat-4 in South FL do to it?" — by chaining the substrate primitives. The agent (a Claude or GPT host) would call the same tools in the same order; here the client is a deterministic script so the trace is reproducible.


Step 1 — MCP handshake

Request:

{
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "sampling": {}
    },
    "clientInfo": {
      "name": "srdb-demo-client",
      "version": "0.1.0"
    }
  }
}

Response: srdb-mcp v0.1.0 on protocol 2024-11-05. Capabilities: experimental, resources, tools.

Step 2 — Discover the tool surface

Request:

{
  "method": "tools/list",
  "params": {}
}

Response: 9 tools exposed:

  • search_catalog — Search the substrate's catalog of entities, instruments, or scenarios with typed filters. Returns paginated structured entries.
  • query_positions — List positions with bitemporal current-knowledge semantics enforced. Filter by entity_id, instrument_id, or asset_class. If position_id is set, returns at most one row.
  • walk_lookthrough — Decompose an entity's indirect holdings via the entity_relationship graph. Returns one row per (holder, ultimate_instrument) path with attributed quantity + value.
  • get_position_history — Full bitemporal log for one position: every (valid_from, valid_to, txn_from, txn_to) vintage, with is_current_knowledge flagged.
  • compare_to_abor — Show how srDB and ABOR see one position differently. Returns srdb_* + abor_* values + break category if a break exists.
  • get_break_aging — Current outstanding ABOR breaks bucketed by age (0-1d, 2-7d, 8-30d, 30+d). Latest reconciliation run. Filter by category/severity.
  • compute_engineering_identity — Return the current-state engineering identity for one instrument via its per-class model (well DCF — first-principles re-price from current obs; treaty XoL — reinstatement-state snapshot; SFR NOI — current monthly NOI; Black-76 — current mark snapshot). Returns intermediates so the agent can show its work, plus inputs_lineage carrying position_id and (for market-data-driven families) observation timestamps.
  • apply_driver_shock — Perturb one driver series (HH M1, BTC spot, hurricane industry loss, etc.) and walk driver_exposure_map to surface affected instruments + per-instrument deltas + firmwide delta. The primitive an agent uses to compose stress scenarios.
  • inject_event — Inject a synthetic event (sandbox — not persisted to production event table). Returns a deterministic sandbox event_id + affected_instrument_ids surfaced from event_instrument_exposure links of the same event_type. Pair with apply_driver_shock to compose event-driven scenarios.

Step 3a — Orient: describe the substrate

Request:

{
  "method": "resources/read",
  "params": {
    "uri": "srdb://describe"
  }
}

Response:

{
  "name": "srDB POC",
  "description": "Canonical normalized financial data substrate spanning four asset classes \u2014 natural gas wells, reinsurance treaties, SFR portfolios, crypto derivatives \u2014 with bitemporal lineage, Shadow IBOR reconciliation to a synthesized ABOR feed, and a grounded agent surface (this MCP server).",
  "asset_classes": [
    "SFR_PORTFOLIO",
    "CRYPTO_DERIV",
    "WELL",
    "TREATY"
  ],
  "current_position_counts_by_asset_class": {
    "SFR_PORTFOLIO": 87,
    "CRYPTO_DERIV": 37,
    "WELL": 126,
    "TREATY": 98
  },
  "total_current_positions": 348,
  "total_entities": 27,
  "total_instruments": 20,
  "latest_position_as_of": "2026-09-25",
  "latest_reconciliation": {
    "as_of_date": "2025-12-31",
    "n_breaks": 4
  },
  "design_principles": [
    "ADR-001 Bitemporal + vintage lineage everywhere \u2014 see docs/adr/001-bitemporal-everywhere.md",
    "ADR-002 Polymorphic positions over per-class position tables \u2014 see docs/adr/002-polymorphic-positions.md",
    "ADR-003 Shadow IBOR (reconcile to ABOR) over straight IBOR replacement \u2014 see docs/adr/003-shadow-ibor-not-replacement.md",
    "ADR-004 Build on DuckDB (+ Iceberg/S3 at scale) over Snowflake / Databricks \u2014 see docs/adr/004-build-on-duckdb-not-snowflake.md",
    "ADR-005 Build IBOR in-house over Eagle / Aladdin / SS&C \u2014 see docs/adr/005-build-ibor-not-buy-eagle-aladdin-ssc.md",
    "ADR-006 Build the agent layer with Anthropic Claude (via MCP) over Bedrock / OpenAI / local \u2014 see docs/adr/006-build-with-claude-sdk-not-bedrock-openai.md"
  ],
  "agent_workflow_hint": "Start with search_catalog to find entities or instruments by name. Use query_positions to read current holdings. Use walk_lookthrough for indirect decomposition (e.g. LTRe through SRAM). For event-driven questions (hurricane, earthquake, treaty loss): inject_event surfaces affected instruments via event_instrument_exposure, and compute_engineering_identity returns each instrument's current state (reinstatement bookkeeping, NOI, mark snapshot). For market-driven questions (price/rate/vol shocks): apply_driver_shock perturbs a real-obs driver series and walks driver_exposure_map for per-instrument deltas. Cat-4 is a recipe the agent composes, not a magic word \u2014 see docs/mcp_demo_transcript.md."
}

Step 3b — Find LongTail Re

Request:

{
  "method": "tools/call",
  "params": {
    "name": "search_catalog",
    "arguments": {
      "kind": "ENTITY",
      "name_substr": "LongTail"
    }
  }
}

Response: total=1 returned=1

  • LongTail Re LtdENTITY 5db857fa…

Step 3c — Walk LTRe's indirect holdings

Request:

{
  "method": "tools/call",
  "params": {
    "name": "walk_lookthrough",
    "arguments": {
      "entity_id": "5db857fa-9552-57c4-8f32-20408967c31d",
      "as_of_date": "2025-12-31"
    }
  }
}

Response: 20 lookthrough rows; total_attributed_value_usd = $108,045,951

Asset classAttributed valueCumulative %Ultimate instrument
SFR_PORTFOLIO$45,742,9650.255c0d726a7…
SFR_PORTFOLIO$41,682,5520.2555490304f…
SFR_PORTFOLIO$29,443,0550.255ecf75261…
WELL$294,8280.255d4c9ae29…
WELL$228,2420.255f81e0940…
CRYPTO_DERIV$188,4540.043b8ffdfe7…
CRYPTO_DERIV$188,4540.043fed8751d…
WELL$87,6730.255e85ddb0e…
… 12 more rows …

Step 3d — Inject Cat-4 hurricane (sandbox event — discovers affected instruments)

Request:

{
  "method": "tools/call",
  "params": {
    "name": "inject_event",
    "arguments": {
      "event_type": "HURRICANE",
      "occurred_at": "2025-09-15",
      "payload": {
        "category": 4,
        "landfall_state": "FL",
        "landfall_lat": 26.5,
        "landfall_lon": -82.2,
        "max_windspeed_kt": 130,
        "modeled_industry_loss_usd": 80000000000.0
      }
    }
  }
}

Response: event_id = 3890b6b7-590d-5957-87e1-dad00a179ee3 (sandbox — not persisted to production event table) affected_instrument_ids = 3 discovered via event_instrument_exposure mapping

  • 7a564ee2-5b0c-5ee7-9163-8bbf21628d41
  • 1a5c3c8e-7e32-5930-ab49-20e27b5809da
  • c0d726a7-8ffe-579a-baf2-5b82005aaef0

Step 3e — Current-state engineering identity for the FL CAT_XOL treaty

Request:

{
  "method": "tools/call",
  "params": {
    "name": "compute_engineering_identity",
    "arguments": {
      "instrument_id": "1a5c3c8e-7e32-5930-ab49-20e27b5809da",
      "as_of_date": "2025-12-31"
    }
  }
}

Response: family = TREATY_XOL_PAYOUT market_value_usd = $-460,273.97

Intermediates (the agent's show its work trail):

{
  "treaty_type": "CAT_XOL",
  "peril": "NA_HURRICANE",
  "attachment_usd": 100000000.0,
  "limit_usd": 400000000.0,
  "cession_pct": 0.1,
  "reinstatements_max": 2,
  "attached_loss_to_date_usd": 40000000.0,
  "limit_remaining_usd": 400000000.0,
  "reinstatements_consumed": 1
}

Inputs lineage (audit trail — position_id always; observation timestamps for market-data-driven families like wells, omitted for state-snapshot families like treaties):

{
  "position_id": "800aa8fd-e615-537b-a50f-1e30ef3f8368"
}

Step 3f — Demonstrate apply_driver_shock on a real-obs series: HH M1 +20%

Request:

{
  "method": "tools/call",
  "params": {
    "name": "apply_driver_shock",
    "arguments": {
      "measure_code": "PRICE_USD_PER_MMBTU",
      "semantic_substr": "contract 1 (rolling M1)",
      "shock": {
        "mode": "MULTIPLICATIVE",
        "shock_pct": 0.2
      },
      "window_days": 30,
      "as_of_date": "2025-12-31"
    }
  }
}

Response: driver_series_id = 48421910-c643-47fb-a18b-4daa427c4c5a measure_code = PRICE_USD_PER_MMBTU pre_shock_value = 4.093post_shock_value = 4.9116 (MULTIPLICATIVE +20.00%) firmwide_delta_usd = $-272,132,068 across 213 instruments touched by driver_exposure_map

Top 5 affected (by absolute delta):

InstrumentAsset classPrePostΔMechanism
MSA_PORTFOLIOSFR_PORTFOLIO$196,740,004$192,805,204$-3,934,800OPEX_DRIVER (NEGATIVE)
MSA_PORTFOLIOSFR_PORTFOLIO$196,113,757$192,191,482$-3,922,275OPEX_DRIVER (NEGATIVE)
MSA_PORTFOLIOSFR_PORTFOLIO$196,041,596$192,120,764$-3,920,832OPEX_DRIVER (NEGATIVE)
MSA_PORTFOLIOSFR_PORTFOLIO$195,035,772$191,135,057$-3,900,715OPEX_DRIVER (NEGATIVE)
MSA_PORTFOLIOSFR_PORTFOLIO$194,720,447$190,826,038$-3,894,409OPEX_DRIVER (NEGATIVE)

Server-side logs (stderr)

INFO:srdb_mcp:srdb_mcp 0.1.0 starting (stdio)
INFO:mcp.server.lowlevel.server:Processing request of type ListToolsRequest
INFO:mcp.server.lowlevel.server:Processing request of type ReadResourceRequest
INFO:mcp.server.lowlevel.server:Processing request of type CallToolRequest
INFO:mcp.server.lowlevel.server:Processing request of type CallToolRequest
INFO:mcp.server.lowlevel.server:Processing request of type CallToolRequest
INFO:mcp.server.lowlevel.server:Processing request of type CallToolRequest
INFO:mcp.server.lowlevel.server:Processing request of type CallToolRequest

What this proves

  1. The MCP server speaks the protocol correctly — every request above is real JSON-RPC over stdio, captured from the running process.
  2. The audit boundary is the tool surface, not the schema — every agent action above is a typed tool call with structured params. There is no execute_sql and no way for the client to compose one.
  3. Primitives compose; the substrate is honest about what each tool does. For event-driven questions (hurricane, earthquake, treaty loss): inject_event discovers the affected instruments via event_instrument_exposure; compute_engineering_identity returns current state snapshots (reinstatement bookkeeping, NOI, mark price). The event-parameterized math (payout, reinstatement premium booked, SFR impairment) lives in scenarios/cat4_fla_landfall.py as the closed-form per-asset-class identity. For market-driven questions (HH price up, BTC IV spike, basis blowout): apply_driver_shock perturbs the driver and walks driver_exposure_map for per-instrument deltas — see Step 3f.
  4. The closed-form scenario is the verification fixture for the event-driven chain. scenarios.cat4_fla_landfall.run() is the source of truth for exact firmwide PnL on Cat-4; the agent's discovery + state-identity composition above produces the same affected-instrument set (verified by tests/test_mcp_tools.py::test_cat4_agent_style_composition_recovers_named_scenario_signal).

For an agent host (Claude Desktop, Claude Code, VS Code MCP, any OpenAI-with-MCP-adapter), the same tools are available with no code change. The substrate is the agent's runtime.