get_security_details
Retrieve security details for a 9-digit CUSIP: issuer, coupon, maturity, dated date, and par. Returns clear 'no records' for redeemed or matured bonds.
Instructions
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.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cusip | Yes |
Implementation Reference
- server.py:1582-1609 (handler)Handler function for get_security_details tool — navigates to EMMA Security/Details page for the given CUSIP, validates 9-char length, checks for 'no records exist' message (matured/invalid CUSIPs), and scrapes label fields from the page.
if name == "get_security_details": cusip = args["cusip"].strip().upper() if len(cusip) != 9: return {"error": "CUSIP must be 9 characters"} async with new_page() as page: await page.goto(f"{EMMA_BASE}/Security/Details/{cusip}", wait_until=NAV_WAIT, timeout=NAV_TIMEOUT_MS) await page.wait_for_timeout(2500) body = await page.evaluate("() => document.body.innerText") if "no records exist" in body.lower(): return { "cusip": cusip, "error": "no records exist for this CUSIP — likely matured, " "pre-refunded, or invalid. Try a currently-outstanding " "CUSIP from get_issuer_outstanding_bonds.", } fields = await page.evaluate( """() => { const out = {}; document.querySelectorAll('[id*=lbl], [id*=Lbl]').forEach(el => { const k = el.id.split('_').pop().replace(/^lbl/i,''); const v = (el.innerText||'').trim(); if (v && v.length<300) out[k]=v; }); return out; }""" ) return {"cusip": cusip, "fields": fields} - server.py:577-589 (schema)Schema/input definition for get_security_details — defines the tool name, description, and inputSchema requiring a single 'cusip' string parameter.
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"], }, ), - server.py:577-755 (registration)Tool registration via @server.list_tools() — get_security_details is listed among the server's tools in the list_tools function.
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": {}}, ), ]