Workspace deploy: root /.well-known/* is routed to Dispatch and ignores the app path suffix, so OAuth discovery for any spoke app's MCP server lands on Dispatch's authorization server and fails
Version: @agent-native/core 0.178.1, dist/deploy/workspace-deploy.js (Vercel routes: { src: "/\\.well-known/(.*)", dest: "/dispatch-server" }; the Netlify and gateway variants do the same), dist/mcp/oauth-route.js (handleAuthorize, getMcpOAuthAudiences).
What happens. In a path-mounted workspace (/chat, /documents, /brand-assets, /dispatch on one host), a spoke app's MCP endpoint advertises itself correctly: GET /chat/mcp returns WWW-Authenticate: Bearer resource_metadata="https://host/chat/.well-known/oauth-protected-resource", and that document names authorization_servers: ["https://host/chat"], whose /chat/.well-known/oauth-authorization-server points at /chat/mcp/oauth/authorize. Claude (claude.ai custom connector) resolves the metadata with the RFC 8414 / RFC 9728 path-insertion form at the site root instead: GET https://host/.well-known/oauth-authorization-server/chat (and /.well-known/oauth-protected-resource/chat/mcp). The deploy routes every /.well-known/* request to the Dispatch server, and Dispatch's handler ignores the suffix, so both documents come back with issuer: https://host/dispatch and authorization_endpoint: https://host/dispatch/mcp/oauth/authorize. Claude then opens /dispatch/mcp/oauth/authorize?...&resource=https://host/chat/mcp; Dispatch's getMcpOAuthAudiences only contains its own /dispatch/mcp prefixes, so handleAuthorize answers {"error":"invalid_request","error_description":"Invalid OAuth authorization request"}. Observed 2026-09-12 on a Vercel production deployment for the Chat, Documents and Assets connectors; the Dispatch connector works because its resource is its own.
Why. Path-insertion discovery is what the RFCs prescribe for resources that live under a path, and popular hosts use it. The root well-known route exists so the workspace has one discovery document, but it is not suffix-aware, and the spoke apps' authorization servers are never reachable through it.
Expected. One of: the root /.well-known/oauth-authorization-server/<app>[/mcp] and /.well-known/oauth-protected-resource/<app>/mcp routes forward to that app's own documents (a route per registered workspace app, or a suffix-aware handler in Dispatch); or Dispatch acts as the workspace authorization server for every app and getMcpOAuthAudiences accepts every registered app's /<app>/mcp resource; or the docs state that in a path-mounted workspace only the Dispatch connector supports OAuth hosts and spoke apps need the bearer fallback.
Impact. In a path-mounted workspace no spoke app can be added to claude.ai (or any host using path-insertion discovery) as its own connector; users get an opaque invalid_request page after clicking Connect.
Workaround in Joney. Use the Dispatch connector (/dispatch/mcp, verbs list_apps, ask_app, open_app) from claude.ai; for hosts that accept a static header (Claude Code, Cursor), mint a token on /<app>/mcp/connect.
Workspace deploy: root
/.well-known/*is routed to Dispatch and ignores the app path suffix, so OAuth discovery for any spoke app's MCP server lands on Dispatch's authorization server and failsVersion:
@agent-native/core0.178.1,dist/deploy/workspace-deploy.js(Vercel routes:{ src: "/\\.well-known/(.*)", dest: "/dispatch-server" }; the Netlify and gateway variants do the same),dist/mcp/oauth-route.js(handleAuthorize,getMcpOAuthAudiences).What happens. In a path-mounted workspace (
/chat,/documents,/brand-assets,/dispatchon one host), a spoke app's MCP endpoint advertises itself correctly:GET /chat/mcpreturnsWWW-Authenticate: Bearer resource_metadata="https://host/chat/.well-known/oauth-protected-resource", and that document namesauthorization_servers: ["https://host/chat"], whose/chat/.well-known/oauth-authorization-serverpoints at/chat/mcp/oauth/authorize. Claude (claude.ai custom connector) resolves the metadata with the RFC 8414 / RFC 9728 path-insertion form at the site root instead:GET https://host/.well-known/oauth-authorization-server/chat(and/.well-known/oauth-protected-resource/chat/mcp). The deploy routes every/.well-known/*request to the Dispatch server, and Dispatch's handler ignores the suffix, so both documents come back withissuer: https://host/dispatchandauthorization_endpoint: https://host/dispatch/mcp/oauth/authorize. Claude then opens/dispatch/mcp/oauth/authorize?...&resource=https://host/chat/mcp; Dispatch'sgetMcpOAuthAudiencesonly contains its own/dispatch/mcpprefixes, sohandleAuthorizeanswers{"error":"invalid_request","error_description":"Invalid OAuth authorization request"}. Observed 2026-09-12 on a Vercel production deployment for the Chat, Documents and Assets connectors; the Dispatch connector works because its resource is its own.Why. Path-insertion discovery is what the RFCs prescribe for resources that live under a path, and popular hosts use it. The root well-known route exists so the workspace has one discovery document, but it is not suffix-aware, and the spoke apps' authorization servers are never reachable through it.
Expected. One of: the root
/.well-known/oauth-authorization-server/<app>[/mcp]and/.well-known/oauth-protected-resource/<app>/mcproutes forward to that app's own documents (a route per registered workspace app, or a suffix-aware handler in Dispatch); or Dispatch acts as the workspace authorization server for every app andgetMcpOAuthAudiencesaccepts every registered app's/<app>/mcpresource; or the docs state that in a path-mounted workspace only the Dispatch connector supports OAuth hosts and spoke apps need the bearer fallback.Impact. In a path-mounted workspace no spoke app can be added to claude.ai (or any host using path-insertion discovery) as its own connector; users get an opaque
invalid_requestpage after clicking Connect.Workaround in Joney. Use the Dispatch connector (
/dispatch/mcp, verbslist_apps,ask_app,open_app) from claude.ai; for hosts that accept a static header (Claude Code, Cursor), mint a token on/<app>/mcp/connect.