I recently made my SaaS usable from the ChatGPT and Claude chat windows, not just from Claude Code. Here is what I learned, for anyone adding MCP to their own product:
・A token based MCP endpoint only reaches developers. ChatGPT and claude.ai have no field to paste a token, so chat users need a sign in and allow flow (OAuth).
・Your MCP endpoint must answer the first keyless call with 401 plus a pointer to your OAuth metadata. If a CSRF check or anything else answers first, the chat app never reaches your sign in page. Mine did exactly that.
・List offline_access in your authorization server metadata. Without it, ChatGPT does not ask for a refresh token and users have to sign in again every time the access token expires.
・Make the key act as the person who allowed it, not as an admin bot. Otherwise a regular team member can hand an AI more power than they have.
・Connecting is not the same as reaching users. In ChatGPT, a custom connector needs a paid plan, developer mode (with a "risk increased" warning), and a risk checkbox. Ordinary users only get a one click install once you are listed in the app directory, and that means review, a verified developer identity, a demo account, a privacy policy, and read or write annotations on every tool.
Why I did this
I run as much of my work as I can from Claude Code: email drafts, calendar, deploys, admin dashboards. My task manager already had an MCP endpoint with an API token, and I had been using it that way for a while.
I believe we are leaving the era in which people operate software by touching its screens. People will ask an AI, and the AI will move the tools. A tool an AI cannot use will not be chosen. So this round of work was for ordinary users, not for me.
What broke when I tried it like a normal user
I opened ChatGPT to connect it the way a customer would, and there was nowhere to put a token. claude.ai is the same, apart from a header option that was a beta for a limited set of organizations when I checked. OpenAI's docs say ChatGPT cannot present custom API keys at all.
I also found a sentence in my own docs claiming ChatGPT could connect "just by reading the spec URL". I had never tested it, and the published spec still pointed at my development machine.
What I built
・Standard OAuth endpoints (register, authorize, token, revoke) plus the two .well-known metadata documents. The official MCP TypeScript SDK ships the handlers, I only wrote storage and the consent page.
・A consent page that shows which assistant is asking, lets you pick a workspace, and says plainly that the assistant can only do what you can do.
・Access tokens that last an hour, with refresh tokens rotated on every swap. When someone leaves a workspace, their key stops working.
・Billing and token creation are blocked for these keys.
・Every connected assistant is listed by name next to regular API tokens, so it can be revoked in one place.
How I tested it
First with the official MCP SDK client against production, pushing the consent page through a headless browser. That exercises the same discovery steps real clients use, so a misread of the spec fails there.
Then for real: claude.ai custom connector (all tools appeared after allowing) and ChatGPT developer mode (OAuth was detected automatically, and my logs showed openai-mcp fetching the tool list).
One more bug worth sharing: when a refresh found that the user had left the workspace, my code revoked the key and then threw an error inside the same database transaction. The error rolled the revoke back. Do the revoke outside the transaction that throws, and check membership when verifying the token too.
Where it stands
The ChatGPT app directory submission is in progress: annotations are on all tools, the privacy policy covers AI assistant connections, and business verification is submitted.
If your SaaS has an API and your users are not all engineers in a terminal, sign in and allow is the door, and the directory is part of the same job.
The product is Pinateca, a kanban and Gantt task manager. How the AI connection works:
Nice to see someone go past the Claude Code integration and into the consumer chat windows. One thing I hit doing similar work is that tool descriptions matter far more than the tool code itself, because the model decides what to call from the description alone, so it's worth treating those strings like product copy and testing them against real user phrasing. Did you find users discovering the integration on their own, or did it only get used once you explicitly pointed them at it?
Interesting, I've noticed the same thing on the content side: if an AI assistant can't reach a product the same way a human would, it just won't get picked. Same logic here, just at the access/infrastructure level instead of content. I think this problem is pretty widespread - being "legible" to an agent and most companies aren't thinking about either side of it yet.
Same conclusion from the other side. It's the reason this round wasn't for me, since I already had token access from Claude Code. It was for the users who'll only ever ask a chat window.
The consent page detail is the part I'd want to steal outright — "says plainly that the assistant can only do what you can do" is exactly the sentence I'm missing on my own confirmation screen. I've been focused on confirming the action (send this text, book this slot), but not on confirming the actor's ceiling — what it's allowed to do in general, separate from what it's about to do right now.
The revoke-inside-a-throwing-transaction bug is a good concrete example of a failure mode I keep running into in the abstract: an operation that looks atomic from the code's perspective (revoke, then continue) but isn't atomic from the authority's perspective, so a crash mid-transaction silently restores access that should have stayed gone. Did you catch that one from a log anomaly, or did someone actually exploit the window before you found it?
Neither, luckily. A test caught it before it went out. It removes the member, tries a refresh, then checks the old access token is dead, and it wasn't.
The ceiling sentence is the one people skip past, but it decides whether a regular member can hand an AI more than they have.
A test catching it before shipping is the good outcome, but it also means the test existed specifically because someone already suspected that boundary was fragile — which is its own useful signal. What made you write that particular test in the first place — general paranoia about transactions, or had something adjacent already gone wrong once?
On the ceiling sentence: I think people skip it because it's the one that costs you something. "Here's what this can do" is a UX line. "This can only do what you personally can do" is an actual constraint on the system's design, and it's harder to retrofit once you've already built the easier version where the AI's identity and the user's identity aren't cleanly the same thing.
Past experience mostly. I know which security issues can't be skipped, so those are covered before anything else, and since I'm building several products at once, a problem found in one gets checked for in all the others.
You never get to 100% on security or bugs. 22 years of this taught me that, which is why the checking never stops and there are two or three layers instead of one.
22 years is enough time to build the right instincts, and "checked for in all the others" is the part I don't have yet at all — I have one product, so a bug I catch has nowhere else to propagate the fix to. That's actually a structural disadvantage of being solo and early that I hadn't thought about before this thread: cross-product pattern-matching only exists once there's more than one product to pattern-match across.
"Two or three layers instead of one" is the thing I'll take away from this whole exchange. Right now StareBrain has basically one layer per concern — one check, one place, trust it and move on. Sounds like the actual lesson from 22 years isn't "write better checks," it's "assume the check you wrote will eventually fail silently, so put something else behind it that doesn't share the same blind spot."
The technical work clearly removes a real access barrier, but the bigger product question seems to be what happens once users have it. Have any real Pinateca users actually shifted tasks into ChatGPT or Claude, or is the value of AI-native access still mostly a hypothesis?
Still a hypothesis. It went live on the 14th, and so far the connections are my own workspace plus the account I set up for the ChatGPT directory review. No customer has moved anything into a chat window yet.
That's also why the directory matters more than the connector. Until it's listed, the only people who can connect are the ones willing to turn on developer mode.
The directory-to-usage gap is the key test now. If you’re open to it, what’s the best email to reach you on?
The OAuth-vs-token split is the part most MCP writeups skip. Token paste is fine for Claude Code; chat windows only get real users once sign-in + refresh (offline_access) actually complete. The CSRF-before-401 trap you hit is nasty because it looks like "auth works" in Postman while ChatGPT never sees the challenge.
Also liked the least-privilege note: a connector key that inherits the allow-er beats an always-admin bot. Connecting and being findable in the directory are two different products of work.
Thanks. Nothing on my side looked broken until I opened ChatGPT to connect it the way a customer would, and there was nowhere to put a token. Test it from the chat window, not from the tools you already have open.
That is a much better acceptance test than “the endpoint returns 200.” I am adding a separate chat-window journey to the checklist: discover → authorize → refresh → revoke → retry as a lower-privilege user. The important failure is not just a broken connection; it is a connection that works only for the person who built it.