## Summary Claude.ai's custom remote MCP connector fails with "Couldn't reach the MCP server" after successfully completing OAuth dynamic client registration. Driving the flow through Chrome DevTools showed Claude's backend creates our DCR client (many hundreds of orphan rows visible in the admin panel), then never returns the user to `/authorize` — it gives up silently. **Empirical comparison against known-working MCP servers Claude.ai connects to identified one concrete difference**: every server that works returns `registration_client_uri` in the DCR response. We didn't. | Server | DCR `registration_client_uri` | Claude.ai web connector | |---|---|---| | Linear (`mcp.linear.app`) | `/register/<client_id>` | ✅ works | | Sentry (`mcp.sentry.dev`) | `/oauth/register/<client_id>` | ✅ works | | Atlassian (`mcp.atlassian.com`) | yes | ✅ works | | **Twenty** (before this PR) | **missing** | ❌ "Couldn't reach" | ## What this PR changes ### 1. Add `registration_client_uri` to the DCR response ``` { "client_id": "…", …existing fields…, + "registration_client_uri": "<issuer>/oauth/register/<client_id>" } ``` Pointer at the registration's management endpoint per RFC 7591 §3.2.1. Marked OPTIONAL in the spec but empirically required by Claude.ai. ### 2. New `GET /oauth/register/:clientId` endpoint (RFC 7592 read-back) Returns public registration metadata (`client_name`, `redirect_uris`, `grant_types`, `scope`, etc.). 404 for unknown clients. No `registration_access_token` is issued (and none required to hit this endpoint): the `client_id` is an unguessable UUID and the fields returned are already public-readable via `findApplicationRegistrationByClientId` GraphQL. This matches Linear's behaviour — they return a `registration_client_uri` but issue no access token. ### 3. Advertise `response_modes_supported: ["query"]` in AS metadata RFC 8414 default, but explicitly listed by Linear / Sentry / Atlassian and absent from ours. Some clients treat its absence as a capability gap. ## Why I'm confident this is the root cause - The failure mode exactly matches an orphaned-DCR retry loop (hundreds of registrations, none `installed` on a workspace). - #19847 reporter confirmed Claude Desktop + VS Code work — those clients use the MCP Python SDK which doesn't require `registration_client_uri`. **Claude.ai web** uses Anthropic's proprietary backend client (`User-Agent: Claude-User`), which empirically does. - All 3 working reference servers return the field; we were the odd one out. ## Test plan - [x] `tsc --noEmit` clean on touched files - [x] `yarn jest --testPathPatterns="oauth-discovery.controller|mcp-auth.guard"` → 4/4 pass - [ ] After deploy: ```bash curl -s -X POST https://<host>/oauth/register -H 'Content-Type: application/json' \ -d '{"client_name":"probe","redirect_uris":["https://claude.ai/api/mcp/auth_callback"],"token_endpoint_auth_method":"none"}' \ | jq .registration_client_uri # expect: "https://<host>/oauth/register/<uuid>" ``` - [ ] After deploy: add the MCP connector in Claude.ai — user should now reach the Twenty `/authorize` page ## Honesty This is the nth fix in a long debugging chain. Unlike the earlier round of fixes (which were real spec-compliance bugs but not Claude's blocker), this one is backed by empirical evidence across 3 known-working implementations. If Claude.ai still fails after this deploys, the remaining delta is `cli_client_id` in AS metadata (non-standard field, could confuse strict parsers) or a field we advertise that others don't (e.g. `client_credentials` grant) — both small, removable, not disruptive. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The #1 Open-Source CRM
🌐 Website · 📚 Documentation · Roadmap ·
Discord ·
Figma
Installation
See: 🚀 Self-hosting 🖥️ Local Setup
Why Twenty
We built Twenty for three reasons:
CRMs are too expensive, and users are trapped. Companies use locked-in customer data to hike prices. It shouldn't be that way.
A fresh start is required to build a better experience. We can learn from past mistakes and craft a cohesive experience inspired by new UX patterns from tools like Notion, Airtable or Linear.
We believe in open-source and community. Hundreds of developers are already building Twenty together. Once we have plugin capabilities, a whole ecosystem will grow around it.
What You Can Do With Twenty
Please feel free to flag any specific needs you have by creating an issue.
Below are a few features we have implemented to date:
- Personalize layouts with filters, sort, group by, kanban and table views
- Customize your objects and fields
- Create and manage permissions with custom roles
- Automate workflow with triggers and actions
- Emails, calendar events, files, and more
Personalize layouts with filters, sort, group by, kanban and table views
Customize your objects and fields
Create and manage permissions with custom roles
Automate workflow with triggers and actions
Emails, calendar events, files, and more
Stack
- TypeScript
- Nx
- NestJS, with BullMQ, PostgreSQL, Redis
- React, with Jotai, Linaria and Lingui
Thanks
Thanks to these amazing services that we use and recommend for UI testing (Chromatic), code review (Greptile), catching bugs (Sentry) and translating (Crowdin).
Join the Community
- Star the repo
- Subscribe to releases (watch -> custom -> releases)
- Follow us on Twitter or LinkedIn
- Join our Discord
- Improve translations on Crowdin
- Contributions are, of course, most welcome!




