-
Notifications
You must be signed in to change notification settings - Fork 487
Description
Problem
When using mixed auth (some tools noauth, some tools oauth2), calling an OAuth-protected tool via window.openai.callTool() from a widget fails with HTTP 400 and an empty response body {}. The same tool works correctly when initiated by the chat (LLM-initiated).
Environment
- MCP server: Python, using
mcpSDK - Auth: OAuth2 (Auth0)
- Connector auth mode: Mixed (noauth + oauth2)
- Browser: Chrome 145 on macOS
Setup
Two tools on the same MCP server:
- Tool A —
securitySchemes: [{"type":"noauth"}, {"type":"oauth2"}]— renders a widget - Tool B —
securitySchemes: [{"type":"oauth2"}]— requires authentication
The widget rendered by Tool A contains a button that calls:
window.openai.callTool('tool_b', {})Steps to Reproduce
- Add the MCP connector in ChatGPT. Because the server supports mixed auth, ChatGPT allows connecting without triggering OAuth
- Ask ChatGPT something that triggers Tool A. This tool supports noauth, so it succeeds without a token.
- Widget renders successfully.
- Click a button in the widget that calls
window.openai.callTool('tool_b', {}).
Expected Behavior
ChatGPT detects that Tool B requires OAuth, triggers the OAuth flow (login popup), obtains an access token, then forwards the tools/call request to the MCP server — same as when the LLM initiates the call via chat.
Actual Behavior
- Browser console shows:
POST https://chatgpt.com/backend-api/ecosystem/call_mcp 400 (Bad Request) - Response body:
{} - No OAuth flow is triggered
- The widget's catch block receives an empty object
- In some attempts, the request reaches the MCP server (without a token); in others, ChatGPT's backend rejects it before forwarding
Comparison: Chat-Initiated Works
When the same OAuth-protected tool is called by the LLM via chat (not from a widget) in the same mixed auth mode with no prior authentication, ChatGPT does trigger the OAuth flow, obtains a token, and the call succeeds.
Comparison: Full OAuth Mode Works
When the connector is configured with full OAuth (not mixed), the user authenticates at connection time. After that, window.openai.callTool('tool_b', {}) from the widget works because the token is already available and attached to all requests.
Conclusion
window.openai.callTool() does not support triggering OAuth for auth-protected tools when no token exists yet. This only affects widget-initiated calls — chat-initiated calls to the same tool in the same mixed auth configuration work correctly.