Custom MCP server connecting Claude to MSRB EMMA (muni bond market data). NYU Stern Blaylock Van capstone — Spring 2026.

EMMA MCP — Custom Muni-Finance Agent for Blaylock Van

NYU Stern Consulting Capstone · Spring 2026 · Marco Figueroa, Justin Ganjian, Andrew Kay, Isaac Mizrahi, Roshan Raja · Professor Marciano

What this is

A custom MCP (Model Context Protocol) server that lets Claude read the muni-bond new-issue market directly from the MSRB's EMMA website. This is the Tier-4 example on our capstone tier ladder — a firm-owned connector to a data source that no vendor covers.

EMMA — the Electronic Municipal Market Access site operated by the Municipal Securities Rulemaking Board — is the official public book of record for every muni bond sold in the United States. New-issue calendars, Official Statements, CUSIP-level details, recent trade prices: all on EMMA. It has no public API.

This MCP exposes 18 tools and 2 resources (a CLAUDE.md rules file and an EMMA_ABBREVIATIONS.md glossary) that Claude auto-loads on connect. Once installed, a banker can ask Claude natural-language questions like "pull every outstanding Rady Children's Hospital bond and download the most recent OS" and Claude executes the full chain — search → issuer lookup → issue details → PDF download → text extraction — in about 20 seconds.

For the full pitch and why it matters to Blaylock, see USAGE.mdWhy this exists.

Prerequisites

You need four things on your laptop. If any are missing, the install instructions below cover it.

Requirement What it is Install check
Claude Desktop Anthropic's native macOS/Windows client (the MCP host) claude.ai/download
Python 3.10+ Runtime for the server Mac: python3 --version · Win: python --version
uv Python package manager (handles the venv automatically) uv --version
Playwright Chromium Headless browser the server drives EMMA with Installed by one command below

Install — Mac

# 1. Unzip this folder somewhere sensible
cd ~/Downloads
unzip emma-mcp.zip -d ~/emma-mcp
cd ~/emma-mcp

# 2. If you don't have uv:
brew install uv

# 3. Create the venv + install dependencies (one command)
uv sync

# 4. Install the headless browser Playwright drives
uv run playwright install chromium

# 5. Smoke-test the server (optional — confirms it boots)
uv run python server.py
# You should see the server start and wait on stdin.
# Press Ctrl+C to stop.

Wire it into Claude Desktop (Mac)

  1. Open Claude Desktop → SettingsDeveloperEdit Config. That opens claude_desktop_config.json.
  2. Add an emma entry inside the mcpServers object. Use the absolute path to the .venv/bin/python that uv sync just created and the absolute path to server.py:
{
  "mcpServers": {
    "emma": {
      "command": "/Users/YOURNAME/emma-mcp/.venv/bin/python",
      "args": ["/Users/YOURNAME/emma-mcp/server.py"]
    }
  }
}
  1. Save, fully quit Claude Desktop (Cmd+Q, not just close the window), and reopen it.
  2. In a new chat, the hammer icon in the composer should now list EMMA tools. That's the tell.

Install — Windows

# 1. Unzip this folder, e.g. to C:\emma-mcp
cd C:\emma-mcp

# 2. If you don't have Python: install from python.org (3.10 or later).
#    Check "Add Python to PATH" during install.

# 3. Install uv
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

# 4. Create the venv + install deps
uv sync

# 5. Install Playwright's Chromium
uv run playwright install chromium

# 6. Smoke-test
uv run python server.py
# Ctrl+C to stop.

Wire it into Claude Desktop (Windows)

  1. Open %APPDATA%\Claude\claude_desktop_config.json in a text editor. (Paste that path into the Explorer address bar — Windows resolves %APPDATA% to C:\Users\YOU\AppData\Roaming.)
  2. Use forward slashes or double backslashes in the JSON paths — Windows single backslashes break JSON:
{
  "mcpServers": {
    "emma": {
      "command": "C:/emma-mcp/.venv/Scripts/python.exe",
      "args": ["C:/emma-mcp/server.py"]
    }
  }
}
  1. Save, fully quit Claude Desktop (right-click tray icon → Quit), reopen.
  2. Check the hammer icon in the composer for EMMA tools.

First prompt — the 60-second verification

Open a new Claude Desktop chat and paste:

