feat(mcp): add OAuth2 authorization for MCP services

Support connecting to MCP servers that require OAuth2, with a Cursor-like
zero-config flow: the user provides only a URL and the system performs
metadata discovery, dynamic client registration (DCR), and the
authorization code flow with PKCE on first connect.

- Persist per-user access/refresh tokens and per-service DCR client
  credentials, encrypted at rest (AES-256-GCM)
- Store the PKCE verifier/state during the flow via Redis with an
  in-memory fallback for Lite mode
- Cache MCP clients per (service, user) so tokens stay user-isolated
- Add endpoints for authorize-url, callback, status, and token revoke;
  the callback is allowlisted for unauthenticated access
- Surface a structured "authorization required" hint when a tool call
  hits an unauthorized MCP service
- Frontend: add an auth-type selector with OAuth config, inline
  authorization status/actions, and render the connection test result
  inline in the editor drawer instead of a stacked centered dialog
This commit is contained in:
wizardchen
2026-06-22 20:15:52 +08:00
committed by lyingbug
parent c25d762ed1
commit 7f3f219f58
27 changed files with 1920 additions and 686 deletions
+33
View File
@@ -417,6 +417,39 @@ CREATE TABLE IF NOT EXISTS mcp_tool_approvals (
CREATE UNIQUE INDEX IF NOT EXISTS idx_mcp_tool_approvals_tenant_svc_tool ON mcp_tool_approvals(tenant_id, service_id, tool_name);
CREATE INDEX IF NOT EXISTS idx_mcp_tool_approvals_service_id ON mcp_tool_approvals(service_id);
CREATE TABLE IF NOT EXISTS mcp_oauth_clients (
id VARCHAR(36) PRIMARY KEY,
tenant_id INTEGER NOT NULL,
service_id VARCHAR(36) NOT NULL,
client_id VARCHAR(512) NOT NULL,
client_secret TEXT,
redirect_uri VARCHAR(1024),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (service_id) REFERENCES mcp_services(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_mcp_oauth_clients_tenant_svc ON mcp_oauth_clients(tenant_id, service_id);
CREATE INDEX IF NOT EXISTS idx_mcp_oauth_clients_service_id ON mcp_oauth_clients(service_id);
CREATE TABLE IF NOT EXISTS mcp_oauth_tokens (
id VARCHAR(36) PRIMARY KEY,
tenant_id INTEGER NOT NULL,
user_id VARCHAR(64) NOT NULL,
service_id VARCHAR(36) NOT NULL,
access_token TEXT,
refresh_token TEXT,
token_type VARCHAR(32),
expires_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (service_id) REFERENCES mcp_services(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_mcp_oauth_tokens_tenant_user_svc ON mcp_oauth_tokens(tenant_id, user_id, service_id);
CREATE INDEX IF NOT EXISTS idx_mcp_oauth_tokens_service_id ON mcp_oauth_tokens(service_id);
CREATE INDEX IF NOT EXISTS idx_mcp_oauth_tokens_user_id ON mcp_oauth_tokens(user_id);
CREATE TABLE IF NOT EXISTS custom_agents (
id VARCHAR(36) NOT NULL,
name VARCHAR(255) NOT NULL,