diff --git a/.gitignore b/.gitignore index 377bf581..e72ce45a 100644 --- a/.gitignore +++ b/.gitignore @@ -90,6 +90,9 @@ Thumbs.db .cache/ tmp/ +# compiled files +memoh + docs/docs/.vitepress/cache .pnpm-store diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 1ad67602..a8538273 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -194,6 +194,7 @@ func runServe() { // containerd handler & tool gateway provideContainerdHandler, + provideFederationGateway, provideToolGatewayService, // http handlers (group:"server_handlers") @@ -220,6 +221,8 @@ func runServe() { provideServerHandler(handlers.NewEmailOutboxHandler), provideServerHandler(handlers.NewEmailWebhookHandler), provideServerHandler(handlers.NewMCPHandler), + provideServerHandler(handlers.NewMCPOAuthHandler), + provideOAuthService, provideServerHandler(handlers.NewInboxHandler), provideServerHandler(handlers.NewTokenUsageHandler), provideServerHandler(provideCLIHandler), @@ -430,7 +433,23 @@ func provideContainerdHandler(log *slog.Logger, service ctr.Service, manager *mc return handlers.NewContainerdHandler(log, service, manager, cfg.MCP, cfg.Containerd.Namespace, rc.ContainerBackend, botService, accountService, policyService, queries) } -func provideToolGatewayService(log *slog.Logger, cfg config.Config, channelManager *channel.Manager, registry *channel.Registry, routeService *route.DBService, scheduleService *schedule.Service, chatService *conversation.Service, accountService *accounts.Service, settingsService *settings.Service, searchProviderService *searchproviders.Service, manager *mcp.Manager, containerdHandler *handlers.ContainerdHandler, mcpConnService *mcp.ConnectionService, mediaService *media.Service, inboxService *inbox.Service, memoryRegistry *memprovider.Registry, emailService *emailpkg.Service, emailManager *emailpkg.Manager) *mcp.ToolGatewayService { +func provideFederationGateway(log *slog.Logger, containerdHandler *handlers.ContainerdHandler) *handlers.MCPFederationGateway { + return handlers.NewMCPFederationGateway(log, containerdHandler) +} +func provideOAuthService(log *slog.Logger, queries *dbsqlc.Queries, cfg config.Config) *mcp.OAuthService { + addr := strings.TrimSpace(cfg.Server.Addr) + if addr == "" { + addr = ":8080" + } + host := addr + if strings.HasPrefix(host, ":") { + host = "localhost" + host + } + callbackURL := "http://" + host + "/api/oauth/mcp/callback" + return mcp.NewOAuthService(log, queries, callbackURL) +} +func provideToolGatewayService(log *slog.Logger, cfg config.Config, channelManager *channel.Manager, registry *channel.Registry, routeService *route.DBService, scheduleService *schedule.Service, chatService *conversation.Service, accountService *accounts.Service, settingsService *settings.Service, searchProviderService *searchproviders.Service, manager *mcp.Manager, containerdHandler *handlers.ContainerdHandler, mcpConnService *mcp.ConnectionService, mediaService *media.Service, inboxService *inbox.Service, memoryRegistry *memprovider.Registry, emailService *emailpkg.Service, emailManager *emailpkg.Manager, fedGateway *handlers.MCPFederationGateway, oauthService *mcp.OAuthService) *mcp.ToolGatewayService { + fedGateway.SetOAuthService(oauthService) var assetResolver mcpmessage.AssetResolver if mediaService != nil { assetResolver = &mediaAssetResolverAdapter{media: mediaService} @@ -442,10 +461,7 @@ func provideToolGatewayService(log *slog.Logger, cfg config.Config, channelManag webExec := mcpweb.NewExecutor(log, settingsService, searchProviderService) inboxExec := mcpinbox.NewExecutor(log, inboxService) fsExec := mcpcontainer.NewExecutor(log, manager, config.DefaultDataMount) - - fedGateway := handlers.NewMCPFederationGateway(log, containerdHandler) fedSource := mcpfederation.NewSource(log, fedGateway, mcpConnService) - emailExec := mcpemail.NewExecutor(log, emailService, emailManager) svc := mcp.NewToolGatewayService( diff --git a/cmd/memoh/serve.go b/cmd/memoh/serve.go index ce44a844..8be69c5b 100644 --- a/cmd/memoh/serve.go +++ b/cmd/memoh/serve.go @@ -123,6 +123,7 @@ func runServe() { provideScheduleTriggerer, schedule.NewService, provideContainerdHandler, + provideFederationGateway, provideToolGatewayService, provideServerHandler(handlers.NewPingHandler), provideServerHandler(provideMemohAuthHandler), @@ -146,6 +147,8 @@ func runServe() { provideServerHandler(handlers.NewEmailOutboxHandler), provideServerHandler(handlers.NewEmailWebhookHandler), provideServerHandler(handlers.NewMCPHandler), + provideServerHandler(handlers.NewMCPOAuthHandler), + provideOAuthService, provideServerHandler(handlers.NewInboxHandler), provideServerHandler(provideCLIHandler), provideServerHandler(provideWebHandler), @@ -294,7 +297,23 @@ func provideChannelLifecycleService(channelStore *channel.Store, channelManager func provideContainerdHandler(log *slog.Logger, service ctr.Service, manager *mcp.Manager, cfg config.Config, rc *boot.RuntimeConfig, botService *bots.Service, accountService *accounts.Service, policyService *policy.Service, queries *dbsqlc.Queries) *handlers.ContainerdHandler { return handlers.NewContainerdHandler(log, service, manager, cfg.MCP, cfg.Containerd.Namespace, rc.ContainerBackend, botService, accountService, policyService, queries) } -func provideToolGatewayService(log *slog.Logger, cfg config.Config, channelManager *channel.Manager, registry *channel.Registry, routeService *route.DBService, scheduleService *schedule.Service, chatService *conversation.Service, accountService *accounts.Service, settingsService *settings.Service, searchProviderService *searchproviders.Service, manager *mcp.Manager, containerdHandler *handlers.ContainerdHandler, mcpConnService *mcp.ConnectionService, mediaService *media.Service, inboxService *inbox.Service, memoryRegistry *memprovider.Registry, emailService *emailpkg.Service, emailManager *emailpkg.Manager) *mcp.ToolGatewayService { +func provideFederationGateway(log *slog.Logger, containerdHandler *handlers.ContainerdHandler) *handlers.MCPFederationGateway { + return handlers.NewMCPFederationGateway(log, containerdHandler) +} +func provideOAuthService(log *slog.Logger, queries *dbsqlc.Queries, cfg config.Config) *mcp.OAuthService { + addr := strings.TrimSpace(cfg.Server.Addr) + if addr == "" { + addr = ":8080" + } + host := addr + if strings.HasPrefix(host, ":") { + host = "localhost" + host + } + callbackURL := "http://" + host + "/oauth/mcp/callback" + return mcp.NewOAuthService(log, queries, callbackURL) +} +func provideToolGatewayService(log *slog.Logger, cfg config.Config, channelManager *channel.Manager, registry *channel.Registry, routeService *route.DBService, scheduleService *schedule.Service, chatService *conversation.Service, accountService *accounts.Service, settingsService *settings.Service, searchProviderService *searchproviders.Service, manager *mcp.Manager, containerdHandler *handlers.ContainerdHandler, mcpConnService *mcp.ConnectionService, mediaService *media.Service, inboxService *inbox.Service, memoryRegistry *memprovider.Registry, emailService *emailpkg.Service, emailManager *emailpkg.Manager, fedGateway *handlers.MCPFederationGateway, oauthService *mcp.OAuthService) *mcp.ToolGatewayService { + fedGateway.SetOAuthService(oauthService) var assetResolver mcpmessage.AssetResolver if mediaService != nil { assetResolver = &mediaAssetResolverAdapter{media: mediaService} @@ -306,7 +325,6 @@ func provideToolGatewayService(log *slog.Logger, cfg config.Config, channelManag webExec := mcpweb.NewExecutor(log, settingsService, searchProviderService) inboxExec := mcpinbox.NewExecutor(log, inboxService) fsExec := mcpcontainer.NewExecutor(log, manager, config.DefaultDataMount) - fedGateway := handlers.NewMCPFederationGateway(log, containerdHandler) fedSource := mcpfederation.NewSource(log, fedGateway, mcpConnService) emailExec := mcpemail.NewExecutor(log, emailService, emailManager) svc := mcp.NewToolGatewayService(log, []mcp.ToolExecutor{messageExec, contactsExec, scheduleExec, memoryExec, webExec, fsExec, inboxExec, emailExec}, []mcp.ToolSource{fedSource}) diff --git a/db/migrations/0001_init.up.sql b/db/migrations/0001_init.up.sql index fcf4c1be..61d3c385 100644 --- a/db/migrations/0001_init.up.sql +++ b/db/migrations/0001_init.up.sql @@ -170,6 +170,11 @@ CREATE TABLE IF NOT EXISTS mcp_connections ( type TEXT NOT NULL, config JSONB NOT NULL DEFAULT '{}'::jsonb, is_active BOOLEAN NOT NULL DEFAULT true, + status TEXT NOT NULL DEFAULT 'unknown', + tools_cache JSONB NOT NULL DEFAULT '[]'::jsonb, + last_probed_at TIMESTAMPTZ, + status_message TEXT NOT NULL DEFAULT '', + auth_type TEXT NOT NULL DEFAULT 'none', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT mcp_connections_type_check CHECK (type IN ('stdio', 'http', 'sse')), @@ -178,6 +183,32 @@ CREATE TABLE IF NOT EXISTS mcp_connections ( CREATE INDEX IF NOT EXISTS idx_mcp_connections_bot_id ON mcp_connections(bot_id); +CREATE TABLE IF NOT EXISTS mcp_oauth_tokens ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + connection_id UUID NOT NULL UNIQUE REFERENCES mcp_connections(id) ON DELETE CASCADE, + resource_metadata_url TEXT NOT NULL DEFAULT '', + authorization_server_url TEXT NOT NULL DEFAULT '', + authorization_endpoint TEXT NOT NULL DEFAULT '', + token_endpoint TEXT NOT NULL DEFAULT '', + registration_endpoint TEXT NOT NULL DEFAULT '', + scopes_supported TEXT[] NOT NULL DEFAULT '{}', + client_id TEXT NOT NULL DEFAULT '', + client_secret TEXT NOT NULL DEFAULT '', + access_token TEXT NOT NULL DEFAULT '', + refresh_token TEXT NOT NULL DEFAULT '', + token_type TEXT NOT NULL DEFAULT 'Bearer', + expires_at TIMESTAMPTZ, + scope TEXT NOT NULL DEFAULT '', + pkce_code_verifier TEXT NOT NULL DEFAULT '', + state_param TEXT NOT NULL DEFAULT '', + resource_uri TEXT NOT NULL DEFAULT '', + redirect_uri TEXT NOT NULL DEFAULT '', + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE INDEX IF NOT EXISTS idx_mcp_oauth_tokens_connection_id ON mcp_oauth_tokens(connection_id); + -- Bot history is bot-scoped (one history container per bot). CREATE TABLE IF NOT EXISTS bot_channel_configs ( diff --git a/db/migrations/0022_mcp_probe_and_oauth.down.sql b/db/migrations/0022_mcp_probe_and_oauth.down.sql new file mode 100644 index 00000000..b3532149 --- /dev/null +++ b/db/migrations/0022_mcp_probe_and_oauth.down.sql @@ -0,0 +1,12 @@ +-- 0022_mcp_probe_and_oauth (rollback) +-- Remove probe status fields and auth_type from mcp_connections; drop mcp_oauth_tokens table + +DROP INDEX IF EXISTS idx_mcp_oauth_tokens_connection_id; +DROP TABLE IF EXISTS mcp_oauth_tokens; + +ALTER TABLE mcp_connections + DROP COLUMN IF EXISTS status, + DROP COLUMN IF EXISTS tools_cache, + DROP COLUMN IF EXISTS last_probed_at, + DROP COLUMN IF EXISTS status_message, + DROP COLUMN IF EXISTS auth_type; diff --git a/db/migrations/0022_mcp_probe_and_oauth.up.sql b/db/migrations/0022_mcp_probe_and_oauth.up.sql new file mode 100644 index 00000000..bfe273a2 --- /dev/null +++ b/db/migrations/0022_mcp_probe_and_oauth.up.sql @@ -0,0 +1,34 @@ +-- 0022_mcp_probe_and_oauth +-- Add probe status fields and auth_type to mcp_connections; create mcp_oauth_tokens table + +ALTER TABLE mcp_connections + ADD COLUMN IF NOT EXISTS status TEXT NOT NULL DEFAULT 'unknown', + ADD COLUMN IF NOT EXISTS tools_cache JSONB NOT NULL DEFAULT '[]'::jsonb, + ADD COLUMN IF NOT EXISTS last_probed_at TIMESTAMPTZ, + ADD COLUMN IF NOT EXISTS status_message TEXT NOT NULL DEFAULT '', + ADD COLUMN IF NOT EXISTS auth_type TEXT NOT NULL DEFAULT 'none'; + +CREATE TABLE IF NOT EXISTS mcp_oauth_tokens ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + connection_id UUID NOT NULL UNIQUE REFERENCES mcp_connections(id) ON DELETE CASCADE, + resource_metadata_url TEXT NOT NULL DEFAULT '', + authorization_server_url TEXT NOT NULL DEFAULT '', + authorization_endpoint TEXT NOT NULL DEFAULT '', + token_endpoint TEXT NOT NULL DEFAULT '', + registration_endpoint TEXT NOT NULL DEFAULT '', + scopes_supported TEXT[] NOT NULL DEFAULT '{}', + client_id TEXT NOT NULL DEFAULT '', + client_secret TEXT NOT NULL DEFAULT '', + access_token TEXT NOT NULL DEFAULT '', + refresh_token TEXT NOT NULL DEFAULT '', + token_type TEXT NOT NULL DEFAULT 'Bearer', + expires_at TIMESTAMPTZ, + scope TEXT NOT NULL DEFAULT '', + pkce_code_verifier TEXT NOT NULL DEFAULT '', + state_param TEXT NOT NULL DEFAULT '', + resource_uri TEXT NOT NULL DEFAULT '', + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE INDEX IF NOT EXISTS idx_mcp_oauth_tokens_connection_id ON mcp_oauth_tokens(connection_id); diff --git a/db/migrations/0023_mcp_oauth_redirect_uri.down.sql b/db/migrations/0023_mcp_oauth_redirect_uri.down.sql new file mode 100644 index 00000000..d76bdd65 --- /dev/null +++ b/db/migrations/0023_mcp_oauth_redirect_uri.down.sql @@ -0,0 +1,4 @@ +-- 0023_mcp_oauth_redirect_uri +-- Remove redirect_uri column from mcp_oauth_tokens + +ALTER TABLE mcp_oauth_tokens DROP COLUMN IF EXISTS redirect_uri; diff --git a/db/migrations/0023_mcp_oauth_redirect_uri.up.sql b/db/migrations/0023_mcp_oauth_redirect_uri.up.sql new file mode 100644 index 00000000..d6478b99 --- /dev/null +++ b/db/migrations/0023_mcp_oauth_redirect_uri.up.sql @@ -0,0 +1,4 @@ +-- 0023_mcp_oauth_redirect_uri +-- Add redirect_uri column to mcp_oauth_tokens for per-flow callback URL storage + +ALTER TABLE mcp_oauth_tokens ADD COLUMN IF NOT EXISTS redirect_uri TEXT NOT NULL DEFAULT ''; diff --git a/db/queries/mcp.sql b/db/queries/mcp.sql index de6621d3..3d1e4517 100644 --- a/db/queries/mcp.sql +++ b/db/queries/mcp.sql @@ -1,19 +1,19 @@ -- name: GetMCPConnectionByID :one -SELECT id, bot_id, name, type, config, is_active, created_at, updated_at +SELECT id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at FROM mcp_connections WHERE bot_id = $1 AND id = $2 LIMIT 1; -- name: ListMCPConnectionsByBotID :many -SELECT id, bot_id, name, type, config, is_active, created_at, updated_at +SELECT id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at FROM mcp_connections WHERE bot_id = $1 ORDER BY created_at DESC; -- name: CreateMCPConnection :one -INSERT INTO mcp_connections (bot_id, name, type, config, is_active) -VALUES ($1, $2, $3, $4, $5) -RETURNING id, bot_id, name, type, config, is_active, created_at, updated_at; +INSERT INTO mcp_connections (bot_id, name, type, config, is_active, auth_type) +VALUES ($1, $2, $3, $4, $5, $6) +RETURNING id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at; -- name: UpdateMCPConnection :one UPDATE mcp_connections @@ -21,9 +21,25 @@ SET name = $3, type = $4, config = $5, is_active = $6, + auth_type = $7, updated_at = now() WHERE bot_id = $1 AND id = $2 -RETURNING id, bot_id, name, type, config, is_active, created_at, updated_at; +RETURNING id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at; + +-- name: UpdateMCPConnectionProbeResult :exec +UPDATE mcp_connections +SET status = $3, + tools_cache = $4, + last_probed_at = now(), + status_message = $5, + updated_at = now() +WHERE bot_id = $1 AND id = $2; + +-- name: UpdateMCPConnectionAuthType :exec +UPDATE mcp_connections +SET auth_type = $2, + updated_at = now() +WHERE id = $1; -- name: DeleteMCPConnection :exec DELETE FROM mcp_connections @@ -36,4 +52,4 @@ ON CONFLICT (bot_id, name) DO UPDATE SET type = EXCLUDED.type, config = EXCLUDED.config, updated_at = now() -RETURNING id, bot_id, name, type, config, is_active, created_at, updated_at; +RETURNING id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at; diff --git a/db/queries/mcp_oauth.sql b/db/queries/mcp_oauth.sql new file mode 100644 index 00000000..732f361f --- /dev/null +++ b/db/queries/mcp_oauth.sql @@ -0,0 +1,82 @@ +-- name: GetMCPOAuthToken :one +SELECT id, connection_id, resource_metadata_url, authorization_server_url, + authorization_endpoint, token_endpoint, registration_endpoint, + scopes_supported, client_id, client_secret, access_token, refresh_token, + token_type, expires_at, scope, pkce_code_verifier, state_param, + resource_uri, redirect_uri, created_at, updated_at +FROM mcp_oauth_tokens +WHERE connection_id = $1 +LIMIT 1; + +-- name: GetMCPOAuthTokenByState :one +SELECT id, connection_id, resource_metadata_url, authorization_server_url, + authorization_endpoint, token_endpoint, registration_endpoint, + scopes_supported, client_id, client_secret, access_token, refresh_token, + token_type, expires_at, scope, pkce_code_verifier, state_param, + resource_uri, redirect_uri, created_at, updated_at +FROM mcp_oauth_tokens +WHERE state_param = $1 +LIMIT 1; + +-- name: UpsertMCPOAuthDiscovery :one +INSERT INTO mcp_oauth_tokens (connection_id, resource_metadata_url, authorization_server_url, + authorization_endpoint, token_endpoint, registration_endpoint, scopes_supported, + resource_uri) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8) +ON CONFLICT (connection_id) +DO UPDATE SET resource_metadata_url = EXCLUDED.resource_metadata_url, + authorization_server_url = EXCLUDED.authorization_server_url, + authorization_endpoint = EXCLUDED.authorization_endpoint, + token_endpoint = EXCLUDED.token_endpoint, + registration_endpoint = EXCLUDED.registration_endpoint, + scopes_supported = EXCLUDED.scopes_supported, + resource_uri = EXCLUDED.resource_uri, + updated_at = now() +RETURNING id, connection_id, resource_metadata_url, authorization_server_url, + authorization_endpoint, token_endpoint, registration_endpoint, + scopes_supported, client_id, client_secret, access_token, refresh_token, + token_type, expires_at, scope, pkce_code_verifier, state_param, + resource_uri, redirect_uri, created_at, updated_at; + +-- name: UpdateMCPOAuthPKCEState :exec +UPDATE mcp_oauth_tokens +SET pkce_code_verifier = $2, + state_param = $3, + client_id = $4, + redirect_uri = $5, + updated_at = now() +WHERE connection_id = $1; + +-- name: UpdateMCPOAuthTokens :exec +UPDATE mcp_oauth_tokens +SET access_token = $2, + refresh_token = $3, + token_type = $4, + expires_at = $5, + scope = $6, + pkce_code_verifier = '', + state_param = '', + updated_at = now() +WHERE connection_id = $1; + +-- name: ClearMCPOAuthTokens :exec +UPDATE mcp_oauth_tokens +SET access_token = '', + refresh_token = '', + expires_at = NULL, + scope = '', + pkce_code_verifier = '', + state_param = '', + redirect_uri = '', + updated_at = now() +WHERE connection_id = $1; + +-- name: UpdateMCPOAuthClientSecret :exec +UPDATE mcp_oauth_tokens +SET client_secret = $2, + updated_at = now() +WHERE connection_id = $1; + +-- name: DeleteMCPOAuthToken :exec +DELETE FROM mcp_oauth_tokens +WHERE connection_id = $1; diff --git a/go.mod b/go.mod index 6614ff83..d1ec9d81 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/larksuite/oapi-sdk-go/v3 v3.5.3 github.com/mailgun/mailgun-go/v5 v5.14.0 github.com/memohai/acgo v0.0.0-20260221232113-babac0d6acd7 - github.com/modelcontextprotocol/go-sdk v1.3.0 + github.com/modelcontextprotocol/go-sdk v1.4.0 github.com/opencontainers/image-spec v1.1.1 github.com/opencontainers/runtime-spec v1.3.0 github.com/robfig/cron/v3 v3.0.1 @@ -100,6 +100,8 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/sasha-s/go-deadlock v0.3.6 // indirect + github.com/segmentio/asm v1.1.3 // indirect + github.com/segmentio/encoding v0.5.3 // indirect github.com/sirupsen/logrus v1.9.4 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect diff --git a/go.sum b/go.sum index e960a8d2..7411e95a 100644 --- a/go.sum +++ b/go.sum @@ -212,8 +212,8 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= -github.com/modelcontextprotocol/go-sdk v1.3.0 h1:gMfZkv3DzQF5q/DcQePo5rahEY+sguyPfXDfNBcT0Zs= -github.com/modelcontextprotocol/go-sdk v1.3.0/go.mod h1:AnQ//Qc6+4nIyyrB4cxBU7UW9VibK4iOZBeyP/rF1IE= +github.com/modelcontextprotocol/go-sdk v1.4.0 h1:u0kr8lbJc1oBcawK7Df+/ajNMpIDFE41OEPxdeTLOn8= +github.com/modelcontextprotocol/go-sdk v1.4.0/go.mod h1:Nxc2n+n/GdCebUaqCOhTetptS17SXXNu9IfNTaLDi1E= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -255,6 +255,10 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sasha-s/go-deadlock v0.3.6 h1:TR7sfOnZ7x00tWPfD397Peodt57KzMDo+9Ae9rMiUmw= github.com/sasha-s/go-deadlock v0.3.6/go.mod h1:CUqNyyvMxTyjFqDT7MRg9mb4Dv/btmGTqSR+rky/UXo= +github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc= +github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg= +github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= +github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= diff --git a/internal/db/sqlc/mcp.sql.go b/internal/db/sqlc/mcp.sql.go index 5a96c150..84cc39d0 100644 --- a/internal/db/sqlc/mcp.sql.go +++ b/internal/db/sqlc/mcp.sql.go @@ -12,9 +12,9 @@ import ( ) const createMCPConnection = `-- name: CreateMCPConnection :one -INSERT INTO mcp_connections (bot_id, name, type, config, is_active) -VALUES ($1, $2, $3, $4, $5) -RETURNING id, bot_id, name, type, config, is_active, created_at, updated_at +INSERT INTO mcp_connections (bot_id, name, type, config, is_active, auth_type) +VALUES ($1, $2, $3, $4, $5, $6) +RETURNING id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at ` type CreateMCPConnectionParams struct { @@ -23,6 +23,7 @@ type CreateMCPConnectionParams struct { Type string `json:"type"` Config []byte `json:"config"` IsActive bool `json:"is_active"` + AuthType string `json:"auth_type"` } func (q *Queries) CreateMCPConnection(ctx context.Context, arg CreateMCPConnectionParams) (McpConnection, error) { @@ -32,6 +33,7 @@ func (q *Queries) CreateMCPConnection(ctx context.Context, arg CreateMCPConnecti arg.Type, arg.Config, arg.IsActive, + arg.AuthType, ) var i McpConnection err := row.Scan( @@ -41,6 +43,11 @@ func (q *Queries) CreateMCPConnection(ctx context.Context, arg CreateMCPConnecti &i.Type, &i.Config, &i.IsActive, + &i.Status, + &i.ToolsCache, + &i.LastProbedAt, + &i.StatusMessage, + &i.AuthType, &i.CreatedAt, &i.UpdatedAt, ) @@ -63,7 +70,7 @@ func (q *Queries) DeleteMCPConnection(ctx context.Context, arg DeleteMCPConnecti } const getMCPConnectionByID = `-- name: GetMCPConnectionByID :one -SELECT id, bot_id, name, type, config, is_active, created_at, updated_at +SELECT id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at FROM mcp_connections WHERE bot_id = $1 AND id = $2 LIMIT 1 @@ -84,6 +91,11 @@ func (q *Queries) GetMCPConnectionByID(ctx context.Context, arg GetMCPConnection &i.Type, &i.Config, &i.IsActive, + &i.Status, + &i.ToolsCache, + &i.LastProbedAt, + &i.StatusMessage, + &i.AuthType, &i.CreatedAt, &i.UpdatedAt, ) @@ -91,7 +103,7 @@ func (q *Queries) GetMCPConnectionByID(ctx context.Context, arg GetMCPConnection } const listMCPConnectionsByBotID = `-- name: ListMCPConnectionsByBotID :many -SELECT id, bot_id, name, type, config, is_active, created_at, updated_at +SELECT id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at FROM mcp_connections WHERE bot_id = $1 ORDER BY created_at DESC @@ -113,6 +125,11 @@ func (q *Queries) ListMCPConnectionsByBotID(ctx context.Context, botID pgtype.UU &i.Type, &i.Config, &i.IsActive, + &i.Status, + &i.ToolsCache, + &i.LastProbedAt, + &i.StatusMessage, + &i.AuthType, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -132,9 +149,10 @@ SET name = $3, type = $4, config = $5, is_active = $6, + auth_type = $7, updated_at = now() WHERE bot_id = $1 AND id = $2 -RETURNING id, bot_id, name, type, config, is_active, created_at, updated_at +RETURNING id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at ` type UpdateMCPConnectionParams struct { @@ -144,6 +162,7 @@ type UpdateMCPConnectionParams struct { Type string `json:"type"` Config []byte `json:"config"` IsActive bool `json:"is_active"` + AuthType string `json:"auth_type"` } func (q *Queries) UpdateMCPConnection(ctx context.Context, arg UpdateMCPConnectionParams) (McpConnection, error) { @@ -154,6 +173,7 @@ func (q *Queries) UpdateMCPConnection(ctx context.Context, arg UpdateMCPConnecti arg.Type, arg.Config, arg.IsActive, + arg.AuthType, ) var i McpConnection err := row.Scan( @@ -163,12 +183,63 @@ func (q *Queries) UpdateMCPConnection(ctx context.Context, arg UpdateMCPConnecti &i.Type, &i.Config, &i.IsActive, + &i.Status, + &i.ToolsCache, + &i.LastProbedAt, + &i.StatusMessage, + &i.AuthType, &i.CreatedAt, &i.UpdatedAt, ) return i, err } +const updateMCPConnectionAuthType = `-- name: UpdateMCPConnectionAuthType :exec +UPDATE mcp_connections +SET auth_type = $2, + updated_at = now() +WHERE id = $1 +` + +type UpdateMCPConnectionAuthTypeParams struct { + ID pgtype.UUID `json:"id"` + AuthType string `json:"auth_type"` +} + +func (q *Queries) UpdateMCPConnectionAuthType(ctx context.Context, arg UpdateMCPConnectionAuthTypeParams) error { + _, err := q.db.Exec(ctx, updateMCPConnectionAuthType, arg.ID, arg.AuthType) + return err +} + +const updateMCPConnectionProbeResult = `-- name: UpdateMCPConnectionProbeResult :exec +UPDATE mcp_connections +SET status = $3, + tools_cache = $4, + last_probed_at = now(), + status_message = $5, + updated_at = now() +WHERE bot_id = $1 AND id = $2 +` + +type UpdateMCPConnectionProbeResultParams struct { + BotID pgtype.UUID `json:"bot_id"` + ID pgtype.UUID `json:"id"` + Status string `json:"status"` + ToolsCache []byte `json:"tools_cache"` + StatusMessage string `json:"status_message"` +} + +func (q *Queries) UpdateMCPConnectionProbeResult(ctx context.Context, arg UpdateMCPConnectionProbeResultParams) error { + _, err := q.db.Exec(ctx, updateMCPConnectionProbeResult, + arg.BotID, + arg.ID, + arg.Status, + arg.ToolsCache, + arg.StatusMessage, + ) + return err +} + const upsertMCPConnectionByName = `-- name: UpsertMCPConnectionByName :one INSERT INTO mcp_connections (bot_id, name, type, config) VALUES ($1, $2, $3, $4) @@ -176,7 +247,7 @@ ON CONFLICT (bot_id, name) DO UPDATE SET type = EXCLUDED.type, config = EXCLUDED.config, updated_at = now() -RETURNING id, bot_id, name, type, config, is_active, created_at, updated_at +RETURNING id, bot_id, name, type, config, is_active, status, tools_cache, last_probed_at, status_message, auth_type, created_at, updated_at ` type UpsertMCPConnectionByNameParams struct { @@ -201,6 +272,11 @@ func (q *Queries) UpsertMCPConnectionByName(ctx context.Context, arg UpsertMCPCo &i.Type, &i.Config, &i.IsActive, + &i.Status, + &i.ToolsCache, + &i.LastProbedAt, + &i.StatusMessage, + &i.AuthType, &i.CreatedAt, &i.UpdatedAt, ) diff --git a/internal/db/sqlc/mcp_oauth.sql.go b/internal/db/sqlc/mcp_oauth.sql.go new file mode 100644 index 00000000..d3d05d11 --- /dev/null +++ b/internal/db/sqlc/mcp_oauth.sql.go @@ -0,0 +1,270 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: mcp_oauth.sql + +package sqlc + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const clearMCPOAuthTokens = `-- name: ClearMCPOAuthTokens :exec +UPDATE mcp_oauth_tokens +SET access_token = '', + refresh_token = '', + expires_at = NULL, + scope = '', + pkce_code_verifier = '', + state_param = '', + redirect_uri = '', + updated_at = now() +WHERE connection_id = $1 +` + +func (q *Queries) ClearMCPOAuthTokens(ctx context.Context, connectionID pgtype.UUID) error { + _, err := q.db.Exec(ctx, clearMCPOAuthTokens, connectionID) + return err +} + +const deleteMCPOAuthToken = `-- name: DeleteMCPOAuthToken :exec +DELETE FROM mcp_oauth_tokens +WHERE connection_id = $1 +` + +func (q *Queries) DeleteMCPOAuthToken(ctx context.Context, connectionID pgtype.UUID) error { + _, err := q.db.Exec(ctx, deleteMCPOAuthToken, connectionID) + return err +} + +const getMCPOAuthToken = `-- name: GetMCPOAuthToken :one +SELECT id, connection_id, resource_metadata_url, authorization_server_url, + authorization_endpoint, token_endpoint, registration_endpoint, + scopes_supported, client_id, client_secret, access_token, refresh_token, + token_type, expires_at, scope, pkce_code_verifier, state_param, + resource_uri, redirect_uri, created_at, updated_at +FROM mcp_oauth_tokens +WHERE connection_id = $1 +LIMIT 1 +` + +func (q *Queries) GetMCPOAuthToken(ctx context.Context, connectionID pgtype.UUID) (McpOauthToken, error) { + row := q.db.QueryRow(ctx, getMCPOAuthToken, connectionID) + var i McpOauthToken + err := row.Scan( + &i.ID, + &i.ConnectionID, + &i.ResourceMetadataUrl, + &i.AuthorizationServerUrl, + &i.AuthorizationEndpoint, + &i.TokenEndpoint, + &i.RegistrationEndpoint, + &i.ScopesSupported, + &i.ClientID, + &i.ClientSecret, + &i.AccessToken, + &i.RefreshToken, + &i.TokenType, + &i.ExpiresAt, + &i.Scope, + &i.PkceCodeVerifier, + &i.StateParam, + &i.ResourceUri, + &i.RedirectUri, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getMCPOAuthTokenByState = `-- name: GetMCPOAuthTokenByState :one +SELECT id, connection_id, resource_metadata_url, authorization_server_url, + authorization_endpoint, token_endpoint, registration_endpoint, + scopes_supported, client_id, client_secret, access_token, refresh_token, + token_type, expires_at, scope, pkce_code_verifier, state_param, + resource_uri, redirect_uri, created_at, updated_at +FROM mcp_oauth_tokens +WHERE state_param = $1 +LIMIT 1 +` + +func (q *Queries) GetMCPOAuthTokenByState(ctx context.Context, stateParam string) (McpOauthToken, error) { + row := q.db.QueryRow(ctx, getMCPOAuthTokenByState, stateParam) + var i McpOauthToken + err := row.Scan( + &i.ID, + &i.ConnectionID, + &i.ResourceMetadataUrl, + &i.AuthorizationServerUrl, + &i.AuthorizationEndpoint, + &i.TokenEndpoint, + &i.RegistrationEndpoint, + &i.ScopesSupported, + &i.ClientID, + &i.ClientSecret, + &i.AccessToken, + &i.RefreshToken, + &i.TokenType, + &i.ExpiresAt, + &i.Scope, + &i.PkceCodeVerifier, + &i.StateParam, + &i.ResourceUri, + &i.RedirectUri, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateMCPOAuthClientSecret = `-- name: UpdateMCPOAuthClientSecret :exec +UPDATE mcp_oauth_tokens +SET client_secret = $2, + updated_at = now() +WHERE connection_id = $1 +` + +type UpdateMCPOAuthClientSecretParams struct { + ConnectionID pgtype.UUID `json:"connection_id"` + ClientSecret string `json:"client_secret"` +} + +func (q *Queries) UpdateMCPOAuthClientSecret(ctx context.Context, arg UpdateMCPOAuthClientSecretParams) error { + _, err := q.db.Exec(ctx, updateMCPOAuthClientSecret, arg.ConnectionID, arg.ClientSecret) + return err +} + +const updateMCPOAuthPKCEState = `-- name: UpdateMCPOAuthPKCEState :exec +UPDATE mcp_oauth_tokens +SET pkce_code_verifier = $2, + state_param = $3, + client_id = $4, + redirect_uri = $5, + updated_at = now() +WHERE connection_id = $1 +` + +type UpdateMCPOAuthPKCEStateParams struct { + ConnectionID pgtype.UUID `json:"connection_id"` + PkceCodeVerifier string `json:"pkce_code_verifier"` + StateParam string `json:"state_param"` + ClientID string `json:"client_id"` + RedirectUri string `json:"redirect_uri"` +} + +func (q *Queries) UpdateMCPOAuthPKCEState(ctx context.Context, arg UpdateMCPOAuthPKCEStateParams) error { + _, err := q.db.Exec(ctx, updateMCPOAuthPKCEState, + arg.ConnectionID, + arg.PkceCodeVerifier, + arg.StateParam, + arg.ClientID, + arg.RedirectUri, + ) + return err +} + +const updateMCPOAuthTokens = `-- name: UpdateMCPOAuthTokens :exec +UPDATE mcp_oauth_tokens +SET access_token = $2, + refresh_token = $3, + token_type = $4, + expires_at = $5, + scope = $6, + pkce_code_verifier = '', + state_param = '', + updated_at = now() +WHERE connection_id = $1 +` + +type UpdateMCPOAuthTokensParams struct { + ConnectionID pgtype.UUID `json:"connection_id"` + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + TokenType string `json:"token_type"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` + Scope string `json:"scope"` +} + +func (q *Queries) UpdateMCPOAuthTokens(ctx context.Context, arg UpdateMCPOAuthTokensParams) error { + _, err := q.db.Exec(ctx, updateMCPOAuthTokens, + arg.ConnectionID, + arg.AccessToken, + arg.RefreshToken, + arg.TokenType, + arg.ExpiresAt, + arg.Scope, + ) + return err +} + +const upsertMCPOAuthDiscovery = `-- name: UpsertMCPOAuthDiscovery :one +INSERT INTO mcp_oauth_tokens (connection_id, resource_metadata_url, authorization_server_url, + authorization_endpoint, token_endpoint, registration_endpoint, scopes_supported, + resource_uri) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8) +ON CONFLICT (connection_id) +DO UPDATE SET resource_metadata_url = EXCLUDED.resource_metadata_url, + authorization_server_url = EXCLUDED.authorization_server_url, + authorization_endpoint = EXCLUDED.authorization_endpoint, + token_endpoint = EXCLUDED.token_endpoint, + registration_endpoint = EXCLUDED.registration_endpoint, + scopes_supported = EXCLUDED.scopes_supported, + resource_uri = EXCLUDED.resource_uri, + updated_at = now() +RETURNING id, connection_id, resource_metadata_url, authorization_server_url, + authorization_endpoint, token_endpoint, registration_endpoint, + scopes_supported, client_id, client_secret, access_token, refresh_token, + token_type, expires_at, scope, pkce_code_verifier, state_param, + resource_uri, redirect_uri, created_at, updated_at +` + +type UpsertMCPOAuthDiscoveryParams struct { + ConnectionID pgtype.UUID `json:"connection_id"` + ResourceMetadataUrl string `json:"resource_metadata_url"` + AuthorizationServerUrl string `json:"authorization_server_url"` + AuthorizationEndpoint string `json:"authorization_endpoint"` + TokenEndpoint string `json:"token_endpoint"` + RegistrationEndpoint string `json:"registration_endpoint"` + ScopesSupported []string `json:"scopes_supported"` + ResourceUri string `json:"resource_uri"` +} + +func (q *Queries) UpsertMCPOAuthDiscovery(ctx context.Context, arg UpsertMCPOAuthDiscoveryParams) (McpOauthToken, error) { + row := q.db.QueryRow(ctx, upsertMCPOAuthDiscovery, + arg.ConnectionID, + arg.ResourceMetadataUrl, + arg.AuthorizationServerUrl, + arg.AuthorizationEndpoint, + arg.TokenEndpoint, + arg.RegistrationEndpoint, + arg.ScopesSupported, + arg.ResourceUri, + ) + var i McpOauthToken + err := row.Scan( + &i.ID, + &i.ConnectionID, + &i.ResourceMetadataUrl, + &i.AuthorizationServerUrl, + &i.AuthorizationEndpoint, + &i.TokenEndpoint, + &i.RegistrationEndpoint, + &i.ScopesSupported, + &i.ClientID, + &i.ClientSecret, + &i.AccessToken, + &i.RefreshToken, + &i.TokenType, + &i.ExpiresAt, + &i.Scope, + &i.PkceCodeVerifier, + &i.StateParam, + &i.ResourceUri, + &i.RedirectUri, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/internal/db/sqlc/models.go b/internal/db/sqlc/models.go index 6d4a1adb..b35ce7ee 100644 --- a/internal/db/sqlc/models.go +++ b/internal/db/sqlc/models.go @@ -246,14 +246,43 @@ type LlmProvider struct { } type McpConnection struct { - ID pgtype.UUID `json:"id"` - BotID pgtype.UUID `json:"bot_id"` - Name string `json:"name"` - Type string `json:"type"` - Config []byte `json:"config"` - IsActive bool `json:"is_active"` - CreatedAt pgtype.Timestamptz `json:"created_at"` - UpdatedAt pgtype.Timestamptz `json:"updated_at"` + ID pgtype.UUID `json:"id"` + BotID pgtype.UUID `json:"bot_id"` + Name string `json:"name"` + Type string `json:"type"` + Config []byte `json:"config"` + IsActive bool `json:"is_active"` + Status string `json:"status"` + ToolsCache []byte `json:"tools_cache"` + LastProbedAt pgtype.Timestamptz `json:"last_probed_at"` + StatusMessage string `json:"status_message"` + AuthType string `json:"auth_type"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type McpOauthToken struct { + ID pgtype.UUID `json:"id"` + ConnectionID pgtype.UUID `json:"connection_id"` + ResourceMetadataUrl string `json:"resource_metadata_url"` + AuthorizationServerUrl string `json:"authorization_server_url"` + AuthorizationEndpoint string `json:"authorization_endpoint"` + TokenEndpoint string `json:"token_endpoint"` + RegistrationEndpoint string `json:"registration_endpoint"` + ScopesSupported []string `json:"scopes_supported"` + ClientID string `json:"client_id"` + ClientSecret string `json:"client_secret"` + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + TokenType string `json:"token_type"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` + Scope string `json:"scope"` + PkceCodeVerifier string `json:"pkce_code_verifier"` + StateParam string `json:"state_param"` + ResourceUri string `json:"resource_uri"` + RedirectUri string `json:"redirect_uri"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` } type MediaAsset struct { diff --git a/internal/handlers/mcp.go b/internal/handlers/mcp.go index 3d1e1dd7..c8877cf9 100644 --- a/internal/handlers/mcp.go +++ b/internal/handlers/mcp.go @@ -3,6 +3,7 @@ package handlers import ( "context" "errors" + "fmt" "log/slog" "net/http" "strings" @@ -19,14 +20,16 @@ type MCPHandler struct { service *mcp.ConnectionService botService *bots.Service accountService *accounts.Service + fedGateway *MCPFederationGateway logger *slog.Logger } -func NewMCPHandler(log *slog.Logger, service *mcp.ConnectionService, botService *bots.Service, accountService *accounts.Service) *MCPHandler { +func NewMCPHandler(log *slog.Logger, service *mcp.ConnectionService, botService *bots.Service, accountService *accounts.Service, fedGateway *MCPFederationGateway) *MCPHandler { return &MCPHandler{ service: service, botService: botService, accountService: accountService, + fedGateway: fedGateway, logger: log.With(slog.String("handler", "mcp")), } } @@ -38,6 +41,7 @@ func (h *MCPHandler) Register(e *echo.Echo) { group.GET("/:id", h.Get) group.PUT("/:id", h.Update) group.DELETE("/:id", h.Delete) + group.POST("/:id/probe", h.Probe) ops := e.Group("/bots/:bot_id/mcp-ops") ops.PUT("/import", h.Import) @@ -220,6 +224,86 @@ func (h *MCPHandler) Delete(c echo.Context) error { return c.NoContent(http.StatusNoContent) } +// ProbeResponse is the response for a probe operation. +type ProbeResponse struct { + Status string `json:"status"` + Tools []mcp.ToolDescriptor `json:"tools"` + Error string `json:"error,omitempty"` + AuthRequired bool `json:"auth_required,omitempty"` +} + +// Probe godoc +// @Summary Probe MCP connection +// @Description Probe a MCP connection to discover tools and verify connectivity +// @Tags mcp +// @Param id path string true "MCP connection ID" +// @Success 200 {object} ProbeResponse +// @Failure 400 {object} ErrorResponse +// @Failure 403 {object} ErrorResponse +// @Failure 404 {object} ErrorResponse +// @Failure 500 {object} ErrorResponse +// @Router /bots/{bot_id}/mcp/{id}/probe [post] +func (h *MCPHandler) Probe(c echo.Context) error { + userID, err := h.requireChannelIdentityID(c) + if err != nil { + return err + } + botID := strings.TrimSpace(c.Param("bot_id")) + if botID == "" { + return echo.NewHTTPError(http.StatusBadRequest, "bot id is required") + } + if _, err := h.authorizeBotAccess(c.Request().Context(), userID, botID); err != nil { + return err + } + id := strings.TrimSpace(c.Param("id")) + if id == "" { + return echo.NewHTTPError(http.StatusBadRequest, "id is required") + } + conn, err := h.service.Get(c.Request().Context(), botID, id) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return echo.NewHTTPError(http.StatusNotFound, "mcp connection not found") + } + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + if h.fedGateway == nil { + return echo.NewHTTPError(http.StatusInternalServerError, "federation gateway not configured") + } + + ctx := c.Request().Context() + var tools []mcp.ToolDescriptor + var probeErr error + + switch strings.ToLower(strings.TrimSpace(conn.Type)) { + case "http": + tools, probeErr = h.fedGateway.ListHTTPConnectionTools(ctx, conn) + case "sse": + tools, probeErr = h.fedGateway.ListSSEConnectionTools(ctx, conn) + case "stdio": + tools, probeErr = h.fedGateway.ListStdioConnectionTools(ctx, botID, conn) + default: + probeErr = fmt.Errorf("unsupported connection type: %s", conn.Type) + } + + resp := ProbeResponse{} + if probeErr != nil { + resp.Status = "error" + resp.Error = probeErr.Error() + resp.Tools = []mcp.ToolDescriptor{} + authRequired := strings.Contains(probeErr.Error(), "401") || strings.Contains(strings.ToLower(probeErr.Error()), "unauthorized") + resp.AuthRequired = authRequired + _ = h.service.UpdateProbeResult(ctx, botID, id, "error", []mcp.ToolDescriptor{}, probeErr.Error()) + } else { + resp.Status = "connected" + if tools == nil { + tools = []mcp.ToolDescriptor{} + } + resp.Tools = tools + _ = h.service.UpdateProbeResult(ctx, botID, id, "connected", tools, "") + } + return c.JSON(http.StatusOK, resp) +} + // Import godoc // @Summary Import MCP connections // @Description Batch import MCP connections from standard mcpServers format. Existing connections (matched by name) get config updated with is_active preserved. New connections are created as active. diff --git a/internal/handlers/mcp_federation_gateway.go b/internal/handlers/mcp_federation_gateway.go index ea9bd57e..6c5ed256 100644 --- a/internal/handlers/mcp_federation_gateway.go +++ b/internal/handlers/mcp_federation_gateway.go @@ -15,9 +15,10 @@ import ( ) type MCPFederationGateway struct { - handler *ContainerdHandler - logger *slog.Logger - client *http.Client + handler *ContainerdHandler + logger *slog.Logger + client *http.Client + oauthService *mcpgw.OAuthService } func NewMCPFederationGateway(log *slog.Logger, handler *ContainerdHandler) *MCPFederationGateway { @@ -33,6 +34,11 @@ func NewMCPFederationGateway(log *slog.Logger, handler *ContainerdHandler) *MCPF } } +// SetOAuthService injects the OAuth service for token-based authentication. +func (g *MCPFederationGateway) SetOAuthService(svc *mcpgw.OAuthService) { + g.oauthService = svc +} + func (g *MCPFederationGateway) ListHTTPConnectionTools(ctx context.Context, connection mcpgw.Connection) ([]mcpgw.ToolDescriptor, error) { session, err := g.connectStreamableSession(ctx, connection) if err != nil { @@ -192,6 +198,21 @@ func (g *MCPFederationGateway) connectionHTTPClient(connection mcpgw.Connection) base = &http.Client{Timeout: 30 * time.Second} } headers := normalizeHeaderMap(connection.Config["headers"]) + + if strings.TrimSpace(connection.AuthType) == "oauth" && g.oauthService != nil { + token, err := g.oauthService.GetValidToken(context.Background(), connection.ID) + if err != nil { + g.logger.Warn("failed to get OAuth token for connection", + slog.String("connection_id", connection.ID), + slog.Any("error", err)) + } else if token != "" { + if headers == nil { + headers = map[string]string{} + } + headers["Authorization"] = "Bearer " + token + } + } + if len(headers) == 0 { return base } diff --git a/internal/handlers/mcp_oauth.go b/internal/handlers/mcp_oauth.go new file mode 100644 index 00000000..5dae17cc --- /dev/null +++ b/internal/handlers/mcp_oauth.go @@ -0,0 +1,250 @@ +package handlers + +import ( + "context" + "errors" + "log/slog" + "net/http" + "strings" + + "github.com/jackc/pgx/v5" + "github.com/labstack/echo/v4" + + "github.com/memohai/memoh/internal/accounts" + "github.com/memohai/memoh/internal/bots" + "github.com/memohai/memoh/internal/mcp" +) + +// MCPOAuthHandler handles OAuth-related endpoints for MCP connections. +type MCPOAuthHandler struct { + oauthService *mcp.OAuthService + connService *mcp.ConnectionService + botService *bots.Service + accountService *accounts.Service + logger *slog.Logger +} + +func NewMCPOAuthHandler(log *slog.Logger, oauthService *mcp.OAuthService, connService *mcp.ConnectionService, botService *bots.Service, accountService *accounts.Service) *MCPOAuthHandler { + return &MCPOAuthHandler{ + oauthService: oauthService, + connService: connService, + botService: botService, + accountService: accountService, + logger: log.With(slog.String("handler", "mcp_oauth")), + } +} + +func (h *MCPOAuthHandler) Register(e *echo.Echo) { + group := e.Group("/bots/:bot_id/mcp/:id/oauth") + group.POST("/discover", h.Discover) + group.POST("/authorize", h.Authorize) + group.GET("/status", h.Status) + group.DELETE("/token", h.RevokeToken) + group.POST("/exchange", h.Exchange) +} + +type oauthDiscoverRequest struct { + URL string `json:"url"` +} + +// Discover godoc +// @Summary Discover OAuth configuration for MCP server +// @Description Probe MCP server URL for OAuth requirements and discover authorization server metadata +// @Tags mcp +// @Param id path string true "MCP connection ID" +// @Param payload body oauthDiscoverRequest false "Optional URL override" +// @Success 200 {object} mcp.DiscoveryResult +// @Failure 400 {object} ErrorResponse +// @Failure 404 {object} ErrorResponse +// @Router /bots/{bot_id}/mcp/{id}/oauth/discover [post] +func (h *MCPOAuthHandler) Discover(c echo.Context) error { + userID, err := h.requireChannelIdentityID(c) + if err != nil { + return err + } + botID := strings.TrimSpace(c.Param("bot_id")) + connID := strings.TrimSpace(c.Param("id")) + if botID == "" || connID == "" { + return echo.NewHTTPError(http.StatusBadRequest, "bot_id and id are required") + } + if _, err := h.authorizeBotAccess(c.Request().Context(), userID, botID); err != nil { + return err + } + + conn, err := h.connService.Get(c.Request().Context(), botID, connID) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return echo.NewHTTPError(http.StatusNotFound, "mcp connection not found") + } + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + + var req oauthDiscoverRequest + _ = c.Bind(&req) + + serverURL := strings.TrimSpace(req.URL) + if serverURL == "" { + if configURL, ok := conn.Config["url"].(string); ok { + serverURL = strings.TrimSpace(configURL) + } + } + if serverURL == "" { + return echo.NewHTTPError(http.StatusBadRequest, "MCP server URL is required for OAuth discovery") + } + + result, err := h.oauthService.Discover(c.Request().Context(), serverURL) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + } + + if err := h.oauthService.SaveDiscovery(c.Request().Context(), connID, result); err != nil { + h.logger.Error("failed to save discovery result", slog.Any("error", err)) + return echo.NewHTTPError(http.StatusInternalServerError, "failed to save discovery result") + } + + return c.JSON(http.StatusOK, result) +} + +type oauthAuthorizeRequest struct { + ClientID string `json:"client_id"` + ClientSecret string `json:"client_secret"` + CallbackURL string `json:"callback_url"` +} + +// Authorize godoc +// @Summary Start OAuth authorization flow +// @Description Generate PKCE and return authorization URL for the user to authorize +// @Tags mcp +// @Param id path string true "MCP connection ID" +// @Param payload body oauthAuthorizeRequest false "Optional client_id" +// @Success 200 {object} mcp.AuthorizeResult +// @Failure 400 {object} ErrorResponse +// @Failure 404 {object} ErrorResponse +// @Router /bots/{bot_id}/mcp/{id}/oauth/authorize [post] +func (h *MCPOAuthHandler) Authorize(c echo.Context) error { + userID, err := h.requireChannelIdentityID(c) + if err != nil { + return err + } + botID := strings.TrimSpace(c.Param("bot_id")) + connID := strings.TrimSpace(c.Param("id")) + if botID == "" || connID == "" { + return echo.NewHTTPError(http.StatusBadRequest, "bot_id and id are required") + } + if _, err := h.authorizeBotAccess(c.Request().Context(), userID, botID); err != nil { + return err + } + + var req oauthAuthorizeRequest + _ = c.Bind(&req) + + result, err := h.oauthService.StartAuthorization(c.Request().Context(), connID, req.ClientID, req.ClientSecret, req.CallbackURL) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + } + + return c.JSON(http.StatusOK, result) +} + +type oauthExchangeRequest struct { + Code string `json:"code"` + State string `json:"state"` +} + +// Exchange godoc +// @Summary Exchange OAuth authorization code for tokens +// @Description Frontend callback page calls this to exchange the authorization code for access/refresh tokens +// @Tags mcp +// @Param payload body oauthExchangeRequest true "Authorization code and state" +// @Success 200 {object} map[string]bool +// @Failure 400 {object} ErrorResponse +// @Router /bots/{bot_id}/mcp/{id}/oauth/exchange [post] +func (h *MCPOAuthHandler) Exchange(c echo.Context) error { + var req oauthExchangeRequest + if err := c.Bind(&req); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "invalid request body") + } + + code := strings.TrimSpace(req.Code) + state := strings.TrimSpace(req.State) + if code == "" || state == "" { + return echo.NewHTTPError(http.StatusBadRequest, "code and state are required") + } + + _, err := h.oauthService.HandleCallback(c.Request().Context(), state, code) + if err != nil { + h.logger.Warn("oauth exchange failed", slog.Any("error", err)) + return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + } + + return c.JSON(http.StatusOK, map[string]bool{"success": true}) +} + +// Status godoc +// @Summary Get OAuth status for MCP connection +// @Description Returns the current OAuth status including whether tokens are available +// @Tags mcp +// @Param id path string true "MCP connection ID" +// @Success 200 {object} mcp.OAuthStatus +// @Failure 400 {object} ErrorResponse +// @Failure 404 {object} ErrorResponse +// @Router /bots/{bot_id}/mcp/{id}/oauth/status [get] +func (h *MCPOAuthHandler) Status(c echo.Context) error { + userID, err := h.requireChannelIdentityID(c) + if err != nil { + return err + } + botID := strings.TrimSpace(c.Param("bot_id")) + connID := strings.TrimSpace(c.Param("id")) + if botID == "" || connID == "" { + return echo.NewHTTPError(http.StatusBadRequest, "bot_id and id are required") + } + if _, err := h.authorizeBotAccess(c.Request().Context(), userID, botID); err != nil { + return err + } + + status, err := h.oauthService.GetStatus(c.Request().Context(), connID) + if err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + + return c.JSON(http.StatusOK, status) +} + +// RevokeToken godoc +// @Summary Revoke OAuth tokens for MCP connection +// @Description Clears stored OAuth tokens +// @Tags mcp +// @Param id path string true "MCP connection ID" +// @Success 204 "No Content" +// @Failure 400 {object} ErrorResponse +// @Router /bots/{bot_id}/mcp/{id}/oauth/token [delete] +func (h *MCPOAuthHandler) RevokeToken(c echo.Context) error { + userID, err := h.requireChannelIdentityID(c) + if err != nil { + return err + } + botID := strings.TrimSpace(c.Param("bot_id")) + connID := strings.TrimSpace(c.Param("id")) + if botID == "" || connID == "" { + return echo.NewHTTPError(http.StatusBadRequest, "bot_id and id are required") + } + if _, err := h.authorizeBotAccess(c.Request().Context(), userID, botID); err != nil { + return err + } + + if err := h.oauthService.RevokeToken(c.Request().Context(), connID); err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + + return c.NoContent(http.StatusNoContent) +} + +func (h *MCPOAuthHandler) requireChannelIdentityID(c echo.Context) (string, error) { + return RequireChannelIdentityID(c) +} + +func (h *MCPOAuthHandler) authorizeBotAccess(ctx context.Context, channelIdentityID, botID string) (bots.Bot, error) { + return AuthorizeBotAccess(ctx, h.botService, h.accountService, channelIdentityID, botID, bots.AccessPolicy{AllowPublicMember: false}) +} + diff --git a/internal/mcp/connections.go b/internal/mcp/connections.go index 206e8951..0a15ea28 100644 --- a/internal/mcp/connections.go +++ b/internal/mcp/connections.go @@ -14,14 +14,19 @@ import ( // Connection represents a stored MCP connection for a bot. type Connection struct { - ID string `json:"id"` - BotID string `json:"bot_id"` - Name string `json:"name"` - Type string `json:"type"` - Config map[string]any `json:"config"` - Active bool `json:"is_active"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID string `json:"id"` + BotID string `json:"bot_id"` + Name string `json:"name"` + Type string `json:"type"` + Config map[string]any `json:"config"` + Active bool `json:"is_active"` + Status string `json:"status"` + ToolsCache []ToolDescriptor `json:"tools_cache"` + LastProbedAt *time.Time `json:"last_probed_at,omitempty"` + StatusMessage string `json:"status_message"` + AuthType string `json:"auth_type"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } // UpsertRequest accepts standard mcpServers item format. @@ -36,6 +41,7 @@ type UpsertRequest struct { Headers map[string]string `json:"headers,omitempty"` Transport string `json:"transport,omitempty"` Active *bool `json:"is_active,omitempty"` + AuthType string `json:"auth_type,omitempty"` } // ImportRequest accepts a standard mcpServers dict for batch import. @@ -168,12 +174,17 @@ func (s *ConnectionService) Create(ctx context.Context, botID string, req Upsert if req.Active != nil { active = *req.Active } + authType := strings.TrimSpace(req.AuthType) + if authType == "" { + authType = "none" + } row, err := s.queries.CreateMCPConnection(ctx, sqlc.CreateMCPConnectionParams{ BotID: botUUID, Name: name, Type: mcpType, Config: configPayload, IsActive: active, + AuthType: authType, }) if err != nil { return Connection{}, err @@ -206,6 +217,10 @@ func (s *ConnectionService) Update(ctx context.Context, botID, id string, req Up if req.Active != nil { active = *req.Active } + authType := strings.TrimSpace(req.AuthType) + if authType == "" { + authType = "none" + } configPayload, err := json.Marshal(config) if err != nil { return Connection{}, err @@ -217,6 +232,7 @@ func (s *ConnectionService) Update(ctx context.Context, botID, id string, req Up Type: mcpType, Config: configPayload, IsActive: active, + AuthType: authType, }) if err != nil { return Connection{}, err @@ -330,18 +346,66 @@ func normalizeMCPConnection(row sqlc.McpConnection) (Connection, error) { if err != nil { return Connection{}, err } + toolsCache, _ := decodeToolsCache(row.ToolsCache) + var lastProbedAt *time.Time + if row.LastProbedAt.Valid { + t := db.TimeFromPg(row.LastProbedAt) + lastProbedAt = &t + } return Connection{ - ID: row.ID.String(), - BotID: row.BotID.String(), - Name: strings.TrimSpace(row.Name), - Type: strings.TrimSpace(row.Type), - Config: config, - Active: row.IsActive, - CreatedAt: db.TimeFromPg(row.CreatedAt), - UpdatedAt: db.TimeFromPg(row.UpdatedAt), + ID: row.ID.String(), + BotID: row.BotID.String(), + Name: strings.TrimSpace(row.Name), + Type: strings.TrimSpace(row.Type), + Config: config, + Active: row.IsActive, + Status: strings.TrimSpace(row.Status), + ToolsCache: toolsCache, + LastProbedAt: lastProbedAt, + StatusMessage: strings.TrimSpace(row.StatusMessage), + AuthType: strings.TrimSpace(row.AuthType), + CreatedAt: db.TimeFromPg(row.CreatedAt), + UpdatedAt: db.TimeFromPg(row.UpdatedAt), }, nil } +func decodeToolsCache(raw []byte) ([]ToolDescriptor, error) { + if len(raw) == 0 { + return []ToolDescriptor{}, nil + } + var tools []ToolDescriptor + if err := json.Unmarshal(raw, &tools); err != nil { + return []ToolDescriptor{}, nil + } + return tools, nil +} + +// UpdateProbeResult persists the result of a probe operation. +func (s *ConnectionService) UpdateProbeResult(ctx context.Context, botID, id, status string, tools []ToolDescriptor, message string) error { + if s.queries == nil { + return fmt.Errorf("mcp queries not configured") + } + pgBotID, err := db.ParseUUID(botID) + if err != nil { + return err + } + pgID, err := db.ParseUUID(id) + if err != nil { + return err + } + toolsPayload, err := json.Marshal(tools) + if err != nil { + return err + } + return s.queries.UpdateMCPConnectionProbeResult(ctx, sqlc.UpdateMCPConnectionProbeResultParams{ + BotID: pgBotID, + ID: pgID, + Status: status, + ToolsCache: toolsPayload, + StatusMessage: message, + }) +} + func decodeMCPConfig(raw []byte) (map[string]any, error) { if len(raw) == 0 { return map[string]any{}, nil diff --git a/internal/mcp/oauth.go b/internal/mcp/oauth.go new file mode 100644 index 00000000..186bd5b9 --- /dev/null +++ b/internal/mcp/oauth.go @@ -0,0 +1,823 @@ +package mcp + +import ( + "context" + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "log/slog" + "net/http" + "net/url" + "strings" + "time" + + "github.com/jackc/pgx/v5/pgtype" + "github.com/memohai/memoh/internal/db" + "github.com/memohai/memoh/internal/db/sqlc" +) + +// OAuthService manages OAuth flows for MCP connections. +type OAuthService struct { + queries *sqlc.Queries + logger *slog.Logger + httpClient *http.Client + callbackURL string +} + +func NewOAuthService(log *slog.Logger, queries *sqlc.Queries, callbackURL string) *OAuthService { + if log == nil { + log = slog.Default() + } + return &OAuthService{ + queries: queries, + logger: log.With(slog.String("service", "mcp_oauth")), + httpClient: &http.Client{Timeout: 15 * time.Second}, + callbackURL: callbackURL, + } +} + +// DiscoveryResult holds the result of an OAuth discovery flow. +type DiscoveryResult struct { + ResourceMetadataURL string `json:"resource_metadata_url"` + AuthorizationServerURL string `json:"authorization_server_url"` + AuthorizationEndpoint string `json:"authorization_endpoint"` + TokenEndpoint string `json:"token_endpoint"` + RegistrationEndpoint string `json:"registration_endpoint,omitempty"` + ScopesSupported []string `json:"scopes_supported,omitempty"` + ResourceURI string `json:"resource_uri"` +} + +// OAuthStatus describes the current OAuth state of a connection. +type OAuthStatus struct { + Configured bool `json:"configured"` + HasToken bool `json:"has_token"` + Expired bool `json:"expired"` + Scopes string `json:"scopes,omitempty"` + ExpiresAt *time.Time `json:"expires_at,omitempty"` + AuthServer string `json:"auth_server,omitempty"` + CallbackURL string `json:"callback_url"` +} + +// AuthorizeResult holds the authorization URL to redirect the user to. +type AuthorizeResult struct { + AuthorizationURL string `json:"authorization_url"` +} + +// Discover performs the MCP OAuth discovery flow: +// 1. Send request to MCP server, expect 401 with WWW-Authenticate +// 2. Fetch Protected Resource Metadata +// 3. Fetch Authorization Server Metadata +func (s *OAuthService) Discover(ctx context.Context, serverURL string) (*DiscoveryResult, error) { + serverURL = strings.TrimSpace(serverURL) + if serverURL == "" { + return nil, fmt.Errorf("server URL is required") + } + + resourceURI := canonicalResourceURI(serverURL) + + // Step 1: Probe the MCP server for 401 + WWW-Authenticate + resourceMetaURL, challengeScope, err := s.probeForAuth(ctx, serverURL) + if err != nil { + return nil, fmt.Errorf("oauth probe failed: %w", err) + } + + // Step 2: Fetch Protected Resource Metadata + if resourceMetaURL == "" { + resourceMetaURL = s.guessResourceMetadataURL(serverURL) + } + prm, prmErr := s.fetchProtectedResourceMetadata(ctx, resourceMetaURL) + + var authServerURL string + var scopes []string + + if prmErr == nil && len(prm.AuthorizationServers) > 0 { + authServerURL = prm.AuthorizationServers[0] + scopes = prm.ScopesSupported + } else { + // Fallback: some MCP servers (e.g. Linear) don't serve PRM. + // Try the server origin directly as the authorization server. + s.logger.Info("PRM unavailable, falling back to direct ASM discovery", + slog.String("server_url", serverURL), + slog.Any("prm_error", prmErr), + ) + parsed, _ := url.Parse(serverURL) + if parsed != nil { + authServerURL = parsed.Scheme + "://" + parsed.Host + if parsed.Path != "" && parsed.Path != "/" { + authServerURL += parsed.Path + } + } + } + + if authServerURL == "" { + if prmErr != nil { + return nil, fmt.Errorf("failed to fetch protected resource metadata: %w", prmErr) + } + return nil, fmt.Errorf("no authorization servers found in protected resource metadata") + } + + // Step 3: Fetch Authorization Server Metadata + asm, err := s.fetchAuthServerMetadata(ctx, authServerURL) + if err != nil { + return nil, fmt.Errorf("failed to fetch authorization server metadata: %w", err) + } + + if len(scopes) == 0 && challengeScope != "" { + scopes = strings.Split(challengeScope, " ") + } + if scopes == nil { + scopes = []string{} + } + + return &DiscoveryResult{ + ResourceMetadataURL: resourceMetaURL, + AuthorizationServerURL: authServerURL, + AuthorizationEndpoint: asm.AuthorizationEndpoint, + TokenEndpoint: asm.TokenEndpoint, + RegistrationEndpoint: asm.RegistrationEndpoint, + ScopesSupported: scopes, + ResourceURI: resourceURI, + }, nil +} + +// SaveDiscovery persists the discovery result for a connection. +func (s *OAuthService) SaveDiscovery(ctx context.Context, connectionID string, result *DiscoveryResult) error { + connUUID, err := db.ParseUUID(connectionID) + if err != nil { + return err + } + _, err = s.queries.UpsertMCPOAuthDiscovery(ctx, sqlc.UpsertMCPOAuthDiscoveryParams{ + ConnectionID: connUUID, + ResourceMetadataUrl: result.ResourceMetadataURL, + AuthorizationServerUrl: result.AuthorizationServerURL, + AuthorizationEndpoint: result.AuthorizationEndpoint, + TokenEndpoint: result.TokenEndpoint, + RegistrationEndpoint: result.RegistrationEndpoint, + ScopesSupported: result.ScopesSupported, + ResourceUri: result.ResourceURI, + }) + return err +} + +// StartAuthorization generates PKCE parameters and returns the authorization URL. +// Client ID resolution follows MCP spec priority: +// 1. User-provided client_id +// 2. Previously stored client_id (from prior registration or user input) +// 3. Dynamic Client Registration (RFC 7591) if registration_endpoint is available +// 4. Error — user must provide a client_id +func (s *OAuthService) StartAuthorization(ctx context.Context, connectionID, clientID, clientSecret, callbackURL string) (*AuthorizeResult, error) { + if callbackURL == "" { + callbackURL = s.callbackURL + } + connUUID, err := db.ParseUUID(connectionID) + if err != nil { + return nil, err + } + + token, err := s.queries.GetMCPOAuthToken(ctx, connUUID) + if err != nil { + return nil, fmt.Errorf("oauth not discovered for this connection: %w", err) + } + + if token.AuthorizationEndpoint == "" { + return nil, fmt.Errorf("authorization endpoint not configured") + } + + // Resolve client_id via priority chain + if clientID == "" { + clientID = token.ClientID + } + if clientSecret == "" { + clientSecret = token.ClientSecret + } + if clientID == "" && token.RegistrationEndpoint != "" { + // Attempt Dynamic Client Registration (RFC 7591) + regResult, regErr := s.registerClient(ctx, token.RegistrationEndpoint, callbackURL) + if regErr != nil { + s.logger.Warn("dynamic client registration failed", slog.Any("error", regErr)) + } else { + clientID = regResult.ClientID + dcrSecret := regResult.ClientSecret + if err := s.queries.UpdateMCPOAuthPKCEState(ctx, sqlc.UpdateMCPOAuthPKCEStateParams{ + ConnectionID: connUUID, + PkceCodeVerifier: "", // will be set below + StateParam: "", // will be set below + ClientID: clientID, + RedirectUri: callbackURL, + }); err != nil { + s.logger.Warn("failed to save DCR client_id", slog.Any("error", err)) + } + if dcrSecret != "" { + clientSecret = dcrSecret + _ = s.queries.UpdateMCPOAuthClientSecret(ctx, sqlc.UpdateMCPOAuthClientSecretParams{ + ConnectionID: connUUID, + ClientSecret: dcrSecret, + }) + } + s.logger.Info("dynamic client registration succeeded", slog.String("client_id", clientID)) + } + } + if clientID == "" { + return nil, fmt.Errorf("client_id is required: the authorization server does not support automatic registration, please provide a client_id from a registered OAuth application") + } + + // Persist client_secret if provided by the user + if clientSecret != "" && clientSecret != token.ClientSecret { + _ = s.queries.UpdateMCPOAuthClientSecret(ctx, sqlc.UpdateMCPOAuthClientSecretParams{ + ConnectionID: connUUID, + ClientSecret: clientSecret, + }) + } + + codeVerifier, err := generateCodeVerifier() + if err != nil { + return nil, fmt.Errorf("failed to generate PKCE code verifier: %w", err) + } + codeChallenge := computeCodeChallenge(codeVerifier) + state, err := generateState() + if err != nil { + return nil, fmt.Errorf("failed to generate state: %w", err) + } + + if err := s.queries.UpdateMCPOAuthPKCEState(ctx, sqlc.UpdateMCPOAuthPKCEStateParams{ + ConnectionID: connUUID, + PkceCodeVerifier: codeVerifier, + StateParam: state, + ClientID: clientID, + RedirectUri: callbackURL, + }); err != nil { + return nil, fmt.Errorf("failed to save PKCE state: %w", err) + } + + params := url.Values{ + "response_type": {"code"}, + "client_id": {clientID}, + "redirect_uri": {callbackURL}, + "state": {state}, + "code_challenge": {codeChallenge}, + "code_challenge_method": {"S256"}, + } + + if token.ResourceUri != "" { + params.Set("resource", token.ResourceUri) + } + + scopes := token.ScopesSupported + if len(scopes) > 0 { + params.Set("scope", strings.Join(scopes, " ")) + } + + authURL := token.AuthorizationEndpoint + "?" + params.Encode() + return &AuthorizeResult{AuthorizationURL: authURL}, nil +} + +// HandleCallback exchanges the authorization code for tokens. +func (s *OAuthService) HandleCallback(ctx context.Context, state, code string) (string, error) { + if state == "" || code == "" { + return "", fmt.Errorf("state and code are required") + } + + token, err := s.queries.GetMCPOAuthTokenByState(ctx, state) + if err != nil { + return "", fmt.Errorf("invalid or expired state parameter: %w", err) + } + + if token.TokenEndpoint == "" || token.PkceCodeVerifier == "" { + return "", fmt.Errorf("invalid OAuth state: missing token endpoint or code verifier") + } + + redirectURI := token.RedirectUri + if redirectURI == "" { + redirectURI = s.callbackURL + } + tokenResp, err := s.exchangeCode(ctx, token.TokenEndpoint, code, token.PkceCodeVerifier, token.ClientID, token.ClientSecret, token.ResourceUri, redirectURI) + if err != nil { + return "", fmt.Errorf("token exchange failed: %w", err) + } + + var expiresAt pgtype.Timestamptz + if tokenResp.ExpiresIn > 0 { + t := time.Now().Add(time.Duration(tokenResp.ExpiresIn) * time.Second) + expiresAt = pgtype.Timestamptz{Time: t, Valid: true} + } + + if err := s.queries.UpdateMCPOAuthTokens(ctx, sqlc.UpdateMCPOAuthTokensParams{ + ConnectionID: token.ConnectionID, + AccessToken: tokenResp.AccessToken, + RefreshToken: tokenResp.RefreshToken, + TokenType: tokenResp.TokenType, + ExpiresAt: expiresAt, + Scope: tokenResp.Scope, + }); err != nil { + return "", fmt.Errorf("failed to save tokens: %w", err) + } + + _ = s.queries.UpdateMCPConnectionAuthType(ctx, sqlc.UpdateMCPConnectionAuthTypeParams{ + ID: token.ConnectionID, + AuthType: "oauth", + }) + + return token.ConnectionID.String(), nil +} + +// GetValidToken returns a valid access token, refreshing if expired. +func (s *OAuthService) GetValidToken(ctx context.Context, connectionID string) (string, error) { + connUUID, err := db.ParseUUID(connectionID) + if err != nil { + return "", err + } + + token, err := s.queries.GetMCPOAuthToken(ctx, connUUID) + if err != nil { + return "", fmt.Errorf("no oauth token found: %w", err) + } + + if token.AccessToken == "" { + return "", fmt.Errorf("no access token available, authorization required") + } + + if token.ExpiresAt.Valid && time.Now().After(token.ExpiresAt.Time.Add(-30*time.Second)) { + if token.RefreshToken == "" { + return "", fmt.Errorf("access token expired and no refresh token available") + } + refreshed, err := s.refreshToken(ctx, token.TokenEndpoint, token.RefreshToken, token.ClientID, token.ResourceUri) + if err != nil { + return "", fmt.Errorf("token refresh failed: %w", err) + } + + var expiresAt pgtype.Timestamptz + if refreshed.ExpiresIn > 0 { + t := time.Now().Add(time.Duration(refreshed.ExpiresIn) * time.Second) + expiresAt = pgtype.Timestamptz{Time: t, Valid: true} + } + + refreshTokenValue := refreshed.RefreshToken + if refreshTokenValue == "" { + refreshTokenValue = token.RefreshToken + } + + if err := s.queries.UpdateMCPOAuthTokens(ctx, sqlc.UpdateMCPOAuthTokensParams{ + ConnectionID: connUUID, + AccessToken: refreshed.AccessToken, + RefreshToken: refreshTokenValue, + TokenType: refreshed.TokenType, + ExpiresAt: expiresAt, + Scope: refreshed.Scope, + }); err != nil { + s.logger.Warn("failed to save refreshed tokens", slog.Any("error", err)) + } + return refreshed.AccessToken, nil + } + + return token.AccessToken, nil +} + +// GetStatus returns the OAuth status for a connection. +func (s *OAuthService) GetStatus(ctx context.Context, connectionID string) (*OAuthStatus, error) { + connUUID, err := db.ParseUUID(connectionID) + if err != nil { + return nil, err + } + + token, err := s.queries.GetMCPOAuthToken(ctx, connUUID) + if err != nil { + return &OAuthStatus{Configured: false, CallbackURL: s.callbackURL}, nil + } + + status := &OAuthStatus{ + Configured: token.AuthorizationEndpoint != "", + HasToken: token.AccessToken != "", + AuthServer: token.AuthorizationServerUrl, + Scopes: token.Scope, + CallbackURL: s.callbackURL, + } + + if token.ExpiresAt.Valid { + t := db.TimeFromPg(token.ExpiresAt) + status.ExpiresAt = &t + status.Expired = time.Now().After(token.ExpiresAt.Time) + } + + return status, nil +} + +// RevokeToken clears stored tokens for a connection. +func (s *OAuthService) RevokeToken(ctx context.Context, connectionID string) error { + connUUID, err := db.ParseUUID(connectionID) + if err != nil { + return err + } + return s.queries.ClearMCPOAuthTokens(ctx, connUUID) +} + +// --- internal helpers --- + +type protectedResourceMetadata struct { + AuthorizationServers []string `json:"authorization_servers"` + ScopesSupported []string `json:"scopes_supported"` +} + +type authServerMetadata struct { + Issuer string `json:"issuer"` + AuthorizationEndpoint string `json:"authorization_endpoint"` + TokenEndpoint string `json:"token_endpoint"` + RegistrationEndpoint string `json:"registration_endpoint"` + ScopesSupported []string `json:"scopes_supported"` +} + +type tokenResponse struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + TokenType string `json:"token_type"` + ExpiresIn int `json:"expires_in"` + Scope string `json:"scope"` + Error string `json:"error,omitempty"` + ErrorDescription string `json:"error_description,omitempty"` +} + +func (s *OAuthService) probeForAuth(ctx context.Context, serverURL string) (resourceMetaURL, scope string, err error) { + req, err := http.NewRequestWithContext(ctx, http.MethodPost, serverURL, nil) + if err != nil { + return "", "", err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := s.httpClient.Do(req) + if err != nil { + return "", "", err + } + defer resp.Body.Close() + io.Copy(io.Discard, resp.Body) + + if resp.StatusCode != http.StatusUnauthorized { + return "", "", fmt.Errorf("expected 401 Unauthorized, got %d (server may not require OAuth)", resp.StatusCode) + } + + wwwAuth := resp.Header.Get("WWW-Authenticate") + if wwwAuth == "" { + return "", "", nil + } + + resourceMetaURL = extractWWWAuthParam(wwwAuth, "resource_metadata") + scope = extractWWWAuthParam(wwwAuth, "scope") + return resourceMetaURL, scope, nil +} + +func (s *OAuthService) guessResourceMetadataURL(serverURL string) string { + parsed, err := url.Parse(serverURL) + if err != nil { + return "" + } + base := parsed.Scheme + "://" + parsed.Host + if parsed.Path != "" && parsed.Path != "/" { + return base + "/.well-known/oauth-protected-resource" + parsed.Path + } + return base + "/.well-known/oauth-protected-resource" +} + +func (s *OAuthService) fetchProtectedResourceMetadata(ctx context.Context, metadataURL string) (*protectedResourceMetadata, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, metadataURL, nil) + if err != nil { + return nil, err + } + resp, err := s.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) + return nil, fmt.Errorf("resource metadata returned %d: %s", resp.StatusCode, string(body)) + } + + var meta protectedResourceMetadata + if err := json.NewDecoder(resp.Body).Decode(&meta); err != nil { + return nil, err + } + return &meta, nil +} + +func (s *OAuthService) fetchAuthServerMetadata(ctx context.Context, issuerURL string) (*authServerMetadata, error) { + parsed, err := url.Parse(issuerURL) + if err != nil { + return nil, err + } + + // Try multiple well-known endpoints per MCP spec (RFC 8414 Section 3.1). + // For issuer URLs with path components (e.g., https://github.com/login/oauth): + // 1. Path appending: https://github.com/login/oauth/.well-known/openid-configuration + // 2. Path insertion (OIDC): https://github.com/.well-known/openid-configuration/login/oauth + // 3. Path insertion (OAuth): https://github.com/.well-known/oauth-authorization-server/login/oauth + base := parsed.Scheme + "://" + parsed.Host + var candidates []string + if parsed.Path != "" && parsed.Path != "/" { + candidates = []string{ + base + "/.well-known/oauth-authorization-server" + parsed.Path, + base + "/.well-known/oauth-authorization-server", + base + "/.well-known/openid-configuration" + parsed.Path, + base + "/.well-known/openid-configuration", + strings.TrimRight(issuerURL, "/") + "/.well-known/openid-configuration", + } + } else { + candidates = []string{ + base + "/.well-known/oauth-authorization-server", + base + "/.well-known/openid-configuration", + } + } + + var lastErr error + for _, candidate := range candidates { + meta, err := s.tryFetchASMetadata(ctx, candidate) + if err == nil { + return meta, nil + } + lastErr = err + } + return nil, fmt.Errorf("could not fetch authorization server metadata: %w", lastErr) +} + +func (s *OAuthService) tryFetchASMetadata(ctx context.Context, metadataURL string) (*authServerMetadata, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, metadataURL, nil) + if err != nil { + return nil, err + } + resp, err := s.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("metadata endpoint %s returned %d", metadataURL, resp.StatusCode) + } + + var meta authServerMetadata + if err := json.NewDecoder(resp.Body).Decode(&meta); err != nil { + return nil, err + } + if meta.AuthorizationEndpoint == "" || meta.TokenEndpoint == "" { + return nil, fmt.Errorf("metadata missing required endpoints") + } + return &meta, nil +} + +func (s *OAuthService) exchangeCode(ctx context.Context, tokenEndpoint, code, codeVerifier, clientID, clientSecret, resourceURI, redirectURI string) (*tokenResponse, error) { + data := url.Values{ + "grant_type": {"authorization_code"}, + "code": {code}, + "redirect_uri": {redirectURI}, + "client_id": {clientID}, + "code_verifier": {codeVerifier}, + } + if clientSecret != "" { + data.Set("client_secret", clientSecret) + } + if resourceURI != "" { + data.Set("resource", resourceURI) + } + + s.logger.Info("exchangeCode request", + slog.String("token_endpoint", tokenEndpoint), + slog.String("redirect_uri", redirectURI), + slog.String("client_id", clientID), + slog.Bool("has_secret", clientSecret != ""), + slog.Bool("has_verifier", codeVerifier != ""), + slog.String("resource_uri", resourceURI), + ) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, tokenEndpoint, strings.NewReader(data.Encode())) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Accept", "application/json") + + resp, err := s.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(io.LimitReader(resp.Body, 64*1024)) + if err != nil { + return nil, fmt.Errorf("failed to read token response: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("token exchange returned %d: %s", resp.StatusCode, string(body)) + } + + tok, err := parseTokenResponse(body) + if err != nil { + return nil, fmt.Errorf("failed to parse token response: %w (body: %s)", err, truncate(string(body), 256)) + } + return tok, nil +} + +// parseTokenResponse tries JSON first, then falls back to form-encoded +// (GitHub's token endpoint returns form-encoded by default). +func parseTokenResponse(body []byte) (*tokenResponse, error) { + var tok tokenResponse + if err := json.Unmarshal(body, &tok); err == nil { + if tok.Error != "" { + if tok.ErrorDescription != "" { + return nil, fmt.Errorf("%s: %s", tok.Error, tok.ErrorDescription) + } + return nil, fmt.Errorf("%s", tok.Error) + } + if tok.AccessToken == "" { + return nil, fmt.Errorf("no access_token in response") + } + if tok.TokenType == "" { + tok.TokenType = "Bearer" + } + return &tok, nil + } + + vals, err := url.ParseQuery(string(body)) + if err != nil { + return nil, fmt.Errorf("response is neither JSON nor form-encoded: %w", err) + } + + if errCode := vals.Get("error"); errCode != "" { + desc := vals.Get("error_description") + if desc != "" { + return nil, fmt.Errorf("%s: %s", errCode, desc) + } + return nil, fmt.Errorf("%s", errCode) + } + + tok.AccessToken = vals.Get("access_token") + tok.RefreshToken = vals.Get("refresh_token") + tok.TokenType = vals.Get("token_type") + tok.Scope = vals.Get("scope") + if tok.TokenType == "" { + tok.TokenType = "Bearer" + } + if tok.AccessToken == "" { + return nil, fmt.Errorf("no access_token in response") + } + return &tok, nil +} + +func truncate(s string, maxLen int) string { + if len(s) <= maxLen { + return s + } + return s[:maxLen] + "..." +} + +func (s *OAuthService) refreshToken(ctx context.Context, tokenEndpoint, refreshToken, clientID, resourceURI string) (*tokenResponse, error) { + data := url.Values{ + "grant_type": {"refresh_token"}, + "refresh_token": {refreshToken}, + "client_id": {clientID}, + } + if resourceURI != "" { + data.Set("resource", resourceURI) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, tokenEndpoint, strings.NewReader(data.Encode())) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Accept", "application/json") + + resp, err := s.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(io.LimitReader(resp.Body, 64*1024)) + if err != nil { + return nil, fmt.Errorf("failed to read refresh response: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("token refresh returned %d: %s", resp.StatusCode, string(body)) + } + + tok, err := parseTokenResponse(body) + if err != nil { + return nil, fmt.Errorf("failed to parse refresh response: %w", err) + } + return tok, nil +} + +// --- Dynamic Client Registration (RFC 7591) --- + +type dcrRequest struct { + ClientName string `json:"client_name"` + RedirectURIs []string `json:"redirect_uris"` + GrantTypes []string `json:"grant_types"` + ResponseTypes []string `json:"response_types"` + TokenEndpointAuthMethod string `json:"token_endpoint_auth_method"` +} + +type dcrResponse struct { + ClientID string `json:"client_id"` + ClientSecret string `json:"client_secret,omitempty"` +} + +func (s *OAuthService) registerClient(ctx context.Context, registrationEndpoint, callbackURL string) (*dcrResponse, error) { + body := dcrRequest{ + ClientName: "Memoh", + RedirectURIs: []string{callbackURL}, + GrantTypes: []string{"authorization_code", "refresh_token"}, + ResponseTypes: []string{"code"}, + TokenEndpointAuthMethod: "none", + } + bodyJSON, err := json.Marshal(body) + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, registrationEndpoint, strings.NewReader(string(bodyJSON))) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := s.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { + respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 2048)) + return nil, fmt.Errorf("DCR returned %d: %s", resp.StatusCode, string(respBody)) + } + + var result dcrResponse + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return nil, fmt.Errorf("failed to decode DCR response: %w", err) + } + if result.ClientID == "" { + return nil, fmt.Errorf("DCR response missing client_id") + } + return &result, nil +} + +// --- PKCE helpers --- + +func generateCodeVerifier() (string, error) { + b := make([]byte, 32) + if _, err := rand.Read(b); err != nil { + return "", err + } + return base64.RawURLEncoding.EncodeToString(b), nil +} + +func computeCodeChallenge(verifier string) string { + h := sha256.Sum256([]byte(verifier)) + return base64.RawURLEncoding.EncodeToString(h[:]) +} + +func generateState() (string, error) { + b := make([]byte, 16) + if _, err := rand.Read(b); err != nil { + return "", err + } + return base64.RawURLEncoding.EncodeToString(b), nil +} + +func canonicalResourceURI(serverURL string) string { + parsed, err := url.Parse(serverURL) + if err != nil { + return serverURL + } + result := strings.ToLower(parsed.Scheme) + "://" + strings.ToLower(parsed.Host) + if parsed.Path != "" && parsed.Path != "/" { + result += strings.TrimRight(parsed.Path, "/") + } + return result +} + +func extractWWWAuthParam(header, param string) string { + lower := strings.ToLower(header) + key := strings.ToLower(param) + "=" + idx := strings.Index(lower, key) + if idx < 0 { + return "" + } + rest := header[idx+len(key):] + if len(rest) > 0 && rest[0] == '"' { + end := strings.Index(rest[1:], "\"") + if end >= 0 { + return rest[1 : end+1] + } + return rest[1:] + } + end := strings.IndexAny(rest, " ,") + if end >= 0 { + return rest[:end] + } + return rest +} diff --git a/packages/sdk/src/@pinia/colada.gen.ts b/packages/sdk/src/@pinia/colada.gen.ts index 203189da..ad8bae0f 100644 --- a/packages/sdk/src/@pinia/colada.gen.ts +++ b/packages/sdk/src/@pinia/colada.gen.ts @@ -4,40 +4,8 @@ import { type _JSONValue, defineQueryOptions, type UseMutationOptions } from '@p import { serializeQueryKeyValue } from '../client'; import { client } from '../client.gen'; -import { deleteBotsByBotIdContainer, deleteBotsByBotIdContainerSkills, deleteBotsByBotIdEmailBindingsById, deleteBotsByBotIdHeartbeatLogs, deleteBotsByBotIdInboxById, deleteBotsByBotIdMcpById, deleteBotsByBotIdMemory, deleteBotsByBotIdMemoryById, deleteBotsByBotIdMessages, deleteBotsByBotIdScheduleById, deleteBotsByBotIdSettings, deleteBotsByBotIdSubagentsById, deleteBotsById, deleteBotsByIdChannelByPlatform, deleteBotsByIdMembersByUserId, deleteEmailProvidersById, deleteMemoryProvidersById, deleteModelsById, deleteModelsModelByModelId, deleteProvidersById, deleteSearchProvidersById, getBots, getBotsByBotIdContainer, getBotsByBotIdContainerFs, getBotsByBotIdContainerFsDownload, getBotsByBotIdContainerFsList, getBotsByBotIdContainerFsRead, getBotsByBotIdContainerSkills, getBotsByBotIdContainerSnapshots, getBotsByBotIdEmailBindings, getBotsByBotIdEmailOutbox, getBotsByBotIdEmailOutboxById, getBotsByBotIdHeartbeatLogs, getBotsByBotIdInbox, getBotsByBotIdInboxById, getBotsByBotIdInboxCount, getBotsByBotIdMcp, getBotsByBotIdMcpById, getBotsByBotIdMcpExport, getBotsByBotIdMemory, getBotsByBotIdMemoryUsage, getBotsByBotIdMessages, getBotsByBotIdSchedule, getBotsByBotIdScheduleById, getBotsByBotIdSettings, getBotsByBotIdSubagents, getBotsByBotIdSubagentsById, getBotsByBotIdSubagentsByIdContext, getBotsByBotIdSubagentsByIdSkills, getBotsByBotIdTokenUsage, getBotsById, getBotsByIdChannelByPlatform, getBotsByIdChecks, getBotsByIdMembers, getChannels, getChannelsByPlatform, getEmailProviders, getEmailProvidersById, getEmailProvidersMeta, getMemoryProviders, getMemoryProvidersById, getMemoryProvidersMeta, getModels, getModelsById, getModelsCount, getModelsModelByModelId, getPing, getProviders, getProvidersById, getProvidersByIdModels, getProvidersCount, getProvidersNameByName, getSearchProviders, getSearchProvidersById, getSearchProvidersMeta, getUsers, getUsersById, getUsersMe, getUsersMeChannelsByPlatform, getUsersMeIdentities, type Options, patchBotsByIdChannelByPlatformStatus, postAuthLogin, postAuthRefresh, postBots, postBotsByBotIdCliMessages, postBotsByBotIdContainer, postBotsByBotIdContainerFsDelete, postBotsByBotIdContainerFsMkdir, postBotsByBotIdContainerFsRename, postBotsByBotIdContainerFsUpload, postBotsByBotIdContainerFsWrite, postBotsByBotIdContainerSkills, postBotsByBotIdContainerSnapshots, postBotsByBotIdContainerStart, postBotsByBotIdContainerStop, postBotsByBotIdEmailBindings, postBotsByBotIdInbox, postBotsByBotIdInboxMarkRead, postBotsByBotIdMcp, postBotsByBotIdMcpOpsBatchDelete, postBotsByBotIdMcpStdio, postBotsByBotIdMcpStdioByConnectionId, postBotsByBotIdMemory, postBotsByBotIdMemoryCompact, postBotsByBotIdMemoryRebuild, postBotsByBotIdMemorySearch, postBotsByBotIdSchedule, postBotsByBotIdSettings, postBotsByBotIdSubagents, postBotsByBotIdSubagentsByIdSkills, postBotsByBotIdTools, postBotsByBotIdWebMessages, postBotsByIdChannelByPlatformSend, postBotsByIdChannelByPlatformSendChat, postEmailMailgunWebhookByConfigId, postEmailProviders, postMemoryProviders, postModels, postModelsByIdTest, postProviders, postProvidersByIdImportModels, postProvidersByIdTest, postSearchProviders, postUsers, putBotsByBotIdEmailBindingsById, putBotsByBotIdMcpById, putBotsByBotIdMcpImport, putBotsByBotIdScheduleById, putBotsByBotIdSettings, putBotsByBotIdSubagentsById, putBotsByBotIdSubagentsByIdContext, putBotsByBotIdSubagentsByIdSkills, putBotsById, putBotsByIdChannelByPlatform, putBotsByIdMembers, putBotsByIdOwner, putEmailProvidersById, putMemoryProvidersById, putModelsById, putModelsModelByModelId, putProvidersById, putSearchProvidersById, putUsersById, putUsersByIdPassword, putUsersMe, putUsersMeChannelsByPlatform, putUsersMePassword } from '../sdk.gen'; -import type { DeleteBotsByBotIdContainerData, DeleteBotsByBotIdContainerError, DeleteBotsByBotIdContainerSkillsData, DeleteBotsByBotIdContainerSkillsError, DeleteBotsByBotIdContainerSkillsResponse, DeleteBotsByBotIdEmailBindingsByIdData, DeleteBotsByBotIdEmailBindingsByIdError, DeleteBotsByBotIdHeartbeatLogsData, DeleteBotsByBotIdHeartbeatLogsError, DeleteBotsByBotIdInboxByIdData, DeleteBotsByBotIdInboxByIdError, DeleteBotsByBotIdMcpByIdData, DeleteBotsByBotIdMcpByIdError, DeleteBotsByBotIdMemoryByIdData, DeleteBotsByBotIdMemoryByIdError, DeleteBotsByBotIdMemoryByIdResponse, DeleteBotsByBotIdMemoryData, DeleteBotsByBotIdMemoryError, DeleteBotsByBotIdMemoryResponse, DeleteBotsByBotIdMessagesData, DeleteBotsByBotIdMessagesError, DeleteBotsByBotIdScheduleByIdData, DeleteBotsByBotIdScheduleByIdError, DeleteBotsByBotIdSettingsData, DeleteBotsByBotIdSettingsError, DeleteBotsByBotIdSubagentsByIdData, DeleteBotsByBotIdSubagentsByIdError, DeleteBotsByIdChannelByPlatformData, DeleteBotsByIdChannelByPlatformError, DeleteBotsByIdData, DeleteBotsByIdError, DeleteBotsByIdMembersByUserIdData, DeleteBotsByIdMembersByUserIdError, DeleteBotsByIdResponse, DeleteEmailProvidersByIdData, DeleteEmailProvidersByIdError, DeleteMemoryProvidersByIdData, DeleteMemoryProvidersByIdError, DeleteModelsByIdData, DeleteModelsByIdError, DeleteModelsModelByModelIdData, DeleteModelsModelByModelIdError, DeleteProvidersByIdData, DeleteProvidersByIdError, DeleteSearchProvidersByIdData, DeleteSearchProvidersByIdError, GetBotsByBotIdContainerData, GetBotsByBotIdContainerFsData, GetBotsByBotIdContainerFsDownloadData, GetBotsByBotIdContainerFsListData, GetBotsByBotIdContainerFsReadData, GetBotsByBotIdContainerSkillsData, GetBotsByBotIdContainerSnapshotsData, GetBotsByBotIdEmailBindingsData, GetBotsByBotIdEmailOutboxByIdData, GetBotsByBotIdEmailOutboxData, GetBotsByBotIdHeartbeatLogsData, GetBotsByBotIdInboxByIdData, GetBotsByBotIdInboxCountData, GetBotsByBotIdInboxData, GetBotsByBotIdMcpByIdData, GetBotsByBotIdMcpData, GetBotsByBotIdMcpExportData, GetBotsByBotIdMemoryData, GetBotsByBotIdMemoryUsageData, GetBotsByBotIdMessagesData, GetBotsByBotIdScheduleByIdData, GetBotsByBotIdScheduleData, GetBotsByBotIdSettingsData, GetBotsByBotIdSubagentsByIdContextData, GetBotsByBotIdSubagentsByIdData, GetBotsByBotIdSubagentsByIdSkillsData, GetBotsByBotIdSubagentsData, GetBotsByBotIdTokenUsageData, GetBotsByIdChannelByPlatformData, GetBotsByIdChecksData, GetBotsByIdData, GetBotsByIdMembersData, GetBotsData, GetChannelsByPlatformData, GetChannelsData, GetEmailProvidersByIdData, GetEmailProvidersData, GetEmailProvidersMetaData, GetMemoryProvidersByIdData, GetMemoryProvidersData, GetMemoryProvidersMetaData, GetModelsByIdData, GetModelsCountData, GetModelsData, GetModelsModelByModelIdData, GetPingData, GetProvidersByIdData, GetProvidersByIdModelsData, GetProvidersCountData, GetProvidersData, GetProvidersNameByNameData, GetSearchProvidersByIdData, GetSearchProvidersData, GetSearchProvidersMetaData, GetUsersByIdData, GetUsersData, GetUsersMeChannelsByPlatformData, GetUsersMeData, GetUsersMeIdentitiesData, PatchBotsByIdChannelByPlatformStatusData, PatchBotsByIdChannelByPlatformStatusError, PatchBotsByIdChannelByPlatformStatusResponse, PostAuthLoginData, PostAuthLoginError, PostAuthLoginResponse, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshResponse, PostBotsByBotIdCliMessagesData, PostBotsByBotIdCliMessagesError, PostBotsByBotIdCliMessagesResponse, PostBotsByBotIdContainerData, PostBotsByBotIdContainerError, PostBotsByBotIdContainerFsDeleteData, PostBotsByBotIdContainerFsDeleteError, PostBotsByBotIdContainerFsDeleteResponse, PostBotsByBotIdContainerFsMkdirData, PostBotsByBotIdContainerFsMkdirError, PostBotsByBotIdContainerFsMkdirResponse, PostBotsByBotIdContainerFsRenameData, PostBotsByBotIdContainerFsRenameError, PostBotsByBotIdContainerFsRenameResponse, PostBotsByBotIdContainerFsUploadData, PostBotsByBotIdContainerFsUploadError, PostBotsByBotIdContainerFsUploadResponse, PostBotsByBotIdContainerFsWriteData, PostBotsByBotIdContainerFsWriteError, PostBotsByBotIdContainerFsWriteResponse, PostBotsByBotIdContainerResponse, PostBotsByBotIdContainerSkillsData, PostBotsByBotIdContainerSkillsError, PostBotsByBotIdContainerSkillsResponse, PostBotsByBotIdContainerSnapshotsData, PostBotsByBotIdContainerSnapshotsError, PostBotsByBotIdContainerSnapshotsResponse, PostBotsByBotIdContainerStartData, PostBotsByBotIdContainerStartError, PostBotsByBotIdContainerStartResponse, PostBotsByBotIdContainerStopData, PostBotsByBotIdContainerStopError, PostBotsByBotIdContainerStopResponse, PostBotsByBotIdEmailBindingsData, PostBotsByBotIdEmailBindingsError, PostBotsByBotIdEmailBindingsResponse, PostBotsByBotIdInboxData, PostBotsByBotIdInboxError, PostBotsByBotIdInboxMarkReadData, PostBotsByBotIdInboxMarkReadError, PostBotsByBotIdInboxResponse, PostBotsByBotIdMcpData, PostBotsByBotIdMcpError, PostBotsByBotIdMcpOpsBatchDeleteData, PostBotsByBotIdMcpOpsBatchDeleteError, PostBotsByBotIdMcpResponse, PostBotsByBotIdMcpStdioByConnectionIdData, PostBotsByBotIdMcpStdioByConnectionIdError, PostBotsByBotIdMcpStdioByConnectionIdResponse, PostBotsByBotIdMcpStdioData, PostBotsByBotIdMcpStdioError, PostBotsByBotIdMcpStdioResponse, PostBotsByBotIdMemoryCompactData, PostBotsByBotIdMemoryCompactError, PostBotsByBotIdMemoryCompactResponse, PostBotsByBotIdMemoryData, PostBotsByBotIdMemoryError, PostBotsByBotIdMemoryRebuildData, PostBotsByBotIdMemoryRebuildError, PostBotsByBotIdMemoryRebuildResponse, PostBotsByBotIdMemoryResponse, PostBotsByBotIdMemorySearchData, PostBotsByBotIdMemorySearchError, PostBotsByBotIdMemorySearchResponse, PostBotsByBotIdScheduleData, PostBotsByBotIdScheduleError, PostBotsByBotIdScheduleResponse, PostBotsByBotIdSettingsData, PostBotsByBotIdSettingsError, PostBotsByBotIdSettingsResponse, PostBotsByBotIdSubagentsByIdSkillsData, PostBotsByBotIdSubagentsByIdSkillsError, PostBotsByBotIdSubagentsByIdSkillsResponse, PostBotsByBotIdSubagentsData, PostBotsByBotIdSubagentsError, PostBotsByBotIdSubagentsResponse, PostBotsByBotIdToolsData, PostBotsByBotIdToolsError, PostBotsByBotIdToolsResponse, PostBotsByBotIdWebMessagesData, PostBotsByBotIdWebMessagesError, PostBotsByBotIdWebMessagesResponse, PostBotsByIdChannelByPlatformSendChatData, PostBotsByIdChannelByPlatformSendChatError, PostBotsByIdChannelByPlatformSendChatResponse, PostBotsByIdChannelByPlatformSendData, PostBotsByIdChannelByPlatformSendError, PostBotsByIdChannelByPlatformSendResponse, PostBotsData, PostBotsError, PostBotsResponse, PostEmailMailgunWebhookByConfigIdData, PostEmailMailgunWebhookByConfigIdError, PostEmailMailgunWebhookByConfigIdResponse, PostEmailProvidersData, PostEmailProvidersError, PostEmailProvidersResponse, PostMemoryProvidersData, PostMemoryProvidersError, PostMemoryProvidersResponse, PostModelsByIdTestData, PostModelsByIdTestError, PostModelsByIdTestResponse, PostModelsData, PostModelsError, PostModelsResponse, PostProvidersByIdImportModelsData, PostProvidersByIdImportModelsError, PostProvidersByIdImportModelsResponse, PostProvidersByIdTestData, PostProvidersByIdTestError, PostProvidersByIdTestResponse, PostProvidersData, PostProvidersError, PostProvidersResponse, PostSearchProvidersData, PostSearchProvidersError, PostSearchProvidersResponse, PostUsersData, PostUsersError, PostUsersResponse, PutBotsByBotIdEmailBindingsByIdData, PutBotsByBotIdEmailBindingsByIdError, PutBotsByBotIdEmailBindingsByIdResponse, PutBotsByBotIdMcpByIdData, PutBotsByBotIdMcpByIdError, PutBotsByBotIdMcpByIdResponse, PutBotsByBotIdMcpImportData, PutBotsByBotIdMcpImportError, PutBotsByBotIdMcpImportResponse, PutBotsByBotIdScheduleByIdData, PutBotsByBotIdScheduleByIdError, PutBotsByBotIdScheduleByIdResponse, PutBotsByBotIdSettingsData, PutBotsByBotIdSettingsError, PutBotsByBotIdSettingsResponse, PutBotsByBotIdSubagentsByIdContextData, PutBotsByBotIdSubagentsByIdContextError, PutBotsByBotIdSubagentsByIdContextResponse, PutBotsByBotIdSubagentsByIdData, PutBotsByBotIdSubagentsByIdError, PutBotsByBotIdSubagentsByIdResponse, PutBotsByBotIdSubagentsByIdSkillsData, PutBotsByBotIdSubagentsByIdSkillsError, PutBotsByBotIdSubagentsByIdSkillsResponse, PutBotsByIdChannelByPlatformData, PutBotsByIdChannelByPlatformError, PutBotsByIdChannelByPlatformResponse, PutBotsByIdData, PutBotsByIdError, PutBotsByIdMembersData, PutBotsByIdMembersError, PutBotsByIdMembersResponse, PutBotsByIdOwnerData, PutBotsByIdOwnerError, PutBotsByIdOwnerResponse, PutBotsByIdResponse, PutEmailProvidersByIdData, PutEmailProvidersByIdError, PutEmailProvidersByIdResponse, PutMemoryProvidersByIdData, PutMemoryProvidersByIdError, PutMemoryProvidersByIdResponse, PutModelsByIdData, PutModelsByIdError, PutModelsByIdResponse, PutModelsModelByModelIdData, PutModelsModelByModelIdError, PutModelsModelByModelIdResponse, PutProvidersByIdData, PutProvidersByIdError, PutProvidersByIdResponse, PutSearchProvidersByIdData, PutSearchProvidersByIdError, PutSearchProvidersByIdResponse, PutUsersByIdData, PutUsersByIdError, PutUsersByIdPasswordData, PutUsersByIdPasswordError, PutUsersByIdResponse, PutUsersMeChannelsByPlatformData, PutUsersMeChannelsByPlatformError, PutUsersMeChannelsByPlatformResponse, PutUsersMeData, PutUsersMeError, PutUsersMePasswordData, PutUsersMePasswordError, PutUsersMeResponse } from '../types.gen'; - -/** - * Login - * - * Validate user credentials and issue a JWT - */ -export const postAuthLoginMutation = (options?: Partial>): UseMutationOptions, PostAuthLoginError> => ({ - mutation: async (vars) => { - const { data } = await postAuthLogin({ - ...options, - ...vars, - throwOnError: true - }); - return data; - } -}); - -/** - * Refresh Token - * - * Issue a new JWT using the existing claims with updated expiration - */ -export const postAuthRefreshMutation = (options?: Partial>): UseMutationOptions, PostAuthRefreshError> => ({ - mutation: async (vars) => { - const { data } = await postAuthRefresh({ - ...options, - ...vars, - throwOnError: true - }); - return data; - } -}); +import { deleteBotsByBotIdContainer, deleteBotsByBotIdContainerSkills, deleteBotsByBotIdEmailBindingsById, deleteBotsByBotIdHeartbeatLogs, deleteBotsByBotIdInboxById, deleteBotsByBotIdMcpById, deleteBotsByBotIdMcpByIdOauthToken, deleteBotsByBotIdMemory, deleteBotsByBotIdMemoryById, deleteBotsByBotIdMessages, deleteBotsByBotIdScheduleById, deleteBotsByBotIdSettings, deleteBotsByBotIdSubagentsById, deleteBotsById, deleteBotsByIdChannelByPlatform, deleteBotsByIdMembersByUserId, deleteEmailProvidersById, deleteMemoryProvidersById, deleteModelsById, deleteModelsModelByModelId, deleteProvidersById, deleteSearchProvidersById, getApiOauthMcpCallback, getBots, getBotsByBotIdContainer, getBotsByBotIdContainerFs, getBotsByBotIdContainerFsDownload, getBotsByBotIdContainerFsList, getBotsByBotIdContainerFsRead, getBotsByBotIdContainerSkills, getBotsByBotIdContainerSnapshots, getBotsByBotIdEmailBindings, getBotsByBotIdEmailOutbox, getBotsByBotIdEmailOutboxById, getBotsByBotIdHeartbeatLogs, getBotsByBotIdInbox, getBotsByBotIdInboxById, getBotsByBotIdInboxCount, getBotsByBotIdMcp, getBotsByBotIdMcpById, getBotsByBotIdMcpByIdOauthStatus, getBotsByBotIdMcpExport, getBotsByBotIdMemory, getBotsByBotIdMemoryUsage, getBotsByBotIdMessages, getBotsByBotIdSchedule, getBotsByBotIdScheduleById, getBotsByBotIdSettings, getBotsByBotIdSubagents, getBotsByBotIdSubagentsById, getBotsByBotIdSubagentsByIdContext, getBotsByBotIdSubagentsByIdSkills, getBotsByBotIdTokenUsage, getBotsById, getBotsByIdChannelByPlatform, getBotsByIdChecks, getBotsByIdMembers, getChannels, getChannelsByPlatform, getEmailProviders, getEmailProvidersById, getEmailProvidersMeta, getMemoryProviders, getMemoryProvidersById, getMemoryProvidersMeta, getModels, getModelsById, getModelsCount, getModelsModelByModelId, getPing, getProviders, getProvidersById, getProvidersByIdModels, getProvidersCount, getProvidersNameByName, getSearchProviders, getSearchProvidersById, getSearchProvidersMeta, getUsers, getUsersById, getUsersMe, getUsersMeChannelsByPlatform, getUsersMeIdentities, type Options, patchBotsByIdChannelByPlatformStatus, postAuthLogin, postAuthRefresh, postBots, postBotsByBotIdCliMessages, postBotsByBotIdContainer, postBotsByBotIdContainerFsDelete, postBotsByBotIdContainerFsMkdir, postBotsByBotIdContainerFsRename, postBotsByBotIdContainerFsUpload, postBotsByBotIdContainerFsWrite, postBotsByBotIdContainerSkills, postBotsByBotIdContainerSnapshots, postBotsByBotIdContainerStart, postBotsByBotIdContainerStop, postBotsByBotIdEmailBindings, postBotsByBotIdInbox, postBotsByBotIdInboxMarkRead, postBotsByBotIdMcp, postBotsByBotIdMcpByIdOauthAuthorize, postBotsByBotIdMcpByIdOauthDiscover, postBotsByBotIdMcpByIdProbe, postBotsByBotIdMcpOpsBatchDelete, postBotsByBotIdMcpStdio, postBotsByBotIdMcpStdioByConnectionId, postBotsByBotIdMemory, postBotsByBotIdMemoryCompact, postBotsByBotIdMemoryRebuild, postBotsByBotIdMemorySearch, postBotsByBotIdSchedule, postBotsByBotIdSettings, postBotsByBotIdSubagents, postBotsByBotIdSubagentsByIdSkills, postBotsByBotIdTools, postBotsByBotIdWebMessages, postBotsByIdChannelByPlatformSend, postBotsByIdChannelByPlatformSendChat, postEmailMailgunWebhookByConfigId, postEmailProviders, postMemoryProviders, postModels, postModelsByIdTest, postProviders, postProvidersByIdImportModels, postProvidersByIdTest, postSearchProviders, postUsers, putBotsByBotIdEmailBindingsById, putBotsByBotIdMcpById, putBotsByBotIdMcpImport, putBotsByBotIdScheduleById, putBotsByBotIdSettings, putBotsByBotIdSubagentsById, putBotsByBotIdSubagentsByIdContext, putBotsByBotIdSubagentsByIdSkills, putBotsById, putBotsByIdChannelByPlatform, putBotsByIdMembers, putBotsByIdOwner, putEmailProvidersById, putMemoryProvidersById, putModelsById, putModelsModelByModelId, putProvidersById, putSearchProvidersById, putUsersById, putUsersByIdPassword, putUsersMe, putUsersMeChannelsByPlatform, putUsersMePassword } from '../sdk.gen'; +import type { DeleteBotsByBotIdContainerData, DeleteBotsByBotIdContainerError, DeleteBotsByBotIdContainerSkillsData, DeleteBotsByBotIdContainerSkillsError, DeleteBotsByBotIdContainerSkillsResponse, DeleteBotsByBotIdEmailBindingsByIdData, DeleteBotsByBotIdEmailBindingsByIdError, DeleteBotsByBotIdHeartbeatLogsData, DeleteBotsByBotIdHeartbeatLogsError, DeleteBotsByBotIdInboxByIdData, DeleteBotsByBotIdInboxByIdError, DeleteBotsByBotIdMcpByIdData, DeleteBotsByBotIdMcpByIdError, DeleteBotsByBotIdMcpByIdOauthTokenData, DeleteBotsByBotIdMcpByIdOauthTokenError, DeleteBotsByBotIdMemoryByIdData, DeleteBotsByBotIdMemoryByIdError, DeleteBotsByBotIdMemoryByIdResponse, DeleteBotsByBotIdMemoryData, DeleteBotsByBotIdMemoryError, DeleteBotsByBotIdMemoryResponse, DeleteBotsByBotIdMessagesData, DeleteBotsByBotIdMessagesError, DeleteBotsByBotIdScheduleByIdData, DeleteBotsByBotIdScheduleByIdError, DeleteBotsByBotIdSettingsData, DeleteBotsByBotIdSettingsError, DeleteBotsByBotIdSubagentsByIdData, DeleteBotsByBotIdSubagentsByIdError, DeleteBotsByIdChannelByPlatformData, DeleteBotsByIdChannelByPlatformError, DeleteBotsByIdData, DeleteBotsByIdError, DeleteBotsByIdMembersByUserIdData, DeleteBotsByIdMembersByUserIdError, DeleteBotsByIdResponse, DeleteEmailProvidersByIdData, DeleteEmailProvidersByIdError, DeleteMemoryProvidersByIdData, DeleteMemoryProvidersByIdError, DeleteModelsByIdData, DeleteModelsByIdError, DeleteModelsModelByModelIdData, DeleteModelsModelByModelIdError, DeleteProvidersByIdData, DeleteProvidersByIdError, DeleteSearchProvidersByIdData, DeleteSearchProvidersByIdError, GetApiOauthMcpCallbackData, GetBotsByBotIdContainerData, GetBotsByBotIdContainerFsData, GetBotsByBotIdContainerFsDownloadData, GetBotsByBotIdContainerFsListData, GetBotsByBotIdContainerFsReadData, GetBotsByBotIdContainerSkillsData, GetBotsByBotIdContainerSnapshotsData, GetBotsByBotIdEmailBindingsData, GetBotsByBotIdEmailOutboxByIdData, GetBotsByBotIdEmailOutboxData, GetBotsByBotIdHeartbeatLogsData, GetBotsByBotIdInboxByIdData, GetBotsByBotIdInboxCountData, GetBotsByBotIdInboxData, GetBotsByBotIdMcpByIdData, GetBotsByBotIdMcpByIdOauthStatusData, GetBotsByBotIdMcpData, GetBotsByBotIdMcpExportData, GetBotsByBotIdMemoryData, GetBotsByBotIdMemoryUsageData, GetBotsByBotIdMessagesData, GetBotsByBotIdScheduleByIdData, GetBotsByBotIdScheduleData, GetBotsByBotIdSettingsData, GetBotsByBotIdSubagentsByIdContextData, GetBotsByBotIdSubagentsByIdData, GetBotsByBotIdSubagentsByIdSkillsData, GetBotsByBotIdSubagentsData, GetBotsByBotIdTokenUsageData, GetBotsByIdChannelByPlatformData, GetBotsByIdChecksData, GetBotsByIdData, GetBotsByIdMembersData, GetBotsData, GetChannelsByPlatformData, GetChannelsData, GetEmailProvidersByIdData, GetEmailProvidersData, GetEmailProvidersMetaData, GetMemoryProvidersByIdData, GetMemoryProvidersData, GetMemoryProvidersMetaData, GetModelsByIdData, GetModelsCountData, GetModelsData, GetModelsModelByModelIdData, GetPingData, GetProvidersByIdData, GetProvidersByIdModelsData, GetProvidersCountData, GetProvidersData, GetProvidersNameByNameData, GetSearchProvidersByIdData, GetSearchProvidersData, GetSearchProvidersMetaData, GetUsersByIdData, GetUsersData, GetUsersMeChannelsByPlatformData, GetUsersMeData, GetUsersMeIdentitiesData, PatchBotsByIdChannelByPlatformStatusData, PatchBotsByIdChannelByPlatformStatusError, PatchBotsByIdChannelByPlatformStatusResponse, PostAuthLoginData, PostAuthLoginError, PostAuthLoginResponse, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshResponse, PostBotsByBotIdCliMessagesData, PostBotsByBotIdCliMessagesError, PostBotsByBotIdCliMessagesResponse, PostBotsByBotIdContainerData, PostBotsByBotIdContainerError, PostBotsByBotIdContainerFsDeleteData, PostBotsByBotIdContainerFsDeleteError, PostBotsByBotIdContainerFsDeleteResponse, PostBotsByBotIdContainerFsMkdirData, PostBotsByBotIdContainerFsMkdirError, PostBotsByBotIdContainerFsMkdirResponse, PostBotsByBotIdContainerFsRenameData, PostBotsByBotIdContainerFsRenameError, PostBotsByBotIdContainerFsRenameResponse, PostBotsByBotIdContainerFsUploadData, PostBotsByBotIdContainerFsUploadError, PostBotsByBotIdContainerFsUploadResponse, PostBotsByBotIdContainerFsWriteData, PostBotsByBotIdContainerFsWriteError, PostBotsByBotIdContainerFsWriteResponse, PostBotsByBotIdContainerResponse, PostBotsByBotIdContainerSkillsData, PostBotsByBotIdContainerSkillsError, PostBotsByBotIdContainerSkillsResponse, PostBotsByBotIdContainerSnapshotsData, PostBotsByBotIdContainerSnapshotsError, PostBotsByBotIdContainerSnapshotsResponse, PostBotsByBotIdContainerStartData, PostBotsByBotIdContainerStartError, PostBotsByBotIdContainerStartResponse, PostBotsByBotIdContainerStopData, PostBotsByBotIdContainerStopError, PostBotsByBotIdContainerStopResponse, PostBotsByBotIdEmailBindingsData, PostBotsByBotIdEmailBindingsError, PostBotsByBotIdEmailBindingsResponse, PostBotsByBotIdInboxData, PostBotsByBotIdInboxError, PostBotsByBotIdInboxMarkReadData, PostBotsByBotIdInboxMarkReadError, PostBotsByBotIdInboxResponse, PostBotsByBotIdMcpByIdOauthAuthorizeData, PostBotsByBotIdMcpByIdOauthAuthorizeError, PostBotsByBotIdMcpByIdOauthAuthorizeResponse, PostBotsByBotIdMcpByIdOauthDiscoverData, PostBotsByBotIdMcpByIdOauthDiscoverError, PostBotsByBotIdMcpByIdOauthDiscoverResponse, PostBotsByBotIdMcpByIdProbeData, PostBotsByBotIdMcpByIdProbeError, PostBotsByBotIdMcpByIdProbeResponse, PostBotsByBotIdMcpData, PostBotsByBotIdMcpError, PostBotsByBotIdMcpOpsBatchDeleteData, PostBotsByBotIdMcpOpsBatchDeleteError, PostBotsByBotIdMcpResponse, PostBotsByBotIdMcpStdioByConnectionIdData, PostBotsByBotIdMcpStdioByConnectionIdError, PostBotsByBotIdMcpStdioByConnectionIdResponse, PostBotsByBotIdMcpStdioData, PostBotsByBotIdMcpStdioError, PostBotsByBotIdMcpStdioResponse, PostBotsByBotIdMemoryCompactData, PostBotsByBotIdMemoryCompactError, PostBotsByBotIdMemoryCompactResponse, PostBotsByBotIdMemoryData, PostBotsByBotIdMemoryError, PostBotsByBotIdMemoryRebuildData, PostBotsByBotIdMemoryRebuildError, PostBotsByBotIdMemoryRebuildResponse, PostBotsByBotIdMemoryResponse, PostBotsByBotIdMemorySearchData, PostBotsByBotIdMemorySearchError, PostBotsByBotIdMemorySearchResponse, PostBotsByBotIdScheduleData, PostBotsByBotIdScheduleError, PostBotsByBotIdScheduleResponse, PostBotsByBotIdSettingsData, PostBotsByBotIdSettingsError, PostBotsByBotIdSettingsResponse, PostBotsByBotIdSubagentsByIdSkillsData, PostBotsByBotIdSubagentsByIdSkillsError, PostBotsByBotIdSubagentsByIdSkillsResponse, PostBotsByBotIdSubagentsData, PostBotsByBotIdSubagentsError, PostBotsByBotIdSubagentsResponse, PostBotsByBotIdToolsData, PostBotsByBotIdToolsError, PostBotsByBotIdToolsResponse, PostBotsByBotIdWebMessagesData, PostBotsByBotIdWebMessagesError, PostBotsByBotIdWebMessagesResponse, PostBotsByIdChannelByPlatformSendChatData, PostBotsByIdChannelByPlatformSendChatError, PostBotsByIdChannelByPlatformSendChatResponse, PostBotsByIdChannelByPlatformSendData, PostBotsByIdChannelByPlatformSendError, PostBotsByIdChannelByPlatformSendResponse, PostBotsData, PostBotsError, PostBotsResponse, PostEmailMailgunWebhookByConfigIdData, PostEmailMailgunWebhookByConfigIdError, PostEmailMailgunWebhookByConfigIdResponse, PostEmailProvidersData, PostEmailProvidersError, PostEmailProvidersResponse, PostMemoryProvidersData, PostMemoryProvidersError, PostMemoryProvidersResponse, PostModelsByIdTestData, PostModelsByIdTestError, PostModelsByIdTestResponse, PostModelsData, PostModelsError, PostModelsResponse, PostProvidersByIdImportModelsData, PostProvidersByIdImportModelsError, PostProvidersByIdImportModelsResponse, PostProvidersByIdTestData, PostProvidersByIdTestError, PostProvidersByIdTestResponse, PostProvidersData, PostProvidersError, PostProvidersResponse, PostSearchProvidersData, PostSearchProvidersError, PostSearchProvidersResponse, PostUsersData, PostUsersError, PostUsersResponse, PutBotsByBotIdEmailBindingsByIdData, PutBotsByBotIdEmailBindingsByIdError, PutBotsByBotIdEmailBindingsByIdResponse, PutBotsByBotIdMcpByIdData, PutBotsByBotIdMcpByIdError, PutBotsByBotIdMcpByIdResponse, PutBotsByBotIdMcpImportData, PutBotsByBotIdMcpImportError, PutBotsByBotIdMcpImportResponse, PutBotsByBotIdScheduleByIdData, PutBotsByBotIdScheduleByIdError, PutBotsByBotIdScheduleByIdResponse, PutBotsByBotIdSettingsData, PutBotsByBotIdSettingsError, PutBotsByBotIdSettingsResponse, PutBotsByBotIdSubagentsByIdContextData, PutBotsByBotIdSubagentsByIdContextError, PutBotsByBotIdSubagentsByIdContextResponse, PutBotsByBotIdSubagentsByIdData, PutBotsByBotIdSubagentsByIdError, PutBotsByBotIdSubagentsByIdResponse, PutBotsByBotIdSubagentsByIdSkillsData, PutBotsByBotIdSubagentsByIdSkillsError, PutBotsByBotIdSubagentsByIdSkillsResponse, PutBotsByIdChannelByPlatformData, PutBotsByIdChannelByPlatformError, PutBotsByIdChannelByPlatformResponse, PutBotsByIdData, PutBotsByIdError, PutBotsByIdMembersData, PutBotsByIdMembersError, PutBotsByIdMembersResponse, PutBotsByIdOwnerData, PutBotsByIdOwnerError, PutBotsByIdOwnerResponse, PutBotsByIdResponse, PutEmailProvidersByIdData, PutEmailProvidersByIdError, PutEmailProvidersByIdResponse, PutMemoryProvidersByIdData, PutMemoryProvidersByIdError, PutMemoryProvidersByIdResponse, PutModelsByIdData, PutModelsByIdError, PutModelsByIdResponse, PutModelsModelByModelIdData, PutModelsModelByModelIdError, PutModelsModelByModelIdResponse, PutProvidersByIdData, PutProvidersByIdError, PutProvidersByIdResponse, PutSearchProvidersByIdData, PutSearchProvidersByIdError, PutSearchProvidersByIdResponse, PutUsersByIdData, PutUsersByIdError, PutUsersByIdPasswordData, PutUsersByIdPasswordError, PutUsersByIdResponse, PutUsersMeChannelsByPlatformData, PutUsersMeChannelsByPlatformError, PutUsersMeChannelsByPlatformResponse, PutUsersMeData, PutUsersMeError, PutUsersMePasswordData, PutUsersMePasswordError, PutUsersMeResponse } from '../types.gen'; export type QueryKey = [ Pick & { @@ -74,6 +42,57 @@ const createQueryKey = (id: string, options?: TOptions return [params]; }; +export const getApiOauthMcpCallbackQueryKey = (options: Options) => createQueryKey('getApiOauthMcpCallback', options); + +/** + * OAuth callback handler + * + * Handles the OAuth authorization callback, exchanges code for tokens + */ +export const getApiOauthMcpCallbackQuery = defineQueryOptions((options: Options) => ({ + key: getApiOauthMcpCallbackQueryKey(options), + query: async (context) => { + const { data } = await getApiOauthMcpCallback({ + ...options, + ...context, + throwOnError: true + }); + return data; + } +})); + +/** + * Login + * + * Validate user credentials and issue a JWT + */ +export const postAuthLoginMutation = (options?: Partial>): UseMutationOptions, PostAuthLoginError> => ({ + mutation: async (vars) => { + const { data } = await postAuthLogin({ + ...options, + ...vars, + throwOnError: true + }); + return data; + } +}); + +/** + * Refresh Token + * + * Issue a new JWT using the existing claims with updated expiration + */ +export const postAuthRefreshMutation = (options?: Partial>): UseMutationOptions, PostAuthRefreshError> => ({ + mutation: async (vars) => { + const { data } = await postAuthRefresh({ + ...options, + ...vars, + throwOnError: true + }); + return data; + } +}); + export const getBotsQueryKey = (options?: Options) => createQueryKey('getBots', options); /** @@ -832,6 +851,89 @@ export const putBotsByBotIdMcpByIdMutation = (options?: Partial>): UseMutationOptions, PostBotsByBotIdMcpByIdOauthAuthorizeError> => ({ + mutation: async (vars) => { + const { data } = await postBotsByBotIdMcpByIdOauthAuthorize({ + ...options, + ...vars, + throwOnError: true + }); + return data; + } +}); + +/** + * Discover OAuth configuration for MCP server + * + * Probe MCP server URL for OAuth requirements and discover authorization server metadata + */ +export const postBotsByBotIdMcpByIdOauthDiscoverMutation = (options?: Partial>): UseMutationOptions, PostBotsByBotIdMcpByIdOauthDiscoverError> => ({ + mutation: async (vars) => { + const { data } = await postBotsByBotIdMcpByIdOauthDiscover({ + ...options, + ...vars, + throwOnError: true + }); + return data; + } +}); + +export const getBotsByBotIdMcpByIdOauthStatusQueryKey = (options: Options) => createQueryKey('getBotsByBotIdMcpByIdOauthStatus', options); + +/** + * Get OAuth status for MCP connection + * + * Returns the current OAuth status including whether tokens are available + */ +export const getBotsByBotIdMcpByIdOauthStatusQuery = defineQueryOptions((options: Options) => ({ + key: getBotsByBotIdMcpByIdOauthStatusQueryKey(options), + query: async (context) => { + const { data } = await getBotsByBotIdMcpByIdOauthStatus({ + ...options, + ...context, + throwOnError: true + }); + return data; + } +})); + +/** + * Revoke OAuth tokens for MCP connection + * + * Clears stored OAuth tokens + */ +export const deleteBotsByBotIdMcpByIdOauthTokenMutation = (options?: Partial>): UseMutationOptions, DeleteBotsByBotIdMcpByIdOauthTokenError> => ({ + mutation: async (vars) => { + const { data } = await deleteBotsByBotIdMcpByIdOauthToken({ + ...options, + ...vars, + throwOnError: true + }); + return data; + } +}); + +/** + * Probe MCP connection + * + * Probe a MCP connection to discover tools and verify connectivity + */ +export const postBotsByBotIdMcpByIdProbeMutation = (options?: Partial>): UseMutationOptions, PostBotsByBotIdMcpByIdProbeError> => ({ + mutation: async (vars) => { + const { data } = await postBotsByBotIdMcpByIdProbe({ + ...options, + ...vars, + throwOnError: true + }); + return data; + } +}); + /** * Delete memories * diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index a5be53ef..b2448a4e 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { deleteBotsByBotIdContainer, deleteBotsByBotIdContainerSkills, deleteBotsByBotIdEmailBindingsById, deleteBotsByBotIdHeartbeatLogs, deleteBotsByBotIdInboxById, deleteBotsByBotIdMcpById, deleteBotsByBotIdMemory, deleteBotsByBotIdMemoryById, deleteBotsByBotIdMessages, deleteBotsByBotIdScheduleById, deleteBotsByBotIdSettings, deleteBotsByBotIdSubagentsById, deleteBotsById, deleteBotsByIdChannelByPlatform, deleteBotsByIdMembersByUserId, deleteEmailProvidersById, deleteMemoryProvidersById, deleteModelsById, deleteModelsModelByModelId, deleteProvidersById, deleteSearchProvidersById, getBots, getBotsByBotIdCliStream, getBotsByBotIdContainer, getBotsByBotIdContainerFs, getBotsByBotIdContainerFsDownload, getBotsByBotIdContainerFsList, getBotsByBotIdContainerFsRead, getBotsByBotIdContainerSkills, getBotsByBotIdContainerSnapshots, getBotsByBotIdEmailBindings, getBotsByBotIdEmailOutbox, getBotsByBotIdEmailOutboxById, getBotsByBotIdHeartbeatLogs, getBotsByBotIdInbox, getBotsByBotIdInboxById, getBotsByBotIdInboxCount, getBotsByBotIdMcp, getBotsByBotIdMcpById, getBotsByBotIdMcpExport, getBotsByBotIdMemory, getBotsByBotIdMemoryUsage, getBotsByBotIdMessages, getBotsByBotIdSchedule, getBotsByBotIdScheduleById, getBotsByBotIdSettings, getBotsByBotIdSubagents, getBotsByBotIdSubagentsById, getBotsByBotIdSubagentsByIdContext, getBotsByBotIdSubagentsByIdSkills, getBotsByBotIdTokenUsage, getBotsByBotIdWebStream, getBotsById, getBotsByIdChannelByPlatform, getBotsByIdChecks, getBotsByIdMembers, getChannels, getChannelsByPlatform, getEmailProviders, getEmailProvidersById, getEmailProvidersMeta, getMemoryProviders, getMemoryProvidersById, getMemoryProvidersMeta, getModels, getModelsById, getModelsCount, getModelsModelByModelId, getPing, getProviders, getProvidersById, getProvidersByIdModels, getProvidersCount, getProvidersNameByName, getSearchProviders, getSearchProvidersById, getSearchProvidersMeta, getUsers, getUsersById, getUsersMe, getUsersMeChannelsByPlatform, getUsersMeIdentities, type Options, patchBotsByIdChannelByPlatformStatus, postAuthLogin, postAuthRefresh, postBots, postBotsByBotIdCliMessages, postBotsByBotIdContainer, postBotsByBotIdContainerFsDelete, postBotsByBotIdContainerFsMkdir, postBotsByBotIdContainerFsRename, postBotsByBotIdContainerFsUpload, postBotsByBotIdContainerFsWrite, postBotsByBotIdContainerSkills, postBotsByBotIdContainerSnapshots, postBotsByBotIdContainerStart, postBotsByBotIdContainerStop, postBotsByBotIdEmailBindings, postBotsByBotIdInbox, postBotsByBotIdInboxMarkRead, postBotsByBotIdMcp, postBotsByBotIdMcpOpsBatchDelete, postBotsByBotIdMcpStdio, postBotsByBotIdMcpStdioByConnectionId, postBotsByBotIdMemory, postBotsByBotIdMemoryCompact, postBotsByBotIdMemoryRebuild, postBotsByBotIdMemorySearch, postBotsByBotIdSchedule, postBotsByBotIdSettings, postBotsByBotIdSubagents, postBotsByBotIdSubagentsByIdSkills, postBotsByBotIdTools, postBotsByBotIdWebMessages, postBotsByIdChannelByPlatformSend, postBotsByIdChannelByPlatformSendChat, postEmailMailgunWebhookByConfigId, postEmailProviders, postMemoryProviders, postModels, postModelsByIdTest, postProviders, postProvidersByIdImportModels, postProvidersByIdTest, postSearchProviders, postUsers, putBotsByBotIdEmailBindingsById, putBotsByBotIdMcpById, putBotsByBotIdMcpImport, putBotsByBotIdScheduleById, putBotsByBotIdSettings, putBotsByBotIdSubagentsById, putBotsByBotIdSubagentsByIdContext, putBotsByBotIdSubagentsByIdSkills, putBotsById, putBotsByIdChannelByPlatform, putBotsByIdMembers, putBotsByIdOwner, putEmailProvidersById, putMemoryProvidersById, putModelsById, putModelsModelByModelId, putProvidersById, putSearchProvidersById, putUsersById, putUsersByIdPassword, putUsersMe, putUsersMeChannelsByPlatform, putUsersMePassword } from './sdk.gen'; -export type { AccountsAccount, AccountsCreateAccountRequest, AccountsListAccountsResponse, AccountsResetPasswordRequest, AccountsUpdateAccountRequest, AccountsUpdatePasswordRequest, AccountsUpdateProfileRequest, BotsBot, BotsBotCheck, BotsBotMember, BotsCreateBotRequest, BotsListBotsResponse, BotsListChecksResponse, BotsListMembersResponse, BotsTransferBotRequest, BotsUpdateBotRequest, BotsUpsertMemberRequest, ChannelAction, ChannelAttachment, ChannelAttachmentType, ChannelChannelCapabilities, ChannelChannelConfig, ChannelChannelIdentityBinding, ChannelConfigSchema, ChannelFieldSchema, ChannelFieldType, ChannelMessage, ChannelMessageFormat, ChannelMessagePart, ChannelMessagePartType, ChannelMessageTextStyle, ChannelReplyRef, ChannelSendRequest, ChannelTargetHint, ChannelTargetSpec, ChannelThreadRef, ChannelUpdateChannelStatusRequest, ChannelUpsertChannelIdentityConfigRequest, ChannelUpsertConfigRequest, ClientOptions, DeleteBotsByBotIdContainerData, DeleteBotsByBotIdContainerError, DeleteBotsByBotIdContainerErrors, DeleteBotsByBotIdContainerResponses, DeleteBotsByBotIdContainerSkillsData, DeleteBotsByBotIdContainerSkillsError, DeleteBotsByBotIdContainerSkillsErrors, DeleteBotsByBotIdContainerSkillsResponse, DeleteBotsByBotIdContainerSkillsResponses, DeleteBotsByBotIdEmailBindingsByIdData, DeleteBotsByBotIdEmailBindingsByIdError, DeleteBotsByBotIdEmailBindingsByIdErrors, DeleteBotsByBotIdEmailBindingsByIdResponses, DeleteBotsByBotIdHeartbeatLogsData, DeleteBotsByBotIdHeartbeatLogsError, DeleteBotsByBotIdHeartbeatLogsErrors, DeleteBotsByBotIdHeartbeatLogsResponses, DeleteBotsByBotIdInboxByIdData, DeleteBotsByBotIdInboxByIdError, DeleteBotsByBotIdInboxByIdErrors, DeleteBotsByBotIdInboxByIdResponses, DeleteBotsByBotIdMcpByIdData, DeleteBotsByBotIdMcpByIdError, DeleteBotsByBotIdMcpByIdErrors, DeleteBotsByBotIdMcpByIdResponses, DeleteBotsByBotIdMemoryByIdData, DeleteBotsByBotIdMemoryByIdError, DeleteBotsByBotIdMemoryByIdErrors, DeleteBotsByBotIdMemoryByIdResponse, DeleteBotsByBotIdMemoryByIdResponses, DeleteBotsByBotIdMemoryData, DeleteBotsByBotIdMemoryError, DeleteBotsByBotIdMemoryErrors, DeleteBotsByBotIdMemoryResponse, DeleteBotsByBotIdMemoryResponses, DeleteBotsByBotIdMessagesData, DeleteBotsByBotIdMessagesError, DeleteBotsByBotIdMessagesErrors, DeleteBotsByBotIdMessagesResponses, DeleteBotsByBotIdScheduleByIdData, DeleteBotsByBotIdScheduleByIdError, DeleteBotsByBotIdScheduleByIdErrors, DeleteBotsByBotIdScheduleByIdResponses, DeleteBotsByBotIdSettingsData, DeleteBotsByBotIdSettingsError, DeleteBotsByBotIdSettingsErrors, DeleteBotsByBotIdSettingsResponses, DeleteBotsByBotIdSubagentsByIdData, DeleteBotsByBotIdSubagentsByIdError, DeleteBotsByBotIdSubagentsByIdErrors, DeleteBotsByBotIdSubagentsByIdResponses, DeleteBotsByIdChannelByPlatformData, DeleteBotsByIdChannelByPlatformError, DeleteBotsByIdChannelByPlatformErrors, DeleteBotsByIdChannelByPlatformResponses, DeleteBotsByIdData, DeleteBotsByIdError, DeleteBotsByIdErrors, DeleteBotsByIdMembersByUserIdData, DeleteBotsByIdMembersByUserIdError, DeleteBotsByIdMembersByUserIdErrors, DeleteBotsByIdMembersByUserIdResponses, DeleteBotsByIdResponse, DeleteBotsByIdResponses, DeleteEmailProvidersByIdData, DeleteEmailProvidersByIdError, DeleteEmailProvidersByIdErrors, DeleteEmailProvidersByIdResponses, DeleteMemoryProvidersByIdData, DeleteMemoryProvidersByIdError, DeleteMemoryProvidersByIdErrors, DeleteMemoryProvidersByIdResponses, DeleteModelsByIdData, DeleteModelsByIdError, DeleteModelsByIdErrors, DeleteModelsByIdResponses, DeleteModelsModelByModelIdData, DeleteModelsModelByModelIdError, DeleteModelsModelByModelIdErrors, DeleteModelsModelByModelIdResponses, DeleteProvidersByIdData, DeleteProvidersByIdError, DeleteProvidersByIdErrors, DeleteProvidersByIdResponses, DeleteSearchProvidersByIdData, DeleteSearchProvidersByIdError, DeleteSearchProvidersByIdErrors, DeleteSearchProvidersByIdResponses, EmailBindingResponse, EmailConfigSchema, EmailCreateBindingRequest, EmailCreateProviderRequest, EmailFieldSchema, EmailOutboxItemResponse, EmailProviderMeta, EmailProviderResponse, EmailUpdateBindingRequest, EmailUpdateProviderRequest, GetBotsByBotIdCliStreamData, GetBotsByBotIdCliStreamError, GetBotsByBotIdCliStreamErrors, GetBotsByBotIdCliStreamResponse, GetBotsByBotIdCliStreamResponses, GetBotsByBotIdContainerData, GetBotsByBotIdContainerError, GetBotsByBotIdContainerErrors, GetBotsByBotIdContainerFsData, GetBotsByBotIdContainerFsDownloadData, GetBotsByBotIdContainerFsDownloadError, GetBotsByBotIdContainerFsDownloadErrors, GetBotsByBotIdContainerFsDownloadResponses, GetBotsByBotIdContainerFsError, GetBotsByBotIdContainerFsErrors, GetBotsByBotIdContainerFsListData, GetBotsByBotIdContainerFsListError, GetBotsByBotIdContainerFsListErrors, GetBotsByBotIdContainerFsListResponse, GetBotsByBotIdContainerFsListResponses, GetBotsByBotIdContainerFsReadData, GetBotsByBotIdContainerFsReadError, GetBotsByBotIdContainerFsReadErrors, GetBotsByBotIdContainerFsReadResponse, GetBotsByBotIdContainerFsReadResponses, GetBotsByBotIdContainerFsResponse, GetBotsByBotIdContainerFsResponses, GetBotsByBotIdContainerResponse, GetBotsByBotIdContainerResponses, GetBotsByBotIdContainerSkillsData, GetBotsByBotIdContainerSkillsError, GetBotsByBotIdContainerSkillsErrors, GetBotsByBotIdContainerSkillsResponse, GetBotsByBotIdContainerSkillsResponses, GetBotsByBotIdContainerSnapshotsData, GetBotsByBotIdContainerSnapshotsError, GetBotsByBotIdContainerSnapshotsErrors, GetBotsByBotIdContainerSnapshotsResponse, GetBotsByBotIdContainerSnapshotsResponses, GetBotsByBotIdEmailBindingsData, GetBotsByBotIdEmailBindingsError, GetBotsByBotIdEmailBindingsErrors, GetBotsByBotIdEmailBindingsResponse, GetBotsByBotIdEmailBindingsResponses, GetBotsByBotIdEmailOutboxByIdData, GetBotsByBotIdEmailOutboxByIdError, GetBotsByBotIdEmailOutboxByIdErrors, GetBotsByBotIdEmailOutboxByIdResponse, GetBotsByBotIdEmailOutboxByIdResponses, GetBotsByBotIdEmailOutboxData, GetBotsByBotIdEmailOutboxError, GetBotsByBotIdEmailOutboxErrors, GetBotsByBotIdEmailOutboxResponse, GetBotsByBotIdEmailOutboxResponses, GetBotsByBotIdHeartbeatLogsData, GetBotsByBotIdHeartbeatLogsError, GetBotsByBotIdHeartbeatLogsErrors, GetBotsByBotIdHeartbeatLogsResponse, GetBotsByBotIdHeartbeatLogsResponses, GetBotsByBotIdInboxByIdData, GetBotsByBotIdInboxByIdError, GetBotsByBotIdInboxByIdErrors, GetBotsByBotIdInboxByIdResponse, GetBotsByBotIdInboxByIdResponses, GetBotsByBotIdInboxCountData, GetBotsByBotIdInboxCountError, GetBotsByBotIdInboxCountErrors, GetBotsByBotIdInboxCountResponse, GetBotsByBotIdInboxCountResponses, GetBotsByBotIdInboxData, GetBotsByBotIdInboxError, GetBotsByBotIdInboxErrors, GetBotsByBotIdInboxResponse, GetBotsByBotIdInboxResponses, GetBotsByBotIdMcpByIdData, GetBotsByBotIdMcpByIdError, GetBotsByBotIdMcpByIdErrors, GetBotsByBotIdMcpByIdResponse, GetBotsByBotIdMcpByIdResponses, GetBotsByBotIdMcpData, GetBotsByBotIdMcpError, GetBotsByBotIdMcpErrors, GetBotsByBotIdMcpExportData, GetBotsByBotIdMcpExportError, GetBotsByBotIdMcpExportErrors, GetBotsByBotIdMcpExportResponse, GetBotsByBotIdMcpExportResponses, GetBotsByBotIdMcpResponse, GetBotsByBotIdMcpResponses, GetBotsByBotIdMemoryData, GetBotsByBotIdMemoryError, GetBotsByBotIdMemoryErrors, GetBotsByBotIdMemoryResponse, GetBotsByBotIdMemoryResponses, GetBotsByBotIdMemoryUsageData, GetBotsByBotIdMemoryUsageError, GetBotsByBotIdMemoryUsageErrors, GetBotsByBotIdMemoryUsageResponse, GetBotsByBotIdMemoryUsageResponses, GetBotsByBotIdMessagesData, GetBotsByBotIdMessagesError, GetBotsByBotIdMessagesErrors, GetBotsByBotIdMessagesResponse, GetBotsByBotIdMessagesResponses, GetBotsByBotIdScheduleByIdData, GetBotsByBotIdScheduleByIdError, GetBotsByBotIdScheduleByIdErrors, GetBotsByBotIdScheduleByIdResponse, GetBotsByBotIdScheduleByIdResponses, GetBotsByBotIdScheduleData, GetBotsByBotIdScheduleError, GetBotsByBotIdScheduleErrors, GetBotsByBotIdScheduleResponse, GetBotsByBotIdScheduleResponses, GetBotsByBotIdSettingsData, GetBotsByBotIdSettingsError, GetBotsByBotIdSettingsErrors, GetBotsByBotIdSettingsResponse, GetBotsByBotIdSettingsResponses, GetBotsByBotIdSubagentsByIdContextData, GetBotsByBotIdSubagentsByIdContextError, GetBotsByBotIdSubagentsByIdContextErrors, GetBotsByBotIdSubagentsByIdContextResponse, GetBotsByBotIdSubagentsByIdContextResponses, GetBotsByBotIdSubagentsByIdData, GetBotsByBotIdSubagentsByIdError, GetBotsByBotIdSubagentsByIdErrors, GetBotsByBotIdSubagentsByIdResponse, GetBotsByBotIdSubagentsByIdResponses, GetBotsByBotIdSubagentsByIdSkillsData, GetBotsByBotIdSubagentsByIdSkillsError, GetBotsByBotIdSubagentsByIdSkillsErrors, GetBotsByBotIdSubagentsByIdSkillsResponse, GetBotsByBotIdSubagentsByIdSkillsResponses, GetBotsByBotIdSubagentsData, GetBotsByBotIdSubagentsError, GetBotsByBotIdSubagentsErrors, GetBotsByBotIdSubagentsResponse, GetBotsByBotIdSubagentsResponses, GetBotsByBotIdTokenUsageData, GetBotsByBotIdTokenUsageError, GetBotsByBotIdTokenUsageErrors, GetBotsByBotIdTokenUsageResponse, GetBotsByBotIdTokenUsageResponses, GetBotsByBotIdWebStreamData, GetBotsByBotIdWebStreamError, GetBotsByBotIdWebStreamErrors, GetBotsByBotIdWebStreamResponse, GetBotsByBotIdWebStreamResponses, GetBotsByIdChannelByPlatformData, GetBotsByIdChannelByPlatformError, GetBotsByIdChannelByPlatformErrors, GetBotsByIdChannelByPlatformResponse, GetBotsByIdChannelByPlatformResponses, GetBotsByIdChecksData, GetBotsByIdChecksError, GetBotsByIdChecksErrors, GetBotsByIdChecksResponse, GetBotsByIdChecksResponses, GetBotsByIdData, GetBotsByIdError, GetBotsByIdErrors, GetBotsByIdMembersData, GetBotsByIdMembersError, GetBotsByIdMembersErrors, GetBotsByIdMembersResponse, GetBotsByIdMembersResponses, GetBotsByIdResponse, GetBotsByIdResponses, GetBotsData, GetBotsError, GetBotsErrors, GetBotsResponse, GetBotsResponses, GetChannelsByPlatformData, GetChannelsByPlatformError, GetChannelsByPlatformErrors, GetChannelsByPlatformResponse, GetChannelsByPlatformResponses, GetChannelsData, GetChannelsError, GetChannelsErrors, GetChannelsResponse, GetChannelsResponses, GetEmailProvidersByIdData, GetEmailProvidersByIdError, GetEmailProvidersByIdErrors, GetEmailProvidersByIdResponse, GetEmailProvidersByIdResponses, GetEmailProvidersData, GetEmailProvidersError, GetEmailProvidersErrors, GetEmailProvidersMetaData, GetEmailProvidersMetaResponse, GetEmailProvidersMetaResponses, GetEmailProvidersResponse, GetEmailProvidersResponses, GetMemoryProvidersByIdData, GetMemoryProvidersByIdError, GetMemoryProvidersByIdErrors, GetMemoryProvidersByIdResponse, GetMemoryProvidersByIdResponses, GetMemoryProvidersData, GetMemoryProvidersError, GetMemoryProvidersErrors, GetMemoryProvidersMetaData, GetMemoryProvidersMetaResponse, GetMemoryProvidersMetaResponses, GetMemoryProvidersResponse, GetMemoryProvidersResponses, GetModelsByIdData, GetModelsByIdError, GetModelsByIdErrors, GetModelsByIdResponse, GetModelsByIdResponses, GetModelsCountData, GetModelsCountError, GetModelsCountErrors, GetModelsCountResponse, GetModelsCountResponses, GetModelsData, GetModelsError, GetModelsErrors, GetModelsModelByModelIdData, GetModelsModelByModelIdError, GetModelsModelByModelIdErrors, GetModelsModelByModelIdResponse, GetModelsModelByModelIdResponses, GetModelsResponse, GetModelsResponses, GetPingData, GetPingResponse, GetPingResponses, GetProvidersByIdData, GetProvidersByIdError, GetProvidersByIdErrors, GetProvidersByIdModelsData, GetProvidersByIdModelsError, GetProvidersByIdModelsErrors, GetProvidersByIdModelsResponse, GetProvidersByIdModelsResponses, GetProvidersByIdResponse, GetProvidersByIdResponses, GetProvidersCountData, GetProvidersCountError, GetProvidersCountErrors, GetProvidersCountResponse, GetProvidersCountResponses, GetProvidersData, GetProvidersError, GetProvidersErrors, GetProvidersNameByNameData, GetProvidersNameByNameError, GetProvidersNameByNameErrors, GetProvidersNameByNameResponse, GetProvidersNameByNameResponses, GetProvidersResponse, GetProvidersResponses, GetSearchProvidersByIdData, GetSearchProvidersByIdError, GetSearchProvidersByIdErrors, GetSearchProvidersByIdResponse, GetSearchProvidersByIdResponses, GetSearchProvidersData, GetSearchProvidersError, GetSearchProvidersErrors, GetSearchProvidersMetaData, GetSearchProvidersMetaResponse, GetSearchProvidersMetaResponses, GetSearchProvidersResponse, GetSearchProvidersResponses, GetUsersByIdData, GetUsersByIdError, GetUsersByIdErrors, GetUsersByIdResponse, GetUsersByIdResponses, GetUsersData, GetUsersError, GetUsersErrors, GetUsersMeChannelsByPlatformData, GetUsersMeChannelsByPlatformError, GetUsersMeChannelsByPlatformErrors, GetUsersMeChannelsByPlatformResponse, GetUsersMeChannelsByPlatformResponses, GetUsersMeData, GetUsersMeError, GetUsersMeErrors, GetUsersMeIdentitiesData, GetUsersMeIdentitiesError, GetUsersMeIdentitiesErrors, GetUsersMeIdentitiesResponse, GetUsersMeIdentitiesResponses, GetUsersMeResponse, GetUsersMeResponses, GetUsersResponse, GetUsersResponses, GithubComMemohaiMemohInternalFsFileInfo, GithubComMemohaiMemohInternalMcpConnection, HandlersBatchDeleteRequest, HandlersChannelMeta, HandlersCreateContainerRequest, HandlersCreateContainerResponse, HandlersCreateSnapshotRequest, HandlersCreateSnapshotResponse, HandlersDailyTokenUsage, HandlersErrorResponse, HandlersFsDeleteRequest, HandlersFsFileInfo, HandlersFsListResponse, HandlersFsMkdirRequest, HandlersFsOpResponse, HandlersFsReadResponse, HandlersFsRenameRequest, HandlersFsUploadResponse, HandlersFsWriteRequest, HandlersGetContainerResponse, HandlersListMyIdentitiesResponse, HandlersListSnapshotsResponse, HandlersLocalChannelMessageRequest, HandlersLoginRequest, HandlersLoginResponse, HandlersMarkReadRequest, HandlersMcpStdioRequest, HandlersMcpStdioResponse, HandlersMemoryAddPayload, HandlersMemoryCompactPayload, HandlersMemoryDeletePayload, HandlersMemorySearchPayload, HandlersModelTokenUsage, HandlersPingResponse, HandlersRefreshResponse, HandlersSkillItem, HandlersSkillsDeleteRequest, HandlersSkillsOpResponse, HandlersSkillsResponse, HandlersSkillsUpsertRequest, HandlersSnapshotInfo, HandlersTokenUsageResponse, HeartbeatListLogsResponse, HeartbeatLog, IdentitiesChannelIdentity, InboxCountResult, InboxCreateRequest, InboxItem, McpExportResponse, McpImportRequest, McpListResponse, McpMcpServerEntry, McpUpsertRequest, MessageMessage, MessageMessageAsset, ModelsAddRequest, ModelsAddResponse, ModelsClientType, ModelsCountResponse, ModelsGetResponse, ModelsModelType, ModelsTestResponse, ModelsTestStatus, ModelsUpdateRequest, PatchBotsByIdChannelByPlatformStatusData, PatchBotsByIdChannelByPlatformStatusError, PatchBotsByIdChannelByPlatformStatusErrors, PatchBotsByIdChannelByPlatformStatusResponse, PatchBotsByIdChannelByPlatformStatusResponses, PostAuthLoginData, PostAuthLoginError, PostAuthLoginErrors, PostAuthLoginResponse, PostAuthLoginResponses, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshErrors, PostAuthRefreshResponse, PostAuthRefreshResponses, PostBotsByBotIdCliMessagesData, PostBotsByBotIdCliMessagesError, PostBotsByBotIdCliMessagesErrors, PostBotsByBotIdCliMessagesResponse, PostBotsByBotIdCliMessagesResponses, PostBotsByBotIdContainerData, PostBotsByBotIdContainerError, PostBotsByBotIdContainerErrors, PostBotsByBotIdContainerFsDeleteData, PostBotsByBotIdContainerFsDeleteError, PostBotsByBotIdContainerFsDeleteErrors, PostBotsByBotIdContainerFsDeleteResponse, PostBotsByBotIdContainerFsDeleteResponses, PostBotsByBotIdContainerFsMkdirData, PostBotsByBotIdContainerFsMkdirError, PostBotsByBotIdContainerFsMkdirErrors, PostBotsByBotIdContainerFsMkdirResponse, PostBotsByBotIdContainerFsMkdirResponses, PostBotsByBotIdContainerFsRenameData, PostBotsByBotIdContainerFsRenameError, PostBotsByBotIdContainerFsRenameErrors, PostBotsByBotIdContainerFsRenameResponse, PostBotsByBotIdContainerFsRenameResponses, PostBotsByBotIdContainerFsUploadData, PostBotsByBotIdContainerFsUploadError, PostBotsByBotIdContainerFsUploadErrors, PostBotsByBotIdContainerFsUploadResponse, PostBotsByBotIdContainerFsUploadResponses, PostBotsByBotIdContainerFsWriteData, PostBotsByBotIdContainerFsWriteError, PostBotsByBotIdContainerFsWriteErrors, PostBotsByBotIdContainerFsWriteResponse, PostBotsByBotIdContainerFsWriteResponses, PostBotsByBotIdContainerResponse, PostBotsByBotIdContainerResponses, PostBotsByBotIdContainerSkillsData, PostBotsByBotIdContainerSkillsError, PostBotsByBotIdContainerSkillsErrors, PostBotsByBotIdContainerSkillsResponse, PostBotsByBotIdContainerSkillsResponses, PostBotsByBotIdContainerSnapshotsData, PostBotsByBotIdContainerSnapshotsError, PostBotsByBotIdContainerSnapshotsErrors, PostBotsByBotIdContainerSnapshotsResponse, PostBotsByBotIdContainerSnapshotsResponses, PostBotsByBotIdContainerStartData, PostBotsByBotIdContainerStartError, PostBotsByBotIdContainerStartErrors, PostBotsByBotIdContainerStartResponse, PostBotsByBotIdContainerStartResponses, PostBotsByBotIdContainerStopData, PostBotsByBotIdContainerStopError, PostBotsByBotIdContainerStopErrors, PostBotsByBotIdContainerStopResponse, PostBotsByBotIdContainerStopResponses, PostBotsByBotIdEmailBindingsData, PostBotsByBotIdEmailBindingsError, PostBotsByBotIdEmailBindingsErrors, PostBotsByBotIdEmailBindingsResponse, PostBotsByBotIdEmailBindingsResponses, PostBotsByBotIdInboxData, PostBotsByBotIdInboxError, PostBotsByBotIdInboxErrors, PostBotsByBotIdInboxMarkReadData, PostBotsByBotIdInboxMarkReadError, PostBotsByBotIdInboxMarkReadErrors, PostBotsByBotIdInboxMarkReadResponses, PostBotsByBotIdInboxResponse, PostBotsByBotIdInboxResponses, PostBotsByBotIdMcpData, PostBotsByBotIdMcpError, PostBotsByBotIdMcpErrors, PostBotsByBotIdMcpOpsBatchDeleteData, PostBotsByBotIdMcpOpsBatchDeleteError, PostBotsByBotIdMcpOpsBatchDeleteErrors, PostBotsByBotIdMcpOpsBatchDeleteResponses, PostBotsByBotIdMcpResponse, PostBotsByBotIdMcpResponses, PostBotsByBotIdMcpStdioByConnectionIdData, PostBotsByBotIdMcpStdioByConnectionIdError, PostBotsByBotIdMcpStdioByConnectionIdErrors, PostBotsByBotIdMcpStdioByConnectionIdResponse, PostBotsByBotIdMcpStdioByConnectionIdResponses, PostBotsByBotIdMcpStdioData, PostBotsByBotIdMcpStdioError, PostBotsByBotIdMcpStdioErrors, PostBotsByBotIdMcpStdioResponse, PostBotsByBotIdMcpStdioResponses, PostBotsByBotIdMemoryCompactData, PostBotsByBotIdMemoryCompactError, PostBotsByBotIdMemoryCompactErrors, PostBotsByBotIdMemoryCompactResponse, PostBotsByBotIdMemoryCompactResponses, PostBotsByBotIdMemoryData, PostBotsByBotIdMemoryError, PostBotsByBotIdMemoryErrors, PostBotsByBotIdMemoryRebuildData, PostBotsByBotIdMemoryRebuildError, PostBotsByBotIdMemoryRebuildErrors, PostBotsByBotIdMemoryRebuildResponse, PostBotsByBotIdMemoryRebuildResponses, PostBotsByBotIdMemoryResponse, PostBotsByBotIdMemoryResponses, PostBotsByBotIdMemorySearchData, PostBotsByBotIdMemorySearchError, PostBotsByBotIdMemorySearchErrors, PostBotsByBotIdMemorySearchResponse, PostBotsByBotIdMemorySearchResponses, PostBotsByBotIdScheduleData, PostBotsByBotIdScheduleError, PostBotsByBotIdScheduleErrors, PostBotsByBotIdScheduleResponse, PostBotsByBotIdScheduleResponses, PostBotsByBotIdSettingsData, PostBotsByBotIdSettingsError, PostBotsByBotIdSettingsErrors, PostBotsByBotIdSettingsResponse, PostBotsByBotIdSettingsResponses, PostBotsByBotIdSubagentsByIdSkillsData, PostBotsByBotIdSubagentsByIdSkillsError, PostBotsByBotIdSubagentsByIdSkillsErrors, PostBotsByBotIdSubagentsByIdSkillsResponse, PostBotsByBotIdSubagentsByIdSkillsResponses, PostBotsByBotIdSubagentsData, PostBotsByBotIdSubagentsError, PostBotsByBotIdSubagentsErrors, PostBotsByBotIdSubagentsResponse, PostBotsByBotIdSubagentsResponses, PostBotsByBotIdToolsData, PostBotsByBotIdToolsError, PostBotsByBotIdToolsErrors, PostBotsByBotIdToolsResponse, PostBotsByBotIdToolsResponses, PostBotsByBotIdWebMessagesData, PostBotsByBotIdWebMessagesError, PostBotsByBotIdWebMessagesErrors, PostBotsByBotIdWebMessagesResponse, PostBotsByBotIdWebMessagesResponses, PostBotsByIdChannelByPlatformSendChatData, PostBotsByIdChannelByPlatformSendChatError, PostBotsByIdChannelByPlatformSendChatErrors, PostBotsByIdChannelByPlatformSendChatResponse, PostBotsByIdChannelByPlatformSendChatResponses, PostBotsByIdChannelByPlatformSendData, PostBotsByIdChannelByPlatformSendError, PostBotsByIdChannelByPlatformSendErrors, PostBotsByIdChannelByPlatformSendResponse, PostBotsByIdChannelByPlatformSendResponses, PostBotsData, PostBotsError, PostBotsErrors, PostBotsResponse, PostBotsResponses, PostEmailMailgunWebhookByConfigIdData, PostEmailMailgunWebhookByConfigIdError, PostEmailMailgunWebhookByConfigIdErrors, PostEmailMailgunWebhookByConfigIdResponse, PostEmailMailgunWebhookByConfigIdResponses, PostEmailProvidersData, PostEmailProvidersError, PostEmailProvidersErrors, PostEmailProvidersResponse, PostEmailProvidersResponses, PostMemoryProvidersData, PostMemoryProvidersError, PostMemoryProvidersErrors, PostMemoryProvidersResponse, PostMemoryProvidersResponses, PostModelsByIdTestData, PostModelsByIdTestError, PostModelsByIdTestErrors, PostModelsByIdTestResponse, PostModelsByIdTestResponses, PostModelsData, PostModelsError, PostModelsErrors, PostModelsResponse, PostModelsResponses, PostProvidersByIdImportModelsData, PostProvidersByIdImportModelsError, PostProvidersByIdImportModelsErrors, PostProvidersByIdImportModelsResponse, PostProvidersByIdImportModelsResponses, PostProvidersByIdTestData, PostProvidersByIdTestError, PostProvidersByIdTestErrors, PostProvidersByIdTestResponse, PostProvidersByIdTestResponses, PostProvidersData, PostProvidersError, PostProvidersErrors, PostProvidersResponse, PostProvidersResponses, PostSearchProvidersData, PostSearchProvidersError, PostSearchProvidersErrors, PostSearchProvidersResponse, PostSearchProvidersResponses, PostUsersData, PostUsersError, PostUsersErrors, PostUsersResponse, PostUsersResponses, ProviderCdfPoint, ProviderCompactResult, ProviderDeleteResponse, ProviderMemoryItem, ProviderMessage, ProviderProviderConfigSchema, ProviderProviderCreateRequest, ProviderProviderFieldSchema, ProviderProviderGetResponse, ProviderProviderMeta, ProviderProviderType, ProviderProviderUpdateRequest, ProviderRebuildResult, ProvidersCountResponse, ProvidersCreateRequest, ProviderSearchResponse, ProvidersGetResponse, ProvidersImportModelsRequest, ProvidersImportModelsResponse, ProvidersTestResponse, ProvidersUpdateRequest, ProviderTopKBucket, ProviderUsageResponse, PutBotsByBotIdEmailBindingsByIdData, PutBotsByBotIdEmailBindingsByIdError, PutBotsByBotIdEmailBindingsByIdErrors, PutBotsByBotIdEmailBindingsByIdResponse, PutBotsByBotIdEmailBindingsByIdResponses, PutBotsByBotIdMcpByIdData, PutBotsByBotIdMcpByIdError, PutBotsByBotIdMcpByIdErrors, PutBotsByBotIdMcpByIdResponse, PutBotsByBotIdMcpByIdResponses, PutBotsByBotIdMcpImportData, PutBotsByBotIdMcpImportError, PutBotsByBotIdMcpImportErrors, PutBotsByBotIdMcpImportResponse, PutBotsByBotIdMcpImportResponses, PutBotsByBotIdScheduleByIdData, PutBotsByBotIdScheduleByIdError, PutBotsByBotIdScheduleByIdErrors, PutBotsByBotIdScheduleByIdResponse, PutBotsByBotIdScheduleByIdResponses, PutBotsByBotIdSettingsData, PutBotsByBotIdSettingsError, PutBotsByBotIdSettingsErrors, PutBotsByBotIdSettingsResponse, PutBotsByBotIdSettingsResponses, PutBotsByBotIdSubagentsByIdContextData, PutBotsByBotIdSubagentsByIdContextError, PutBotsByBotIdSubagentsByIdContextErrors, PutBotsByBotIdSubagentsByIdContextResponse, PutBotsByBotIdSubagentsByIdContextResponses, PutBotsByBotIdSubagentsByIdData, PutBotsByBotIdSubagentsByIdError, PutBotsByBotIdSubagentsByIdErrors, PutBotsByBotIdSubagentsByIdResponse, PutBotsByBotIdSubagentsByIdResponses, PutBotsByBotIdSubagentsByIdSkillsData, PutBotsByBotIdSubagentsByIdSkillsError, PutBotsByBotIdSubagentsByIdSkillsErrors, PutBotsByBotIdSubagentsByIdSkillsResponse, PutBotsByBotIdSubagentsByIdSkillsResponses, PutBotsByIdChannelByPlatformData, PutBotsByIdChannelByPlatformError, PutBotsByIdChannelByPlatformErrors, PutBotsByIdChannelByPlatformResponse, PutBotsByIdChannelByPlatformResponses, PutBotsByIdData, PutBotsByIdError, PutBotsByIdErrors, PutBotsByIdMembersData, PutBotsByIdMembersError, PutBotsByIdMembersErrors, PutBotsByIdMembersResponse, PutBotsByIdMembersResponses, PutBotsByIdOwnerData, PutBotsByIdOwnerError, PutBotsByIdOwnerErrors, PutBotsByIdOwnerResponse, PutBotsByIdOwnerResponses, PutBotsByIdResponse, PutBotsByIdResponses, PutEmailProvidersByIdData, PutEmailProvidersByIdError, PutEmailProvidersByIdErrors, PutEmailProvidersByIdResponse, PutEmailProvidersByIdResponses, PutMemoryProvidersByIdData, PutMemoryProvidersByIdError, PutMemoryProvidersByIdErrors, PutMemoryProvidersByIdResponse, PutMemoryProvidersByIdResponses, PutModelsByIdData, PutModelsByIdError, PutModelsByIdErrors, PutModelsByIdResponse, PutModelsByIdResponses, PutModelsModelByModelIdData, PutModelsModelByModelIdError, PutModelsModelByModelIdErrors, PutModelsModelByModelIdResponse, PutModelsModelByModelIdResponses, PutProvidersByIdData, PutProvidersByIdError, PutProvidersByIdErrors, PutProvidersByIdResponse, PutProvidersByIdResponses, PutSearchProvidersByIdData, PutSearchProvidersByIdError, PutSearchProvidersByIdErrors, PutSearchProvidersByIdResponse, PutSearchProvidersByIdResponses, PutUsersByIdData, PutUsersByIdError, PutUsersByIdErrors, PutUsersByIdPasswordData, PutUsersByIdPasswordError, PutUsersByIdPasswordErrors, PutUsersByIdPasswordResponses, PutUsersByIdResponse, PutUsersByIdResponses, PutUsersMeChannelsByPlatformData, PutUsersMeChannelsByPlatformError, PutUsersMeChannelsByPlatformErrors, PutUsersMeChannelsByPlatformResponse, PutUsersMeChannelsByPlatformResponses, PutUsersMeData, PutUsersMeError, PutUsersMeErrors, PutUsersMePasswordData, PutUsersMePasswordError, PutUsersMePasswordErrors, PutUsersMePasswordResponses, PutUsersMeResponse, PutUsersMeResponses, ScheduleCreateRequest, ScheduleListResponse, ScheduleNullableInt, ScheduleSchedule, ScheduleUpdateRequest, SearchprovidersCreateRequest, SearchprovidersGetResponse, SearchprovidersProviderConfigSchema, SearchprovidersProviderFieldSchema, SearchprovidersProviderMeta, SearchprovidersProviderName, SearchprovidersUpdateRequest, SettingsSettings, SettingsUpsertRequest, SubagentAddSkillsRequest, SubagentContextResponse, SubagentCreateRequest, SubagentListResponse, SubagentSkillsResponse, SubagentSubagent, SubagentUpdateContextRequest, SubagentUpdateRequest, SubagentUpdateSkillsRequest } from './types.gen'; +export { deleteBotsByBotIdContainer, deleteBotsByBotIdContainerSkills, deleteBotsByBotIdEmailBindingsById, deleteBotsByBotIdHeartbeatLogs, deleteBotsByBotIdInboxById, deleteBotsByBotIdMcpById, deleteBotsByBotIdMcpByIdOauthToken, deleteBotsByBotIdMemory, deleteBotsByBotIdMemoryById, deleteBotsByBotIdMessages, deleteBotsByBotIdScheduleById, deleteBotsByBotIdSettings, deleteBotsByBotIdSubagentsById, deleteBotsById, deleteBotsByIdChannelByPlatform, deleteBotsByIdMembersByUserId, deleteEmailProvidersById, deleteMemoryProvidersById, deleteModelsById, deleteModelsModelByModelId, deleteProvidersById, deleteSearchProvidersById, getApiOauthMcpCallback, getBots, getBotsByBotIdCliStream, getBotsByBotIdContainer, getBotsByBotIdContainerFs, getBotsByBotIdContainerFsDownload, getBotsByBotIdContainerFsList, getBotsByBotIdContainerFsRead, getBotsByBotIdContainerSkills, getBotsByBotIdContainerSnapshots, getBotsByBotIdEmailBindings, getBotsByBotIdEmailOutbox, getBotsByBotIdEmailOutboxById, getBotsByBotIdHeartbeatLogs, getBotsByBotIdInbox, getBotsByBotIdInboxById, getBotsByBotIdInboxCount, getBotsByBotIdMcp, getBotsByBotIdMcpById, getBotsByBotIdMcpByIdOauthStatus, getBotsByBotIdMcpExport, getBotsByBotIdMemory, getBotsByBotIdMemoryUsage, getBotsByBotIdMessages, getBotsByBotIdSchedule, getBotsByBotIdScheduleById, getBotsByBotIdSettings, getBotsByBotIdSubagents, getBotsByBotIdSubagentsById, getBotsByBotIdSubagentsByIdContext, getBotsByBotIdSubagentsByIdSkills, getBotsByBotIdTokenUsage, getBotsByBotIdWebStream, getBotsById, getBotsByIdChannelByPlatform, getBotsByIdChecks, getBotsByIdMembers, getChannels, getChannelsByPlatform, getEmailProviders, getEmailProvidersById, getEmailProvidersMeta, getMemoryProviders, getMemoryProvidersById, getMemoryProvidersMeta, getModels, getModelsById, getModelsCount, getModelsModelByModelId, getPing, getProviders, getProvidersById, getProvidersByIdModels, getProvidersCount, getProvidersNameByName, getSearchProviders, getSearchProvidersById, getSearchProvidersMeta, getUsers, getUsersById, getUsersMe, getUsersMeChannelsByPlatform, getUsersMeIdentities, type Options, patchBotsByIdChannelByPlatformStatus, postAuthLogin, postAuthRefresh, postBots, postBotsByBotIdCliMessages, postBotsByBotIdContainer, postBotsByBotIdContainerFsDelete, postBotsByBotIdContainerFsMkdir, postBotsByBotIdContainerFsRename, postBotsByBotIdContainerFsUpload, postBotsByBotIdContainerFsWrite, postBotsByBotIdContainerSkills, postBotsByBotIdContainerSnapshots, postBotsByBotIdContainerStart, postBotsByBotIdContainerStop, postBotsByBotIdEmailBindings, postBotsByBotIdInbox, postBotsByBotIdInboxMarkRead, postBotsByBotIdMcp, postBotsByBotIdMcpByIdOauthAuthorize, postBotsByBotIdMcpByIdOauthDiscover, postBotsByBotIdMcpByIdProbe, postBotsByBotIdMcpOpsBatchDelete, postBotsByBotIdMcpStdio, postBotsByBotIdMcpStdioByConnectionId, postBotsByBotIdMemory, postBotsByBotIdMemoryCompact, postBotsByBotIdMemoryRebuild, postBotsByBotIdMemorySearch, postBotsByBotIdSchedule, postBotsByBotIdSettings, postBotsByBotIdSubagents, postBotsByBotIdSubagentsByIdSkills, postBotsByBotIdTools, postBotsByBotIdWebMessages, postBotsByIdChannelByPlatformSend, postBotsByIdChannelByPlatformSendChat, postEmailMailgunWebhookByConfigId, postEmailProviders, postMemoryProviders, postModels, postModelsByIdTest, postProviders, postProvidersByIdImportModels, postProvidersByIdTest, postSearchProviders, postUsers, putBotsByBotIdEmailBindingsById, putBotsByBotIdMcpById, putBotsByBotIdMcpImport, putBotsByBotIdScheduleById, putBotsByBotIdSettings, putBotsByBotIdSubagentsById, putBotsByBotIdSubagentsByIdContext, putBotsByBotIdSubagentsByIdSkills, putBotsById, putBotsByIdChannelByPlatform, putBotsByIdMembers, putBotsByIdOwner, putEmailProvidersById, putMemoryProvidersById, putModelsById, putModelsModelByModelId, putProvidersById, putSearchProvidersById, putUsersById, putUsersByIdPassword, putUsersMe, putUsersMeChannelsByPlatform, putUsersMePassword } from './sdk.gen'; +export type { AccountsAccount, AccountsCreateAccountRequest, AccountsListAccountsResponse, AccountsResetPasswordRequest, AccountsUpdateAccountRequest, AccountsUpdatePasswordRequest, AccountsUpdateProfileRequest, BotsBot, BotsBotCheck, BotsBotMember, BotsCreateBotRequest, BotsListBotsResponse, BotsListChecksResponse, BotsListMembersResponse, BotsTransferBotRequest, BotsUpdateBotRequest, BotsUpsertMemberRequest, ChannelAction, ChannelAttachment, ChannelAttachmentType, ChannelChannelCapabilities, ChannelChannelConfig, ChannelChannelIdentityBinding, ChannelConfigSchema, ChannelFieldSchema, ChannelFieldType, ChannelMessage, ChannelMessageFormat, ChannelMessagePart, ChannelMessagePartType, ChannelMessageTextStyle, ChannelReplyRef, ChannelSendRequest, ChannelTargetHint, ChannelTargetSpec, ChannelThreadRef, ChannelUpdateChannelStatusRequest, ChannelUpsertChannelIdentityConfigRequest, ChannelUpsertConfigRequest, ClientOptions, DeleteBotsByBotIdContainerData, DeleteBotsByBotIdContainerError, DeleteBotsByBotIdContainerErrors, DeleteBotsByBotIdContainerResponses, DeleteBotsByBotIdContainerSkillsData, DeleteBotsByBotIdContainerSkillsError, DeleteBotsByBotIdContainerSkillsErrors, DeleteBotsByBotIdContainerSkillsResponse, DeleteBotsByBotIdContainerSkillsResponses, DeleteBotsByBotIdEmailBindingsByIdData, DeleteBotsByBotIdEmailBindingsByIdError, DeleteBotsByBotIdEmailBindingsByIdErrors, DeleteBotsByBotIdEmailBindingsByIdResponses, DeleteBotsByBotIdHeartbeatLogsData, DeleteBotsByBotIdHeartbeatLogsError, DeleteBotsByBotIdHeartbeatLogsErrors, DeleteBotsByBotIdHeartbeatLogsResponses, DeleteBotsByBotIdInboxByIdData, DeleteBotsByBotIdInboxByIdError, DeleteBotsByBotIdInboxByIdErrors, DeleteBotsByBotIdInboxByIdResponses, DeleteBotsByBotIdMcpByIdData, DeleteBotsByBotIdMcpByIdError, DeleteBotsByBotIdMcpByIdErrors, DeleteBotsByBotIdMcpByIdOauthTokenData, DeleteBotsByBotIdMcpByIdOauthTokenError, DeleteBotsByBotIdMcpByIdOauthTokenErrors, DeleteBotsByBotIdMcpByIdOauthTokenResponses, DeleteBotsByBotIdMcpByIdResponses, DeleteBotsByBotIdMemoryByIdData, DeleteBotsByBotIdMemoryByIdError, DeleteBotsByBotIdMemoryByIdErrors, DeleteBotsByBotIdMemoryByIdResponse, DeleteBotsByBotIdMemoryByIdResponses, DeleteBotsByBotIdMemoryData, DeleteBotsByBotIdMemoryError, DeleteBotsByBotIdMemoryErrors, DeleteBotsByBotIdMemoryResponse, DeleteBotsByBotIdMemoryResponses, DeleteBotsByBotIdMessagesData, DeleteBotsByBotIdMessagesError, DeleteBotsByBotIdMessagesErrors, DeleteBotsByBotIdMessagesResponses, DeleteBotsByBotIdScheduleByIdData, DeleteBotsByBotIdScheduleByIdError, DeleteBotsByBotIdScheduleByIdErrors, DeleteBotsByBotIdScheduleByIdResponses, DeleteBotsByBotIdSettingsData, DeleteBotsByBotIdSettingsError, DeleteBotsByBotIdSettingsErrors, DeleteBotsByBotIdSettingsResponses, DeleteBotsByBotIdSubagentsByIdData, DeleteBotsByBotIdSubagentsByIdError, DeleteBotsByBotIdSubagentsByIdErrors, DeleteBotsByBotIdSubagentsByIdResponses, DeleteBotsByIdChannelByPlatformData, DeleteBotsByIdChannelByPlatformError, DeleteBotsByIdChannelByPlatformErrors, DeleteBotsByIdChannelByPlatformResponses, DeleteBotsByIdData, DeleteBotsByIdError, DeleteBotsByIdErrors, DeleteBotsByIdMembersByUserIdData, DeleteBotsByIdMembersByUserIdError, DeleteBotsByIdMembersByUserIdErrors, DeleteBotsByIdMembersByUserIdResponses, DeleteBotsByIdResponse, DeleteBotsByIdResponses, DeleteEmailProvidersByIdData, DeleteEmailProvidersByIdError, DeleteEmailProvidersByIdErrors, DeleteEmailProvidersByIdResponses, DeleteMemoryProvidersByIdData, DeleteMemoryProvidersByIdError, DeleteMemoryProvidersByIdErrors, DeleteMemoryProvidersByIdResponses, DeleteModelsByIdData, DeleteModelsByIdError, DeleteModelsByIdErrors, DeleteModelsByIdResponses, DeleteModelsModelByModelIdData, DeleteModelsModelByModelIdError, DeleteModelsModelByModelIdErrors, DeleteModelsModelByModelIdResponses, DeleteProvidersByIdData, DeleteProvidersByIdError, DeleteProvidersByIdErrors, DeleteProvidersByIdResponses, DeleteSearchProvidersByIdData, DeleteSearchProvidersByIdError, DeleteSearchProvidersByIdErrors, DeleteSearchProvidersByIdResponses, EmailBindingResponse, EmailConfigSchema, EmailCreateBindingRequest, EmailCreateProviderRequest, EmailFieldSchema, EmailOutboxItemResponse, EmailProviderMeta, EmailProviderResponse, EmailUpdateBindingRequest, EmailUpdateProviderRequest, GetApiOauthMcpCallbackData, GetApiOauthMcpCallbackError, GetApiOauthMcpCallbackErrors, GetApiOauthMcpCallbackResponse, GetApiOauthMcpCallbackResponses, GetBotsByBotIdCliStreamData, GetBotsByBotIdCliStreamError, GetBotsByBotIdCliStreamErrors, GetBotsByBotIdCliStreamResponse, GetBotsByBotIdCliStreamResponses, GetBotsByBotIdContainerData, GetBotsByBotIdContainerError, GetBotsByBotIdContainerErrors, GetBotsByBotIdContainerFsData, GetBotsByBotIdContainerFsDownloadData, GetBotsByBotIdContainerFsDownloadError, GetBotsByBotIdContainerFsDownloadErrors, GetBotsByBotIdContainerFsDownloadResponses, GetBotsByBotIdContainerFsError, GetBotsByBotIdContainerFsErrors, GetBotsByBotIdContainerFsListData, GetBotsByBotIdContainerFsListError, GetBotsByBotIdContainerFsListErrors, GetBotsByBotIdContainerFsListResponse, GetBotsByBotIdContainerFsListResponses, GetBotsByBotIdContainerFsReadData, GetBotsByBotIdContainerFsReadError, GetBotsByBotIdContainerFsReadErrors, GetBotsByBotIdContainerFsReadResponse, GetBotsByBotIdContainerFsReadResponses, GetBotsByBotIdContainerFsResponse, GetBotsByBotIdContainerFsResponses, GetBotsByBotIdContainerResponse, GetBotsByBotIdContainerResponses, GetBotsByBotIdContainerSkillsData, GetBotsByBotIdContainerSkillsError, GetBotsByBotIdContainerSkillsErrors, GetBotsByBotIdContainerSkillsResponse, GetBotsByBotIdContainerSkillsResponses, GetBotsByBotIdContainerSnapshotsData, GetBotsByBotIdContainerSnapshotsError, GetBotsByBotIdContainerSnapshotsErrors, GetBotsByBotIdContainerSnapshotsResponse, GetBotsByBotIdContainerSnapshotsResponses, GetBotsByBotIdEmailBindingsData, GetBotsByBotIdEmailBindingsError, GetBotsByBotIdEmailBindingsErrors, GetBotsByBotIdEmailBindingsResponse, GetBotsByBotIdEmailBindingsResponses, GetBotsByBotIdEmailOutboxByIdData, GetBotsByBotIdEmailOutboxByIdError, GetBotsByBotIdEmailOutboxByIdErrors, GetBotsByBotIdEmailOutboxByIdResponse, GetBotsByBotIdEmailOutboxByIdResponses, GetBotsByBotIdEmailOutboxData, GetBotsByBotIdEmailOutboxError, GetBotsByBotIdEmailOutboxErrors, GetBotsByBotIdEmailOutboxResponse, GetBotsByBotIdEmailOutboxResponses, GetBotsByBotIdHeartbeatLogsData, GetBotsByBotIdHeartbeatLogsError, GetBotsByBotIdHeartbeatLogsErrors, GetBotsByBotIdHeartbeatLogsResponse, GetBotsByBotIdHeartbeatLogsResponses, GetBotsByBotIdInboxByIdData, GetBotsByBotIdInboxByIdError, GetBotsByBotIdInboxByIdErrors, GetBotsByBotIdInboxByIdResponse, GetBotsByBotIdInboxByIdResponses, GetBotsByBotIdInboxCountData, GetBotsByBotIdInboxCountError, GetBotsByBotIdInboxCountErrors, GetBotsByBotIdInboxCountResponse, GetBotsByBotIdInboxCountResponses, GetBotsByBotIdInboxData, GetBotsByBotIdInboxError, GetBotsByBotIdInboxErrors, GetBotsByBotIdInboxResponse, GetBotsByBotIdInboxResponses, GetBotsByBotIdMcpByIdData, GetBotsByBotIdMcpByIdError, GetBotsByBotIdMcpByIdErrors, GetBotsByBotIdMcpByIdOauthStatusData, GetBotsByBotIdMcpByIdOauthStatusError, GetBotsByBotIdMcpByIdOauthStatusErrors, GetBotsByBotIdMcpByIdOauthStatusResponse, GetBotsByBotIdMcpByIdOauthStatusResponses, GetBotsByBotIdMcpByIdResponse, GetBotsByBotIdMcpByIdResponses, GetBotsByBotIdMcpData, GetBotsByBotIdMcpError, GetBotsByBotIdMcpErrors, GetBotsByBotIdMcpExportData, GetBotsByBotIdMcpExportError, GetBotsByBotIdMcpExportErrors, GetBotsByBotIdMcpExportResponse, GetBotsByBotIdMcpExportResponses, GetBotsByBotIdMcpResponse, GetBotsByBotIdMcpResponses, GetBotsByBotIdMemoryData, GetBotsByBotIdMemoryError, GetBotsByBotIdMemoryErrors, GetBotsByBotIdMemoryResponse, GetBotsByBotIdMemoryResponses, GetBotsByBotIdMemoryUsageData, GetBotsByBotIdMemoryUsageError, GetBotsByBotIdMemoryUsageErrors, GetBotsByBotIdMemoryUsageResponse, GetBotsByBotIdMemoryUsageResponses, GetBotsByBotIdMessagesData, GetBotsByBotIdMessagesError, GetBotsByBotIdMessagesErrors, GetBotsByBotIdMessagesResponse, GetBotsByBotIdMessagesResponses, GetBotsByBotIdScheduleByIdData, GetBotsByBotIdScheduleByIdError, GetBotsByBotIdScheduleByIdErrors, GetBotsByBotIdScheduleByIdResponse, GetBotsByBotIdScheduleByIdResponses, GetBotsByBotIdScheduleData, GetBotsByBotIdScheduleError, GetBotsByBotIdScheduleErrors, GetBotsByBotIdScheduleResponse, GetBotsByBotIdScheduleResponses, GetBotsByBotIdSettingsData, GetBotsByBotIdSettingsError, GetBotsByBotIdSettingsErrors, GetBotsByBotIdSettingsResponse, GetBotsByBotIdSettingsResponses, GetBotsByBotIdSubagentsByIdContextData, GetBotsByBotIdSubagentsByIdContextError, GetBotsByBotIdSubagentsByIdContextErrors, GetBotsByBotIdSubagentsByIdContextResponse, GetBotsByBotIdSubagentsByIdContextResponses, GetBotsByBotIdSubagentsByIdData, GetBotsByBotIdSubagentsByIdError, GetBotsByBotIdSubagentsByIdErrors, GetBotsByBotIdSubagentsByIdResponse, GetBotsByBotIdSubagentsByIdResponses, GetBotsByBotIdSubagentsByIdSkillsData, GetBotsByBotIdSubagentsByIdSkillsError, GetBotsByBotIdSubagentsByIdSkillsErrors, GetBotsByBotIdSubagentsByIdSkillsResponse, GetBotsByBotIdSubagentsByIdSkillsResponses, GetBotsByBotIdSubagentsData, GetBotsByBotIdSubagentsError, GetBotsByBotIdSubagentsErrors, GetBotsByBotIdSubagentsResponse, GetBotsByBotIdSubagentsResponses, GetBotsByBotIdTokenUsageData, GetBotsByBotIdTokenUsageError, GetBotsByBotIdTokenUsageErrors, GetBotsByBotIdTokenUsageResponse, GetBotsByBotIdTokenUsageResponses, GetBotsByBotIdWebStreamData, GetBotsByBotIdWebStreamError, GetBotsByBotIdWebStreamErrors, GetBotsByBotIdWebStreamResponse, GetBotsByBotIdWebStreamResponses, GetBotsByIdChannelByPlatformData, GetBotsByIdChannelByPlatformError, GetBotsByIdChannelByPlatformErrors, GetBotsByIdChannelByPlatformResponse, GetBotsByIdChannelByPlatformResponses, GetBotsByIdChecksData, GetBotsByIdChecksError, GetBotsByIdChecksErrors, GetBotsByIdChecksResponse, GetBotsByIdChecksResponses, GetBotsByIdData, GetBotsByIdError, GetBotsByIdErrors, GetBotsByIdMembersData, GetBotsByIdMembersError, GetBotsByIdMembersErrors, GetBotsByIdMembersResponse, GetBotsByIdMembersResponses, GetBotsByIdResponse, GetBotsByIdResponses, GetBotsData, GetBotsError, GetBotsErrors, GetBotsResponse, GetBotsResponses, GetChannelsByPlatformData, GetChannelsByPlatformError, GetChannelsByPlatformErrors, GetChannelsByPlatformResponse, GetChannelsByPlatformResponses, GetChannelsData, GetChannelsError, GetChannelsErrors, GetChannelsResponse, GetChannelsResponses, GetEmailProvidersByIdData, GetEmailProvidersByIdError, GetEmailProvidersByIdErrors, GetEmailProvidersByIdResponse, GetEmailProvidersByIdResponses, GetEmailProvidersData, GetEmailProvidersError, GetEmailProvidersErrors, GetEmailProvidersMetaData, GetEmailProvidersMetaResponse, GetEmailProvidersMetaResponses, GetEmailProvidersResponse, GetEmailProvidersResponses, GetMemoryProvidersByIdData, GetMemoryProvidersByIdError, GetMemoryProvidersByIdErrors, GetMemoryProvidersByIdResponse, GetMemoryProvidersByIdResponses, GetMemoryProvidersData, GetMemoryProvidersError, GetMemoryProvidersErrors, GetMemoryProvidersMetaData, GetMemoryProvidersMetaResponse, GetMemoryProvidersMetaResponses, GetMemoryProvidersResponse, GetMemoryProvidersResponses, GetModelsByIdData, GetModelsByIdError, GetModelsByIdErrors, GetModelsByIdResponse, GetModelsByIdResponses, GetModelsCountData, GetModelsCountError, GetModelsCountErrors, GetModelsCountResponse, GetModelsCountResponses, GetModelsData, GetModelsError, GetModelsErrors, GetModelsModelByModelIdData, GetModelsModelByModelIdError, GetModelsModelByModelIdErrors, GetModelsModelByModelIdResponse, GetModelsModelByModelIdResponses, GetModelsResponse, GetModelsResponses, GetPingData, GetPingResponse, GetPingResponses, GetProvidersByIdData, GetProvidersByIdError, GetProvidersByIdErrors, GetProvidersByIdModelsData, GetProvidersByIdModelsError, GetProvidersByIdModelsErrors, GetProvidersByIdModelsResponse, GetProvidersByIdModelsResponses, GetProvidersByIdResponse, GetProvidersByIdResponses, GetProvidersCountData, GetProvidersCountError, GetProvidersCountErrors, GetProvidersCountResponse, GetProvidersCountResponses, GetProvidersData, GetProvidersError, GetProvidersErrors, GetProvidersNameByNameData, GetProvidersNameByNameError, GetProvidersNameByNameErrors, GetProvidersNameByNameResponse, GetProvidersNameByNameResponses, GetProvidersResponse, GetProvidersResponses, GetSearchProvidersByIdData, GetSearchProvidersByIdError, GetSearchProvidersByIdErrors, GetSearchProvidersByIdResponse, GetSearchProvidersByIdResponses, GetSearchProvidersData, GetSearchProvidersError, GetSearchProvidersErrors, GetSearchProvidersMetaData, GetSearchProvidersMetaResponse, GetSearchProvidersMetaResponses, GetSearchProvidersResponse, GetSearchProvidersResponses, GetUsersByIdData, GetUsersByIdError, GetUsersByIdErrors, GetUsersByIdResponse, GetUsersByIdResponses, GetUsersData, GetUsersError, GetUsersErrors, GetUsersMeChannelsByPlatformData, GetUsersMeChannelsByPlatformError, GetUsersMeChannelsByPlatformErrors, GetUsersMeChannelsByPlatformResponse, GetUsersMeChannelsByPlatformResponses, GetUsersMeData, GetUsersMeError, GetUsersMeErrors, GetUsersMeIdentitiesData, GetUsersMeIdentitiesError, GetUsersMeIdentitiesErrors, GetUsersMeIdentitiesResponse, GetUsersMeIdentitiesResponses, GetUsersMeResponse, GetUsersMeResponses, GetUsersResponse, GetUsersResponses, GithubComMemohaiMemohInternalFsFileInfo, GithubComMemohaiMemohInternalMcpConnection, HandlersBatchDeleteRequest, HandlersChannelMeta, HandlersCreateContainerRequest, HandlersCreateContainerResponse, HandlersCreateSnapshotRequest, HandlersCreateSnapshotResponse, HandlersDailyTokenUsage, HandlersErrorResponse, HandlersFsDeleteRequest, HandlersFsFileInfo, HandlersFsListResponse, HandlersFsMkdirRequest, HandlersFsOpResponse, HandlersFsReadResponse, HandlersFsRenameRequest, HandlersFsUploadResponse, HandlersFsWriteRequest, HandlersGetContainerResponse, HandlersListMyIdentitiesResponse, HandlersListSnapshotsResponse, HandlersLocalChannelMessageRequest, HandlersLoginRequest, HandlersLoginResponse, HandlersMarkReadRequest, HandlersMcpStdioRequest, HandlersMcpStdioResponse, HandlersMemoryAddPayload, HandlersMemoryCompactPayload, HandlersMemoryDeletePayload, HandlersMemorySearchPayload, HandlersModelTokenUsage, HandlersOauthAuthorizeRequest, HandlersOauthDiscoverRequest, HandlersPingResponse, HandlersProbeResponse, HandlersRefreshResponse, HandlersSkillItem, HandlersSkillsDeleteRequest, HandlersSkillsOpResponse, HandlersSkillsResponse, HandlersSkillsUpsertRequest, HandlersSnapshotInfo, HandlersTokenUsageResponse, HeartbeatListLogsResponse, HeartbeatLog, IdentitiesChannelIdentity, InboxCountResult, InboxCreateRequest, InboxItem, McpAuthorizeResult, McpDiscoveryResult, McpExportResponse, McpImportRequest, McpListResponse, McpMcpServerEntry, McpOAuthStatus, McpToolDescriptor, McpUpsertRequest, MessageMessage, MessageMessageAsset, ModelsAddRequest, ModelsAddResponse, ModelsClientType, ModelsCountResponse, ModelsGetResponse, ModelsModelType, ModelsTestResponse, ModelsTestStatus, ModelsUpdateRequest, PatchBotsByIdChannelByPlatformStatusData, PatchBotsByIdChannelByPlatformStatusError, PatchBotsByIdChannelByPlatformStatusErrors, PatchBotsByIdChannelByPlatformStatusResponse, PatchBotsByIdChannelByPlatformStatusResponses, PostAuthLoginData, PostAuthLoginError, PostAuthLoginErrors, PostAuthLoginResponse, PostAuthLoginResponses, PostAuthRefreshData, PostAuthRefreshError, PostAuthRefreshErrors, PostAuthRefreshResponse, PostAuthRefreshResponses, PostBotsByBotIdCliMessagesData, PostBotsByBotIdCliMessagesError, PostBotsByBotIdCliMessagesErrors, PostBotsByBotIdCliMessagesResponse, PostBotsByBotIdCliMessagesResponses, PostBotsByBotIdContainerData, PostBotsByBotIdContainerError, PostBotsByBotIdContainerErrors, PostBotsByBotIdContainerFsDeleteData, PostBotsByBotIdContainerFsDeleteError, PostBotsByBotIdContainerFsDeleteErrors, PostBotsByBotIdContainerFsDeleteResponse, PostBotsByBotIdContainerFsDeleteResponses, PostBotsByBotIdContainerFsMkdirData, PostBotsByBotIdContainerFsMkdirError, PostBotsByBotIdContainerFsMkdirErrors, PostBotsByBotIdContainerFsMkdirResponse, PostBotsByBotIdContainerFsMkdirResponses, PostBotsByBotIdContainerFsRenameData, PostBotsByBotIdContainerFsRenameError, PostBotsByBotIdContainerFsRenameErrors, PostBotsByBotIdContainerFsRenameResponse, PostBotsByBotIdContainerFsRenameResponses, PostBotsByBotIdContainerFsUploadData, PostBotsByBotIdContainerFsUploadError, PostBotsByBotIdContainerFsUploadErrors, PostBotsByBotIdContainerFsUploadResponse, PostBotsByBotIdContainerFsUploadResponses, PostBotsByBotIdContainerFsWriteData, PostBotsByBotIdContainerFsWriteError, PostBotsByBotIdContainerFsWriteErrors, PostBotsByBotIdContainerFsWriteResponse, PostBotsByBotIdContainerFsWriteResponses, PostBotsByBotIdContainerResponse, PostBotsByBotIdContainerResponses, PostBotsByBotIdContainerSkillsData, PostBotsByBotIdContainerSkillsError, PostBotsByBotIdContainerSkillsErrors, PostBotsByBotIdContainerSkillsResponse, PostBotsByBotIdContainerSkillsResponses, PostBotsByBotIdContainerSnapshotsData, PostBotsByBotIdContainerSnapshotsError, PostBotsByBotIdContainerSnapshotsErrors, PostBotsByBotIdContainerSnapshotsResponse, PostBotsByBotIdContainerSnapshotsResponses, PostBotsByBotIdContainerStartData, PostBotsByBotIdContainerStartError, PostBotsByBotIdContainerStartErrors, PostBotsByBotIdContainerStartResponse, PostBotsByBotIdContainerStartResponses, PostBotsByBotIdContainerStopData, PostBotsByBotIdContainerStopError, PostBotsByBotIdContainerStopErrors, PostBotsByBotIdContainerStopResponse, PostBotsByBotIdContainerStopResponses, PostBotsByBotIdEmailBindingsData, PostBotsByBotIdEmailBindingsError, PostBotsByBotIdEmailBindingsErrors, PostBotsByBotIdEmailBindingsResponse, PostBotsByBotIdEmailBindingsResponses, PostBotsByBotIdInboxData, PostBotsByBotIdInboxError, PostBotsByBotIdInboxErrors, PostBotsByBotIdInboxMarkReadData, PostBotsByBotIdInboxMarkReadError, PostBotsByBotIdInboxMarkReadErrors, PostBotsByBotIdInboxMarkReadResponses, PostBotsByBotIdInboxResponse, PostBotsByBotIdInboxResponses, PostBotsByBotIdMcpByIdOauthAuthorizeData, PostBotsByBotIdMcpByIdOauthAuthorizeError, PostBotsByBotIdMcpByIdOauthAuthorizeErrors, PostBotsByBotIdMcpByIdOauthAuthorizeResponse, PostBotsByBotIdMcpByIdOauthAuthorizeResponses, PostBotsByBotIdMcpByIdOauthDiscoverData, PostBotsByBotIdMcpByIdOauthDiscoverError, PostBotsByBotIdMcpByIdOauthDiscoverErrors, PostBotsByBotIdMcpByIdOauthDiscoverResponse, PostBotsByBotIdMcpByIdOauthDiscoverResponses, PostBotsByBotIdMcpByIdProbeData, PostBotsByBotIdMcpByIdProbeError, PostBotsByBotIdMcpByIdProbeErrors, PostBotsByBotIdMcpByIdProbeResponse, PostBotsByBotIdMcpByIdProbeResponses, PostBotsByBotIdMcpData, PostBotsByBotIdMcpError, PostBotsByBotIdMcpErrors, PostBotsByBotIdMcpOpsBatchDeleteData, PostBotsByBotIdMcpOpsBatchDeleteError, PostBotsByBotIdMcpOpsBatchDeleteErrors, PostBotsByBotIdMcpOpsBatchDeleteResponses, PostBotsByBotIdMcpResponse, PostBotsByBotIdMcpResponses, PostBotsByBotIdMcpStdioByConnectionIdData, PostBotsByBotIdMcpStdioByConnectionIdError, PostBotsByBotIdMcpStdioByConnectionIdErrors, PostBotsByBotIdMcpStdioByConnectionIdResponse, PostBotsByBotIdMcpStdioByConnectionIdResponses, PostBotsByBotIdMcpStdioData, PostBotsByBotIdMcpStdioError, PostBotsByBotIdMcpStdioErrors, PostBotsByBotIdMcpStdioResponse, PostBotsByBotIdMcpStdioResponses, PostBotsByBotIdMemoryCompactData, PostBotsByBotIdMemoryCompactError, PostBotsByBotIdMemoryCompactErrors, PostBotsByBotIdMemoryCompactResponse, PostBotsByBotIdMemoryCompactResponses, PostBotsByBotIdMemoryData, PostBotsByBotIdMemoryError, PostBotsByBotIdMemoryErrors, PostBotsByBotIdMemoryRebuildData, PostBotsByBotIdMemoryRebuildError, PostBotsByBotIdMemoryRebuildErrors, PostBotsByBotIdMemoryRebuildResponse, PostBotsByBotIdMemoryRebuildResponses, PostBotsByBotIdMemoryResponse, PostBotsByBotIdMemoryResponses, PostBotsByBotIdMemorySearchData, PostBotsByBotIdMemorySearchError, PostBotsByBotIdMemorySearchErrors, PostBotsByBotIdMemorySearchResponse, PostBotsByBotIdMemorySearchResponses, PostBotsByBotIdScheduleData, PostBotsByBotIdScheduleError, PostBotsByBotIdScheduleErrors, PostBotsByBotIdScheduleResponse, PostBotsByBotIdScheduleResponses, PostBotsByBotIdSettingsData, PostBotsByBotIdSettingsError, PostBotsByBotIdSettingsErrors, PostBotsByBotIdSettingsResponse, PostBotsByBotIdSettingsResponses, PostBotsByBotIdSubagentsByIdSkillsData, PostBotsByBotIdSubagentsByIdSkillsError, PostBotsByBotIdSubagentsByIdSkillsErrors, PostBotsByBotIdSubagentsByIdSkillsResponse, PostBotsByBotIdSubagentsByIdSkillsResponses, PostBotsByBotIdSubagentsData, PostBotsByBotIdSubagentsError, PostBotsByBotIdSubagentsErrors, PostBotsByBotIdSubagentsResponse, PostBotsByBotIdSubagentsResponses, PostBotsByBotIdToolsData, PostBotsByBotIdToolsError, PostBotsByBotIdToolsErrors, PostBotsByBotIdToolsResponse, PostBotsByBotIdToolsResponses, PostBotsByBotIdWebMessagesData, PostBotsByBotIdWebMessagesError, PostBotsByBotIdWebMessagesErrors, PostBotsByBotIdWebMessagesResponse, PostBotsByBotIdWebMessagesResponses, PostBotsByIdChannelByPlatformSendChatData, PostBotsByIdChannelByPlatformSendChatError, PostBotsByIdChannelByPlatformSendChatErrors, PostBotsByIdChannelByPlatformSendChatResponse, PostBotsByIdChannelByPlatformSendChatResponses, PostBotsByIdChannelByPlatformSendData, PostBotsByIdChannelByPlatformSendError, PostBotsByIdChannelByPlatformSendErrors, PostBotsByIdChannelByPlatformSendResponse, PostBotsByIdChannelByPlatformSendResponses, PostBotsData, PostBotsError, PostBotsErrors, PostBotsResponse, PostBotsResponses, PostEmailMailgunWebhookByConfigIdData, PostEmailMailgunWebhookByConfigIdError, PostEmailMailgunWebhookByConfigIdErrors, PostEmailMailgunWebhookByConfigIdResponse, PostEmailMailgunWebhookByConfigIdResponses, PostEmailProvidersData, PostEmailProvidersError, PostEmailProvidersErrors, PostEmailProvidersResponse, PostEmailProvidersResponses, PostMemoryProvidersData, PostMemoryProvidersError, PostMemoryProvidersErrors, PostMemoryProvidersResponse, PostMemoryProvidersResponses, PostModelsByIdTestData, PostModelsByIdTestError, PostModelsByIdTestErrors, PostModelsByIdTestResponse, PostModelsByIdTestResponses, PostModelsData, PostModelsError, PostModelsErrors, PostModelsResponse, PostModelsResponses, PostProvidersByIdImportModelsData, PostProvidersByIdImportModelsError, PostProvidersByIdImportModelsErrors, PostProvidersByIdImportModelsResponse, PostProvidersByIdImportModelsResponses, PostProvidersByIdTestData, PostProvidersByIdTestError, PostProvidersByIdTestErrors, PostProvidersByIdTestResponse, PostProvidersByIdTestResponses, PostProvidersData, PostProvidersError, PostProvidersErrors, PostProvidersResponse, PostProvidersResponses, PostSearchProvidersData, PostSearchProvidersError, PostSearchProvidersErrors, PostSearchProvidersResponse, PostSearchProvidersResponses, PostUsersData, PostUsersError, PostUsersErrors, PostUsersResponse, PostUsersResponses, ProviderCdfPoint, ProviderCompactResult, ProviderDeleteResponse, ProviderMemoryItem, ProviderMessage, ProviderProviderConfigSchema, ProviderProviderCreateRequest, ProviderProviderFieldSchema, ProviderProviderGetResponse, ProviderProviderMeta, ProviderProviderType, ProviderProviderUpdateRequest, ProviderRebuildResult, ProvidersCountResponse, ProvidersCreateRequest, ProviderSearchResponse, ProvidersGetResponse, ProvidersImportModelsRequest, ProvidersImportModelsResponse, ProvidersTestResponse, ProvidersUpdateRequest, ProviderTopKBucket, ProviderUsageResponse, PutBotsByBotIdEmailBindingsByIdData, PutBotsByBotIdEmailBindingsByIdError, PutBotsByBotIdEmailBindingsByIdErrors, PutBotsByBotIdEmailBindingsByIdResponse, PutBotsByBotIdEmailBindingsByIdResponses, PutBotsByBotIdMcpByIdData, PutBotsByBotIdMcpByIdError, PutBotsByBotIdMcpByIdErrors, PutBotsByBotIdMcpByIdResponse, PutBotsByBotIdMcpByIdResponses, PutBotsByBotIdMcpImportData, PutBotsByBotIdMcpImportError, PutBotsByBotIdMcpImportErrors, PutBotsByBotIdMcpImportResponse, PutBotsByBotIdMcpImportResponses, PutBotsByBotIdScheduleByIdData, PutBotsByBotIdScheduleByIdError, PutBotsByBotIdScheduleByIdErrors, PutBotsByBotIdScheduleByIdResponse, PutBotsByBotIdScheduleByIdResponses, PutBotsByBotIdSettingsData, PutBotsByBotIdSettingsError, PutBotsByBotIdSettingsErrors, PutBotsByBotIdSettingsResponse, PutBotsByBotIdSettingsResponses, PutBotsByBotIdSubagentsByIdContextData, PutBotsByBotIdSubagentsByIdContextError, PutBotsByBotIdSubagentsByIdContextErrors, PutBotsByBotIdSubagentsByIdContextResponse, PutBotsByBotIdSubagentsByIdContextResponses, PutBotsByBotIdSubagentsByIdData, PutBotsByBotIdSubagentsByIdError, PutBotsByBotIdSubagentsByIdErrors, PutBotsByBotIdSubagentsByIdResponse, PutBotsByBotIdSubagentsByIdResponses, PutBotsByBotIdSubagentsByIdSkillsData, PutBotsByBotIdSubagentsByIdSkillsError, PutBotsByBotIdSubagentsByIdSkillsErrors, PutBotsByBotIdSubagentsByIdSkillsResponse, PutBotsByBotIdSubagentsByIdSkillsResponses, PutBotsByIdChannelByPlatformData, PutBotsByIdChannelByPlatformError, PutBotsByIdChannelByPlatformErrors, PutBotsByIdChannelByPlatformResponse, PutBotsByIdChannelByPlatformResponses, PutBotsByIdData, PutBotsByIdError, PutBotsByIdErrors, PutBotsByIdMembersData, PutBotsByIdMembersError, PutBotsByIdMembersErrors, PutBotsByIdMembersResponse, PutBotsByIdMembersResponses, PutBotsByIdOwnerData, PutBotsByIdOwnerError, PutBotsByIdOwnerErrors, PutBotsByIdOwnerResponse, PutBotsByIdOwnerResponses, PutBotsByIdResponse, PutBotsByIdResponses, PutEmailProvidersByIdData, PutEmailProvidersByIdError, PutEmailProvidersByIdErrors, PutEmailProvidersByIdResponse, PutEmailProvidersByIdResponses, PutMemoryProvidersByIdData, PutMemoryProvidersByIdError, PutMemoryProvidersByIdErrors, PutMemoryProvidersByIdResponse, PutMemoryProvidersByIdResponses, PutModelsByIdData, PutModelsByIdError, PutModelsByIdErrors, PutModelsByIdResponse, PutModelsByIdResponses, PutModelsModelByModelIdData, PutModelsModelByModelIdError, PutModelsModelByModelIdErrors, PutModelsModelByModelIdResponse, PutModelsModelByModelIdResponses, PutProvidersByIdData, PutProvidersByIdError, PutProvidersByIdErrors, PutProvidersByIdResponse, PutProvidersByIdResponses, PutSearchProvidersByIdData, PutSearchProvidersByIdError, PutSearchProvidersByIdErrors, PutSearchProvidersByIdResponse, PutSearchProvidersByIdResponses, PutUsersByIdData, PutUsersByIdError, PutUsersByIdErrors, PutUsersByIdPasswordData, PutUsersByIdPasswordError, PutUsersByIdPasswordErrors, PutUsersByIdPasswordResponses, PutUsersByIdResponse, PutUsersByIdResponses, PutUsersMeChannelsByPlatformData, PutUsersMeChannelsByPlatformError, PutUsersMeChannelsByPlatformErrors, PutUsersMeChannelsByPlatformResponse, PutUsersMeChannelsByPlatformResponses, PutUsersMeData, PutUsersMeError, PutUsersMeErrors, PutUsersMePasswordData, PutUsersMePasswordError, PutUsersMePasswordErrors, PutUsersMePasswordResponses, PutUsersMeResponse, PutUsersMeResponses, ScheduleCreateRequest, ScheduleListResponse, ScheduleNullableInt, ScheduleSchedule, ScheduleUpdateRequest, SearchprovidersCreateRequest, SearchprovidersGetResponse, SearchprovidersProviderConfigSchema, SearchprovidersProviderFieldSchema, SearchprovidersProviderMeta, SearchprovidersProviderName, SearchprovidersUpdateRequest, SettingsSettings, SettingsUpsertRequest, SubagentAddSkillsRequest, SubagentContextResponse, SubagentCreateRequest, SubagentListResponse, SubagentSkillsResponse, SubagentSubagent, SubagentUpdateContextRequest, SubagentUpdateRequest, SubagentUpdateSkillsRequest } from './types.gen'; diff --git a/packages/sdk/src/sdk.gen.ts b/packages/sdk/src/sdk.gen.ts index 87eee661..1bfddc81 100644 --- a/packages/sdk/src/sdk.gen.ts +++ b/packages/sdk/src/sdk.gen.ts @@ -2,7 +2,7 @@ import { type Client, formDataBodySerializer, type Options as Options2, type TDataShape } from './client'; import { client } from './client.gen'; -import type { DeleteBotsByBotIdContainerData, DeleteBotsByBotIdContainerErrors, DeleteBotsByBotIdContainerResponses, DeleteBotsByBotIdContainerSkillsData, DeleteBotsByBotIdContainerSkillsErrors, DeleteBotsByBotIdContainerSkillsResponses, DeleteBotsByBotIdEmailBindingsByIdData, DeleteBotsByBotIdEmailBindingsByIdErrors, DeleteBotsByBotIdEmailBindingsByIdResponses, DeleteBotsByBotIdHeartbeatLogsData, DeleteBotsByBotIdHeartbeatLogsErrors, DeleteBotsByBotIdHeartbeatLogsResponses, DeleteBotsByBotIdInboxByIdData, DeleteBotsByBotIdInboxByIdErrors, DeleteBotsByBotIdInboxByIdResponses, DeleteBotsByBotIdMcpByIdData, DeleteBotsByBotIdMcpByIdErrors, DeleteBotsByBotIdMcpByIdResponses, DeleteBotsByBotIdMemoryByIdData, DeleteBotsByBotIdMemoryByIdErrors, DeleteBotsByBotIdMemoryByIdResponses, DeleteBotsByBotIdMemoryData, DeleteBotsByBotIdMemoryErrors, DeleteBotsByBotIdMemoryResponses, DeleteBotsByBotIdMessagesData, DeleteBotsByBotIdMessagesErrors, DeleteBotsByBotIdMessagesResponses, DeleteBotsByBotIdScheduleByIdData, DeleteBotsByBotIdScheduleByIdErrors, DeleteBotsByBotIdScheduleByIdResponses, DeleteBotsByBotIdSettingsData, DeleteBotsByBotIdSettingsErrors, DeleteBotsByBotIdSettingsResponses, DeleteBotsByBotIdSubagentsByIdData, DeleteBotsByBotIdSubagentsByIdErrors, DeleteBotsByBotIdSubagentsByIdResponses, DeleteBotsByIdChannelByPlatformData, DeleteBotsByIdChannelByPlatformErrors, DeleteBotsByIdChannelByPlatformResponses, DeleteBotsByIdData, DeleteBotsByIdErrors, DeleteBotsByIdMembersByUserIdData, DeleteBotsByIdMembersByUserIdErrors, DeleteBotsByIdMembersByUserIdResponses, DeleteBotsByIdResponses, DeleteEmailProvidersByIdData, DeleteEmailProvidersByIdErrors, DeleteEmailProvidersByIdResponses, DeleteMemoryProvidersByIdData, DeleteMemoryProvidersByIdErrors, DeleteMemoryProvidersByIdResponses, DeleteModelsByIdData, DeleteModelsByIdErrors, DeleteModelsByIdResponses, DeleteModelsModelByModelIdData, DeleteModelsModelByModelIdErrors, DeleteModelsModelByModelIdResponses, DeleteProvidersByIdData, DeleteProvidersByIdErrors, DeleteProvidersByIdResponses, DeleteSearchProvidersByIdData, DeleteSearchProvidersByIdErrors, DeleteSearchProvidersByIdResponses, GetBotsByBotIdCliStreamData, GetBotsByBotIdCliStreamErrors, GetBotsByBotIdCliStreamResponses, GetBotsByBotIdContainerData, GetBotsByBotIdContainerErrors, GetBotsByBotIdContainerFsData, GetBotsByBotIdContainerFsDownloadData, GetBotsByBotIdContainerFsDownloadErrors, GetBotsByBotIdContainerFsDownloadResponses, GetBotsByBotIdContainerFsErrors, GetBotsByBotIdContainerFsListData, GetBotsByBotIdContainerFsListErrors, GetBotsByBotIdContainerFsListResponses, GetBotsByBotIdContainerFsReadData, GetBotsByBotIdContainerFsReadErrors, GetBotsByBotIdContainerFsReadResponses, GetBotsByBotIdContainerFsResponses, GetBotsByBotIdContainerResponses, GetBotsByBotIdContainerSkillsData, GetBotsByBotIdContainerSkillsErrors, GetBotsByBotIdContainerSkillsResponses, GetBotsByBotIdContainerSnapshotsData, GetBotsByBotIdContainerSnapshotsErrors, GetBotsByBotIdContainerSnapshotsResponses, GetBotsByBotIdEmailBindingsData, GetBotsByBotIdEmailBindingsErrors, GetBotsByBotIdEmailBindingsResponses, GetBotsByBotIdEmailOutboxByIdData, GetBotsByBotIdEmailOutboxByIdErrors, GetBotsByBotIdEmailOutboxByIdResponses, GetBotsByBotIdEmailOutboxData, GetBotsByBotIdEmailOutboxErrors, GetBotsByBotIdEmailOutboxResponses, GetBotsByBotIdHeartbeatLogsData, GetBotsByBotIdHeartbeatLogsErrors, GetBotsByBotIdHeartbeatLogsResponses, GetBotsByBotIdInboxByIdData, GetBotsByBotIdInboxByIdErrors, GetBotsByBotIdInboxByIdResponses, GetBotsByBotIdInboxCountData, GetBotsByBotIdInboxCountErrors, GetBotsByBotIdInboxCountResponses, GetBotsByBotIdInboxData, GetBotsByBotIdInboxErrors, GetBotsByBotIdInboxResponses, GetBotsByBotIdMcpByIdData, GetBotsByBotIdMcpByIdErrors, GetBotsByBotIdMcpByIdResponses, GetBotsByBotIdMcpData, GetBotsByBotIdMcpErrors, GetBotsByBotIdMcpExportData, GetBotsByBotIdMcpExportErrors, GetBotsByBotIdMcpExportResponses, GetBotsByBotIdMcpResponses, GetBotsByBotIdMemoryData, GetBotsByBotIdMemoryErrors, GetBotsByBotIdMemoryResponses, GetBotsByBotIdMemoryUsageData, GetBotsByBotIdMemoryUsageErrors, GetBotsByBotIdMemoryUsageResponses, GetBotsByBotIdMessagesData, GetBotsByBotIdMessagesErrors, GetBotsByBotIdMessagesResponses, GetBotsByBotIdScheduleByIdData, GetBotsByBotIdScheduleByIdErrors, GetBotsByBotIdScheduleByIdResponses, GetBotsByBotIdScheduleData, GetBotsByBotIdScheduleErrors, GetBotsByBotIdScheduleResponses, GetBotsByBotIdSettingsData, GetBotsByBotIdSettingsErrors, GetBotsByBotIdSettingsResponses, GetBotsByBotIdSubagentsByIdContextData, GetBotsByBotIdSubagentsByIdContextErrors, GetBotsByBotIdSubagentsByIdContextResponses, GetBotsByBotIdSubagentsByIdData, GetBotsByBotIdSubagentsByIdErrors, GetBotsByBotIdSubagentsByIdResponses, GetBotsByBotIdSubagentsByIdSkillsData, GetBotsByBotIdSubagentsByIdSkillsErrors, GetBotsByBotIdSubagentsByIdSkillsResponses, GetBotsByBotIdSubagentsData, GetBotsByBotIdSubagentsErrors, GetBotsByBotIdSubagentsResponses, GetBotsByBotIdTokenUsageData, GetBotsByBotIdTokenUsageErrors, GetBotsByBotIdTokenUsageResponses, GetBotsByBotIdWebStreamData, GetBotsByBotIdWebStreamErrors, GetBotsByBotIdWebStreamResponses, GetBotsByIdChannelByPlatformData, GetBotsByIdChannelByPlatformErrors, GetBotsByIdChannelByPlatformResponses, GetBotsByIdChecksData, GetBotsByIdChecksErrors, GetBotsByIdChecksResponses, GetBotsByIdData, GetBotsByIdErrors, GetBotsByIdMembersData, GetBotsByIdMembersErrors, GetBotsByIdMembersResponses, GetBotsByIdResponses, GetBotsData, GetBotsErrors, GetBotsResponses, GetChannelsByPlatformData, GetChannelsByPlatformErrors, GetChannelsByPlatformResponses, GetChannelsData, GetChannelsErrors, GetChannelsResponses, GetEmailProvidersByIdData, GetEmailProvidersByIdErrors, GetEmailProvidersByIdResponses, GetEmailProvidersData, GetEmailProvidersErrors, GetEmailProvidersMetaData, GetEmailProvidersMetaResponses, GetEmailProvidersResponses, GetMemoryProvidersByIdData, GetMemoryProvidersByIdErrors, GetMemoryProvidersByIdResponses, GetMemoryProvidersData, GetMemoryProvidersErrors, GetMemoryProvidersMetaData, GetMemoryProvidersMetaResponses, GetMemoryProvidersResponses, GetModelsByIdData, GetModelsByIdErrors, GetModelsByIdResponses, GetModelsCountData, GetModelsCountErrors, GetModelsCountResponses, GetModelsData, GetModelsErrors, GetModelsModelByModelIdData, GetModelsModelByModelIdErrors, GetModelsModelByModelIdResponses, GetModelsResponses, GetPingData, GetPingResponses, GetProvidersByIdData, GetProvidersByIdErrors, GetProvidersByIdModelsData, GetProvidersByIdModelsErrors, GetProvidersByIdModelsResponses, GetProvidersByIdResponses, GetProvidersCountData, GetProvidersCountErrors, GetProvidersCountResponses, GetProvidersData, GetProvidersErrors, GetProvidersNameByNameData, GetProvidersNameByNameErrors, GetProvidersNameByNameResponses, GetProvidersResponses, GetSearchProvidersByIdData, GetSearchProvidersByIdErrors, GetSearchProvidersByIdResponses, GetSearchProvidersData, GetSearchProvidersErrors, GetSearchProvidersMetaData, GetSearchProvidersMetaResponses, GetSearchProvidersResponses, GetUsersByIdData, GetUsersByIdErrors, GetUsersByIdResponses, GetUsersData, GetUsersErrors, GetUsersMeChannelsByPlatformData, GetUsersMeChannelsByPlatformErrors, GetUsersMeChannelsByPlatformResponses, GetUsersMeData, GetUsersMeErrors, GetUsersMeIdentitiesData, GetUsersMeIdentitiesErrors, GetUsersMeIdentitiesResponses, GetUsersMeResponses, GetUsersResponses, PatchBotsByIdChannelByPlatformStatusData, PatchBotsByIdChannelByPlatformStatusErrors, PatchBotsByIdChannelByPlatformStatusResponses, PostAuthLoginData, PostAuthLoginErrors, PostAuthLoginResponses, PostAuthRefreshData, PostAuthRefreshErrors, PostAuthRefreshResponses, PostBotsByBotIdCliMessagesData, PostBotsByBotIdCliMessagesErrors, PostBotsByBotIdCliMessagesResponses, PostBotsByBotIdContainerData, PostBotsByBotIdContainerErrors, PostBotsByBotIdContainerFsDeleteData, PostBotsByBotIdContainerFsDeleteErrors, PostBotsByBotIdContainerFsDeleteResponses, PostBotsByBotIdContainerFsMkdirData, PostBotsByBotIdContainerFsMkdirErrors, PostBotsByBotIdContainerFsMkdirResponses, PostBotsByBotIdContainerFsRenameData, PostBotsByBotIdContainerFsRenameErrors, PostBotsByBotIdContainerFsRenameResponses, PostBotsByBotIdContainerFsUploadData, PostBotsByBotIdContainerFsUploadErrors, PostBotsByBotIdContainerFsUploadResponses, PostBotsByBotIdContainerFsWriteData, PostBotsByBotIdContainerFsWriteErrors, PostBotsByBotIdContainerFsWriteResponses, PostBotsByBotIdContainerResponses, PostBotsByBotIdContainerSkillsData, PostBotsByBotIdContainerSkillsErrors, PostBotsByBotIdContainerSkillsResponses, PostBotsByBotIdContainerSnapshotsData, PostBotsByBotIdContainerSnapshotsErrors, PostBotsByBotIdContainerSnapshotsResponses, PostBotsByBotIdContainerStartData, PostBotsByBotIdContainerStartErrors, PostBotsByBotIdContainerStartResponses, PostBotsByBotIdContainerStopData, PostBotsByBotIdContainerStopErrors, PostBotsByBotIdContainerStopResponses, PostBotsByBotIdEmailBindingsData, PostBotsByBotIdEmailBindingsErrors, PostBotsByBotIdEmailBindingsResponses, PostBotsByBotIdInboxData, PostBotsByBotIdInboxErrors, PostBotsByBotIdInboxMarkReadData, PostBotsByBotIdInboxMarkReadErrors, PostBotsByBotIdInboxMarkReadResponses, PostBotsByBotIdInboxResponses, PostBotsByBotIdMcpData, PostBotsByBotIdMcpErrors, PostBotsByBotIdMcpOpsBatchDeleteData, PostBotsByBotIdMcpOpsBatchDeleteErrors, PostBotsByBotIdMcpOpsBatchDeleteResponses, PostBotsByBotIdMcpResponses, PostBotsByBotIdMcpStdioByConnectionIdData, PostBotsByBotIdMcpStdioByConnectionIdErrors, PostBotsByBotIdMcpStdioByConnectionIdResponses, PostBotsByBotIdMcpStdioData, PostBotsByBotIdMcpStdioErrors, PostBotsByBotIdMcpStdioResponses, PostBotsByBotIdMemoryCompactData, PostBotsByBotIdMemoryCompactErrors, PostBotsByBotIdMemoryCompactResponses, PostBotsByBotIdMemoryData, PostBotsByBotIdMemoryErrors, PostBotsByBotIdMemoryRebuildData, PostBotsByBotIdMemoryRebuildErrors, PostBotsByBotIdMemoryRebuildResponses, PostBotsByBotIdMemoryResponses, PostBotsByBotIdMemorySearchData, PostBotsByBotIdMemorySearchErrors, PostBotsByBotIdMemorySearchResponses, PostBotsByBotIdScheduleData, PostBotsByBotIdScheduleErrors, PostBotsByBotIdScheduleResponses, PostBotsByBotIdSettingsData, PostBotsByBotIdSettingsErrors, PostBotsByBotIdSettingsResponses, PostBotsByBotIdSubagentsByIdSkillsData, PostBotsByBotIdSubagentsByIdSkillsErrors, PostBotsByBotIdSubagentsByIdSkillsResponses, PostBotsByBotIdSubagentsData, PostBotsByBotIdSubagentsErrors, PostBotsByBotIdSubagentsResponses, PostBotsByBotIdToolsData, PostBotsByBotIdToolsErrors, PostBotsByBotIdToolsResponses, PostBotsByBotIdWebMessagesData, PostBotsByBotIdWebMessagesErrors, PostBotsByBotIdWebMessagesResponses, PostBotsByIdChannelByPlatformSendChatData, PostBotsByIdChannelByPlatformSendChatErrors, PostBotsByIdChannelByPlatformSendChatResponses, PostBotsByIdChannelByPlatformSendData, PostBotsByIdChannelByPlatformSendErrors, PostBotsByIdChannelByPlatformSendResponses, PostBotsData, PostBotsErrors, PostBotsResponses, PostEmailMailgunWebhookByConfigIdData, PostEmailMailgunWebhookByConfigIdErrors, PostEmailMailgunWebhookByConfigIdResponses, PostEmailProvidersData, PostEmailProvidersErrors, PostEmailProvidersResponses, PostMemoryProvidersData, PostMemoryProvidersErrors, PostMemoryProvidersResponses, PostModelsByIdTestData, PostModelsByIdTestErrors, PostModelsByIdTestResponses, PostModelsData, PostModelsErrors, PostModelsResponses, PostProvidersByIdImportModelsData, PostProvidersByIdImportModelsErrors, PostProvidersByIdImportModelsResponses, PostProvidersByIdTestData, PostProvidersByIdTestErrors, PostProvidersByIdTestResponses, PostProvidersData, PostProvidersErrors, PostProvidersResponses, PostSearchProvidersData, PostSearchProvidersErrors, PostSearchProvidersResponses, PostUsersData, PostUsersErrors, PostUsersResponses, PutBotsByBotIdEmailBindingsByIdData, PutBotsByBotIdEmailBindingsByIdErrors, PutBotsByBotIdEmailBindingsByIdResponses, PutBotsByBotIdMcpByIdData, PutBotsByBotIdMcpByIdErrors, PutBotsByBotIdMcpByIdResponses, PutBotsByBotIdMcpImportData, PutBotsByBotIdMcpImportErrors, PutBotsByBotIdMcpImportResponses, PutBotsByBotIdScheduleByIdData, PutBotsByBotIdScheduleByIdErrors, PutBotsByBotIdScheduleByIdResponses, PutBotsByBotIdSettingsData, PutBotsByBotIdSettingsErrors, PutBotsByBotIdSettingsResponses, PutBotsByBotIdSubagentsByIdContextData, PutBotsByBotIdSubagentsByIdContextErrors, PutBotsByBotIdSubagentsByIdContextResponses, PutBotsByBotIdSubagentsByIdData, PutBotsByBotIdSubagentsByIdErrors, PutBotsByBotIdSubagentsByIdResponses, PutBotsByBotIdSubagentsByIdSkillsData, PutBotsByBotIdSubagentsByIdSkillsErrors, PutBotsByBotIdSubagentsByIdSkillsResponses, PutBotsByIdChannelByPlatformData, PutBotsByIdChannelByPlatformErrors, PutBotsByIdChannelByPlatformResponses, PutBotsByIdData, PutBotsByIdErrors, PutBotsByIdMembersData, PutBotsByIdMembersErrors, PutBotsByIdMembersResponses, PutBotsByIdOwnerData, PutBotsByIdOwnerErrors, PutBotsByIdOwnerResponses, PutBotsByIdResponses, PutEmailProvidersByIdData, PutEmailProvidersByIdErrors, PutEmailProvidersByIdResponses, PutMemoryProvidersByIdData, PutMemoryProvidersByIdErrors, PutMemoryProvidersByIdResponses, PutModelsByIdData, PutModelsByIdErrors, PutModelsByIdResponses, PutModelsModelByModelIdData, PutModelsModelByModelIdErrors, PutModelsModelByModelIdResponses, PutProvidersByIdData, PutProvidersByIdErrors, PutProvidersByIdResponses, PutSearchProvidersByIdData, PutSearchProvidersByIdErrors, PutSearchProvidersByIdResponses, PutUsersByIdData, PutUsersByIdErrors, PutUsersByIdPasswordData, PutUsersByIdPasswordErrors, PutUsersByIdPasswordResponses, PutUsersByIdResponses, PutUsersMeChannelsByPlatformData, PutUsersMeChannelsByPlatformErrors, PutUsersMeChannelsByPlatformResponses, PutUsersMeData, PutUsersMeErrors, PutUsersMePasswordData, PutUsersMePasswordErrors, PutUsersMePasswordResponses, PutUsersMeResponses } from './types.gen'; +import type { DeleteBotsByBotIdContainerData, DeleteBotsByBotIdContainerErrors, DeleteBotsByBotIdContainerResponses, DeleteBotsByBotIdContainerSkillsData, DeleteBotsByBotIdContainerSkillsErrors, DeleteBotsByBotIdContainerSkillsResponses, DeleteBotsByBotIdEmailBindingsByIdData, DeleteBotsByBotIdEmailBindingsByIdErrors, DeleteBotsByBotIdEmailBindingsByIdResponses, DeleteBotsByBotIdHeartbeatLogsData, DeleteBotsByBotIdHeartbeatLogsErrors, DeleteBotsByBotIdHeartbeatLogsResponses, DeleteBotsByBotIdInboxByIdData, DeleteBotsByBotIdInboxByIdErrors, DeleteBotsByBotIdInboxByIdResponses, DeleteBotsByBotIdMcpByIdData, DeleteBotsByBotIdMcpByIdErrors, DeleteBotsByBotIdMcpByIdOauthTokenData, DeleteBotsByBotIdMcpByIdOauthTokenErrors, DeleteBotsByBotIdMcpByIdOauthTokenResponses, DeleteBotsByBotIdMcpByIdResponses, DeleteBotsByBotIdMemoryByIdData, DeleteBotsByBotIdMemoryByIdErrors, DeleteBotsByBotIdMemoryByIdResponses, DeleteBotsByBotIdMemoryData, DeleteBotsByBotIdMemoryErrors, DeleteBotsByBotIdMemoryResponses, DeleteBotsByBotIdMessagesData, DeleteBotsByBotIdMessagesErrors, DeleteBotsByBotIdMessagesResponses, DeleteBotsByBotIdScheduleByIdData, DeleteBotsByBotIdScheduleByIdErrors, DeleteBotsByBotIdScheduleByIdResponses, DeleteBotsByBotIdSettingsData, DeleteBotsByBotIdSettingsErrors, DeleteBotsByBotIdSettingsResponses, DeleteBotsByBotIdSubagentsByIdData, DeleteBotsByBotIdSubagentsByIdErrors, DeleteBotsByBotIdSubagentsByIdResponses, DeleteBotsByIdChannelByPlatformData, DeleteBotsByIdChannelByPlatformErrors, DeleteBotsByIdChannelByPlatformResponses, DeleteBotsByIdData, DeleteBotsByIdErrors, DeleteBotsByIdMembersByUserIdData, DeleteBotsByIdMembersByUserIdErrors, DeleteBotsByIdMembersByUserIdResponses, DeleteBotsByIdResponses, DeleteEmailProvidersByIdData, DeleteEmailProvidersByIdErrors, DeleteEmailProvidersByIdResponses, DeleteMemoryProvidersByIdData, DeleteMemoryProvidersByIdErrors, DeleteMemoryProvidersByIdResponses, DeleteModelsByIdData, DeleteModelsByIdErrors, DeleteModelsByIdResponses, DeleteModelsModelByModelIdData, DeleteModelsModelByModelIdErrors, DeleteModelsModelByModelIdResponses, DeleteProvidersByIdData, DeleteProvidersByIdErrors, DeleteProvidersByIdResponses, DeleteSearchProvidersByIdData, DeleteSearchProvidersByIdErrors, DeleteSearchProvidersByIdResponses, GetApiOauthMcpCallbackData, GetApiOauthMcpCallbackErrors, GetApiOauthMcpCallbackResponses, GetBotsByBotIdCliStreamData, GetBotsByBotIdCliStreamErrors, GetBotsByBotIdCliStreamResponses, GetBotsByBotIdContainerData, GetBotsByBotIdContainerErrors, GetBotsByBotIdContainerFsData, GetBotsByBotIdContainerFsDownloadData, GetBotsByBotIdContainerFsDownloadErrors, GetBotsByBotIdContainerFsDownloadResponses, GetBotsByBotIdContainerFsErrors, GetBotsByBotIdContainerFsListData, GetBotsByBotIdContainerFsListErrors, GetBotsByBotIdContainerFsListResponses, GetBotsByBotIdContainerFsReadData, GetBotsByBotIdContainerFsReadErrors, GetBotsByBotIdContainerFsReadResponses, GetBotsByBotIdContainerFsResponses, GetBotsByBotIdContainerResponses, GetBotsByBotIdContainerSkillsData, GetBotsByBotIdContainerSkillsErrors, GetBotsByBotIdContainerSkillsResponses, GetBotsByBotIdContainerSnapshotsData, GetBotsByBotIdContainerSnapshotsErrors, GetBotsByBotIdContainerSnapshotsResponses, GetBotsByBotIdEmailBindingsData, GetBotsByBotIdEmailBindingsErrors, GetBotsByBotIdEmailBindingsResponses, GetBotsByBotIdEmailOutboxByIdData, GetBotsByBotIdEmailOutboxByIdErrors, GetBotsByBotIdEmailOutboxByIdResponses, GetBotsByBotIdEmailOutboxData, GetBotsByBotIdEmailOutboxErrors, GetBotsByBotIdEmailOutboxResponses, GetBotsByBotIdHeartbeatLogsData, GetBotsByBotIdHeartbeatLogsErrors, GetBotsByBotIdHeartbeatLogsResponses, GetBotsByBotIdInboxByIdData, GetBotsByBotIdInboxByIdErrors, GetBotsByBotIdInboxByIdResponses, GetBotsByBotIdInboxCountData, GetBotsByBotIdInboxCountErrors, GetBotsByBotIdInboxCountResponses, GetBotsByBotIdInboxData, GetBotsByBotIdInboxErrors, GetBotsByBotIdInboxResponses, GetBotsByBotIdMcpByIdData, GetBotsByBotIdMcpByIdErrors, GetBotsByBotIdMcpByIdOauthStatusData, GetBotsByBotIdMcpByIdOauthStatusErrors, GetBotsByBotIdMcpByIdOauthStatusResponses, GetBotsByBotIdMcpByIdResponses, GetBotsByBotIdMcpData, GetBotsByBotIdMcpErrors, GetBotsByBotIdMcpExportData, GetBotsByBotIdMcpExportErrors, GetBotsByBotIdMcpExportResponses, GetBotsByBotIdMcpResponses, GetBotsByBotIdMemoryData, GetBotsByBotIdMemoryErrors, GetBotsByBotIdMemoryResponses, GetBotsByBotIdMemoryUsageData, GetBotsByBotIdMemoryUsageErrors, GetBotsByBotIdMemoryUsageResponses, GetBotsByBotIdMessagesData, GetBotsByBotIdMessagesErrors, GetBotsByBotIdMessagesResponses, GetBotsByBotIdScheduleByIdData, GetBotsByBotIdScheduleByIdErrors, GetBotsByBotIdScheduleByIdResponses, GetBotsByBotIdScheduleData, GetBotsByBotIdScheduleErrors, GetBotsByBotIdScheduleResponses, GetBotsByBotIdSettingsData, GetBotsByBotIdSettingsErrors, GetBotsByBotIdSettingsResponses, GetBotsByBotIdSubagentsByIdContextData, GetBotsByBotIdSubagentsByIdContextErrors, GetBotsByBotIdSubagentsByIdContextResponses, GetBotsByBotIdSubagentsByIdData, GetBotsByBotIdSubagentsByIdErrors, GetBotsByBotIdSubagentsByIdResponses, GetBotsByBotIdSubagentsByIdSkillsData, GetBotsByBotIdSubagentsByIdSkillsErrors, GetBotsByBotIdSubagentsByIdSkillsResponses, GetBotsByBotIdSubagentsData, GetBotsByBotIdSubagentsErrors, GetBotsByBotIdSubagentsResponses, GetBotsByBotIdTokenUsageData, GetBotsByBotIdTokenUsageErrors, GetBotsByBotIdTokenUsageResponses, GetBotsByBotIdWebStreamData, GetBotsByBotIdWebStreamErrors, GetBotsByBotIdWebStreamResponses, GetBotsByIdChannelByPlatformData, GetBotsByIdChannelByPlatformErrors, GetBotsByIdChannelByPlatformResponses, GetBotsByIdChecksData, GetBotsByIdChecksErrors, GetBotsByIdChecksResponses, GetBotsByIdData, GetBotsByIdErrors, GetBotsByIdMembersData, GetBotsByIdMembersErrors, GetBotsByIdMembersResponses, GetBotsByIdResponses, GetBotsData, GetBotsErrors, GetBotsResponses, GetChannelsByPlatformData, GetChannelsByPlatformErrors, GetChannelsByPlatformResponses, GetChannelsData, GetChannelsErrors, GetChannelsResponses, GetEmailProvidersByIdData, GetEmailProvidersByIdErrors, GetEmailProvidersByIdResponses, GetEmailProvidersData, GetEmailProvidersErrors, GetEmailProvidersMetaData, GetEmailProvidersMetaResponses, GetEmailProvidersResponses, GetMemoryProvidersByIdData, GetMemoryProvidersByIdErrors, GetMemoryProvidersByIdResponses, GetMemoryProvidersData, GetMemoryProvidersErrors, GetMemoryProvidersMetaData, GetMemoryProvidersMetaResponses, GetMemoryProvidersResponses, GetModelsByIdData, GetModelsByIdErrors, GetModelsByIdResponses, GetModelsCountData, GetModelsCountErrors, GetModelsCountResponses, GetModelsData, GetModelsErrors, GetModelsModelByModelIdData, GetModelsModelByModelIdErrors, GetModelsModelByModelIdResponses, GetModelsResponses, GetPingData, GetPingResponses, GetProvidersByIdData, GetProvidersByIdErrors, GetProvidersByIdModelsData, GetProvidersByIdModelsErrors, GetProvidersByIdModelsResponses, GetProvidersByIdResponses, GetProvidersCountData, GetProvidersCountErrors, GetProvidersCountResponses, GetProvidersData, GetProvidersErrors, GetProvidersNameByNameData, GetProvidersNameByNameErrors, GetProvidersNameByNameResponses, GetProvidersResponses, GetSearchProvidersByIdData, GetSearchProvidersByIdErrors, GetSearchProvidersByIdResponses, GetSearchProvidersData, GetSearchProvidersErrors, GetSearchProvidersMetaData, GetSearchProvidersMetaResponses, GetSearchProvidersResponses, GetUsersByIdData, GetUsersByIdErrors, GetUsersByIdResponses, GetUsersData, GetUsersErrors, GetUsersMeChannelsByPlatformData, GetUsersMeChannelsByPlatformErrors, GetUsersMeChannelsByPlatformResponses, GetUsersMeData, GetUsersMeErrors, GetUsersMeIdentitiesData, GetUsersMeIdentitiesErrors, GetUsersMeIdentitiesResponses, GetUsersMeResponses, GetUsersResponses, PatchBotsByIdChannelByPlatformStatusData, PatchBotsByIdChannelByPlatformStatusErrors, PatchBotsByIdChannelByPlatformStatusResponses, PostAuthLoginData, PostAuthLoginErrors, PostAuthLoginResponses, PostAuthRefreshData, PostAuthRefreshErrors, PostAuthRefreshResponses, PostBotsByBotIdCliMessagesData, PostBotsByBotIdCliMessagesErrors, PostBotsByBotIdCliMessagesResponses, PostBotsByBotIdContainerData, PostBotsByBotIdContainerErrors, PostBotsByBotIdContainerFsDeleteData, PostBotsByBotIdContainerFsDeleteErrors, PostBotsByBotIdContainerFsDeleteResponses, PostBotsByBotIdContainerFsMkdirData, PostBotsByBotIdContainerFsMkdirErrors, PostBotsByBotIdContainerFsMkdirResponses, PostBotsByBotIdContainerFsRenameData, PostBotsByBotIdContainerFsRenameErrors, PostBotsByBotIdContainerFsRenameResponses, PostBotsByBotIdContainerFsUploadData, PostBotsByBotIdContainerFsUploadErrors, PostBotsByBotIdContainerFsUploadResponses, PostBotsByBotIdContainerFsWriteData, PostBotsByBotIdContainerFsWriteErrors, PostBotsByBotIdContainerFsWriteResponses, PostBotsByBotIdContainerResponses, PostBotsByBotIdContainerSkillsData, PostBotsByBotIdContainerSkillsErrors, PostBotsByBotIdContainerSkillsResponses, PostBotsByBotIdContainerSnapshotsData, PostBotsByBotIdContainerSnapshotsErrors, PostBotsByBotIdContainerSnapshotsResponses, PostBotsByBotIdContainerStartData, PostBotsByBotIdContainerStartErrors, PostBotsByBotIdContainerStartResponses, PostBotsByBotIdContainerStopData, PostBotsByBotIdContainerStopErrors, PostBotsByBotIdContainerStopResponses, PostBotsByBotIdEmailBindingsData, PostBotsByBotIdEmailBindingsErrors, PostBotsByBotIdEmailBindingsResponses, PostBotsByBotIdInboxData, PostBotsByBotIdInboxErrors, PostBotsByBotIdInboxMarkReadData, PostBotsByBotIdInboxMarkReadErrors, PostBotsByBotIdInboxMarkReadResponses, PostBotsByBotIdInboxResponses, PostBotsByBotIdMcpByIdOauthAuthorizeData, PostBotsByBotIdMcpByIdOauthAuthorizeErrors, PostBotsByBotIdMcpByIdOauthAuthorizeResponses, PostBotsByBotIdMcpByIdOauthDiscoverData, PostBotsByBotIdMcpByIdOauthDiscoverErrors, PostBotsByBotIdMcpByIdOauthDiscoverResponses, PostBotsByBotIdMcpByIdProbeData, PostBotsByBotIdMcpByIdProbeErrors, PostBotsByBotIdMcpByIdProbeResponses, PostBotsByBotIdMcpData, PostBotsByBotIdMcpErrors, PostBotsByBotIdMcpOpsBatchDeleteData, PostBotsByBotIdMcpOpsBatchDeleteErrors, PostBotsByBotIdMcpOpsBatchDeleteResponses, PostBotsByBotIdMcpResponses, PostBotsByBotIdMcpStdioByConnectionIdData, PostBotsByBotIdMcpStdioByConnectionIdErrors, PostBotsByBotIdMcpStdioByConnectionIdResponses, PostBotsByBotIdMcpStdioData, PostBotsByBotIdMcpStdioErrors, PostBotsByBotIdMcpStdioResponses, PostBotsByBotIdMemoryCompactData, PostBotsByBotIdMemoryCompactErrors, PostBotsByBotIdMemoryCompactResponses, PostBotsByBotIdMemoryData, PostBotsByBotIdMemoryErrors, PostBotsByBotIdMemoryRebuildData, PostBotsByBotIdMemoryRebuildErrors, PostBotsByBotIdMemoryRebuildResponses, PostBotsByBotIdMemoryResponses, PostBotsByBotIdMemorySearchData, PostBotsByBotIdMemorySearchErrors, PostBotsByBotIdMemorySearchResponses, PostBotsByBotIdScheduleData, PostBotsByBotIdScheduleErrors, PostBotsByBotIdScheduleResponses, PostBotsByBotIdSettingsData, PostBotsByBotIdSettingsErrors, PostBotsByBotIdSettingsResponses, PostBotsByBotIdSubagentsByIdSkillsData, PostBotsByBotIdSubagentsByIdSkillsErrors, PostBotsByBotIdSubagentsByIdSkillsResponses, PostBotsByBotIdSubagentsData, PostBotsByBotIdSubagentsErrors, PostBotsByBotIdSubagentsResponses, PostBotsByBotIdToolsData, PostBotsByBotIdToolsErrors, PostBotsByBotIdToolsResponses, PostBotsByBotIdWebMessagesData, PostBotsByBotIdWebMessagesErrors, PostBotsByBotIdWebMessagesResponses, PostBotsByIdChannelByPlatformSendChatData, PostBotsByIdChannelByPlatformSendChatErrors, PostBotsByIdChannelByPlatformSendChatResponses, PostBotsByIdChannelByPlatformSendData, PostBotsByIdChannelByPlatformSendErrors, PostBotsByIdChannelByPlatformSendResponses, PostBotsData, PostBotsErrors, PostBotsResponses, PostEmailMailgunWebhookByConfigIdData, PostEmailMailgunWebhookByConfigIdErrors, PostEmailMailgunWebhookByConfigIdResponses, PostEmailProvidersData, PostEmailProvidersErrors, PostEmailProvidersResponses, PostMemoryProvidersData, PostMemoryProvidersErrors, PostMemoryProvidersResponses, PostModelsByIdTestData, PostModelsByIdTestErrors, PostModelsByIdTestResponses, PostModelsData, PostModelsErrors, PostModelsResponses, PostProvidersByIdImportModelsData, PostProvidersByIdImportModelsErrors, PostProvidersByIdImportModelsResponses, PostProvidersByIdTestData, PostProvidersByIdTestErrors, PostProvidersByIdTestResponses, PostProvidersData, PostProvidersErrors, PostProvidersResponses, PostSearchProvidersData, PostSearchProvidersErrors, PostSearchProvidersResponses, PostUsersData, PostUsersErrors, PostUsersResponses, PutBotsByBotIdEmailBindingsByIdData, PutBotsByBotIdEmailBindingsByIdErrors, PutBotsByBotIdEmailBindingsByIdResponses, PutBotsByBotIdMcpByIdData, PutBotsByBotIdMcpByIdErrors, PutBotsByBotIdMcpByIdResponses, PutBotsByBotIdMcpImportData, PutBotsByBotIdMcpImportErrors, PutBotsByBotIdMcpImportResponses, PutBotsByBotIdScheduleByIdData, PutBotsByBotIdScheduleByIdErrors, PutBotsByBotIdScheduleByIdResponses, PutBotsByBotIdSettingsData, PutBotsByBotIdSettingsErrors, PutBotsByBotIdSettingsResponses, PutBotsByBotIdSubagentsByIdContextData, PutBotsByBotIdSubagentsByIdContextErrors, PutBotsByBotIdSubagentsByIdContextResponses, PutBotsByBotIdSubagentsByIdData, PutBotsByBotIdSubagentsByIdErrors, PutBotsByBotIdSubagentsByIdResponses, PutBotsByBotIdSubagentsByIdSkillsData, PutBotsByBotIdSubagentsByIdSkillsErrors, PutBotsByBotIdSubagentsByIdSkillsResponses, PutBotsByIdChannelByPlatformData, PutBotsByIdChannelByPlatformErrors, PutBotsByIdChannelByPlatformResponses, PutBotsByIdData, PutBotsByIdErrors, PutBotsByIdMembersData, PutBotsByIdMembersErrors, PutBotsByIdMembersResponses, PutBotsByIdOwnerData, PutBotsByIdOwnerErrors, PutBotsByIdOwnerResponses, PutBotsByIdResponses, PutEmailProvidersByIdData, PutEmailProvidersByIdErrors, PutEmailProvidersByIdResponses, PutMemoryProvidersByIdData, PutMemoryProvidersByIdErrors, PutMemoryProvidersByIdResponses, PutModelsByIdData, PutModelsByIdErrors, PutModelsByIdResponses, PutModelsModelByModelIdData, PutModelsModelByModelIdErrors, PutModelsModelByModelIdResponses, PutProvidersByIdData, PutProvidersByIdErrors, PutProvidersByIdResponses, PutSearchProvidersByIdData, PutSearchProvidersByIdErrors, PutSearchProvidersByIdResponses, PutUsersByIdData, PutUsersByIdErrors, PutUsersByIdPasswordData, PutUsersByIdPasswordErrors, PutUsersByIdPasswordResponses, PutUsersByIdResponses, PutUsersMeChannelsByPlatformData, PutUsersMeChannelsByPlatformErrors, PutUsersMeChannelsByPlatformResponses, PutUsersMeData, PutUsersMeErrors, PutUsersMePasswordData, PutUsersMePasswordErrors, PutUsersMePasswordResponses, PutUsersMeResponses } from './types.gen'; export type Options = Options2 & { /** @@ -18,6 +18,13 @@ export type Options; }; +/** + * OAuth callback handler + * + * Handles the OAuth authorization callback, exchanges code for tokens + */ +export const getApiOauthMcpCallback = (options: Options) => (options.client ?? client).get({ url: '/api/oauth/mcp/callback', ...options }); + /** * Login * @@ -484,6 +491,55 @@ export const putBotsByBotIdMcpById = (opti } }); +/** + * Start OAuth authorization flow + * + * Generate PKCE and return authorization URL for the user to authorize + */ +export const postBotsByBotIdMcpByIdOauthAuthorize = (options: Options) => (options.client ?? client).post({ + url: '/bots/{bot_id}/mcp/{id}/oauth/authorize', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Discover OAuth configuration for MCP server + * + * Probe MCP server URL for OAuth requirements and discover authorization server metadata + */ +export const postBotsByBotIdMcpByIdOauthDiscover = (options: Options) => (options.client ?? client).post({ + url: '/bots/{bot_id}/mcp/{id}/oauth/discover', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + +/** + * Get OAuth status for MCP connection + * + * Returns the current OAuth status including whether tokens are available + */ +export const getBotsByBotIdMcpByIdOauthStatus = (options: Options) => (options.client ?? client).get({ url: '/bots/{bot_id}/mcp/{id}/oauth/status', ...options }); + +/** + * Revoke OAuth tokens for MCP connection + * + * Clears stored OAuth tokens + */ +export const deleteBotsByBotIdMcpByIdOauthToken = (options: Options) => (options.client ?? client).delete({ url: '/bots/{bot_id}/mcp/{id}/oauth/token', ...options }); + +/** + * Probe MCP connection + * + * Probe a MCP connection to discover tools and verify connectivity + */ +export const postBotsByBotIdMcpByIdProbe = (options: Options) => (options.client ?? client).post({ url: '/bots/{bot_id}/mcp/{id}/probe', ...options }); + /** * Delete memories * diff --git a/packages/sdk/src/types.gen.ts b/packages/sdk/src/types.gen.ts index 342790e0..3e1247ff 100644 --- a/packages/sdk/src/types.gen.ts +++ b/packages/sdk/src/types.gen.ts @@ -424,6 +424,7 @@ export type GithubComMemohaiMemohInternalFsFileInfo = { }; export type GithubComMemohaiMemohInternalMcpConnection = { + auth_type?: string; bot_id?: string; config?: { [key: string]: unknown; @@ -431,7 +432,11 @@ export type GithubComMemohaiMemohInternalMcpConnection = { created_at?: string; id?: string; is_active?: boolean; + last_probed_at?: string; name?: string; + status?: string; + status_message?: string; + tools_cache?: Array; type?: string; updated_at?: string; }; @@ -597,6 +602,13 @@ export type HandlersPingResponse = { status?: string; }; +export type HandlersProbeResponse = { + auth_required?: boolean; + error?: string; + status?: string; + tools?: Array; +}; + export type HandlersRefreshResponse = { access_token?: string; expires_at?: string; @@ -695,6 +707,14 @@ export type HandlersMemorySearchPayload = { sources?: Array; }; +export type HandlersOauthAuthorizeRequest = { + client_id?: string; +}; + +export type HandlersOauthDiscoverRequest = { + url?: string; +}; + export type HandlersSkillsOpResponse = { ok?: boolean; }; @@ -757,6 +777,20 @@ export type InboxItem = { source?: string; }; +export type McpAuthorizeResult = { + authorization_url?: string; +}; + +export type McpDiscoveryResult = { + authorization_endpoint?: string; + authorization_server_url?: string; + registration_endpoint?: string; + resource_metadata_url?: string; + resource_uri?: string; + scopes_supported?: Array; + token_endpoint?: string; +}; + export type McpExportResponse = { mcpServers?: { [key: string]: McpMcpServerEntry; @@ -787,8 +821,26 @@ export type McpMcpServerEntry = { url?: string; }; +export type McpOAuthStatus = { + auth_server?: string; + configured?: boolean; + expired?: boolean; + expires_at?: string; + has_token?: boolean; + scopes?: string; +}; + +export type McpToolDescriptor = { + description?: string; + inputSchema?: { + [key: string]: unknown; + }; + name?: string; +}; + export type McpUpsertRequest = { args?: Array; + auth_type?: string; command?: string; cwd?: string; env?: { @@ -1263,6 +1315,40 @@ export type SubagentUpdateSkillsRequest = { skills?: Array; }; +export type GetApiOauthMcpCallbackData = { + body?: never; + path?: never; + query: { + /** + * Authorization code + */ + code: string; + /** + * State parameter + */ + state: string; + }; + url: '/api/oauth/mcp/callback'; +}; + +export type GetApiOauthMcpCallbackErrors = { + /** + * Bad Request + */ + 400: HandlersErrorResponse; +}; + +export type GetApiOauthMcpCallbackError = GetApiOauthMcpCallbackErrors[keyof GetApiOauthMcpCallbackErrors]; + +export type GetApiOauthMcpCallbackResponses = { + /** + * HTML page that closes the popup + */ + 200: string; +}; + +export type GetApiOauthMcpCallbackResponse = GetApiOauthMcpCallbackResponses[keyof GetApiOauthMcpCallbackResponses]; + export type PostAuthLoginData = { /** * Login request @@ -3169,6 +3255,184 @@ export type PutBotsByBotIdMcpByIdResponses = { export type PutBotsByBotIdMcpByIdResponse = PutBotsByBotIdMcpByIdResponses[keyof PutBotsByBotIdMcpByIdResponses]; +export type PostBotsByBotIdMcpByIdOauthAuthorizeData = { + /** + * Optional client_id + */ + body?: HandlersOauthAuthorizeRequest; + path: { + /** + * MCP connection ID + */ + id: string; + }; + query?: never; + url: '/bots/{bot_id}/mcp/{id}/oauth/authorize'; +}; + +export type PostBotsByBotIdMcpByIdOauthAuthorizeErrors = { + /** + * Bad Request + */ + 400: HandlersErrorResponse; + /** + * Not Found + */ + 404: HandlersErrorResponse; +}; + +export type PostBotsByBotIdMcpByIdOauthAuthorizeError = PostBotsByBotIdMcpByIdOauthAuthorizeErrors[keyof PostBotsByBotIdMcpByIdOauthAuthorizeErrors]; + +export type PostBotsByBotIdMcpByIdOauthAuthorizeResponses = { + /** + * OK + */ + 200: McpAuthorizeResult; +}; + +export type PostBotsByBotIdMcpByIdOauthAuthorizeResponse = PostBotsByBotIdMcpByIdOauthAuthorizeResponses[keyof PostBotsByBotIdMcpByIdOauthAuthorizeResponses]; + +export type PostBotsByBotIdMcpByIdOauthDiscoverData = { + /** + * Optional URL override + */ + body?: HandlersOauthDiscoverRequest; + path: { + /** + * MCP connection ID + */ + id: string; + }; + query?: never; + url: '/bots/{bot_id}/mcp/{id}/oauth/discover'; +}; + +export type PostBotsByBotIdMcpByIdOauthDiscoverErrors = { + /** + * Bad Request + */ + 400: HandlersErrorResponse; + /** + * Not Found + */ + 404: HandlersErrorResponse; +}; + +export type PostBotsByBotIdMcpByIdOauthDiscoverError = PostBotsByBotIdMcpByIdOauthDiscoverErrors[keyof PostBotsByBotIdMcpByIdOauthDiscoverErrors]; + +export type PostBotsByBotIdMcpByIdOauthDiscoverResponses = { + /** + * OK + */ + 200: McpDiscoveryResult; +}; + +export type PostBotsByBotIdMcpByIdOauthDiscoverResponse = PostBotsByBotIdMcpByIdOauthDiscoverResponses[keyof PostBotsByBotIdMcpByIdOauthDiscoverResponses]; + +export type GetBotsByBotIdMcpByIdOauthStatusData = { + body?: never; + path: { + /** + * MCP connection ID + */ + id: string; + }; + query?: never; + url: '/bots/{bot_id}/mcp/{id}/oauth/status'; +}; + +export type GetBotsByBotIdMcpByIdOauthStatusErrors = { + /** + * Bad Request + */ + 400: HandlersErrorResponse; + /** + * Not Found + */ + 404: HandlersErrorResponse; +}; + +export type GetBotsByBotIdMcpByIdOauthStatusError = GetBotsByBotIdMcpByIdOauthStatusErrors[keyof GetBotsByBotIdMcpByIdOauthStatusErrors]; + +export type GetBotsByBotIdMcpByIdOauthStatusResponses = { + /** + * OK + */ + 200: McpOAuthStatus; +}; + +export type GetBotsByBotIdMcpByIdOauthStatusResponse = GetBotsByBotIdMcpByIdOauthStatusResponses[keyof GetBotsByBotIdMcpByIdOauthStatusResponses]; + +export type DeleteBotsByBotIdMcpByIdOauthTokenData = { + body?: never; + path: { + /** + * MCP connection ID + */ + id: string; + }; + query?: never; + url: '/bots/{bot_id}/mcp/{id}/oauth/token'; +}; + +export type DeleteBotsByBotIdMcpByIdOauthTokenErrors = { + /** + * Bad Request + */ + 400: HandlersErrorResponse; +}; + +export type DeleteBotsByBotIdMcpByIdOauthTokenError = DeleteBotsByBotIdMcpByIdOauthTokenErrors[keyof DeleteBotsByBotIdMcpByIdOauthTokenErrors]; + +export type DeleteBotsByBotIdMcpByIdOauthTokenResponses = { + /** + * No Content + */ + 204: unknown; +}; + +export type PostBotsByBotIdMcpByIdProbeData = { + body?: never; + path: { + /** + * MCP connection ID + */ + id: string; + }; + query?: never; + url: '/bots/{bot_id}/mcp/{id}/probe'; +}; + +export type PostBotsByBotIdMcpByIdProbeErrors = { + /** + * Bad Request + */ + 400: HandlersErrorResponse; + /** + * Forbidden + */ + 403: HandlersErrorResponse; + /** + * Not Found + */ + 404: HandlersErrorResponse; + /** + * Internal Server Error + */ + 500: HandlersErrorResponse; +}; + +export type PostBotsByBotIdMcpByIdProbeError = PostBotsByBotIdMcpByIdProbeErrors[keyof PostBotsByBotIdMcpByIdProbeErrors]; + +export type PostBotsByBotIdMcpByIdProbeResponses = { + /** + * OK + */ + 200: HandlersProbeResponse; +}; + +export type PostBotsByBotIdMcpByIdProbeResponse = PostBotsByBotIdMcpByIdProbeResponses[keyof PostBotsByBotIdMcpByIdProbeResponses]; + export type DeleteBotsByBotIdMemoryData = { /** * Optional: specify memory_ids to delete; if omitted, deletes all diff --git a/packages/web/src/i18n/locales/en.json b/packages/web/src/i18n/locales/en.json index 7b1242c8..24948d95 100644 --- a/packages/web/src/i18n/locales/en.json +++ b/packages/web/src/i18n/locales/en.json @@ -315,7 +315,49 @@ "importHint": "Paste a standard mcpServers JSON configuration. Existing servers with the same name will be updated.", "importSuccess": "MCP servers imported", "importFailed": "Failed to import MCP servers", - "exportFailed": "Failed to export MCP servers" + "exportFailed": "Failed to export MCP servers", + "probe": "Test Connection", + "probing": "Testing...", + "probeSuccess": "Connection verified", + "probeFailed": "Connection test failed", + "probeRefresh": "Refresh", + "tools": "Tools", + "toolsEmpty": "No tools discovered", + "toolsCount": "{count} tool(s) available", + "statusConnected": "Connected", + "statusError": "Error", + "statusUnknown": "Not tested", + "lastProbed": "Last tested", + "authRequired": "Authorization required", + "oauth": { + "title": "Authentication", + "status": "OAuth Status", + "notConfigured": "Not configured", + "authorized": "Authorized", + "expired": "Token expired", + "discover": "Detect OAuth", + "discovering": "Detecting...", + "authorize": "Authorize", + "authorizing": "Authorizing...", + "revoke": "Revoke", + "revokeConfirm": "Are you sure you want to revoke OAuth authorization?", + "revokeSuccess": "OAuth authorization revoked", + "revokeFailed": "Failed to revoke OAuth", + "discoverSuccess": "OAuth server detected", + "discoverFailed": "OAuth detection failed", + "authSuccess": "Authorization successful", + "authFailed": "Authorization failed", + "scopes": "Scopes", + "authServer": "Authorization Server", + "clientId": "Client ID", + "clientIdPlaceholder": "OAuth App Client ID", + "clientSecret": "Client Secret", + "clientSecretPlaceholder": "OAuth App Client Secret (if required)", + "clientIdHint": "The authorization server does not support automatic registration. Please create an OAuth App and enter its Client ID.", + "callbackUrl": "Callback URL", + "callbackUrlHint": "Set this as the callback/redirect URL in your OAuth App settings.", + "callbackMissingParams": "Missing authorization code or state parameter" + } }, "home": { "title": "Home" diff --git a/packages/web/src/i18n/locales/zh.json b/packages/web/src/i18n/locales/zh.json index 9c8cfef4..14c7f1c0 100644 --- a/packages/web/src/i18n/locales/zh.json +++ b/packages/web/src/i18n/locales/zh.json @@ -311,7 +311,49 @@ "importHint": "粘贴标准 mcpServers JSON 配置。同名的服务器会被更新配置。", "importSuccess": "MCP 服务器已导入", "importFailed": "导入 MCP 服务器失败", - "exportFailed": "导出 MCP 服务器失败" + "exportFailed": "导出 MCP 服务器失败", + "probe": "测试连接", + "probing": "测试中...", + "probeSuccess": "连接验证成功", + "probeFailed": "连接测试失败", + "probeRefresh": "刷新", + "tools": "工具", + "toolsEmpty": "未发现工具", + "toolsCount": "已发现 {count} 个工具", + "statusConnected": "已连接", + "statusError": "错误", + "statusUnknown": "未测试", + "lastProbed": "上次测试", + "authRequired": "需要授权", + "oauth": { + "title": "认证", + "status": "OAuth 状态", + "notConfigured": "未配置", + "authorized": "已授权", + "expired": "令牌已过期", + "discover": "检测 OAuth", + "discovering": "检测中...", + "authorize": "授权", + "authorizing": "授权中...", + "revoke": "撤销", + "revokeConfirm": "确定要撤销 OAuth 授权吗?", + "revokeSuccess": "OAuth 授权已撤销", + "revokeFailed": "撤销 OAuth 失败", + "discoverSuccess": "已检测到 OAuth 服务器", + "discoverFailed": "OAuth 检测失败", + "authSuccess": "授权成功", + "authFailed": "授权失败", + "scopes": "权限范围", + "authServer": "授权服务器", + "clientId": "Client ID", + "clientIdPlaceholder": "OAuth 应用的 Client ID", + "clientSecret": "Client Secret", + "clientSecretPlaceholder": "OAuth 应用的 Client Secret(如需要)", + "clientIdHint": "该授权服务器不支持自动注册,请创建 OAuth 应用并输入其 Client ID。", + "callbackUrl": "回调地址", + "callbackUrlHint": "请在 OAuth 应用设置中填入此回调地址。", + "callbackMissingParams": "缺少授权码或状态参数" + } }, "home": { "title": "首页" diff --git a/packages/web/src/pages/bots/components/bot-mcp.vue b/packages/web/src/pages/bots/components/bot-mcp.vue index 0c3cd9f0..ae0b0a11 100644 --- a/packages/web/src/pages/bots/components/bot-mcp.vue +++ b/packages/web/src/pages/bots/components/bot-mcp.vue @@ -45,7 +45,7 @@
{{ item.name }} @@ -266,6 +266,235 @@
+ + +
+
+
+

