get_issue_details
Retrieve comprehensive details for a municipal bond issue using its EMMA IssueView URL, including offering terms, ratings, official statement, and trade history.
Instructions
Full IssueView page for a given IssueView URL — per-CUSIP detail (par at issuance, coupon, maturity, initial offering price, current LT rating, price, yield, and ratings from Fitch, KBRA, Moody's, S&P), the Official Statement PDF link, and recent trade activity. This is the single most information-dense page on EMMA for modeling a specific deal.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| issue_url | Yes | EMMA IssueView URL (https://emma.msrb.org/IssueView/Details/P#####) |
Implementation Reference
- server.py:1250-1323 (handler)The _dispatch function handles 'get_issue_details' by navigating to the IssueView URL, scraping per-CUSIP details (par, coupon, maturity, offering price, ratings), the OS PDF link, and recent trades/filings from the EMMA page.
if name == "get_issue_details": issue_url = args["issue_url"] async with new_page() as page: await page.goto(issue_url, wait_until=NAV_WAIT, timeout=NAV_TIMEOUT_MS) try: await page.wait_for_selector("#dtSecurities tbody tr", timeout=15000) except Exception: pass await page.wait_for_timeout(500) info = await page.evaluate( """() => { const pull = id => { const t = document.getElementById(id); if (!t) return null; const head = Array.from(t.querySelectorAll('thead th')).map(th => th.innerText.trim()); const rows = Array.from(t.querySelectorAll('tbody tr')).map(tr => { const cells = Array.from(tr.cells).map(td => td.innerText.trim()); // EMMA renders CUSIPs as <img data-cusip9="HASH"> inside <a class="sec" href="/Security/Details/HASH">. // Ratings similarly rendered as <img data-rating="HASH">. Pull both. const secA = tr.querySelector('a[href*="/Security/Details/"]'); const cusipImg = tr.querySelector('img[data-cusip9]'); const ratingImgs = Array.from(tr.querySelectorAll('img[data-rating]')).map(i => i.getAttribute('data-rating')); return { cells, security_url: secA ? secA.href : null, cusip_hash: cusipImg ? cusipImg.getAttribute('data-cusip9') : null, rating_hashes: ratingImgs, }; }); return {head, rows}; }; const pdfA = Array.from(document.querySelectorAll('a[href]')) .find(a => /Official Statement\\s*\\(.*MB\\)/i.test(a.innerText) && /\\.pdf($|\\?)/i.test(a.href)); const title = (document.querySelector('h1, h2, .pageTitle')?.innerText || '').trim(); return { title, pdf: pdfA ? {url: pdfA.href, label: pdfA.innerText.trim()} : null, securities: pull('dtSecurities'), trades: pull('lvIssueTrades'), filings: pull('submissionFileListArchiveTable'), }; }""" ) out: dict[str, Any] = { "issue_url": issue_url, "title": info.get("title") or "", "official_statement_pdf": info.get("pdf"), } for key in ("securities", "trades", "filings"): block = info.get(key) if not block: out[key] = [] continue rows = [] for r in block.get("rows", []): item = structured(block.get("head", []), [r.get("cells", [])]) if item: rr = item[0] if r.get("security_url"): rr["security_url"] = r["security_url"] if r.get("cusip_hash"): rr["cusip_hash"] = r["cusip_hash"] if r.get("rating_hashes"): rr["rating_hashes"] = r["rating_hashes"] rows.append(rr) out[key] = rows out["_note"] = ( "EMMA renders CUSIPs as images (anti-scraping). `cusip_hash` is " "an opaque EMMA ID, NOT the 9-digit CUSIP. Real CUSIPs must be " "read from the OS PDF (compliance: never synthesize a CUSIP). " "`security_url` is the per-security EMMA page." ) return out - server.py:616-636 (schema)Tool registration/input schema for 'get_issue_details' defining the 'issue_url' parameter (EMMA IssueView URL).
Tool( name="get_issue_details", description=( "Full IssueView page for a given IssueView URL — per-CUSIP " "detail (par at issuance, coupon, maturity, initial offering " "price, current LT rating, price, yield, and ratings from " "Fitch, KBRA, Moody's, S&P), the Official Statement PDF link, " "and recent trade activity. This is the single most " "information-dense page on EMMA for modeling a specific deal." ), inputSchema={ "type": "object", "properties": { "issue_url": { "type": "string", "description": "EMMA IssueView URL (https://emma.msrb.org/IssueView/Details/P#####)", } }, "required": ["issue_url"], }, ), - server.py:370-755 (registration)The tool is registered in the list_tools() function at line 616-636 via the Tool() named 'get_issue_details'.
async def list_tools() -> list[Tool]: return [ Tool( name="get_new_issue_calendar", description=( "Upcoming municipal bond issues from MSRB EMMA — the primary " "competitive-intel tool for any muni banker. Each row is enriched " "with an inferred sector classification. Multi-axis filters: state, " "sector, tax_status, bank_qualified, sale_method, description_contains, " "min_principal, max_principal. Use this to answer questions like " "'what hospital deals over $100M are pricing this week?'" ), inputSchema={ "type": "object", "properties": { "state": {"type": "string", "description": "2-letter state code"}, "sector": { "type": "string", "description": ( "Sector name, matched case-insensitive substring. One of: " "Healthcare / Hospital, Housing, Education / Schools, " "Water / Sewer / Utility, Transportation, " "Industrial Development / IDB, Tobacco Settlement, " "Pension / OPEB, Refunding, General Obligation, Revenue" ), }, "tax_status": { "type": "string", "description": "'Tax Exempt', 'Taxable', 'AMT', or 'Subject to AMT'", }, "bank_qualified": {"type": "boolean"}, "sale_method": { "type": "string", "enum": ["competitive", "negotiated", "all"], "default": "all", }, "description_contains": { "type": "string", "description": ( "Free-text filter on the issue description. Query is " "auto-expanded to EMMA abbreviations (hospital→HOSP, " "authority→AUTH, senior→SR, revenue→REV, etc.) — " "search in natural English, not telegraphic shorthand." ), }, "min_principal": {"type": "number"}, "max_principal": {"type": "number"}, "limit": {"type": "integer", "default": 25}, "offset": {"type": "integer", "default": 0}, }, }, ), Tool( name="get_calendar_summary", description=( "Aggregate the new-issue calendar by a grouping dimension. Returns " "count and total par per group, sorted by par descending. Perfect " "for slides: 'NY leads this week at $1.2B across 8 deals; hospitals " "and schools dominate the sector mix.'" ), inputSchema={ "type": "object", "properties": { "group_by": { "type": "string", "enum": ["state", "sector", "tax_status", "bank_qualified", "sale_method"], "default": "state", }, "top_n": {"type": "integer", "default": 10}, }, }, ), Tool( name="classify_sector", description=( "Classify a muni bond issue description into a sector using the same " "keyword rules the calendar tool uses. Useful to show Marciano the " "classifier is deterministic, not a black box." ), inputSchema={ "type": "object", "properties": { "description": {"type": "string"}, }, "required": ["description"], }, ), Tool( name="get_recent_sales", description=( "Most actively traded muni CUSIPs right now from EMMA's " "/TradeData grid — description, coupon, maturity, high/low " "price & yield, trade count, total trade amount, and a link " "to each security's EMMA detail page. Use this to gauge " "live-market color for comparable deals." ), inputSchema={ "type": "object", "properties": {"limit": {"type": "integer", "default": 25}}, }, ), Tool( name="get_recent_preliminary_statements", description=( "Recent Preliminary Official Statements (POS) — pre-pricing " "documents filed right before a deal comes to market. This " "is the leading edge of the new-issue pipeline. Each row " "links to the filing PDF and the issuer page." ), inputSchema={ "type": "object", "properties": { "limit": {"type": "integer", "default": 25}, "issuer_contains": { "type": "string", "description": "Filter issuer (auto-expanded for abbreviations)", }, }, }, ), Tool( name="get_recent_annual_reports", description=( "Recent issuer annual financial reports filed as continuing " "disclosures — the source for post-issuance updated obligor " "financials (revenue, operating income, debt-service coverage)." ), inputSchema={ "type": "object", "properties": { "limit": {"type": "integer", "default": 25}, "issuer_contains": {"type": "string"}, }, }, ), Tool( name="search_issuers_by_state", description=( "List municipal issuers for a state (all 9k+ rows, not just " "page 1) and filter by name. Feed the issuer_id into " "get_issuer_outstanding_bonds or get_issuer_profile to drill " "down. IMPORTANT: the `contains` filter auto-expands your " "query into every EMMA abbreviation variant (hospital→HOSP, " "authority→AUTH, children→CHLDN, senior→SR, community→CMNTY, " "etc.) — always search in natural English, never in the " "telegraphic form. For hospital/senior-living/charter-school " "obligors, search the CONDUIT, not the obligor: e.g. CHLA " "bonds are filed under CALIFORNIA PUB FIN AUTH HEALTH CARE " "FACS REV — found by searching `contains=\"health care " "facilities\"`. See the emma://rules/EMMA_ABBREVIATIONS.md " "resource for the full variant map and conduit cheat sheet." ), inputSchema={ "type": "object", "properties": { "state": {"type": "string", "description": "2-letter state code"}, "contains": { "type": "string", "description": "Case-insensitive name filter", }, "limit": {"type": "integer", "default": 50}, }, "required": ["state"], }, ), Tool( name="get_issuer_outstanding_bonds", description=( "List an issuer's outstanding bond issues from their EMMA profile — " "issue description, dated date, maturity range. The most reliable " "drill-down on any issuer." ), inputSchema={ "type": "object", "properties": { "issuer_id": { "type": "string", "description": "EMMA issuer GUID (from search_issuers_by_state)", }, "issuer_url": { "type": "string", "description": "Any EMMA issuer URL (from emma_quick_search; can be a QuickSearch/Navigate redirect)", }, "limit": {"type": "integer", "default": 25}, }, }, ), Tool( name="get_issuer_profile", description=( "Full issuer profile: name, outstanding issues, attempted fetch of " "Official Statements, Pre-Sale docs, Continuing Disclosures, and " "Recent Trades. EMMA loads the latter via tab interaction; empty " "sections are reported honestly rather than guessed at." ), inputSchema={ "type": "object", "properties": { "issuer_id": {"type": "string", "description": "EMMA issuer GUID"}, "issuer_url": { "type": "string", "description": "Any EMMA issuer URL (from emma_quick_search)", }, }, }, ), Tool( name="get_security_details", description=( "Pull security-level fields for a 9-digit CUSIP: issuer, coupon, " "maturity, dated date, par. CUSIPs that are redeemed / matured / " "pre-refunded return a clear 'no records' response — try a " "currently-outstanding CUSIP from get_issuer_outstanding_bonds." ), inputSchema={ "type": "object", "properties": {"cusip": {"type": "string"}}, "required": ["cusip"], }, ), Tool( name="emma_quick_search", description=( "**START HERE** when the user names a specific obligor, issuer, " "or keyword. Uses EMMA's global quick search (the same box in " "EMMA's header) which indexes BOTH long-form and obligor-in-" "parens names — so 'Childrens Hospital' finds " "'CALIFORNIA HEALTH FACILITIES FINANCING AUTHORITY (LUCILE " "SALTER PACKARD CHILDRENS HOSPITAL AT STANFORD)' without " "needing the conduit-issuer chase. Returns matching issuers " "(across all states) and matching specific issues. Each " "issuer row has a URL you can feed into " "get_issuer_outstanding_bonds." ), inputSchema={ "type": "object", "properties": { "query": { "type": "string", "description": "Natural-language search: obligor name, issuer name, CUSIP, state, or keyword", }, "limit": {"type": "integer", "default": 25}, }, "required": ["query"], }, ), Tool( name="get_issue_details", description=( "Full IssueView page for a given IssueView URL — per-CUSIP " "detail (par at issuance, coupon, maturity, initial offering " "price, current LT rating, price, yield, and ratings from " "Fitch, KBRA, Moody's, S&P), the Official Statement PDF link, " "and recent trade activity. This is the single most " "information-dense page on EMMA for modeling a specific deal." ), inputSchema={ "type": "object", "properties": { "issue_url": { "type": "string", "description": "EMMA IssueView URL (https://emma.msrb.org/IssueView/Details/P#####)", } }, "required": ["issue_url"], }, ), Tool( name="get_recent_continuing_disclosures", description=( "Recent continuing-disclosure filings (audited financials, " "material events, rating changes, quarterly operating data). " "Each row has a direct link to the filed PDF. This is where " "post-issuance credit work lives — ratings today, not at " "issuance; updated obligor financials for modeling." ), inputSchema={ "type": "object", "properties": { "limit": {"type": "integer", "default": 50}, "disclosure_contains": { "type": "string", "description": "Filter disclosure description (auto-expanded for EMMA abbreviations)", }, "issuer_contains": { "type": "string", "description": "Filter issuer name (auto-expanded for EMMA abbreviations)", }, }, }, ), Tool( name="extract_pdf_text", description=( "Extract text from a previously-downloaded OS PDF so you can " "pull financials, debt service tables, obligor financials, " "rating language, bond purpose, sources-and-uses, etc. into " "an Excel model. Works best on OS PDFs saved via " "download_official_statement." ), inputSchema={ "type": "object", "properties": { "path": { "type": "string", "description": "Absolute path to the saved PDF", }, "pages": { "type": "string", "description": "Page range like '1-20' or '45,46,47' (optional — default: all)", }, "max_chars": { "type": "integer", "default": 120000, "description": "Cap on returned characters to protect context", }, }, "required": ["path"], }, ), Tool( name="get_recent_official_statements", description=( "List the EMMA Recent Official Statements grid — the 10 most " "recently filed OS documents across the muni market, with issuer, " "series, dated date, and a link back to the issuer. Feed a row's " "issue_url into get_official_statement_pdf to grab the PDF URL." ), inputSchema={ "type": "object", "properties": {"limit": {"type": "integer", "default": 10}}, }, ), Tool( name="get_official_statement_pdf", description=( "Given an EMMA IssueView/Details/P##### URL, return the direct " "Official Statement PDF URL (and issue title). This is the " "canonical primary-source OS — use it before quoting coupons, " "maturities, or call features." ), inputSchema={ "type": "object", "properties": { "issue_url": { "type": "string", "description": "EMMA IssueView URL (https://emma.msrb.org/IssueView/Details/P#####)", } }, "required": ["issue_url"], }, ), Tool( name="download_official_statement", description=( "Download an Official Statement PDF from EMMA to local disk. " "Pass either a direct PDF URL or an IssueView URL (the tool will " "resolve it to the PDF link). Returns file path + size. Use when " "the banker wants the OS to attach to a deck or read offline." ), inputSchema={ "type": "object", "properties": { "url": { "type": "string", "description": "Either a direct .pdf URL or an IssueView/Details/P##### URL", }, "filename": { "type": "string", "description": "Optional filename (without extension)", }, }, "required": ["url"], }, ), Tool( name="get_market_pulse", description=( "Snapshot of this week's muni primary market: total par, deal count, " "top 5 states, top 5 sectors, top 5 lead managers if available, " "competitive-vs-negotiated split. Built entirely from the live " "new-issue calendar — one call, boardroom-ready." ), inputSchema={"type": "object", "properties": {}}, ), ]