# Connect Rogo to MuniPro

Status: Active
Contract reviewed: 2026-09-17

Related HTTP endpoints and credential requirements:
https://munipro.com/static/mcp/api-route-reference.md.

Banker integration, profile schemas and datasets:
https://munipro.com/static/mcp/banker-integration-guide.md,
https://munipro.com/static/mcp/banker-tool-profile.json,
https://munipro.com/static/mcp/banker-data-guide.md.

Auditable citations, browser login and stable series identifiers:
https://munipro.com/static/mcp/citation-guide.md.

Use Rogo's custom MCP capability to connect an entitled MuniPro user to
authorized data and calculations. Start at https://munipro.com/ai/#client-rogo.
Rogo workspace policy controls who can add and enable a custom connector.

## Connection contract

| Setting | Value |
| --- | --- |
| MCP server | `https://munipro.com/mcp` |
| Transport | Streamable HTTP over HTTPS; JSON-RPC 2.0 |
| Resource / token audience | `https://munipro.com/mcp` (no trailing slash) |
| Protected-resource metadata | `https://munipro.com/.well-known/oauth-protected-resource/mcp` |
| Authorization-server metadata | `https://munipro.com/.well-known/oauth-authorization-server` |
| Issuer | `https://munipro.com/` (trailing slash required for exact comparison) |
| Authorization endpoint | `https://munipro.com/oauth/authorize` |
| Token endpoint | `https://munipro.com/oauth/token` |
| Registration endpoint | `https://munipro.com/oauth/register` |
| Revocation endpoint | `https://munipro.com/oauth/revoke` |
| Grant types | `authorization_code`, `refresh_token` |
| PKCE | `S256` required |
| Token endpoint authentication | `none` (public OAuth clients; no client secret) |
| Rogo application callback | `https://app.rogo.ai/nest/tool-proxy/integrations/callback` |
| Rogo development callback | `https://app.dev.rogo.ai/nest/tool-proxy/integrations/callback` |
| Bearer presentation | `Authorization: Bearer <access_token>` request header |

Follow live discovery rather than hardcoding a guessed metadata path. The
resource-specific metadata endpoint includes `/mcp`; its root-only equivalent
is not advertised. A missing bearer credential receives HTTP 401 with the
discovery challenge. Send `Accept: application/json, text/event-stream` and
`Content-Type: application/json` for JSON-RPC POST requests. Support both
advertised response media types and use the negotiated MCP protocol version.

MuniPro supports dynamic client registration and HTTPS Client ID Metadata
Documents for users signing in with a valid MuniPro account. Callback hostnames
do not require prior review. Native clients may register an HTTP loopback
callback, including Rogo Support's
`http://localhost:4004/tool-proxy/integrations/callback`; web clients use HTTPS.
Register the actual application callback, then use its registered URI during
authorization. Native loopback ports follow the protocol's matching rules.
Client types and hostnames are logged for operational review; user consent,
permissions, scopes and tool profiles still govern access. Client-credentials
grants are unsupported.

Use `response_type=code`, a fresh `state`, an S256 challenge, and the exact
resource in authorization. Verify returned `state` and `iss`; exchange the
single-use code with the same client, redirect URI, resource, and PKCE verifier.
Never follow an unvalidated redirect or place bearer credentials in URLs.

Registration uses HTTP POST with a JSON body including `client_name`,
`redirect_uris`, and `token_endpoint_auth_method: "none"`. Authorization starts
with an HTTP GET carrying the parameters above. Token exchange and revocation
use HTTP POST with `application/x-www-form-urlencoded` bodies. Refresh sends
`grant_type=refresh_token`, `refresh_token`, `client_id`, and `resource`.
Revocation sends `token`, `token_type_hint=refresh_token`, and `client_id`.

## User access and scopes

Each person signs in to MuniPro and reviews the company, identity, scopes,
and return destination on the consent screen. MuniPro internal administrator
accounts cannot authorize an external connector. Use the intended company
account; no shared administrator credential is required.