Use the EMMA MCP to pull the upcoming new-issue calendar for the next week. Filter to NY state only. Return a clean table with issuer, par, dated, and sector.

You should see Claude call get_new_issue_calendar with state="NY", get ~10-25 rows back in a few seconds, and format them as a table with EMMA URLs. If that works, every other tool works the same way.

For a more impressive demo, try:

Find Rady Children's Hospital on EMMA, pull their outstanding bonds, get the most recent issue's details, download the Official Statement, and summarize the rating language and use of proceeds from the first 10 pages.

That runs the full five-tool chain end-to-end in about 20 seconds.

More demo prompts in USAGE.md.

Troubleshooting

Claude Desktop doesn't show EMMA tools after restart.

  • Confirm the JSON is valid (python3 -m json.tool < claude_desktop_config.json — no output = good).
  • Confirm both paths in the config are absolute and exist. Relative paths and ~ do not work.
  • Fully quit Claude Desktop (Cmd+Q / tray Quit) — closing the window keeps it running.
  • Check Claude Desktop's MCP logs at ~/Library/Logs/Claude/mcp*.log (Mac) or %APPDATA%\Claude\logs\mcp*.log (Windows) for a specific error.

playwright install chromium hangs or fails.

  • First-time install downloads ~150 MB and takes 1-2 min on a home connection. Be patient.
  • Behind a corporate proxy, set HTTPS_PROXY and HTTP_PROXY before running.

Claude calls a tool and it returns "EMMA disclaimer loop" or times out.

  • EMMA sets a CUSIP disclaimer cookie on first visit. The server pre-seeds it (Disclaimer6=msrborg) but very rarely EMMA changes the cookie name. Restart Claude Desktop to reset the browser context. If it persists, EMMA may be down — check https://emma.msrb.org in a regular browser.

A returned table shows cusip_hash: ABC123… instead of a 9-digit CUSIP.

  • This is intentional, not a bug. EMMA renders CUSIPs as image tags (CGS licensing rule), so the server cannot read them off HTML. The Official Statement PDF is the authoritative CUSIP source. Use download_official_statement then extract_pdf_text — the cover and inside-cover carry the real CUSIPs.

"Rady Children's" search finds Franklin OH and Pittsburgh PA children's hospitals but not Rady.

  • This is a known EMMA quirk, not a server bug. Rady's bonds file under a California conduit (CHFFA / CPFA) with "RADY CHILDRENS" only in the obligor-in-parens portion, which EMMA's QuickSearch does index but weakly. Try emma_quick_search {query: "rady"} or search the conduit directly: search_issuers_by_state {state: "CA", contains: "health care facilities"}. Full obligor lookup playbook in USAGE.mdThe conduit cheat sheet.

Server starts but Claude says "no tools available."

  • You likely edited server.py and there's a Python syntax error. Run uv run python server.py in a terminal — any error prints to stderr. Fix and restart Claude Desktop.

What's in this folder

File / folder What it is
server.py The MCP server itself — ~1,500 lines, Python, Playwright. 18 tools, 2 resources.
CLAUDE.md Blaylock compliance rules. Loaded into every EMMA session as MCP resource emma://rules/CLAUDE.md.
EMMA_ABBREVIATIONS.md EMMA's telegraphic issuer-name abbreviations (HOSP, AUTH, SR, CMNTY, etc.) + conduit cheat sheet. Loaded as resource emma://rules/EMMA_ABBREVIATIONS.md.
README.md This file.
USAGE.md Extensive reference: the 18 tools, the canonical workflow chain, sample banker prompts, caveats.
pyproject.toml, uv.lock Python dependency manifest.
_demo_pulse.py One-shot driver used during slide preparation — calls the MCP directly so we could screenshot outputs. Not needed to run the server.
_fetch_os_pdfs.py Companion script that batch-downloaded OS PDFs for the capstone's Tier 2 (Cowork) demo. Not needed to run the server.
os_pdfs/ Sample Official Statements downloaded via the MCP during testing. Keep or delete — the folder auto-recreates on first download_official_statement call.

The one-line version

We built the EMMA MCP that no vendor ships, wired it into Claude via the same protocol as every marketplace connector, and governed it with a plain-markdown rules file a banker can read and edit. That is what Tier 4 looks like when a firm actually owns its own tool.

MCP Server · Populars

MCP Server · New