# MuniPro MCP and related API routes

Status: Active

For Rogo and other AI clients, connect to **https://munipro.com/mcp** using
Streamable HTTP and per-user OAuth. MCP calls MuniPro's internal adapters and
services. The related HTTP routes below are alternative interfaces; MCP does
not forward each tool call to that URL. An audit label such as
`mcp.debt_summary` is not a URL.

## Connect and discover

- Setup and support: https://munipro.com/ai/
- Rogo contract and demo: https://munipro.com/static/mcp/rogo-connection-guide.md
- Protected-resource metadata: https://munipro.com/.well-known/oauth-protected-resource/mcp
- Authorization-server metadata: https://munipro.com/.well-known/oauth-authorization-server

Use the advertised authorization-code/PKCE S256 flow. After `initialize` and
`notifications/initialized`, call `tools/list` and follow every `nextCursor`.
Use each returned `inputSchema` for `tools/call`. The visible catalog depends
on company, user, role, scope, entitlement, host policy and record access.
There is no universal partner tool count or one REST endpoint per MCP tool.

## Credentials are specific to the interface

**The dedicated `/api/assistant/v1/banker/` routes accept MCP OAuth tokens.**
See https://munipro.com/static/mcp/banker-integration-guide.md for JSON and
authenticated-file delivery. Other REST API-key routes reject MCP OAuth tokens
and need separately provisioned access. Matching scope names do not make
credentials interchangeable. Browser routes
require a signed-in MuniPro session and CSRF protection for unsafe requests.
Never send a MuniPro password to an AI host or put a token in a URL, prompt,
source file or support message.

All paths in this table are relative to `https://munipro.com`. Preserve
trailing slashes. A reviewed counterpart identifies related behavior, not
identical inputs, pagination, response shape or acceptance evidence. Other
HTTP relationships remain under review; this is not the whole API inventory.

| MCP tool | Related HTTP operation | HTTP authentication |
| --- | --- | --- |
| `calculate_bond_pricing` | POST `/muni/calculateBondPricing/` | MuniPro browser session + CSRF |
| `calculate_bond_pricing_batch` | POST `/muni/calculateBondPricingBatch/` | MuniPro browser session + CSRF |
| `get_debt_details_dataset` | POST `/api/assistant/v1/banker/issuers/{issuer_id}/datasets/` | Current MCP OAuth bearer; profile, scope and record checks |
| `get_debt_summary` | GET `/api/assistant/v1/issuers/{issuer_id}/debt_summary` | Separate Assistant service token; operator-enabled only |
| `get_investor_document_detail` | GET `/api/v1/investor-documents/{document_id}/status/` | Dedicated REST key: documents:read |
| `get_investor_document_text` | GET `/api/v1/investor-documents/{document_id}/text/` | Dedicated REST key: documents:text |
| `get_issuer_file_download` | GET `/api/assistant/v1/banker/issuers/{issuer_id}/files/{file_id}/` | Current MCP OAuth bearer; profile, scope and record checks |
| `get_issuer_financial_statement_detail` | GET `/api/v1/issuer-financials/{issuer_key}/statements/{statement_id}/` | Dedicated REST key: financials:read |
| `get_issuer_income_statement_series` | GET `/api/v1/issuer-financials/{issuer_key}/income-statement/` | Dedicated REST key: financials:read |
| `get_job_status` | GET `/api/assistant/v1/banker/jobs/{job_id}/` | Current MCP OAuth bearer; profile, scope and record checks |
| `get_series_cashflows` | GET `/api/assistant/v1/series/{series_id}/cashflow` | Separate Assistant service token; operator-enabled only |
| `get_verified_debt_profile` | GET `/api/assistant/v1/issuers/{issuer_id}/debt_profile` | Separate Assistant service token; operator-enabled only |
| `list_issuer_debt_documents` | GET `/api/assistant/v1/banker/issuers/{issuer_id}/documents/` | Current MCP OAuth bearer; profile, scope and record checks |
| `list_issuer_files` | GET `/api/assistant/v1/banker/issuers/{issuer_id}/files/` | Current MCP OAuth bearer; profile, scope and record checks |
| `list_outstanding_series` | GET `/api/assistant/v1/issuers/{issuer_id}/outstanding_series` | Separate Assistant service token; operator-enabled only |
| `list_verified_borrowers` | GET `/api/assistant/v1/banker/borrowers/` | Current MCP OAuth bearer; profile, scope and record checks |
| `request_borrower_verification` | POST `/api/assistant/v1/banker/verification-requests/` | Current MCP OAuth bearer; profile, scope and record checks |
| `search_investor_documents_by_cusip` | GET `/api/v1/investor-documents/doclist/` | Dedicated REST key: documents:read |
| `search_issuers` | GET `/api/assistant/v1/issuers/search` | Separate Assistant service token; operator-enabled only |
| `search_securities_by_cusip` | GET `/api/assistant/v1/securities/search_by_cusip` | Separate Assistant service token; operator-enabled only |
| `search_securities_by_text` | GET `/api/assistant/v1/securities/search` | Separate Assistant service token; operator-enabled only |
| `search_series` | GET `/api/assistant/v1/series/search` | Separate Assistant service token; operator-enabled only |