For the initial banker profile, request
`catalog.read debt.read borrowers.request offline_access`.
Omit `borrowers.request` for read-only use. The profile has six business tools
and five discovery/result/job utilities: **11 tools maximum**. Every discovered
tool must belong to the banker profile; live access can narrow its ceiling.
Start with summary context and load detailed recipes only for a presentation task.
For a separately entitled broader modeling profile, request `model.run` too.
Additional read scopes are `cash.read`, `documents:read`, `documents:text`,
and `financials:read`; request only those needed for the integration.
`offline_access` is advertised for session renewal. Requestable scopes and
their current availability come from live discovery and consent.

The account must have the relevant product entitlement and borrower access.
OAuth scopes never grant a product, expand the roster, or change a person's
MuniPro role. An empty borrower list can be a valid result. Tool discovery is
filtered by role, tenant, scope, entitlement, and host policy; do not assert a
fixed tool count or use another user's catalog as an access specification.

The banker profile admits only a staff verification request as a governed
change. `request_borrower_verification` requires `borrowers.request` and human
approval in the same user's MuniPro session; it never verifies or publishes
debt. Other workspace changes remain held for Rogo. Requesting a scope alone
does not grant a tool. This connector does not execute payments or trades.

## Discovery and results

1. Send `initialize`; use the returned protocol version and server instructions.
2. Send `notifications/initialized`.
3. Call `tools/list`, following `nextCursor` until absent. Use the returned
   names, `inputSchema`, descriptions, and annotations as the tool contract.
4. Call `get_munipro_navigation` for the workflows available to this user.
5. Call tools using their advertised arguments. Inspect JSON-RPC errors,
   MCP `isError`, and the application status/outcome in the returned content.

An HTTP 200 or a successful transport call does not prove the calculation
succeeded. Validation errors can be returned in structured tool content.
Preserve source dates, assumptions, provenance, and professional-use notices
when presenting an answer. Do not describe a ratings-based baseline as a
live market quote. The dedicated `/api/assistant/v1/banker/` JSON and file
routes accept the current MCP bearer. Other REST API endpoints retain their
separate authentication; see the banker guide for the exact boundary.

## Initial banker demo

Start by proving citations in Rogo's default custom connector. Use
`https://munipro.com` as the origin for relative MuniPro page paths. Prefer the
returned `citation.url` for an exact-record link; existing MuniPro browser
sessions are reused, otherwise the reader signs in. MCP OAuth does not transfer
a browser session. Issue IDs identify series records, but there is currently no
series-row browser permalink. The citation guide explains grouped summary rows,
working-copy identity and the evidence to retain with each answer.

1. Confirm the company on MuniPro's account/consent screen, then call
   `get_current_munipro_context` with `detail="summary"` to check the banker
   profile and current access. The context payload does not expose company identity.
2. Page `list_verified_borrowers` and choose a visible verified issuer.
3. Request `get_debt_details_dataset` with `outstanding`, `groupedRollup` and
   `annualChart`; explicitly set as-of date, fiscal year end and variable rate.
4. Poll the job to completion and reconcile to the same debtDetails selection.
   Separately prove Rogo can retrieve `api_download.url` with the current bearer
   and verify SHA-256. Files over 1 MiB and uploaded workbooks require this HTTP
   delivery path; default-connector support is an explicit acceptance gate.
5. List/download an available workbook or DDL, then page all debt documents.
   For debt-document rows, send the bearer only if `download_authentication`
   is `munipro_oauth_bearer` and the parsed `download_url` origin is exactly
   `https://munipro.com`. Never send it to EMMA or another origin, including
   when following redirects. A `public_EMMA` row is a public source link.
   Verify a MuniPro PDF download's SHA-256 against its ETag. Keep `source_url`
   for upstream provenance. See the banker guide for the 24-hour locator,
   proxy/cache error handling and the nine HTTP routes.
6. With an intended new coverage request, show the preview and human approval
   journey; confirm a pending staff request and harmless approval replay.

An empty authorized list is a valid result. Do not broaden a user's roster
merely to make the demonstration appear populated. Full arguments and failure
cases are in the banker integration guide.

When an issuer file result carries `ddl.download_page_url`, show it to the banker
as a link they click to download the original `.ddl` file in their MuniPro browser
session. The link is single use and expires at `ddl.download_page_expires_at`, so
ask for a fresh result after it expires. It never needs a token pasted anywhere.

## Optional broader modeling demo (outside the initial banker profile)

First ask Rogo to call `get_munipro_navigation` and describe available areas.
Then invoke `calculate_bond_pricing` with these arguments:

