Skip to main content
Glama

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

TableJSON Schema
NameRequiredDescriptionDefault
issue_urlYesEMMA IssueView URL (https://emma.msrb.org/IssueView/Details/P#####)

Implementation Reference

  • 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
  • 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": {}},
            ),
        ]
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must convey behavioral traits. It lists the returned data fields and indicates it's a single page, which is helpful. However, it does not disclose idempotency, rate limits, or error behavior, which would be beneficial for a read operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences efficiently deliver the tool's purpose and key details. Every word adds value, and critical information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description adequately lists the major data fields returned (ratings, pricing, trade activity, etc.). It is complete for the tool's purpose, though it could mention if the output is an object or array.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage for the single parameter, detailing the URL format. The description adds context about the parameter being an IssueView URL and emphasizes per-CUSIP detail, but does not significantly extend beyond the schema's own description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly specifies the tool retrieves the full IssueView page with per-CUSIP details, listing specific fields (par, coupon, maturity, etc.). It distinguishes itself as the most information-dense page for modeling a deal, setting it apart from sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use when needing detailed CUSIP-level information but does not explicitly state when not to use or mention alternative tools. Usage context is clear but lacks exclusions or comparisons to siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ark9164-create/blaylock-emma-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server