diff --git a/config/mcp.php b/config/mcp.php new file mode 100644 index 00000000..ca0052a0 --- /dev/null +++ b/config/mcp.php @@ -0,0 +1,55 @@ + [ + // Anthropic's hosted callback for Claude Desktop / Claude web connectors. + 'https://claude.ai', + // OpenAI's hosted callback for ChatGPT connectors. + 'https://chatgpt.com', + ], + + /* + |-------------------------------------------------------------------------- + | Allowed Custom Schemes + |-------------------------------------------------------------------------- + | + | Native desktop OAuth clients like Cursor and VS Code use private-use URI + | schemes (RFC 8252) for redirect callbacks instead of standard schemes + | like HTTPS. Here, you may list which custom schemes you will allow. + | + */ + + 'custom_schemes' => [ + // 'claude', + // 'cursor', + // 'vscode', + ], + + /* + |-------------------------------------------------------------------------- + | Authorization Server + |-------------------------------------------------------------------------- + | + | Here you may configure the OAuth authorization server issuer identifier + | per RFC 8414. This value appears in your protected resource and auth + | server metadata endpoints. When null, this defaults to `url('/')`. + | + */ + + 'authorization_server' => null, + +]; diff --git a/routes/ai.php b/routes/ai.php index a86b053a..64055af6 100644 --- a/routes/ai.php +++ b/routes/ai.php @@ -8,12 +8,29 @@ use Laravel\Mcp\Facades\Mcp; | MCP Routes |-------------------------------------------------------------------------- | -| Remote (streamable HTTP) MCP server. Authenticated with Sanctum personal -| access tokens carrying an `mcp:read` ability, throttled per user. The -| Pro-plan gate is enforced inside each tool so a lapsed subscription stops -| working without the user having to revoke their token. +| Remote (streamable HTTP) MCP server, exposed on two endpoints: +| +| - `/mcp` is authenticated with Sanctum personal access tokens carrying an +| `mcp:read` ability (Claude Code, static bearer token, read/read_write via +| abilities). Left completely unchanged. +| - `/mcp/oauth` is authenticated with OAuth 2.1 (Authorization Code + PKCE) +| for clients that sign in rather than paste a token — Claude Desktop / web +| and ChatGPT connectors. `Mcp::oauthRoutes()` registers the RFC 8414 / 9728 +| discovery endpoints, the RFC 7591 DCR endpoint and the `mcp:use` Passport +| scope; the package's AddWwwAuthenticateHeader middleware then turns an +| unauthenticated request into the mandatory 401 bootstrap challenge. +| +| OAuth connections carry only the single `mcp:use` scope, so `tokenCan` +| reports no `mcp:write` ability and the write tools stay read-only for them +| (see WriteTool). The Pro-plan gate is enforced inside each tool under either +| guard, so a lapsed subscription stops working without revoking access. | */ +Mcp::oauthRoutes(); + Mcp::web('/mcp', WhisperMoneyServer::class) ->middleware(['auth:sanctum', 'abilities:mcp:read', 'throttle:60,1']); + +Mcp::web('/mcp/oauth', WhisperMoneyServer::class) + ->middleware(['auth:api', 'throttle:60,1']);