Jehan
June 4, 2026, 10:26am
1
Hey,
We’re self-hosting metabase, but we do have an issue regarding the installation of the Claude MCP, it doesn’t recognize our URL, whereas it is the url I do get from our admin settings interface.
We’ve followed the tutorial right there, but didn’t help.
Any idea? Did anyone have the same issue?
Thanks a lot!
Seems related to this bug:
opened 07:15PM - 02 Jun 26 UTC
Priority:P2
Type:New Feature
.Team/Embedding
.Auto triaged
**What problem will this feature request solve?**
The official Claude Desktop i… ntegration for Metabase MCP requires using publicly accessible HTTPS URLs. When self-hosting, this is not always possible (e.g. port forwarding or having a VPN handle DNS and TLS). Existing third-party integrations such as https://github.com/jerichosequitin/metabase-mcp do not have this requirement, and allow connections to localhost and non-HTTPS URLs.
Users might be able to work around this by using an MCP proxy such as https://github.com/geelen/mcp-remote, but this is not doable from the Claude Desktop app itself.
**Describe the solution you'd like.**
Officially support connecting Claude Desktop to Metabase MCP using arbitrary URLs.
**How does this feature request impact you?**
Entire customers might be blocked entirely from using Claude Desktop because of this limitation.
**Additional information**
N/A
Update, this bug is closer to the problem identified:
opened 12:11PM - 29 May 26 UTC
Type:Bug
Priority:P2
.Team/Embedding
.Auto triaged
### Describe the bug
Claude connectors look at the MCP URL to determine what co… nnector should be used for a given server. In the case of Metabase, the URL is `/api/mcp` at a generic level, which is too broad of a match. Because of this, the Claude connector only supports domains that include `metabaseapp.com/api/mcp`, which excludes self-hosted Metabase instances or Cloud instances on custom domains.
<img width="592" height="459" alt="Image" src="https://github.com/user-attachments/assets/764a7af3-0cc4-45e1-b9c0-e47d76d4a67a" />
The workaround is to add a custom connector through the Claude app, which accepts any MCP URL. None of this is mentioned by the description for the Metabase Claude connector.
### To Reproduce
1. Self-host Metabase, or use Metabase Cloud with a custom domain
2. Try to connect the Claude app to Metabase using the official integration. It will reject the URL as invalid
### Expected behavior
The Claude connector for Metabase should work for all instances, no matter what their domain is.
One possibility could be to make an alias of the existing MCP URL, like `/api/metabase-mcp` or similar, which could be used to match against any instance. The old URL would continue working but would not be presented or suggested in any UI.
### Logs
_No response_
### Information about your Metabase installation
```JSON
N/A
```
### Severity
P2
### Additional context
_No response_
Update: this was a Cloudflare issue - not a Metabase issue.
I’m having this problem too and it’s very flaky. The MCP connection is incredibly handy for me (having Claude back up its theories with real data regularly results in better outcomes), but it’s down around 20% of the time.
Over the past month, the MCP has required reauthorization in Claude at least 20 times. Sometimes it will reconnect immediately, other times I have to wait an hour to two days. Currently, I’ve been waiting 2 days and it still won’t reconnect.
In Claude, I get this error:
Connection issue
Connection has expired. You can reconnect to re-authenticate.
Couldn’t register with Metabase’s sign-in service. You can try again, or add an OAuth Client ID in the connector settings. If this persists, share this reference with support: “ofid_114e4f1e450a89ae”
Only theories I have:
If the MCP connection touches base with metabase.com , even for local installs, then any outage or flakiness on Metabase’s side could cause this. That would be ridiculous though.
I pull new images nightly, so if new images regularly break the MCP, that would explain the flakiness. In that case, should I pin to a specific working version and stop getting updates?
What I’ve tried:
Reconnecting (results in error above)
Removing from Claude and readding the official MCP
Removing from Claude and adding a custom MCP (same “couldn’t register” error - although it picks up my favicon so it’s at least reaching the server)
Changing to a different Metabase installation on a different subdomain (same “couldn’t register” error)
Switching to “Metabase (Unofficial — Community)” also results in a connection error but has never worked for me
Verifying that the URL and Metabase itself is reachable and usable through the web interface
Going to try: pinning the Metabase image to different older versions to see if that fixes it
My setup:
Self-hosted on a public HTTPS subdomain
Directing MCP at the provided URL ~ https://metabase-dev.xxx.xxx/api/metabase-mcp
Docker image pinned at 0.62.4.5 (updated below) because it seemed to work more often
7 other, working MCP connectors (GitHub, PostHog, etc.) with zero flakiness, but none self-hosted
Let me know if you need any more info.
May be related to this bug:
opened 10:56PM - 20 Aug 26 UTC
Priority:P2
.Team/Metabot
# OAuth token endpoint returns `invalid_request` for every error, never `invalid… _grant` — strands MCP clients holding an expired refresh token
## Summary
`POST /oauth/token` collapses all failure modes into a single response:
```json
{"error":"invalid_request","error_description":"The token request is invalid."}
```
Per RFC 6749 §5.2 (retained by OAuth 2.1, which the MCP authorization spec builds on), an invalid or expired `refresh_token` must return `error: "invalid_grant"`. Because Metabase reports `invalid_request` instead, MCP clients cannot distinguish "this grant is permanently dead, re-authorize the user" from "I sent a malformed request, retrying may help." Clients that implement the spec-conformant retry policy retry the dead token indefinitely and never re-prompt for consent.
## Impact
This turns a routine, recoverable event — a refresh token going stale after a network interruption — into a permanent wedge that an end user cannot resolve through any retry affordance.
Observed with Claude Desktop against Metabase v0.63.5. A network change interrupted a token rotation overnight; every subsequent refresh returned `400 invalid_request`. The client classified that as transient and re-tried on a backoff **26 consecutive times over ~11 hours**, never falling back to a fresh authorization-code flow:
```
02:22:08 [warn] mid-session refresh did not rotate { failCount: 1, reason: 'refresh: net::ERR_NETWORK_CHANGED' }
02:23:09 [warn] token endpoint non-success { grantType: 'refresh_token', status: 400, error: 'invalid_request' }
...
13:30:13 [warn] mid-session refresh did not rotate { failCount: 26, backoffMs: 1800000, reason: 'invalid_request' }
14:22:25 [error] authorizeDirectMcpServer: failed: Version negotiation probe failed: The token request is invalid.
```
Had the endpoint returned `invalid_grant`, the client would have discarded the token and re-authorized automatically. Recovery required manually clearing the cached credential.
Note this is strictly worse for *correct* clients: a client that treats all 400s as fatal recovers fine, while one that follows §5.2 and distinguishes `invalid_request` (retryable) from `invalid_grant` (fatal) gets stuck.
## Reproduction
No authentication required — the error responses are reachable on any Metabase instance with the MCP/OAuth endpoints enabled.
```bash
# 1. Invalid refresh token -> expected invalid_grant
curl -sS -X POST https://metabase.example.com/oauth/token \
-d 'grant_type=refresh_token&refresh_token=not-a-real-token'
# {"error":"invalid_request","error_description":"The token request is invalid."}
# 2. Invalid authorization code -> expected invalid_grant
curl -sS -X POST https://metabase.example.com/oauth/token \
-d 'grant_type=authorization_code&code=not-a-real-code&client_id=probe&redirect_uri=http://localhost:1234/cb&code_verifier=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
# {"error":"invalid_request","error_description":"The token request is invalid."}
# 3. Unsupported grant type -> expected unsupported_grant_type
curl -sS -X POST https://metabase.example.com/oauth/token \
-d 'grant_type=client_credentials&client_id=probe'
# {"error":"invalid_request","error_description":"The token request is invalid."}
# 4. Bad client credentials -> expected invalid_client, and 401 not 400
curl -sS -X POST https://metabase.example.com/oauth/token \
-u 'bogus-client:bogus-secret' -d 'grant_type=refresh_token&refresh_token=whatever'
# 400 {"error":"invalid_request","error_description":"The token request is invalid."}
# 5. Missing grant_type -> invalid_request IS correct here
curl -sS -X POST https://metabase.example.com/oauth/token -d 'client_id=probe'
# {"error":"invalid_request","error_description":"The token request is invalid."}
```
## Expected vs. actual
| Request | RFC 6749 §5.2 | Metabase v0.63.5 |
|---|---|---|
| Invalid/expired/revoked `refresh_token` | `invalid_grant` | `invalid_request` |
| Invalid/expired `authorization_code` | `invalid_grant` | `invalid_request` |
| Unsupported `grant_type` | `unsupported_grant_type` | `invalid_request` |
| Client authentication failed (HTTP Basic) | `invalid_client`, and **401** per §5.2 | `invalid_request`, **400** |
| Missing required parameter | `invalid_request` | `invalid_request` ✅ |
Only the last case is correct, and it appears correct by coincidence rather than by mapping.
Every case also returns HTTP 400. §5.2 requires 401 for `invalid_client` when the client authenticated via the `Authorization` header.
## Suggested fix
Map token-endpoint failures to their RFC 6749 §5.2 codes. The single highest-value change is returning `invalid_grant` when a presented `refresh_token` or `authorization_code` is unknown, expired, revoked, or already consumed — that alone unblocks automatic client re-authorization. A more specific `error_description` would also help operators, since the current generic string gives no diagnostic signal.
## Environment
- Metabase **v0.63.5** (OSS), build `1dca717`, release date 2026-08-05
- Discovery metadata is otherwise well-formed: `/.well-known/oauth-protected-resource/api/metabase-mcp` and `/.well-known/oauth-authorization-server` both resolve correctly, and the MCP endpoint returns a proper `401` with `WWW-Authenticate: Bearer realm="mcp" resource_metadata="..."`
- Client: Claude Desktop 1.34493.0
## Possibly related
- #75084 — Unable to get MCP working with Claude Web or Claude Code
- #76850 — OAuth MCP consent fails with `csrf_validation_failed`
- #77723 — MCP OAuth consent form posts to wrong path under a subpath
- #76305 — Authorizing MCP clients can fail with 431
- anthropics/claude-code#79505 — client-side cousin: no re-registration when a cached DCR client is rejected, and Metabase likewise returns a generic `invalid_request` for the *authorization* request
It might be related, but I’m not getting those specific token errors in my logs. I was just looking into them and noticed these from my connection attempts.
2026-Aug-21 13:34:132026-08-21 09:34:13,921 DEBUG middleware.log :: GET /api/health 200 0ms (0 DB calls) App DB connections: 0/3 Jetty threads: 3/50 (5 idle, 0 queued) (42 total active threads) Queries in flight: 0 (0 queued) {:metabase-user-id nil}
2026-Aug-21 13:34:432026-08-21 09:34:43,961 DEBUG middleware.log :: GET /api/health 200 0ms (0 DB calls) App DB connections: 0/3 Jetty threads: 3/50 (5 idle, 0 queued) (42 total active threads) Queries in flight: 0 (0 queued) {:metabase-user-id nil}
2026-Aug-21 13:35:102026-08-21 09:35:10,751 DEBUG middleware.log :: POST /api/metabase-mcp 401 0ms (0 DB calls) {:metabase-user-id nil}
2026-Aug-21 13:35:10"{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32603,\"message\":\"Authentication required\"}}"
2026-Aug-21 13:35:10
2026-Aug-21 13:35:132026-08-21 09:35:13,736 DEBUG middleware.log :: POST /api/metabase-mcp 401 0ms (0 DB calls) {:metabase-user-id nil}
2026-Aug-21 13:35:13"{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32603,\"message\":\"Authentication required\"}}"
2026-Aug-21 13:35:13
Uninstalling and reinstalling the MCP doesn’t fix it, so at first glance it doesn’t seem like a token issue, unless it’s server-side.
I had apparently already previously pinned the version to 0.62.4.5 because that version worked for a while. The previous messages were on 0.62.4.5.
I moved to 0.63.14.1 and now get these errors when trying to connect the MCP:
2026-Aug-21 14:06:262026-08-21 10:06:26,180 DEBUG middleware.log :: GET /api/health 200 0ms (0 DB calls) App DB connections: 0/10 Jetty threads: 3/50 (7 idle, 0 queued) (46 total active threads) Queries in flight: 0 (0 queued) {:metabase-user-id nil}
2026-Aug-21 14:06:262026-08-21 10:06:26,836 DEBUG middleware.log :: POST /api/metabase-mcp 401 1ms (0 DB calls) {:metabase-user-id nil}
2026-Aug-21 14:06:272026-08-21 10:06:27,517 DEBUG middleware.log :: POST /api/metabase-mcp 401 0ms (0 DB calls) {:metabase-user-id nil}
The error Claude produces is unchanged.
It doesn’t trigger the auth flow so it’s unsurprising that the metabase-user-id is blank.
Well I’ll eat my hat. I did it to myself.
I changed a few things in Cloudflare few days ago and thought maybe I should investigate that, too. Well, the problem was twofold in Cloudflare:
A new rule I set up to block any requests for paths containing “/.” was blocking “/.well-known” paths for oAuth.
Cloudflare’s bot-fight mode may have been the cause of the flakiness, letting it work sometimes and throttling/blocking at other times.
Turned both off and it now works! (You can probably also just set a higher skip path for “.well-known” if you prefer to keep blocking “/.”)
So it was never an issue with Metabase. Apologies if this ate anyone’s time and hopefully this helps anyone that made the same mistakes as me.
1 Like