durable-mcp
This server connects Claude Desktop to Snowflake-based energy trading data, enabling plain-English queries without writing SQL. It enforces read-only access (SELECT/WITH only) and supports credentials from a keyring or environment variables.
Portfolio PnL Analysis (
get_spread_portfolios): Retrieve PnL summaries for spread trading portfolios over a date range, including total PnL, win rate, and best/worst days.Spread Trading Breakdown (
get_spread_analysis): Detailed PnL breakdowns by trading path (source→sink), book, or book+path, including win rate and Calmar ratio.Nodal Price Spread (
get_nodal_spread): Analyze DA and RT LMP price spreads between two price nodes, with hourly stats, summary statistics, and peak-hour breakdowns.Price Node Lookup (
list_price_nodes): Search for available price nodes by name and filter by ISO (e.g., ERCOT, PJM, MISO, SPP).List Transmission Constraints (
list_constraints): Retrieve all available ERCOT transmission constraint names.Constraint Loading Analysis (
get_constraint_loading): Get hourly max/min loading percentages for a specific ERCOT transmission constraint.Grid Flow Analysis (
get_flow_analysis): View all ERCOT transmission constraint loading for a single date to identify the most congested lines.Generator Forecast vs. Actual (
get_gen_comparison): Compare MUSE forecast vs. Edison actual generation by plant and fuel type, sortable by forecast error magnitude.Plant-Level Generation Detail (
get_gen_detail): Hourly Edison vs. MUSE generation data for a specific plant.PJM Western Hub Prices (
get_pjm_wh): Access PJM Western Hub DA/RT LMP prices and load data with configurable historical comparison days (up to 90).Bid Segment Tracker (
get_segment_tracker): Monitor bid segment submission counts per day and portfolio, filtered by submission status.
Performance is optimized via warehouse pre-warming and a TTL cache to reduce query response times.
Provides tools for querying energy trading analytics from Snowflake, including spread portfolios, constraint loading, generator comparisons, and PJM price data.
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., "@durable-mcp What was our total PnL last week?"
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.
durable-mcp
MCP server for Durable energy trading analytics. Connects Claude Desktop to your Snowflake data so traders can ask plain-English questions about spread portfolios, nodal prices, transmission constraints, generator performance, and PJM markets — without writing SQL or opening the right dashboard.
How it works
Trader asks a question in Claude Desktop
↓
Claude picks the right tool based on the question
↓
MCP server (this repo, runs locally) queries your Snowflake
↓
Results come back → Claude reads them → answers the questionNote on data privacy: your trading data (PnL, portfolio names, bid paths) passes through Anthropic's servers as part of the Claude conversation. See Data & Security before using in production.
Related MCP server: redash-mcp
Setup (30 seconds)
1. Add to Claude Desktop
Open your Claude Desktop config file:
Windows:
%APPDATA%\Claude\claude_desktop_config.jsonMac:
~/Library/Application Support/Claude/claude_desktop_config.json
Add this block:
{
"mcpServers": {
"durable": {
"command": "npx",
"args": ["-y", "github:cshah26/Chatbot-MCP"]
}
}
}2. Restart Claude Desktop
That's it. The server reads credentials automatically from the Durable desktop app's keyring — no extra configuration needed if you already have the app installed.
Credential fallback
The server tries credentials in this order:
Durable app keyring — Windows Credential Manager under
durable-desktop / snowflake-config. Works automatically if the desktop app is installed.Environment variables — copy
.env.exampleto.envand fill in:
SNOWFLAKE_ACCOUNT=your_account.region
SNOWFLAKE_USERNAME=your_username
SNOWFLAKE_PASSWORD=your_password
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
SNOWFLAKE_ROLE=READ_ONLY_ROLEAvailable tools
Tool | What it does |
| PnL summary by portfolio — total PnL, win rate, best/worst days |
| Breakdown by path (source→sink), book, or book+path — win rate, avg/day |
| DA and RT LMP spread between two nodes — hourly stats, peak-hour breakdown, day-of-week heatmap |
| Search available price nodes by name or ISO |
| List all ERCOT transmission constraint names |
| Hourly max/min loading % for a specific ERCOT constraint |
| All constraint loading for a single date — shows which lines are most at risk |
| MUSE forecast vs Edison actual by plant and fuel type |
| Hourly Edison vs MUSE generation for a single plant |
| PJM Western Hub DA/RT LMP prices and load with historical daily averages |
| Bid segment counts by day and portfolio — submitted vs unsubmitted |
Example questions
"What was our total PnL last week?"
"Show me the spread between HB_NORTH and HB_SOUTH for July"
"Which constraints were most loaded yesterday?"
"How accurate was MUSE for gas plants this month?"
"What were PJM Western Hub prices on July 10th?"
Performance
What was slow (and what's fixed)
Snowflake warehouse cold start — 10–30s on the first question of the day
Snowflake auto-suspends idle warehouses. The server now sends a SELECT 1 immediately on startup — before any trader types anything — so the warehouse is warm and the connection is live by the time the first query arrives.
No caching — every question hit Snowflake live A TTL cache now sits in front of every query:
Data type | Cache TTL |
Historical PnL, spreads, constraint loading | 3 minutes |
Node list, constraint names (static reference data) | 1 hour |
Repeat questions are served from memory instantly.
Expected response times
Scenario | Before | After |
First question of the day | 15–35s | 1–3s |
Same question asked again | 3–8s | <100ms |
New question, warm warehouse | 2–5s | 1–3s |
Snowflake warehouse tip
Set auto-suspend to 10 minutes in your Snowflake account settings (default is 5) to give more buffer during trading hours. Optionally schedule a SELECT 1 at 6am on trading days to pre-warm the warehouse before traders arrive.
Data & Security
What leaves your network
When a tool runs, the SQL results — PnL numbers, portfolio names, bid paths, generator data — are sent to Anthropic's servers as part of the Claude conversation. This is real trading data: positions, performance, and strategy details.
It does not go anywhere else. The MCP server has no telemetry, no external logging, and no analytics calls beyond Snowflake and Claude.
Anthropic's data policy
Claude API | Claude.ai (consumer) | |
Trains on your data | No | Depends on settings |
Data retention | Short-term for safety review | Longer |
Enterprise agreement / BAA | Available | Not available |
Options if your firm has data sensitivity requirements
Option 1 — Claude Enterprise Anthropic's enterprise offering includes a data processing agreement, zero retention, and stricter data handling. Designed for financial firms. The MCP server works unchanged.
Option 2 — Local model Run a local LLM (e.g. Llama 3 via Ollama) instead of Claude. Nothing leaves your network. Tradeoff: local models are less capable. The MCP protocol is identical — only the model endpoint changes.
Option 3 — Data minimization Modify tools to send only aggregated summaries to Claude (totals, averages) rather than raw row data. Claude can still answer most questions but sees less sensitive detail.
Consult your compliance team before using this with live trading data.
Architecture
src/
index.ts — entry point: stdout guard, module loading, server setup, pre-warm
db.ts — Snowflake connection, TTL cache, query execution, auto-retry
keyring.ts — reads credentials from Windows Credential Manager
tools/
spread.ts — get_spread_portfolios, get_spread_analysis
nodal.ts — get_nodal_spread, list_price_nodes
constraints.ts — list_constraints, get_constraint_loading, get_flow_analysis
generators.ts — get_gen_comparison, get_gen_detail
pjm.ts — get_pjm_wh
segments.ts — get_segment_trackerKey design decisions
stdout guard
Snowflake's SDK (winston) writes logs directly to process.stdout, which would corrupt the MCP JSON-RPC stream. index.ts patches process.stdout.write before any modules load, redirecting anything that isn't a JSON-RPC 2.0 message to stderr. The filter checks for "jsonrpc":"2.0" specifically to avoid false positives.
Read-only enforcement
db.ts rejects any SQL that does not start with SELECT or WITH. No writes possible.
Connection auto-retry If the Snowflake connection drops between queries (idle timeout, network reset), the next query transparently resets the connection state and retries once with a fresh connection before surfacing an error to the caller.
Development
npm install
npm run build # compile TypeScript → dist/
npm start # run the compiled serverThe dist/ directory is committed so npx github:... works without a build step on the consumer side.
Publishing updates
Push to GitHub — team members get the latest automatically on the next Claude Desktop restart:
git add -A && git commit -m "your message" && git pushChangelog
391cbaf — fix+perf: resolve 9 code review issues
Bugs fixed
logLevelrestored from'OFF'to'ERROR'— Snowflake SDK error events (TLS drops, connection resets) are visible on stderr again; the stdout intercept already handled MCP stream safetyAuto-retry on stale connection — if the connection drops between queries, it resets and retries once transparently instead of failing
stdout filter tightened from
"jsonrpc"to"jsonrpc":"2.0"— eliminates false positives from any library that logs JSON containing the word "jsonrpc"Comment corrected: snowflake-sdk uses winston internally, not log4js
Performance
Snowflake connection and warehouse pre-warmed on startup — first question no longer pays 10–30s resume cost
TTL query cache added — repeat questions served from memory; static reference data (node list, constraint names) cached for 1 hour
Dynamic imports parallelised with
Promise.all— all 8 tool modules load concurrently at startup
Cleanup
console.errorandconsole.warnoverrides removed — dead code (those methods write to stderr internally and never touched stdout)
3f4f7d2 — fix: intercept process.stdout.write to block snowflake log4js from corrupting MCP stream
1017fff — fix: redirect all stdout to stderr to keep MCP protocol stream clean
f706a7b — fix: include dist/ in repo so npx github: works without build step
Available Tools
11 toolsget_constraint_loadingA
Get hourly max and min loading percentages for a specific ERCOT transmission constraint over a date range. Use this when asked about constraint loading, line loading, transmission utilization, or how loaded a specific constraint is. Values near 100% indicate the constraint is at or near its limit.
Inputs: date_to (required), date_from (required), constraint_name (required).
get_flow_analysisA
Get all ERCOT transmission constraint loading for a single date. Shows which constraints are most loaded and at risk of binding. Use this when asked about transmission congestion, binding constraints, or overall grid loading on a specific day.
Inputs: date (required).
get_gen_comparisonA
Compare generator forecast vs actual output. Compares MUSE (forecast) vs Edison (actual/IIR) generation by plant and fuel type. Shows average percentage difference — positive means Edison produced more than MUSE forecast. Use this when asked about generator forecasts, forecast accuracy, MUSE vs Edison, plant output, or fuel-type generation.
Inputs: date_to (required), date_from (required), sort_by, fuel_type, +1 more.
get_gen_detailA
Get hourly Edison vs MUSE generation detail for a specific plant. Use this when asked about a specific plant's hourly output, forecast vs actual for a single plant, or generation time series.
Inputs: date_to (required), date_from (required), plant_name (required).
get_nodal_spreadA
Get DA (day-ahead) and RT (real-time) LMP price spread between two price nodes over a date range. Returns hourly spread data, summary statistics, and peak-hour breakdown. Use this when asked about spread between locations, node prices, DA vs RT spread, price differences, or specific source/sink pairs.
Inputs: date_to (required), date_from (required), sink_node (required), source_node (required).
get_pjm_whA
Get PJM Western Hub DA/RT LMP prices and load data. Use this when asked about PJM Western Hub prices, PJM WH, Eastern power prices, or PJM load.
Inputs: target_date (required), historical_days.
get_segment_trackerA
Get bid segment counts for spread portfolios — how many segments were submitted per day and portfolio. Use this when asked about bid activity, segment counts, submission status, or how many bids were placed.
Inputs: date_to (required), date_from (required), submitted_filter.
get_spread_analysisA
Get detailed breakdown of spread trading PnL by path (source→sink), book, or book+path. Shows win rate, Calmar ratio, best/worst days per path or book. Use this when asked about specific paths, books, source/sink pairs, or route-level performance.
Inputs: date_to (required), date_from (required), group, breakdown.
get_spread_portfoliosA
Get PnL summary for spread trading portfolios over a date range. Returns total PnL, win rate, best/worst days, and per-portfolio breakdown. Use this when asked about portfolio performance, PnL, profit/loss, trading results.
Inputs: date_to (required), date_from (required), submitted_filter.
list_constraintsA
List all available ERCOT transmission constraint names. Use this to find constraint names before calling get_constraint_loading.
Inputs: no named parameters.
list_price_nodesA
Search for price nodes by name. Use this to look up node names before calling get_nodal_spread. Returns node name, ISO, zone, and type.
Inputs: search (required), iso.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Tools target distinct domains (constraints, generation, spreads, PJM) with clear descriptions. Minor overlap exists between get_spread_analysis and get_spread_portfolios, but their granularity differs (path/book vs portfolio summary).
All tool names follow a consistent verb_noun pattern: 'get_' for data retrieval and 'list_' for enumeration. No mixed conventions or vague verbs.
11 tools cover the energy trading analytics domain comprehensively without being excessive. Each tool serves a clear purpose and earns its place.
The tool set covers listing, detail, and comparison for constraints, generation, spreads, and prices. A minor gap is the lack of tools for submitting trades or updating data, but the server appears focused on read-only analytics.
Related MCP Connectors
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
The Ramp MCP server enables users to securely connect Ramp with AI assistants like ChatGPT and Claude to query financial data and take actions using natural language. It transforms Ramp's developer API into a SQL interface that LLMs can query, allowing admins to analyze spend trends, identify cost savings, and run complex SQL analyses on comprehensive datasets (transactions, purchase orders, vendors, users), while all users can manage cards, view transactions, request reimbursements, and get expense policy answers.
Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.
Hosted Amazon Seller Central and Amazon Ads MCP server for Claude, ChatGPT, Cursor, and agents.
Related MCP Servers
- AlicenseAqualityBmaintenanceA Snowflake MCP server — SQL queries, schema exploration, and data insights for AI assistants658 PyPI2MIT
- AlicenseAqualityBmaintenanceMCP server that connects Redash to Claude AI, enabling natural language data queries, dashboard management, and SQL execution.251,462 npm1MIT
- FlicenseAqualityDmaintenanceA unified MCP server that lets Claude query any SQLite database and build live Streamlit dashboards — all from a single conversation.101-
- AlicenseAqualityDmaintenanceMCP server exposing portfolio AI tools including semantic search, evaluation framework, and prompt management, enabling natural language interaction with these services via Claude Desktop.5ISC