```json
{
  "request_payload": {
    "settleDate": "2026-09-17",
    "maturityDate": "2036-09-17",
    "coupon": 5.0,
    "yield": 4.0,
    "dayCountBasis": "30/360",
    "feb30360Adjustment": false,
    "eom30360Adjustment": false
  }
}
```

For these exact inputs, the production check on September 17 returned
`status: ok` and a clean price of **108.175717 per 100 of maturity principal**.
Check the returned convention and calculation outcome as well as the price.
Coupon and yield inputs here are percentages: `5.0` means 5%.

Next call `get_financing_scale_data` with
`{"scale_id":"ratings:AAA","scale_scope":"ratings","limit":3}`.
Show its `scale_date`, the first three rows, and the ratings-based label.
Follow the returned `refs.next_page` using `fetch` to retrieve the next rows;
pass that exact reference as the tool's `id` argument. Do not invent a reference
or imply that the first page is the full result.

For a borrower demonstration, select a borrower the same user can already
access, inspect its data, and compare it with that user's MuniPro workspace.
Do not broaden a user's roster merely to make a demonstration appear populated.

## Long-running work and large results

Use a tool's advertised asynchronous form for heavy calculations. Poll its
canonical `mcp-job://` reference using `get_job_status` until `done`, `failed`,
or `cancelled`. The poll's outer success indicates only that polling worked;
inspect the terminal result and `result_outcome` before reporting completion.

For paged results, follow the returned manifest and references. Fetch the
`s000` root initializer before selected child sections. A partial section is
partial evidence. To verify a complete result, traverse every global page in
order, apply the structural operations, and verify page/result SHA-256 values
over RFC 8785/JCS canonical UTF-8 bytes. Preserve the retained notices and
provenance. Detailed paging and job-control guidance is at
https://munipro.com/ai/#guidance.

## Sessions, errors, and acceptance

Access tokens last one hour. Refresh tokens rotate, with a 30-day idle window
and a 180-day maximum grant lifetime. Store tokens securely; serialize refresh
operations and replace the old refresh credential after each successful use.
Replaying a consumed authorization code or refresh token revokes its grant
family. Revoke the grant on disconnect and verify old access receives 401.
Product or pilot expiry can restrict access sooner than the OAuth lifetime.

| Symptom | Action |
| --- | --- |
| 401 | Follow discovery or renew the session; reconnect after revocation. |
| Host refused / invalid registration | Verify exact callback or metadata host with MuniPro. |
| Tool absent / access denied | Check company, role, requested scope, entitlement, and borrower access. |
| Validation error | Read the application error and current schema; correct the inputs. |
| Timeout | Use the asynchronous form where available and poll the returned job. |
| 429 | Honor `Retry-After` when present. Otherwise stop automatic retries, retain the quota message and confirm the reset with MuniPro support. |
| Saved artifact link asks for login | Open in the authorized MuniPro browser session; MCP access is not a public share grant. |

Before signing off in Rogo, record the workspace/client version, UTC time,
user/company, tool names, request IDs, and redacted results for:

- OAuth consent and successful connection.
- Clickable citations in the actual Rogo answer; signed-in and signed-out link
  behavior; returned borrower/workspace and series IDs preserved.
- Complete catalog discovery: no more than 11 tools, all within the initial
  11-tool banker profile, with correct role filtering.
- A successful dataset export and one fully paginated read. Run the optional
  pricing example only if the connected profile actually advertises it.
- A permitted borrower read and an unauthorized borrower refusal.
- An asynchronous job and complete large-result retrieval, when used.
- Refresh, reconnect, disconnect, and revoked-token refusal.
- Preservation of provenance, notices, and application-error handling.

MuniPro-side protocol checks do not substitute for this actual Rogo client
acceptance. Record the banker verification request's preview, human approval,
receipt and replay separately before claiming that workflow works in Rogo.

Support: https://munipro.com/ai/#support. Include the client, approximate UTC
time, MuniPro username, and error text. Never send access tokens, refresh
tokens, API keys, passwords, or authorization codes in a support message.

Rogo confirms its custom MCP capability in its official announcement:
https://rogo.com/news/may-product-update. Confirm workspace-specific setup
controls and client requirements with Rogo's integration team.