## Parameters and response differences

- The older Assistant service API routes (outside `/banker/`) require explicit operator enablement and their own
  configured service-company token. Source documentation is not a promise that
  those routes are enabled for your organization. `issuer_id` means Borrower ID.
  Search uses `q`; security-prefix search uses `cusip` (at least six characters).
  Series search uses `cusip`, or `issuer_id` plus `designation`. Search `limit`
  defaults to 10 and clamps to 1-25; these REST search handlers have no cursor.
- Investor document `doclist` requires a full nine-character `cusip`; its MCP
  counterpart names that input `cusip9`. Follow `pagination.next_cursor` and
  `has_more`. Use the returned opaque signed `document_id` for status/text;
  never substitute an upstream URL or internal storage path.
- The separate REST document `prepare/` POST and `download/` GET/HEAD actions
  require `documents:download`. They have no dedicated MCP counterpart asserted
  here. Preparation can cache a document. A successful MCP metadata/text call
  does not grant binary-download access.
- Financial `issuer_key` accepts the supported issuer slug, `profile:`,
  `cusip6:` or `cusip9:` form. It is not automatically a Borrower ID. Income
  statements accept `years`, `before` and `mix_statement_kinds`; statement
  detail accepts `limit` and `cursor`. Wrong-issuer/unaccepted statements
  return 404. Issuer-scoped key grants still apply.
- Browser pricing accepts calculation fields directly as the JSON body. MCP
  nests them under `arguments.request_payload`. Include the required day-count
  controls. Coupon and yield inputs here are percentages (`5.0` means 5%). MCP
  batch pricing caps the maturities array at 200. Browser responses include
  user-bound report/export metadata that MCP does not promise to return.

For complete JSON argument schemas, use your authenticated MCP `tools/list`.
Authorized users can inspect the configured DRF schema at
https://munipro.com/api/v1/schema/ and Swagger at
https://munipro.com/api/v1/docs/. Those signed-in schemas do not describe every
browser handler or replace the MCP tool schemas.

## Results, jobs and governed changes

Check the JSON-RPC error, MCP `isError`, and application status/outcome. HTTP
200 can carry validation or calculation failure. For heavy work, use the
advertised async tool and poll its `mcp-job://` reference with `get_job_status`
to a terminal result. A successful poll does not mean the calculation passed.
Follow exact returned references using `fetch` with the `id` argument. Preserve
source dates, assumptions, notices and provenance. Complete paged-result
reconstruction and digest rules are at https://munipro.com/ai/#guidance.

An artifact link can require the authorized MuniPro browser session. Banker
dataset results also return `api_download` for the current MCP bearer. Neither
creates a public download or sharing permission.
The banker HTTP job route can return `result.result_paged`,
`result.first_page_ref` and a root `result_manifest`. Reconstruct it with MCP
`fetch` before reading artifact fields; these HTTP routes have no page-fetch
endpoint. Six banker routes return application JSON; three stream file bytes
(uploaded files, debt-document PDFs and dataset JSON). Debt-document manifests
return MuniPro bearer download links and retain separate public EMMA source URLs.
Use each route's response schema and inspect application status where supplied.
See the banker integration guide for the complete retrieval sequence.
Confirmed workspace changes require separate host acceptance, a bound preview,
human approval, a committed receipt and read-back. Connecting successfully
does not enable writes. A preview or queued job is not a completed change.

On 401, renew/reconnect; on 403, resolve the actual access requirement; on 409,
re-read state. On 429, honor `Retry-After` when present. If it is absent, stop
automatic retries, retain the returned quota message and confirm the reset
with MuniPro support. Revoke the grant on disconnect and verify old access is
refused. Do not reuse a consumed authorization code or refresh token: replay
revokes its grant family.

Before calling the integration accepted, demonstrate it in the actual client:
OAuth, complete discovery, a successful calculation, pagination, a permitted
record and a refused record, async/artifact flows when needed, refresh and
disconnect. Registration and source mapping alone are not end-to-end evidence.

Support: https://munipro.com/ai/#support. Include client, UTC time, username
and redacted error text; never include credentials or authorization codes.