+ {{ $t('mcp.tools') }} +

+ + {{ $t('mcp.statusConnected') }} + + + {{ $t('mcp.statusError') }} + + + {{ $t('mcp.statusUnknown') }} + +
+ +
+ +
+ {{ selectedItem.status_message }} +
+ +
+ + {{ $t('mcp.authRequired') }} +
+ + +
+
+

+ {{ $t('mcp.oauth.title') }} +

+ + {{ $t('mcp.oauth.authorized') }} + + + {{ $t('mcp.oauth.expired') }} + + + {{ $t('mcp.oauth.notConfigured') }} + +
+ +
+ {{ $t('mcp.oauth.authServer') }}: {{ oauthStatus.auth_server }} +
+ + +
+

+ {{ $t('mcp.oauth.clientIdHint') }} +

+
+ + +
+
+ + +
+
+ +
+ {{ oauthCallbackUrl }} + +
+

+ {{ $t('mcp.oauth.callbackUrlHint') }} +

+
+
+ +
+ + +
+
+ +
+

+ {{ $t('mcp.toolsCount', { count: displayTools.length }) }} +

+
+ +
+ {{ tool.name }} +

+ {{ tool.description }} +

+
+
+
+

+ {{ $t('mcp.toolsEmpty') }} +

+ +

