* feat(mcp): add OAuth well-known discovery endpoints (RFC 8414 + RFC 9728)
Serves /.well-known/oauth-protected-resource (RFC 9728) and
/.well-known/oauth-authorization-server (RFC 8414) so MCP clients
can auto-discover the authorization server. Both endpoints are
unauthenticated and respect APP_URL for reverse-proxy deployments.
* feat(mcp): add dynamic client registration endpoint (RFC 7591)
POST /register creates a public Doorkeeper::Application on demand so
MCP clients (e.g. Claude.ai) can self-register without manual setup.
Validates redirect_uris (including blank entries), falls back to
"MCP Client" name, returns no client_secret (public client, PKCE only).
Rate-limited to 10 registrations/min/IP via Rack::Attack.
* feat(mcp): authenticate via Doorkeeper OAuth2, keep MCP_API_TOKEN as fallback
MCP endpoint now accepts OAuth2 Bearer tokens issued by Doorkeeper.
Falls back to the existing MCP_API_TOKEN env-var flow so self-hosted
deployments are not broken. Requires MCP_OAUTH_ENABLED or MCP_API_TOKEN
to be set — the endpoint returns 503 otherwise.
- OauthBase concern provides APP_URL-aware configured_base_url (trailing
slash stripped to prevent double-slash URLs)
- Bearer scheme parsed case-insensitively (RFC 7235)
- Only read_write scope accepted — read scope would allow mutating tools
(CreateGoal, ImportBankStatement), so read-only tokens are rejected
- Deactivated users rejected even with a valid Doorkeeper token
- WWW-Authenticate header on 401 points to RFC 9728 resource metadata
- SHA-256 digest used for constant-time env-var comparison
- Rack::Attack throttle added for POST /register
- Routes wired: /.well-known/*, /register, use_doorkeeper
* fix(mcp): disable Turbo on OAuth consent form for external redirect URIs
Turbo was intercepting the authorization form POST and XHR-fetching
the redirect_uri (e.g. https://claude.ai/api/mcp/auth_callback),
which CORS blocks. Extend the existing turbo_disabled guard to cover
any redirect_uri that doesn't originate from the app itself.
* feat(mcp): add Settings::McpController with connected clients view
- Settings > MCP page (under Advanced) shows the MCP server URL with
copy button and step-by-step instructions for connecting Claude.ai
- Lists active non-mobile OAuth tokens with app name and revoke action;
mobile device tokens are excluded to prevent accidental disconnection
- Removes the MCP_OAUTH_ENABLED env-var gate — OAuth auth is always
available since Doorkeeper handles consent; MCP_API_TOKEN remains
as a self-hosted fallback
* fix(mcp): remove client_credentials from grant_types_supported metadata
Only authorization_code is supported by the registration endpoint.
Advertising client_credentials was misleading — a client that reads
the metadata and attempts that flow would get an application with the
wrong grant type.
* Add MCP server endpoint for external AI assistants
Expose Sure's Assistant::Function tools via JSON-RPC 2.0 at POST /mcp,
enabling external AI clients (Claude, GPT, etc.) to query financial data
through the Model Context Protocol.
- Bearer token auth via MCP_API_TOKEN / MCP_USER_EMAIL env vars
- JSON-RPC 2.0 with proper id threading, notification handling (204)
- Transient session (sessions.build) to prevent impersonation leaks
- Centralize function_classes in Assistant module
- Docker Compose example with Pipelock forward proxy
- 18 integration tests with scoped env (ClimateControl)
* Update compose for full Pipelock MCP reverse proxy integration
Use Pipelock's --mcp-listen/--mcp-upstream flags (PR #127) to run
bidirectional MCP scanning in the same container as the forward proxy.
External AI clients connect to port 8889, Pipelock scans requests
(DLP, injection, tool policy) and responses (injection, tool poisoning)
before forwarding to Sure's /mcp endpoint.
This supersedes the standalone compose in PR #1050.
* Fix compose --preset→--mode, add port 3000 trust comment, notification test
Review fixes:
- pipelock run uses --mode not --preset (would prevent stack startup)
- Document port 3000 exposes /mcp directly (auth still required)
- Add version requirement note for Pipelock MCP listener support
- Add test: tools/call sent as notification does not execute