> For the complete documentation index, see [llms.txt](https://api-docs.realfinity.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://api-docs.realfinity.io/mcp/connecting/troubleshooting.md).

# Troubleshooting

Use this page when the MCP connection won't establish, tools don't show up, or tool calls fail once connected. Work through it top to bottom — most reported issues are one of the five connection problems below, not a bug in a specific tool.

## Step 1: Check the server itself

Before touching auth or client config, confirm the server is up:

```bash
curl https://ai.realfinity.io/health
```

A healthy server returns:

```json
{"status":"healthy"}
```

If this fails or times out, the problem is server-side outage/deploy, not your authentication or client configuration — stop here and check with the team before debugging further. If it succeeds, the server is fine and the issue is somewhere in auth or client setup — move on to the table below.

## Connection problems

| Symptom                                                       | Cause                                                                                                                                                                                                                                                                                                                                                                                   | Fix                                                                                                                                                                                                                                                                                                                                                        |
| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 401 Unauthorized on every call                                | No token was sent, or the token was minted for the wrong audience                                                                                                                                                                                                                                                                                                                       | Follow the `resource_metadata` challenge the server returns rather than hardcoding an audience. Do not set `audience` yourself when initiating the OAuth flow — the `/authorize` facade strips any incoming `audience` (or `resource`) parameter and replaces it with the correct MCP audience before forwarding to Auth0.                                 |
| Connects successfully, but exposes no tools                   | The client is pointed at `mcp.realfinity.io` instead of `ai.realfinity.io`. `mcp.realfinity.io` is an unrelated third-party service, not this server, and must not be used. Whatever it responds with, it is not the Realfinity MCP server and exposes none of these tools.                                                                                                             | Point the client at `https://ai.realfinity.io/mcp` (or `https://ai-uat.realfinity.io/mcp` for UAT). This is a working-looking failure: no error, no red flag in the client UI, just zero tools — double-check the hostname first whenever tools silently don't appear.                                                                                     |
| Refresh stops working (session dies and needs a full re-auth) | The `/authorize` facade preserves the scopes the client requests and appends `offline_access` to that list when it is missing, then forwards the merged list to Auth0. The client's own scopes are not dropped — but `offline_access` is always present in what gets forwarded, so a client dropping `offline_access` via its requested scope is not possible. That cause is ruled out. | Check instead: whether the client is persisting and actually using the refresh token it received; whether the client implements the `refresh_token` grant (the facade advertises it in `grant_types_supported`); and whether Auth0 is issuing a refresh token at all for this API/client on the tenant side, since offline access must be permitted there. |
| Auth succeeds, but every tool call fails                      | The signed-in Auth0 identity has no matching Realfinity agent. On token validation, `OnTokenValidated` looks up the agent by email via `IAgentService.GetByEmail`, and fails the request outright when no match is found — this happens after the OAuth handshake completes, so the client believes it's authenticated.                                                                 | Sign in with the Auth0 account tied to an existing Realfinity agent record. A valid Auth0 login is not sufficient on its own — the email must resolve to an agent in Realfinity.                                                                                                                                                                           |
| Empty results, no error                                       | Row-level RBAC scoping is doing exactly what it's supposed to do. This is expected behavior, not a fault.                                                                                                                                                                                                                                                                               | See [Scoping](#scoping) below. Confirm the signed-in agent's role and check whether the loans/users you expect are actually within that role's scope.                                                                                                                                                                                                      |

### Scoping

Most tool results are scoped to the calling agent's role, the same way the Private API scopes them:

* **Admin:** sees everything.
* **Processor:** sees **all loans org-wide** for per-loan access: `get_loan_application`, `get_loan_application_contacts`, the two per-loan task tools, and `search_loan_applications`. A Processor is **not** limited to their own company for those. The aggregate and reporting tools narrow a Processor to their own company's users instead — `report_loans`, `loan_pipeline_report`, `report_loan_milestones`, `query_loans`, `search_loan_tasks`, `conditions_by_outcome`, and `search_users`.
* **ConciergeKey:** sees the agents they manage.
* **Agent / DualLicensedAgent:** sees loans they originate or that were referred to them.
* **Pre-licensed agents:** see referred loans only.

{% hint style="warning" %}
**Exception — the four Data Warehouse-backed tools are not row-scoped at all.** `query_data_warehouse`, `get_data_warehouse_fields`, `mlo_pipeline_report`, and `warehouse_loan_milestone_report` return **org-wide** results: the warehouse tables carry no loan-officer or company column, so their rows cannot be filtered to a caller. They are gated by role instead — `Admin`, `Processor`, and `ConciergeKey` only, with `Agent` and `DualLicensedAgent` rejected outright. Do not diagnose a broad result set from one of these four as a scoping bug. See [Data Warehouse](/mcp/tool-reference/data-warehouse.md).
{% endhint %}

Also note that `get_user_licenses` and the three pricing tools use a narrower per-user access check with no Processor branch at all — a Processor is limited to themselves, agents they assist, and agents they manage as ConciergeKey.

If a query comes back empty, check the caller's role and whether the record in question is actually within that role's visible set before assuming the tool is broken.

## Reading tool error messages

Tool failures surface to the client as a `ModelContextProtocol.McpException`. Only `McpException.Message` crosses the wire to the client — the original exception's stack trace and any `InnerException` stay server-side in the application logs. In practice this means a client-side debugging session sees a short labeled message and nothing else; if the label and message aren't enough to diagnose the problem, the next step is server logs, not more probing from the client.

Every tool error message starts with one of the following labels, in order of how the server's error handler evaluates the underlying exception:

| Label                      | Meaning                                                                 | Example trigger                                                                        |
| -------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `Bad request:`             | The request was malformed or failed validation.                         | Invalid or missing required parameters.                                                |
| `Not found:`               | The requested entity does not exist or could not be resolved.           | Looking up a loan, user, or other record by an ID that doesn't resolve.                |
| `Unauthorized:`            | The caller's credentials were rejected by a downstream check.           | Invalid credentials against an internal or third-party service.                        |
| `Upstream error (status):` | A downstream HTTP-based integration returned a non-success response.    | An upstream service (e.g. a pricing or LOS integration) responds with an error status. |
| `Business rule violation:` | The request was well-formed and authorized, but violates a domain rule. | Things like duplicate records, mismatched loan state, or a failed business validation. |
| `Internal server error:`   | Anything not covered by the categories above.                           | An unexpected exception with no more specific mapping.                                 |

All six labels are the complete set defined by the server's error handler — there are no other label prefixes in current use.

## Still stuck?

If the health check succeeds, authentication completes, the agent lookup resolves, and a tool call still fails or returns something unexpected, capture the exact label and message from the `McpException` and escalate with that text — the deeper detail lives in server logs and isn't available from the client. See [Authentication](/mcp/connecting/authentication.md) and [Clients & Configuration](/mcp/connecting/clients-and-configuration.md) for setup details that may be the underlying cause.