+ {{ $t('mcp.lastProbed') }}: {{ formatDate(selectedItem.last_probed_at) }} +

+
@@ -469,12 +698,22 @@ import { client } from '@memoh/sdk/client' import { resolveApiErrorMessage } from '@/utils/api-error' import { useClipboard } from '@/composables/useClipboard' +interface ToolDescriptor { + name: string + description: string +} + interface McpItem { id: string name: string type: string config: Record is_active: boolean + status: string + tools_cache: ToolDescriptor[] + last_probed_at: string | null + status_message: string + auth_type: string } interface McpServerEntry { @@ -487,6 +726,13 @@ interface McpServerEntry { transport?: string } +interface ProbeResponse { + status: string + tools: ToolDescriptor[] + error?: string + auth_required?: boolean +} + const DRAFT_ID = '' const IMPORT_EXAMPLE = JSON.stringify({ @@ -513,6 +759,33 @@ const items = ref([]) const selectedItem = ref(null) const searchText = ref('') const submitting = ref(false) +const probing = ref(false) +const probeAuthRequired = ref(false) +const oauthDiscovering = ref(false) +const oauthAuthorizing = ref(false) + +interface OAuthStatusResponse { + configured: boolean + has_token: boolean + expired: boolean + scopes?: string + expires_at?: string + auth_server?: string + callback_url?: string +} + +interface OAuthDiscoveryResponse { + registration_endpoint?: string + authorization_endpoint?: string + token_endpoint?: string +} + +const oauthStatus = ref(null) +const oauthClientId = ref('') +const oauthClientSecret = ref('') +const oauthNeedsClientId = ref(false) +const oauthCallbackUrl = ref('') +const oauthDiscovered = ref(false) const createDialogOpen = ref(false) const createName = ref('') @@ -544,6 +817,30 @@ const filteredItems = computed(() => { return items.value.filter((i) => i.id === DRAFT_ID || i.name.toLowerCase().includes(kw)) }) +const displayTools = computed(() => { + if (!selectedItem.value) return [] + return selectedItem.value.tools_cache ?? [] +}) + +function statusDotClass(item: McpItem): string { + if (!item.id) return 'bg-muted-foreground/40' + if (!item.is_active) return 'bg-muted-foreground/40' + switch (item.status) { + case 'connected': return 'bg-green-500' + case 'error': return 'bg-destructive' + default: return 'bg-amber-400' + } +} + +function formatDate(dateStr: string | null): string { + if (!dateStr) return '' + try { + return new Date(dateStr).toLocaleString() + } catch { + return dateStr + } +} + function configValue(config: Record, key: string): string { const val = config?.[key] return typeof val === 'string' ? val : '' @@ -581,6 +878,16 @@ function pairsToRecord(pairs: KeyValuePair[]): Record { function selectItem(item: McpItem) { selectedItem.value = item + probeAuthRequired.value = false + oauthStatus.value = null + oauthClientId.value = '' + oauthClientSecret.value = '' + oauthNeedsClientId.value = false + oauthCallbackUrl.value = '' + oauthDiscovered.value = false + if (item.id && item.type !== 'stdio') { + loadOAuthStatus(item) + } const cfg = item.config ?? {} connectionType.value = item.type === 'stdio' ? 'stdio' : 'remote' formData.value = { @@ -621,6 +928,11 @@ function handleCreateDraft() { type: createType.value === 'stdio' ? 'stdio' : 'http', config: {}, is_active: true, + status: 'unknown', + tools_cache: [], + last_probed_at: null, + status_message: '', + auth_type: 'none', } items.value = [draft, ...items.value] selectItem(draft) @@ -677,7 +989,14 @@ async function loadList() { path: { bot_id: props.botId }, throwOnError: true, }) - const serverItems: McpItem[] = data.items ?? [] + const serverItems: McpItem[] = (data.items ?? []).map((item: Record) => ({ + ...item, + status: item.status ?? 'unknown', + tools_cache: item.tools_cache ?? [], + last_probed_at: item.last_probed_at ?? null, + status_message: item.status_message ?? '', + auth_type: item.auth_type ?? 'none', + })) const draft = items.value.find((i) => i.id === DRAFT_ID) items.value = draft ? [draft, ...serverItems] : serverItems @@ -696,23 +1015,57 @@ async function loadList() { } } +async function handleProbe(item: McpItem) { + if (!item.id) return + probing.value = true + probeAuthRequired.value = false + try { + const { data } = await client.post({ + url: '/bots/{bot_id}/mcp/{id}/probe', + path: { bot_id: props.botId, id: item.id }, + throwOnError: true, + }) + if (data) { + item.status = data.status + item.tools_cache = data.tools ?? [] + item.status_message = data.error ?? '' + item.last_probed_at = new Date().toISOString() + probeAuthRequired.value = !!data.auth_required + if (data.status === 'connected') { + toast.success(t('mcp.probeSuccess')) + } else if (data.auth_required) { + toast.warning(t('mcp.authRequired')) + } else { + toast.error(data.error || t('mcp.probeFailed')) + } + } + } catch (error) { + toast.error(resolveApiErrorMessage(error, t('mcp.probeFailed'))) + } finally { + probing.value = false + } +} + async function handleSubmit() { if (!selectedItem.value) return submitting.value = true try { const body = buildRequestBody(formData.value, connectionType.value, argsTags.value, envPairs.value, headerPairs.value) + let savedId: string | undefined if (isDraft.value) { const { data } = await postBotsByBotIdMcp({ path: { bot_id: props.botId }, body, throwOnError: true, }) + savedId = data?.id removeDraft() await loadList() - const created = items.value.find((i) => i.id === data?.id) ?? items.value.find((i) => i.name === body.name) + const created = items.value.find((i) => i.id === savedId) ?? items.value.find((i) => i.name === body.name) if (created) selectItem(created) toast.success(t('mcp.createSuccess')) } else { + savedId = selectedItem.value.id await putBotsByBotIdMcpById({ path: { bot_id: props.botId, id: selectedItem.value.id }, body, @@ -721,6 +1074,9 @@ async function handleSubmit() { await loadList() toast.success(t('mcp.updateSuccess')) } + if (savedId && selectedItem.value) { + handleProbe(selectedItem.value) + } } catch (error) { toast.error(resolveApiErrorMessage(error, t('common.saveFailed'))) } finally { @@ -786,6 +1142,130 @@ function handleCopyExport() { toast.success(t('common.copied')) } +async function loadOAuthStatus(item: McpItem) { + if (!item.id || item.type === 'stdio') { + oauthStatus.value = null + return + } + try { + const { data } = await client.get({ + url: '/bots/{bot_id}/mcp/{id}/oauth/status', + path: { bot_id: props.botId, id: item.id }, + throwOnError: true, + }) + oauthStatus.value = data ?? null + oauthCallbackUrl.value = `${window.location.origin}/oauth/mcp/callback` + } catch { + oauthStatus.value = null + } +} + +async function handleOAuthDiscover() { + if (!selectedItem.value?.id) return + const item = selectedItem.value + + oauthDiscovering.value = true + oauthNeedsClientId.value = false + try { + const { data } = await client.post({ + url: '/bots/{bot_id}/mcp/{id}/oauth/discover', + path: { bot_id: props.botId, id: item.id }, + throwOnError: true, + }) + toast.success(t('mcp.oauth.discoverSuccess')) + if (!data?.registration_endpoint) { + oauthNeedsClientId.value = true + } + } catch (error) { + toast.error(resolveApiErrorMessage(error, t('mcp.oauth.discoverFailed'))) + oauthDiscovering.value = false + return false + } + oauthDiscovering.value = false + return true +} + +async function handleOAuthFlow() { + if (!selectedItem.value?.id) return + const item = selectedItem.value + + if (!oauthDiscovered.value) { + const discovered = await handleOAuthDiscover() + if (!discovered) return + oauthDiscovered.value = true + if (oauthNeedsClientId.value && !oauthClientId.value.trim()) { + return + } + } + + oauthAuthorizing.value = true + try { + const { data } = await client.post<{ authorization_url: string }>({ + url: '/bots/{bot_id}/mcp/{id}/oauth/authorize', + path: { bot_id: props.botId, id: item.id }, + body: { + client_id: oauthClientId.value.trim() || undefined, + client_secret: oauthClientSecret.value.trim() || undefined, + callback_url: `${window.location.origin}/oauth/mcp/callback`, + }, + throwOnError: true, + }) + if (!data?.authorization_url) { + toast.error(t('mcp.oauth.authFailed')) + oauthAuthorizing.value = false + return + } + + const popup = window.open(data.authorization_url, 'mcp-oauth', 'width=600,height=700') + + const onMessage = async (event: MessageEvent) => { + if (event.data?.type === 'mcp-oauth-callback') { + window.removeEventListener('message', onMessage) + oauthAuthorizing.value = false + if (event.data.status === 'success') { + toast.success(t('mcp.oauth.authSuccess')) + await loadOAuthStatus(item) + handleProbe(item) + } else { + toast.error(event.data.error || t('mcp.oauth.authFailed')) + } + } + } + window.addEventListener('message', onMessage) + + const pollTimer = setInterval(() => { + if (popup && popup.closed) { + clearInterval(pollTimer) + window.removeEventListener('message', onMessage) + oauthAuthorizing.value = false + loadOAuthStatus(item) + } + }, 500) + } catch (error) { + toast.error(resolveApiErrorMessage(error, t('mcp.oauth.authFailed'))) + oauthAuthorizing.value = false + } +} + +async function handleOAuthRevoke() { + if (!selectedItem.value?.id) return + try { + await client.delete({ + url: '/bots/{bot_id}/mcp/{id}/oauth/token', + path: { bot_id: props.botId, id: selectedItem.value.id }, + throwOnError: true, + }) + toast.success(t('mcp.oauth.revokeSuccess')) + oauthDiscovered.value = false + oauthNeedsClientId.value = false + oauthClientId.value = '' + oauthClientSecret.value = '' + await loadOAuthStatus(selectedItem.value) + } catch (error) { + toast.error(resolveApiErrorMessage(error, t('mcp.oauth.revokeFailed'))) + } +} + watch(connectionType, (mode) => { if (mode === 'stdio') { formData.value.url = '' diff --git a/packages/web/src/pages/oauth/mcp-callback.vue b/packages/web/src/pages/oauth/mcp-callback.vue new file mode 100644 index 00000000..5dc9a9c2 --- /dev/null +++ b/packages/web/src/pages/oauth/mcp-callback.vue @@ -0,0 +1,94 @@ + + + diff --git a/packages/web/src/router.ts b/packages/web/src/router.ts index f80f47f5..41f629f2 100644 --- a/packages/web/src/router.ts +++ b/packages/web/src/router.ts @@ -114,6 +114,11 @@ const routes = [ path: '/login', component: () => import('@/pages/login/index.vue'), }, + { + name: 'oauth-mcp-callback', + path: '/oauth/mcp/callback', + component: () => import('@/pages/oauth/mcp-callback.vue'), + }, ] const router = createRouter({ @@ -123,11 +128,13 @@ const router = createRouter({ router.beforeEach((to) => { const token = localStorage.getItem('token') - if (to.fullPath !== '/login') { - return token ? true : { name: 'Login' } - } else { + if (to.fullPath === '/login') { return token ? { path: '/chat' } : true } + if (to.path.startsWith('/oauth/')) { + return true + } + return token ? true : { name: 'Login' } }) export default router diff --git a/scripts/release.sh b/scripts/release.sh index 88a34460..42450064 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +çç#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" diff --git a/spec/docs.go b/spec/docs.go index 02cfbaa0..130e353f 100644 --- a/spec/docs.go +++ b/spec/docs.go @@ -15,6 +15,45 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/api/oauth/mcp/callback": { + "get": { + "description": "Handles the OAuth authorization callback, exchanges code for tokens", + "tags": [ + "mcp" + ], + "summary": "OAuth callback handler", + "parameters": [ + { + "type": "string", + "description": "Authorization code", + "name": "code", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "State parameter", + "name": "state", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "HTML page that closes the popup", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, "/auth/login": { "post": { "description": "Validate user credentials and issue a JWT", @@ -2324,6 +2363,215 @@ const docTemplate = `{ } } }, + "/bots/{bot_id}/mcp/{id}/oauth/authorize": { + "post": { + "description": "Generate PKCE and return authorization URL for the user to authorize", + "tags": [ + "mcp" + ], + "summary": "Start OAuth authorization flow", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Optional client_id", + "name": "payload", + "in": "body", + "schema": { + "$ref": "#/definitions/handlers.oauthAuthorizeRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/mcp.AuthorizeResult" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/bots/{bot_id}/mcp/{id}/oauth/discover": { + "post": { + "description": "Probe MCP server URL for OAuth requirements and discover authorization server metadata", + "tags": [ + "mcp" + ], + "summary": "Discover OAuth configuration for MCP server", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Optional URL override", + "name": "payload", + "in": "body", + "schema": { + "$ref": "#/definitions/handlers.oauthDiscoverRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/mcp.DiscoveryResult" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/bots/{bot_id}/mcp/{id}/oauth/status": { + "get": { + "description": "Returns the current OAuth status including whether tokens are available", + "tags": [ + "mcp" + ], + "summary": "Get OAuth status for MCP connection", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/mcp.OAuthStatus" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/bots/{bot_id}/mcp/{id}/oauth/token": { + "delete": { + "description": "Clears stored OAuth tokens", + "tags": [ + "mcp" + ], + "summary": "Revoke OAuth tokens for MCP connection", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/bots/{bot_id}/mcp/{id}/probe": { + "post": { + "description": "Probe a MCP connection to discover tools and verify connectivity", + "tags": [ + "mcp" + ], + "summary": "Probe MCP connection", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.ProbeResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, "/bots/{bot_id}/memory": { "get": { "description": "List all memories in the bot-shared namespace", @@ -7928,6 +8176,9 @@ const docTemplate = `{ "github_com_memohai_memoh_internal_mcp.Connection": { "type": "object", "properties": { + "auth_type": { + "type": "string" + }, "bot_id": { "type": "string" }, @@ -7944,9 +8195,24 @@ const docTemplate = `{ "is_active": { "type": "boolean" }, + "last_probed_at": { + "type": "string" + }, "name": { "type": "string" }, + "status": { + "type": "string" + }, + "status_message": { + "type": "string" + }, + "tools_cache": { + "type": "array", + "items": { + "$ref": "#/definitions/mcp.ToolDescriptor" + } + }, "type": { "type": "string" }, @@ -8350,6 +8616,26 @@ const docTemplate = `{ } } }, + "handlers.ProbeResponse": { + "type": "object", + "properties": { + "auth_required": { + "type": "boolean" + }, + "error": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/mcp.ToolDescriptor" + } + } + } + }, "handlers.RefreshResponse": { "type": "object", "properties": { @@ -8598,6 +8884,22 @@ const docTemplate = `{ } } }, + "handlers.oauthAuthorizeRequest": { + "type": "object", + "properties": { + "client_id": { + "type": "string" + } + } + }, + "handlers.oauthDiscoverRequest": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, "handlers.skillsOpResponse": { "type": "object", "properties": { @@ -8742,6 +9044,43 @@ const docTemplate = `{ } } }, + "mcp.AuthorizeResult": { + "type": "object", + "properties": { + "authorization_url": { + "type": "string" + } + } + }, + "mcp.DiscoveryResult": { + "type": "object", + "properties": { + "authorization_endpoint": { + "type": "string" + }, + "authorization_server_url": { + "type": "string" + }, + "registration_endpoint": { + "type": "string" + }, + "resource_metadata_url": { + "type": "string" + }, + "resource_uri": { + "type": "string" + }, + "scopes_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "token_endpoint": { + "type": "string" + } + } + }, "mcp.ExportResponse": { "type": "object", "properties": { @@ -8810,6 +9149,44 @@ const docTemplate = `{ } } }, + "mcp.OAuthStatus": { + "type": "object", + "properties": { + "auth_server": { + "type": "string" + }, + "configured": { + "type": "boolean" + }, + "expired": { + "type": "boolean" + }, + "expires_at": { + "type": "string" + }, + "has_token": { + "type": "boolean" + }, + "scopes": { + "type": "string" + } + } + }, + "mcp.ToolDescriptor": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "inputSchema": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + } + } + }, "mcp.UpsertRequest": { "type": "object", "properties": { @@ -8819,6 +9196,9 @@ const docTemplate = `{ "type": "string" } }, + "auth_type": { + "type": "string" + }, "command": { "type": "string" }, diff --git a/spec/swagger.json b/spec/swagger.json index 6b65ae79..22731a82 100644 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -6,6 +6,45 @@ "version": "1.0.0" }, "paths": { + "/api/oauth/mcp/callback": { + "get": { + "description": "Handles the OAuth authorization callback, exchanges code for tokens", + "tags": [ + "mcp" + ], + "summary": "OAuth callback handler", + "parameters": [ + { + "type": "string", + "description": "Authorization code", + "name": "code", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "State parameter", + "name": "state", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "HTML page that closes the popup", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, "/auth/login": { "post": { "description": "Validate user credentials and issue a JWT", @@ -2315,6 +2354,215 @@ } } }, + "/bots/{bot_id}/mcp/{id}/oauth/authorize": { + "post": { + "description": "Generate PKCE and return authorization URL for the user to authorize", + "tags": [ + "mcp" + ], + "summary": "Start OAuth authorization flow", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Optional client_id", + "name": "payload", + "in": "body", + "schema": { + "$ref": "#/definitions/handlers.oauthAuthorizeRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/mcp.AuthorizeResult" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/bots/{bot_id}/mcp/{id}/oauth/discover": { + "post": { + "description": "Probe MCP server URL for OAuth requirements and discover authorization server metadata", + "tags": [ + "mcp" + ], + "summary": "Discover OAuth configuration for MCP server", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Optional URL override", + "name": "payload", + "in": "body", + "schema": { + "$ref": "#/definitions/handlers.oauthDiscoverRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/mcp.DiscoveryResult" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/bots/{bot_id}/mcp/{id}/oauth/status": { + "get": { + "description": "Returns the current OAuth status including whether tokens are available", + "tags": [ + "mcp" + ], + "summary": "Get OAuth status for MCP connection", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/mcp.OAuthStatus" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/bots/{bot_id}/mcp/{id}/oauth/token": { + "delete": { + "description": "Clears stored OAuth tokens", + "tags": [ + "mcp" + ], + "summary": "Revoke OAuth tokens for MCP connection", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/bots/{bot_id}/mcp/{id}/probe": { + "post": { + "description": "Probe a MCP connection to discover tools and verify connectivity", + "tags": [ + "mcp" + ], + "summary": "Probe MCP connection", + "parameters": [ + { + "type": "string", + "description": "MCP connection ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.ProbeResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, "/bots/{bot_id}/memory": { "get": { "description": "List all memories in the bot-shared namespace", @@ -7919,6 +8167,9 @@ "github_com_memohai_memoh_internal_mcp.Connection": { "type": "object", "properties": { + "auth_type": { + "type": "string" + }, "bot_id": { "type": "string" }, @@ -7935,9 +8186,24 @@ "is_active": { "type": "boolean" }, + "last_probed_at": { + "type": "string" + }, "name": { "type": "string" }, + "status": { + "type": "string" + }, + "status_message": { + "type": "string" + }, + "tools_cache": { + "type": "array", + "items": { + "$ref": "#/definitions/mcp.ToolDescriptor" + } + }, "type": { "type": "string" }, @@ -8341,6 +8607,26 @@ } } }, + "handlers.ProbeResponse": { + "type": "object", + "properties": { + "auth_required": { + "type": "boolean" + }, + "error": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/definitions/mcp.ToolDescriptor" + } + } + } + }, "handlers.RefreshResponse": { "type": "object", "properties": { @@ -8589,6 +8875,22 @@ } } }, + "handlers.oauthAuthorizeRequest": { + "type": "object", + "properties": { + "client_id": { + "type": "string" + } + } + }, + "handlers.oauthDiscoverRequest": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, "handlers.skillsOpResponse": { "type": "object", "properties": { @@ -8733,6 +9035,43 @@ } } }, + "mcp.AuthorizeResult": { + "type": "object", + "properties": { + "authorization_url": { + "type": "string" + } + } + }, + "mcp.DiscoveryResult": { + "type": "object", + "properties": { + "authorization_endpoint": { + "type": "string" + }, + "authorization_server_url": { + "type": "string" + }, + "registration_endpoint": { + "type": "string" + }, + "resource_metadata_url": { + "type": "string" + }, + "resource_uri": { + "type": "string" + }, + "scopes_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "token_endpoint": { + "type": "string" + } + } + }, "mcp.ExportResponse": { "type": "object", "properties": { @@ -8801,6 +9140,44 @@ } } }, + "mcp.OAuthStatus": { + "type": "object", + "properties": { + "auth_server": { + "type": "string" + }, + "configured": { + "type": "boolean" + }, + "expired": { + "type": "boolean" + }, + "expires_at": { + "type": "string" + }, + "has_token": { + "type": "boolean" + }, + "scopes": { + "type": "string" + } + } + }, + "mcp.ToolDescriptor": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "inputSchema": { + "type": "object", + "additionalProperties": {} + }, + "name": { + "type": "string" + } + } + }, "mcp.UpsertRequest": { "type": "object", "properties": { @@ -8810,6 +9187,9 @@ "type": "string" } }, + "auth_type": { + "type": "string" + }, "command": { "type": "string" }, diff --git a/spec/swagger.yaml b/spec/swagger.yaml index bffcce9b..219476d7 100644 --- a/spec/swagger.yaml +++ b/spec/swagger.yaml @@ -707,6 +707,8 @@ definitions: type: object github_com_memohai_memoh_internal_mcp.Connection: properties: + auth_type: + type: string bot_id: type: string config: @@ -718,8 +720,18 @@ definitions: type: string is_active: type: boolean + last_probed_at: + type: string name: type: string + status: + type: string + status_message: + type: string + tools_cache: + items: + $ref: '#/definitions/mcp.ToolDescriptor' + type: array type: type: string updated_at: @@ -980,6 +992,19 @@ definitions: status: type: string type: object + handlers.ProbeResponse: + properties: + auth_required: + type: boolean + error: + type: string + status: + type: string + tools: + items: + $ref: '#/definitions/mcp.ToolDescriptor' + type: array + type: object handlers.RefreshResponse: properties: access_token: @@ -1142,6 +1167,16 @@ definitions: type: string type: array type: object + handlers.oauthAuthorizeRequest: + properties: + client_id: + type: string + type: object + handlers.oauthDiscoverRequest: + properties: + url: + type: string + type: object handlers.skillsOpResponse: properties: ok: @@ -1237,6 +1272,30 @@ definitions: source: type: string type: object + mcp.AuthorizeResult: + properties: + authorization_url: + type: string + type: object + mcp.DiscoveryResult: + properties: + authorization_endpoint: + type: string + authorization_server_url: + type: string + registration_endpoint: + type: string + resource_metadata_url: + type: string + resource_uri: + type: string + scopes_supported: + items: + type: string + type: array + token_endpoint: + type: string + type: object mcp.ExportResponse: properties: mcpServers: @@ -1281,12 +1340,39 @@ definitions: url: type: string type: object + mcp.OAuthStatus: + properties: + auth_server: + type: string + configured: + type: boolean + expired: + type: boolean + expires_at: + type: string + has_token: + type: boolean + scopes: + type: string + type: object + mcp.ToolDescriptor: + properties: + description: + type: string + inputSchema: + additionalProperties: {} + type: object + name: + type: string + type: object mcp.UpsertRequest: properties: args: items: type: string type: array + auth_type: + type: string command: type: string cwd: @@ -2077,6 +2163,32 @@ info: title: Memoh API version: 1.0.0 paths: + /api/oauth/mcp/callback: + get: + description: Handles the OAuth authorization callback, exchanges code for tokens + parameters: + - description: Authorization code + in: query + name: code + required: true + type: string + - description: State parameter + in: query + name: state + required: true + type: string + responses: + "200": + description: HTML page that closes the popup + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: OAuth callback handler + tags: + - mcp /auth/login: post: description: Validate user credentials and issue a JWT @@ -3553,6 +3665,144 @@ paths: summary: Update MCP connection tags: - mcp + /bots/{bot_id}/mcp/{id}/oauth/authorize: + post: + description: Generate PKCE and return authorization URL for the user to authorize + parameters: + - description: MCP connection ID + in: path + name: id + required: true + type: string + - description: Optional client_id + in: body + name: payload + schema: + $ref: '#/definitions/handlers.oauthAuthorizeRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/mcp.AuthorizeResult' + "400": + description: Bad Request + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Start OAuth authorization flow + tags: + - mcp + /bots/{bot_id}/mcp/{id}/oauth/discover: + post: + description: Probe MCP server URL for OAuth requirements and discover authorization + server metadata + parameters: + - description: MCP connection ID + in: path + name: id + required: true + type: string + - description: Optional URL override + in: body + name: payload + schema: + $ref: '#/definitions/handlers.oauthDiscoverRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/mcp.DiscoveryResult' + "400": + description: Bad Request + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Discover OAuth configuration for MCP server + tags: + - mcp + /bots/{bot_id}/mcp/{id}/oauth/status: + get: + description: Returns the current OAuth status including whether tokens are available + parameters: + - description: MCP connection ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/mcp.OAuthStatus' + "400": + description: Bad Request + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Get OAuth status for MCP connection + tags: + - mcp + /bots/{bot_id}/mcp/{id}/oauth/token: + delete: + description: Clears stored OAuth tokens + parameters: + - description: MCP connection ID + in: path + name: id + required: true + type: string + responses: + "204": + description: No Content + "400": + description: Bad Request + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Revoke OAuth tokens for MCP connection + tags: + - mcp + /bots/{bot_id}/mcp/{id}/probe: + post: + description: Probe a MCP connection to discover tools and verify connectivity + parameters: + - description: MCP connection ID + in: path + name: id + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.ProbeResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Probe MCP connection + tags: + - mcp /bots/{bot_id}/mcp/export: get: description: Export all MCP connections for a bot in standard mcpServers format.