diff --git a/apps/sim/app/api/mcp/servers/route.ts b/apps/sim/app/api/mcp/servers/route.ts index 9394e5bf8b..8e30ef8022 100644 --- a/apps/sim/app/api/mcp/servers/route.ts +++ b/apps/sim/app/api/mcp/servers/route.ts @@ -17,7 +17,7 @@ export const dynamic = 'force-dynamic' * Check if transport type requires a URL */ function isUrlBasedTransport(transport: McpTransport): boolean { - return transport === 'http' || transport === 'sse' || transport === 'streamable-http' + return transport === 'streamable-http' } /** diff --git a/apps/sim/app/api/mcp/servers/test-connection/route.ts b/apps/sim/app/api/mcp/servers/test-connection/route.ts index a1e479b85f..840fb4aaeb 100644 --- a/apps/sim/app/api/mcp/servers/test-connection/route.ts +++ b/apps/sim/app/api/mcp/servers/test-connection/route.ts @@ -13,9 +13,10 @@ export const dynamic = 'force-dynamic' /** * Check if transport type requires a URL + * All modern MCP connections use Streamable HTTP which requires a URL */ function isUrlBasedTransport(transport: McpTransport): boolean { - return transport === 'http' || transport === 'sse' || transport === 'streamable-http' + return transport === 'streamable-http' } /** @@ -151,16 +152,21 @@ export const POST = withMcpAuth('write')( client = new McpClient(testConfig, testSecurityPolicy) await client.connect() - result.success = true result.negotiatedVersion = client.getNegotiatedVersion() try { const tools = await client.listTools() result.toolCount = tools.length + result.success = true } catch (toolError) { - logger.warn(`[${requestId}] Could not list tools from test server:`, toolError) + logger.warn(`[${requestId}] Connection established but could not list tools:`, toolError) + result.success = false + const errorMessage = toolError instanceof Error ? toolError.message : 'Unknown error' + result.error = `Connection established but could not list tools: ${errorMessage}` result.warnings = result.warnings || [] - result.warnings.push('Could not list tools from server') + result.warnings.push( + 'Server connected but tool listing failed - connection may be incomplete' + ) } const clientVersionInfo = McpClient.getVersionInfo() diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/mcp-server-modal/mcp-server-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/mcp-server-modal/mcp-server-modal.tsx deleted file mode 100644 index aba7bdc397..0000000000 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/mcp-server-modal/mcp-server-modal.tsx +++ /dev/null @@ -1,581 +0,0 @@ -'use client' - -import { useCallback, useRef, useState } from 'react' -import { X } from 'lucide-react' -import { useParams } from 'next/navigation' -import { Button } from '@/components/ui/button' -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog' -import { checkEnvVarTrigger, EnvVarDropdown } from '@/components/ui/env-var-dropdown' -import { formatDisplayText } from '@/components/ui/formatted-text' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { createLogger } from '@/lib/logs/console/logger' -import type { McpTransport } from '@/lib/mcp/types' -import { useAccessibleReferencePrefixes } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-accessible-reference-prefixes' -import { useMcpServerTest } from '@/hooks/use-mcp-server-test' -import { useMcpServersStore } from '@/stores/mcp-servers/store' - -const logger = createLogger('McpServerModal') - -interface McpServerModalProps { - open: boolean - onOpenChange: (open: boolean) => void - onServerCreated?: () => void - blockId: string -} - -interface McpServerFormData { - name: string - transport: McpTransport - url?: string - headers?: Record -} - -export function McpServerModal({ - open, - onOpenChange, - onServerCreated, - blockId, -}: McpServerModalProps) { - const params = useParams() - const workspaceId = params.workspaceId as string - const [formData, setFormData] = useState({ - name: '', - transport: 'streamable-http', - url: '', - headers: { '': '' }, - }) - const { createServer, isLoading, error: storeError, clearError } = useMcpServersStore() - const [localError, setLocalError] = useState(null) - - // MCP server testing - const { testResult, isTestingConnection, testConnection, clearTestResult } = useMcpServerTest() - - // Environment variable dropdown state - const [showEnvVars, setShowEnvVars] = useState(false) - const [searchTerm, setSearchTerm] = useState('') - const [cursorPosition, setCursorPosition] = useState(0) - const [activeInputField, setActiveInputField] = useState< - 'url' | 'header-key' | 'header-value' | null - >(null) - const [activeHeaderIndex, setActiveHeaderIndex] = useState(null) - const urlInputRef = useRef(null) - const [urlScrollLeft, setUrlScrollLeft] = useState(0) - const [headerScrollLeft, setHeaderScrollLeft] = useState>({}) - - const error = localError || storeError - - const resetForm = () => { - setFormData({ - name: '', - transport: 'streamable-http', - url: '', - headers: { '': '' }, - }) - setLocalError(null) - clearError() - setShowEnvVars(false) - setActiveInputField(null) - setActiveHeaderIndex(null) - clearTestResult() - } - - // Handle environment variable selection - const handleEnvVarSelect = useCallback( - (newValue: string) => { - if (activeInputField === 'url') { - setFormData((prev) => ({ ...prev, url: newValue })) - } else if (activeInputField === 'header-key' && activeHeaderIndex !== null) { - const headerEntries = Object.entries(formData.headers || {}) - const [oldKey, value] = headerEntries[activeHeaderIndex] - const newHeaders = { ...formData.headers } - delete newHeaders[oldKey] - newHeaders[newValue.replace(/[{}]/g, '')] = value - setFormData((prev) => ({ ...prev, headers: newHeaders })) - } else if (activeInputField === 'header-value' && activeHeaderIndex !== null) { - const headerEntries = Object.entries(formData.headers || {}) - const [key] = headerEntries[activeHeaderIndex] - setFormData((prev) => ({ - ...prev, - headers: { ...prev.headers, [key]: newValue }, - })) - } - setShowEnvVars(false) - setActiveInputField(null) - setActiveHeaderIndex(null) - }, - [activeInputField, activeHeaderIndex, formData.headers] - ) - - // Handle input change with env var detection - const handleInputChange = useCallback( - (field: 'url' | 'header-key' | 'header-value', value: string, headerIndex?: number) => { - const input = document.activeElement as HTMLInputElement - const pos = input?.selectionStart || 0 - - setCursorPosition(pos) - - // Clear test result when any field changes - if (testResult) { - clearTestResult() - } - - // Check if we should show the environment variables dropdown - const envVarTrigger = checkEnvVarTrigger(value, pos) - setShowEnvVars(envVarTrigger.show) - setSearchTerm(envVarTrigger.show ? envVarTrigger.searchTerm : '') - - if (envVarTrigger.show) { - setActiveInputField(field) - setActiveHeaderIndex(headerIndex ?? null) - } else { - setActiveInputField(null) - setActiveHeaderIndex(null) - } - - // Update form data - if (field === 'url') { - setFormData((prev) => ({ ...prev, url: value })) - } else if (field === 'header-key' && headerIndex !== undefined) { - const headerEntries = Object.entries(formData.headers || {}) - const [oldKey, headerValue] = headerEntries[headerIndex] - const newHeaders = { ...formData.headers } - delete newHeaders[oldKey] - newHeaders[value] = headerValue - - // Add a new empty header row if this is the last row and both key and value have content - const isLastRow = headerIndex === headerEntries.length - 1 - const hasContent = value.trim() !== '' && headerValue.trim() !== '' - if (isLastRow && hasContent) { - newHeaders[''] = '' - } - - setFormData((prev) => ({ ...prev, headers: newHeaders })) - } else if (field === 'header-value' && headerIndex !== undefined) { - const headerEntries = Object.entries(formData.headers || {}) - const [key] = headerEntries[headerIndex] - const newHeaders = { ...formData.headers, [key]: value } - - // Add a new empty header row if this is the last row and both key and value have content - const isLastRow = headerIndex === headerEntries.length - 1 - const hasContent = key.trim() !== '' && value.trim() !== '' - if (isLastRow && hasContent) { - newHeaders[''] = '' - } - - setFormData((prev) => ({ ...prev, headers: newHeaders })) - } - }, - [formData.headers, testResult, clearTestResult] - ) - - const handleTestConnection = useCallback(async () => { - if (!formData.name.trim() || !formData.url?.trim()) return - - await testConnection({ - name: formData.name, - transport: formData.transport, - url: formData.url, - headers: formData.headers, - timeout: 30000, - workspaceId, - }) - }, [formData, testConnection, workspaceId]) - - const handleSubmit = useCallback(async () => { - if (!formData.name.trim()) { - setLocalError('Server name is required') - return - } - - if (!formData.url?.trim()) { - setLocalError('Server URL is required for HTTP/SSE transport') - return - } - - setLocalError(null) - clearError() - - try { - // If no test has been done, test first - if (!testResult) { - const result = await testConnection({ - name: formData.name, - transport: formData.transport, - url: formData.url, - headers: formData.headers, - timeout: 30000, - workspaceId, - }) - - // If test fails, don't proceed - if (!result.success) { - return - } - } - - // If we have a failed test result, don't proceed - if (testResult && !testResult.success) { - return - } - - // Filter out empty headers - const cleanHeaders = Object.fromEntries( - Object.entries(formData.headers || {}).filter( - ([key, value]) => key.trim() !== '' && value.trim() !== '' - ) - ) - - await createServer(workspaceId, { - name: formData.name.trim(), - transport: formData.transport, - url: formData.url, - timeout: 30000, - headers: cleanHeaders, - enabled: true, - }) - - logger.info(`Added MCP server: ${formData.name}`) - - // Close modal and reset form immediately after successful creation - resetForm() - onOpenChange(false) - onServerCreated?.() - } catch (error) { - logger.error('Failed to add MCP server:', error) - setLocalError(error instanceof Error ? error.message : 'Failed to add MCP server') - } - }, [ - formData, - testResult, - testConnection, - onOpenChange, - onServerCreated, - createServer, - clearError, - workspaceId, - ]) - - const accessiblePrefixes = useAccessibleReferencePrefixes(blockId) - - return ( - - - - Add MCP Server - - Configure a new Model Context Protocol server to extend your workflow capabilities. - - - -
-
-
- - { - if (testResult) clearTestResult() - setFormData((prev) => ({ ...prev, name: e.target.value })) - }} - className='h-9' - /> -
-
- - -
-
- -
- -
- handleInputChange('url', e.target.value)} - onScroll={(e) => { - const scrollLeft = e.currentTarget.scrollLeft - setUrlScrollLeft(scrollLeft) - }} - onInput={(e) => { - const scrollLeft = e.currentTarget.scrollLeft - setUrlScrollLeft(scrollLeft) - }} - className='h-9 text-transparent caret-foreground placeholder:text-muted-foreground/50' - /> - - {/* Overlay for styled text display */} -
-
- {formatDisplayText(formData.url || '', { - accessiblePrefixes, - highlightAll: !accessiblePrefixes, - })} -
-
-
- - {/* Environment Variables Dropdown */} - {showEnvVars && activeInputField === 'url' && ( - { - setShowEnvVars(false) - setActiveInputField(null) - }} - className='w-full' - maxHeight='250px' - /> - )} -
- -
- -
- {Object.entries(formData.headers || {}).map(([key, value], index) => ( -
- {/* Header Name Input */} -
- handleInputChange('header-key', e.target.value, index)} - onScroll={(e) => { - const scrollLeft = e.currentTarget.scrollLeft - setHeaderScrollLeft((prev) => ({ ...prev, [`key-${index}`]: scrollLeft })) - }} - onInput={(e) => { - const scrollLeft = e.currentTarget.scrollLeft - setHeaderScrollLeft((prev) => ({ ...prev, [`key-${index}`]: scrollLeft })) - }} - className='h-9 text-transparent caret-foreground placeholder:text-muted-foreground/50' - /> -
-
- {formatDisplayText(key || '', { - accessiblePrefixes, - highlightAll: !accessiblePrefixes, - })} -
-
-
- - {/* Header Value Input */} -
- handleInputChange('header-value', e.target.value, index)} - onScroll={(e) => { - const scrollLeft = e.currentTarget.scrollLeft - setHeaderScrollLeft((prev) => ({ ...prev, [`value-${index}`]: scrollLeft })) - }} - onInput={(e) => { - const scrollLeft = e.currentTarget.scrollLeft - setHeaderScrollLeft((prev) => ({ ...prev, [`value-${index}`]: scrollLeft })) - }} - className='h-9 text-transparent caret-foreground placeholder:text-muted-foreground/50' - /> -
-
- {formatDisplayText(value || '', { - accessiblePrefixes, - highlightAll: !accessiblePrefixes, - })} -
-
-
- - - - {/* Environment Variables Dropdown for Header Key */} - {showEnvVars && - activeInputField === 'header-key' && - activeHeaderIndex === index && ( - { - setShowEnvVars(false) - setActiveInputField(null) - setActiveHeaderIndex(null) - }} - className='w-full' - maxHeight='150px' - style={{ - position: 'absolute', - top: '100%', - left: 0, - zIndex: 9999, - }} - /> - )} - - {/* Environment Variables Dropdown for Header Value */} - {showEnvVars && - activeInputField === 'header-value' && - activeHeaderIndex === index && ( - { - setShowEnvVars(false) - setActiveInputField(null) - setActiveHeaderIndex(null) - }} - className='w-full' - maxHeight='250px' - style={{ - position: 'absolute', - top: '100%', - right: 0, - zIndex: 9999, - }} - /> - )} -
- ))} -
-
- - {error && ( -
- {error} -
- )} - - {/* Test Connection and Actions */} -
-
-
-
- - {testResult?.success && ( - ✓ Connected - )} -
- {testResult && !testResult.success && ( -
-
Connection failed
-
- {testResult.error || testResult.message} -
-
- )} -
-
- - -
-
-
-
-
-
- ) -} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/tool-credential-selector.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/tool-credential-selector.tsx index e40ed60045..24e472d3e8 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/tool-credential-selector.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/tool-credential-selector.tsx @@ -30,7 +30,6 @@ const getProviderIcon = (providerName: OAuthProvider) => { if (!baseProviderConfig) { return } - // Always use the base provider icon for a more consistent UI return baseProviderConfig.icon({ className: 'h-4 w-4' }) } @@ -42,7 +41,6 @@ const getProviderName = (providerName: OAuthProvider) => { return baseProviderConfig.name } - // Fallback: capitalize the provider name return providerName .split('-') .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) @@ -75,7 +73,6 @@ export function ToolCredentialSelector({ const [selectedId, setSelectedId] = useState('') const { activeWorkflowId } = useWorkflowRegistry() - // Update selected ID when value changes useEffect(() => { setSelectedId(value) }, [value]) @@ -88,7 +85,6 @@ export function ToolCredentialSelector({ const data = await response.json() setCredentials(data.credentials || []) - // If persisted selection is not among viewer's credentials, attempt to fetch its metadata if ( value && !(data.credentials || []).some((cred: Credential) => cred.id === value) && @@ -127,7 +123,6 @@ export function ToolCredentialSelector({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []) - // Listen for visibility changes to update credentials when user returns from settings useEffect(() => { const handleVisibilityChange = () => { if (document.visibilityState === 'visible') { @@ -150,15 +145,12 @@ export function ToolCredentialSelector({ const handleOAuthClose = () => { setShowOAuthModal(false) - // Refetch credentials to include any new ones fetchCredentials() } - // Handle popover open to fetch fresh credentials const handleOpenChange = (isOpen: boolean) => { setOpen(isOpen) if (isOpen) { - // Fetch fresh credentials when opening the dropdown fetchCredentials() } } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx index 6a6ac9cbca..392181e2a4 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx @@ -35,7 +35,6 @@ import { type CustomTool, CustomToolModal, } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/custom-tool-modal/custom-tool-modal' -import { McpServerModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/mcp-server-modal/mcp-server-modal' import { McpToolsList } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/mcp-tools-list' import { ToolCommand } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/tool-command/tool-command' import { ToolCredentialSelector } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/components/tool-credential-selector' @@ -430,7 +429,6 @@ export function ToolInput({ const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlockId) const [open, setOpen] = useState(false) const [customToolModalOpen, setCustomToolModalOpen] = useState(false) - const [mcpServerModalOpen, setMcpServerModalOpen] = useState(false) const [editingToolIndex, setEditingToolIndex] = useState(null) const [searchQuery, setSearchQuery] = useState('') const [draggedIndex, setDraggedIndex] = useState(null) @@ -1274,8 +1272,10 @@ export function ToolInput({ value='Add MCP Server' onSelect={() => { if (!isPreview) { - setMcpServerModalOpen(true) setOpen(false) + window.dispatchEvent( + new CustomEvent('open-settings', { detail: { tab: 'mcp' } }) + ) } }} className='mb-1 flex cursor-pointer items-center gap-2' @@ -1839,7 +1839,9 @@ export function ToolInput({ value='Add MCP Server' onSelect={() => { setOpen(false) - setMcpServerModalOpen(true) + window.dispatchEvent( + new CustomEvent('open-settings', { detail: { tab: 'mcp' } }) + ) }} className='mb-1 flex cursor-pointer items-center gap-2' > @@ -1976,17 +1978,6 @@ export function ToolInput({ : undefined } /> - - {/* MCP Server Modal */} - { - // Refresh MCP tools when a new server is created - refreshTools(true) - }} - blockId={blockId} - /> ) } diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx index 7f1ce4b6f7..24dad296e2 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/mcp/mcp.tsx @@ -3,19 +3,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { AlertCircle, Plus, Search, X } from 'lucide-react' import { useParams } from 'next/navigation' -import { - Alert, - AlertDescription, - Button, - Input, - Label, - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, - Skeleton, -} from '@/components/ui' +import { Alert, AlertDescription, Button, Input, Label, Skeleton } from '@/components/ui' import { checkEnvVarTrigger, EnvVarDropdown } from '@/components/ui/env-var-dropdown' import { formatDisplayText } from '@/components/ui/formatted-text' import { createLogger } from '@/lib/logs/console/logger' @@ -349,30 +337,6 @@ export function MCP() { -
-
- -
-
- -
-
-
@@ -728,30 +692,6 @@ export function MCP() {
-
-
- -
-
- -
-
-
diff --git a/apps/sim/hooks/use-mcp-server-test.ts b/apps/sim/hooks/use-mcp-server-test.ts index 72be29b33b..77978d8e29 100644 --- a/apps/sim/hooks/use-mcp-server-test.ts +++ b/apps/sim/hooks/use-mcp-server-test.ts @@ -10,7 +10,7 @@ const logger = createLogger('useMcpServerTest') * Check if transport type requires a URL */ function isUrlBasedTransport(transport: McpTransport): boolean { - return transport === 'http' || transport === 'sse' || transport === 'streamable-http' + return transport === 'streamable-http' } export interface McpServerTestConfig { diff --git a/apps/sim/lib/mcp/client.ts b/apps/sim/lib/mcp/client.ts index 53703bbd9c..ca3fc604b2 100644 --- a/apps/sim/lib/mcp/client.ts +++ b/apps/sim/lib/mcp/client.ts @@ -1,28 +1,25 @@ /** - * MCP (Model Context Protocol) JSON-RPC 2.0 Client + * MCP (Model Context Protocol) Client * * Implements the client side of MCP protocol with support for: - * - Streamable HTTP transport (MCP 2025-03-26) - * - Connection lifecycle management + * - Streamable HTTP transport (MCP 2025-06-18) * - Tool execution and discovery - * - Session management with Mcp-Session-Id header + * - Session management and protocol version negotiation + * - Custom security/consent layer */ +import { Client } from '@modelcontextprotocol/sdk/client/index.js' +import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js' +import type { ListToolsResult, Tool } from '@modelcontextprotocol/sdk/types.js' import { createLogger } from '@/lib/logs/console/logger' import { - type JsonRpcRequest, - type JsonRpcResponse, - type McpCapabilities, McpConnectionError, type McpConnectionStatus, type McpConsentRequest, type McpConsentResponse, McpError, - type McpInitializeParams, - type McpInitializeResult, type McpSecurityPolicy, type McpServerConfig, - McpTimeoutError, type McpTool, type McpToolCall, type McpToolResult, @@ -32,23 +29,13 @@ import { const logger = createLogger('McpClient') export class McpClient { + private client: Client + private transport: StreamableHTTPClientTransport private config: McpServerConfig private connectionStatus: McpConnectionStatus - private requestId = 0 - private pendingRequests = new Map< - string | number, - { - resolve: (value: JsonRpcResponse) => void - reject: (error: Error) => void - timeout: NodeJS.Timeout - } - >() - private serverCapabilities?: McpCapabilities - private mcpSessionId?: string - private negotiatedVersion?: string private securityPolicy: McpSecurityPolicy + private isConnected = false - // Supported protocol versions private static readonly SUPPORTED_VERSIONS = [ '2025-06-18', // Latest stable with elicitation and OAuth 2.1 '2025-03-26', // Streamable HTTP support @@ -58,12 +45,36 @@ export class McpClient { constructor(config: McpServerConfig, securityPolicy?: McpSecurityPolicy) { this.config = config this.connectionStatus = { connected: false } - this.securityPolicy = securityPolicy ?? { requireConsent: true, auditLevel: 'basic', maxToolExecutionsPerHour: 1000, } + + if (!this.config.url) { + throw new McpError('URL required for Streamable HTTP transport') + } + + this.transport = new StreamableHTTPClientTransport(new URL(this.config.url), { + requestInit: { + headers: this.config.headers, + }, + }) + + this.client = new Client( + { + name: 'sim-platform', + version: '1.0.0', + }, + { + capabilities: { + tools: {}, + // Resources and prompts can be added later + // resources: {}, + // prompts: {}, + }, + } + ) } /** @@ -73,28 +84,20 @@ export class McpClient { logger.info(`Connecting to MCP server: ${this.config.name} (${this.config.transport})`) try { - switch (this.config.transport) { - case 'http': - await this.connectStreamableHttp() - break - case 'sse': - await this.connectStreamableHttp() - break - case 'streamable-http': - await this.connectStreamableHttp() - break - default: - throw new McpError(`Unsupported transport: ${this.config.transport}`) - } + await this.client.connect(this.transport) - await this.initialize() + this.isConnected = true this.connectionStatus.connected = true this.connectionStatus.lastConnected = new Date() - logger.info(`Successfully connected to MCP server: ${this.config.name}`) + const serverVersion = this.client.getServerVersion() + logger.info(`Successfully connected to MCP server: ${this.config.name}`, { + protocolVersion: serverVersion, + }) } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error' this.connectionStatus.lastError = errorMessage + this.isConnected = false logger.error(`Failed to connect to MCP server ${this.config.name}:`, error) throw new McpConnectionError(errorMessage, this.config.id) } @@ -106,12 +109,13 @@ export class McpClient { async disconnect(): Promise { logger.info(`Disconnecting from MCP server: ${this.config.name}`) - for (const [, pending] of this.pendingRequests) { - clearTimeout(pending.timeout) - pending.reject(new McpError('Connection closed')) + try { + await this.client.close() + } catch (error) { + logger.warn(`Error during disconnect from ${this.config.name}:`, error) } - this.pendingRequests.clear() + this.isConnected = false this.connectionStatus.connected = false logger.info(`Disconnected from MCP server: ${this.config.name}`) } @@ -127,19 +131,19 @@ export class McpClient { * List all available tools from the server */ async listTools(): Promise { - if (!this.connectionStatus.connected) { + if (!this.isConnected) { throw new McpConnectionError('Not connected to server', this.config.id) } try { - const response = await this.sendRequest('tools/list', {}) + const result: ListToolsResult = await this.client.listTools() - if (!response.tools || !Array.isArray(response.tools)) { - logger.warn(`Invalid tools response from server ${this.config.name}:`, response) + if (!result.tools || !Array.isArray(result.tools)) { + logger.warn(`Invalid tools response from server ${this.config.name}:`, result) return [] } - return response.tools.map((tool: any) => ({ + return result.tools.map((tool: Tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, @@ -156,11 +160,10 @@ export class McpClient { * Execute a tool on the MCP server */ async callTool(toolCall: McpToolCall): Promise { - if (!this.connectionStatus.connected) { + if (!this.isConnected) { throw new McpConnectionError('Not connected to server', this.config.id) } - // Request consent for tool execution const consentRequest: McpConsentRequest = { type: 'tool_execution', context: { @@ -171,7 +174,7 @@ export class McpClient { dataAccess: Object.keys(toolCall.arguments || {}), sideEffects: ['tool_execution'], }, - expires: Date.now() + 5 * 60 * 1000, // 5 minute consent window + expires: Date.now() + 5 * 60 * 1000, } const consentResponse = await this.requestConsent(consentRequest) @@ -184,16 +187,15 @@ export class McpClient { try { logger.info(`Calling tool ${toolCall.name} on server ${this.config.name}`, { consentAuditId: consentResponse.auditId, - protocolVersion: this.negotiatedVersion, + protocolVersion: this.getNegotiatedVersion(), }) - const response = await this.sendRequest('tools/call', { + const sdkResult = await this.client.callTool({ name: toolCall.name, arguments: toolCall.arguments, }) - // The response is the JSON-RPC 'result' field - return response as McpToolResult + return sdkResult as McpToolResult } catch (error) { logger.error(`Failed to call tool ${toolCall.name} on server ${this.config.name}:`, error) throw error @@ -201,337 +203,31 @@ export class McpClient { } /** - * Send a JSON-RPC request to the server - */ - private async sendRequest(method: string, params: any): Promise { - const id = ++this.requestId - const request: JsonRpcRequest = { - jsonrpc: '2.0', - id, - method, - params, - } - - return new Promise((resolve, reject) => { - const timeout = setTimeout(() => { - this.pendingRequests.delete(id) - reject(new McpTimeoutError(this.config.id, this.config.timeout || 30000)) - }, this.config.timeout || 30000) - - this.pendingRequests.set(id, { resolve, reject, timeout }) - - this.sendHttpRequest(request).catch(reject) - }) - } - - /** - * Initialize connection with capability and version negotiation - */ - private async initialize(): Promise { - // Start with latest supported version for negotiation - const preferredVersion = McpClient.SUPPORTED_VERSIONS[0] - - const initParams: McpInitializeParams = { - protocolVersion: preferredVersion, - capabilities: { - tools: { listChanged: true }, - resources: { subscribe: true, listChanged: true }, - prompts: { listChanged: true }, - logging: { level: 'info' }, - }, - clientInfo: { - name: 'sim-platform', - version: '1.0.0', - }, - } - - try { - const result: McpInitializeResult = await this.sendRequest('initialize', initParams) - - // Handle version negotiation - if (result.protocolVersion !== preferredVersion) { - // Server proposed a different version - check if we support it - if (!McpClient.SUPPORTED_VERSIONS.includes(result.protocolVersion)) { - // Client SHOULD disconnect if it cannot support proposed version - throw new McpError( - `Version negotiation failed: Server proposed unsupported version '${result.protocolVersion}'. ` + - `This client supports versions: ${McpClient.SUPPORTED_VERSIONS.join(', ')}. ` + - `To use this server, you may need to update your client or find a compatible version of the server.` - ) - } - - logger.info( - `Version negotiation: Server proposed version '${result.protocolVersion}' ` + - `instead of requested '${preferredVersion}'. Using server version.` - ) - } - - this.negotiatedVersion = result.protocolVersion - this.serverCapabilities = result.capabilities - - logger.info(`MCP initialization successful with protocol version '${this.negotiatedVersion}'`) - } catch (error) { - // Enhanced error handling - if (error instanceof McpError) { - throw error // Re-throw MCP errors as-is - } - - // Handle network errors - if (error instanceof Error) { - if (error.message.includes('fetch') || error.message.includes('network')) { - throw new McpError( - `Failed to connect to MCP server '${this.config.name}': ${error.message}. ` + - `Please check the server URL and ensure the server is running.` - ) - } - - if (error.message.includes('timeout')) { - throw new McpError( - `Connection timeout to MCP server '${this.config.name}'. ` + - `The server may be slow to respond or unreachable.` - ) - } - - // Generic error - throw new McpError( - `Connection to MCP server '${this.config.name}' failed: ${error.message}. ` + - `Please verify the server configuration and try again.` - ) - } - - throw new McpError(`Unexpected error during MCP initialization: ${String(error)}`) - } - - await this.sendNotification('notifications/initialized', {}) - } - - /** - * Send a notification - */ - private async sendNotification(method: string, params: any): Promise { - const notification = { - jsonrpc: '2.0' as const, - method, - params, - } - - await this.sendHttpRequest(notification) - } - - /** - * Connect using Streamable HTTP transport - */ - private async connectStreamableHttp(): Promise { - if (!this.config.url) { - throw new McpError('URL required for Streamable HTTP transport') - } - - logger.info(`Using Streamable HTTP transport for ${this.config.name}`) - } - - /** - * Send HTTP request with automatic retry - */ - private async sendHttpRequest(request: JsonRpcRequest | any): Promise { - if (!this.config.url) { - throw new McpError('URL required for HTTP transport') - } - - const urlsToTry = [this.config.url] - if (!this.config.url.endsWith('/')) { - urlsToTry.push(`${this.config.url}/`) - } else { - urlsToTry.push(this.config.url.slice(0, -1)) - } - - let lastError: Error | null = null - const originalUrl = this.config.url - - for (const [index, url] of urlsToTry.entries()) { - try { - await this.attemptHttpRequest(request, url, index === 0) - - if (index > 0) { - logger.info( - `[${this.config.name}] Successfully used alternative URL format: ${url} (original: ${originalUrl})` - ) - } - return - } catch (error) { - lastError = error as Error - - if (error instanceof McpError && !error.message.includes('404')) { - break - } - - if (index < urlsToTry.length - 1) { - logger.info( - `[${this.config.name}] Retrying with different URL format: ${urlsToTry[index + 1]}` - ) - } - } - } - - throw lastError || new McpError('All URL variations failed') - } - - /** - * Attempt HTTP request - */ - private async attemptHttpRequest( - request: JsonRpcRequest | any, - url: string, - isOriginalUrl = true - ): Promise { - if (!isOriginalUrl) { - logger.info(`[${this.config.name}] Trying alternative URL format: ${url}`) - } - - const headers: Record = { - 'Content-Type': 'application/json', - Accept: 'application/json, text/event-stream', - ...this.config.headers, - } - - if (this.mcpSessionId) { - headers['Mcp-Session-Id'] = this.mcpSessionId - } - - const response = await fetch(url, { - method: 'POST', - headers, - body: JSON.stringify(request), - }) - - if (!response.ok) { - const responseText = await response.text().catch(() => 'Could not read response body') - logger.error(`[${this.config.name}] HTTP request failed:`, { - status: response.status, - statusText: response.statusText, - url, - responseBody: responseText.substring(0, 500), - }) - throw new McpError(`HTTP request failed: ${response.status} ${response.statusText}`) - } - - if ('id' in request) { - const contentType = response.headers.get('Content-Type') - - if (contentType?.includes('application/json')) { - const sessionId = response.headers.get('Mcp-Session-Id') - if (sessionId && !this.mcpSessionId) { - this.mcpSessionId = sessionId - logger.info(`[${this.config.name}] Received MCP Session ID: ${sessionId}`) - } - - const responseData: JsonRpcResponse = await response.json() - this.handleResponse(responseData) - } else if (contentType?.includes('text/event-stream')) { - const responseText = await response.text() - this.handleSseResponse(responseText, request.id) - } else { - const unexpectedType = contentType || 'unknown' - logger.warn(`[${this.config.name}] Unexpected response content type: ${unexpectedType}`) - - const responseText = await response.text() - logger.debug( - `[${this.config.name}] Unexpected response body:`, - responseText.substring(0, 200) - ) - - throw new McpError( - `Unexpected response content type: ${unexpectedType}. Expected application/json or text/event-stream.` - ) - } - } - } - - /** - * Handle JSON-RPC response + * Ping the server to check if it's still alive and responsive + * Per MCP spec: servers should respond to ping requests */ - private handleResponse(response: JsonRpcResponse): void { - const pending = this.pendingRequests.get(response.id) - if (!pending) { - logger.warn(`Received response for unknown request ID: ${response.id}`) - return - } - - this.pendingRequests.delete(response.id) - clearTimeout(pending.timeout) - - if (response.error) { - const error = new McpError(response.error.message, response.error.code, response.error.data) - pending.reject(error) - } else { - pending.resolve(response.result) - } - } - - /** - * Handle Server-Sent Events response format - */ - private handleSseResponse(responseText: string, requestId: string | number): void { - const pending = this.pendingRequests.get(requestId) - if (!pending) { - logger.warn(`Received SSE response for unknown request ID: ${requestId}`) - return + async ping(): Promise<{ _meta?: Record }> { + if (!this.isConnected) { + throw new McpConnectionError('Not connected to server', this.config.id) } try { - // Parse SSE format - look for data: lines - const lines = responseText.split('\n') - let jsonData = '' - - for (const line of lines) { - if (line.startsWith('data: ')) { - const data = line.substring(6).trim() - if (data && data !== '[DONE]') { - jsonData += data - } - } - } - - if (!jsonData) { - logger.error( - `[${this.config.name}] No valid data found in SSE response for request ${requestId}` - ) - pending.reject(new McpError('No data in SSE response')) - return - } - - // Parse the JSON data - const responseData: JsonRpcResponse = JSON.parse(jsonData) - - this.pendingRequests.delete(requestId) - clearTimeout(pending.timeout) - - if (responseData.error) { - const error = new McpError( - responseData.error.message, - responseData.error.code, - responseData.error.data - ) - pending.reject(error) - } else { - pending.resolve(responseData.result) - } + logger.info(`[${this.config.name}] Sending ping to server`) + const response = await this.client.ping() + logger.info(`[${this.config.name}] Ping successful`) + return response } catch (error) { - logger.error(`[${this.config.name}] Failed to parse SSE response for request ${requestId}:`, { - error: error instanceof Error ? error.message : 'Unknown error', - responseText: responseText.substring(0, 500), - }) - - this.pendingRequests.delete(requestId) - clearTimeout(pending.timeout) - pending.reject(new McpError('Failed to parse SSE response')) + logger.error(`[${this.config.name}] Ping failed:`, error) + throw error } } /** * Check if server has capability */ - hasCapability(capability: keyof McpCapabilities): boolean { - return !!this.serverCapabilities?.[capability] + hasCapability(capability: string): boolean { + const serverCapabilities = this.client.getServerCapabilities() + return !!serverCapabilities?.[capability] } /** @@ -555,7 +251,8 @@ export class McpClient { * Get the negotiated protocol version for this connection */ getNegotiatedVersion(): string | undefined { - return this.negotiatedVersion + const serverVersion = this.client.getServerVersion() + return typeof serverVersion === 'string' ? serverVersion : undefined } /** @@ -566,10 +263,8 @@ export class McpClient { return { granted: true, auditId: `audit-${Date.now()}` } } - // Basic security checks const { serverId, serverName, action, sideEffects } = consentRequest.context - // Check if server is in blocked if (this.securityPolicy.blockedOrigins?.includes(this.config.url || '')) { logger.warn(`Tool execution blocked: Server ${serverName} is in blocked origins`) return { @@ -578,7 +273,6 @@ export class McpClient { } } - // For high-risk operations, log detailed audit if (this.securityPolicy.auditLevel === 'detailed') { logger.info(`Consent requested for ${action} on ${serverName}`, { serverId, diff --git a/apps/sim/lib/mcp/service.ts b/apps/sim/lib/mcp/service.ts index d0e57b764a..a8c3ba088d 100644 --- a/apps/sim/lib/mcp/service.ts +++ b/apps/sim/lib/mcp/service.ts @@ -264,7 +264,7 @@ class McpService { id: server.id, name: server.name, description: server.description || undefined, - transport: server.transport as 'http' | 'sse', + transport: 'streamable-http' as const, url: server.url || undefined, headers: (server.headers as Record) || {}, timeout: server.timeout || 30000, diff --git a/apps/sim/lib/mcp/types.ts b/apps/sim/lib/mcp/types.ts index 87ab114376..169d07dcfa 100644 --- a/apps/sim/lib/mcp/types.ts +++ b/apps/sim/lib/mcp/types.ts @@ -1,39 +1,10 @@ /** * Model Context Protocol (MCP) Types - * - * Type definitions for JSON-RPC 2.0 based MCP implementation - * Supporting HTTP/SSE and Streamable HTTP transports */ -// JSON-RPC 2.0 Base Types -export interface JsonRpcRequest { - jsonrpc: '2.0' - id: string | number - method: string - params?: any -} - -export interface JsonRpcResponse { - jsonrpc: '2.0' - id: string | number - result?: T - error?: JsonRpcError -} - -export interface JsonRpcNotification { - jsonrpc: '2.0' - method: string - params?: any -} - -export interface JsonRpcError { - code: number - message: string - data?: any -} - // MCP Transport Types -export type McpTransport = 'http' | 'sse' | 'streamable-http' +// Modern MCP uses Streamable HTTP which handles both HTTP POST and SSE responses +export type McpTransport = 'streamable-http' export interface McpServerConfig { id: string @@ -53,55 +24,12 @@ export interface McpServerConfig { updatedAt?: string } -// MCP Protocol Types -export interface McpCapabilities { - tools?: { - listChanged?: boolean - } - resources?: { - subscribe?: boolean - listChanged?: boolean - } - prompts?: { - listChanged?: boolean - } - logging?: Record -} - -export interface McpInitializeParams { - protocolVersion: string - capabilities: McpCapabilities - clientInfo: { - name: string - version: string - } -} - // Version negotiation support export interface McpVersionInfo { supported: string[] // List of supported protocol versions preferred: string // Preferred version to use } -export interface McpVersionNegotiationError extends JsonRpcError { - code: -32000 // Custom error code for version negotiation failures - message: 'Version negotiation failed' - data: { - clientVersions: string[] - serverVersions: string[] - reason: string - } -} - -export interface McpInitializeResult { - protocolVersion: string - capabilities: McpCapabilities - serverInfo: { - name: string - version: string - } -} - // Security and Consent Framework export interface McpConsentRequest { type: 'tool_execution' | 'resource_access' | 'data_sharing' @@ -166,48 +94,11 @@ export interface McpToolResult { [key: string]: any } -// MCP Resource Types -export interface McpResource { - uri: string - name: string - description?: string - mimeType?: string -} - -export interface McpResourceContent { - uri: string - mimeType?: string - text?: string - blob?: string -} - -// MCP Prompt Types -export interface McpPrompt { - name: string - description?: string - arguments?: Array<{ - name: string - description?: string - required?: boolean - }> -} - -export interface McpPromptMessage { - role: 'user' | 'assistant' - content: { - type: 'text' | 'image' | 'resource' - text?: string - data?: string - mimeType?: string - } -} - // Connection and Error Types export interface McpConnectionStatus { connected: boolean lastConnected?: Date lastError?: string - serverInfo?: McpInitializeResult['serverInfo'] } export class McpError extends Error { @@ -228,22 +119,6 @@ export class McpConnectionError extends McpError { } } -export class McpTimeoutError extends McpError { - constructor(serverId: string, timeout: number) { - super(`MCP request to server ${serverId} timed out after ${timeout}ms`) - this.name = 'McpTimeoutError' - } -} - -// Integration Types (for existing platform) -export interface McpToolInput { - type: 'mcp' - serverId: string - toolName: string - params: Record - usageControl?: 'auto' | 'force' | 'none' -} - export interface McpServerSummary { id: string name: string diff --git a/apps/sim/stores/mcp-servers/types.ts b/apps/sim/stores/mcp-servers/types.ts index aa55a0214c..adcc279d6e 100644 --- a/apps/sim/stores/mcp-servers/types.ts +++ b/apps/sim/stores/mcp-servers/types.ts @@ -7,9 +7,6 @@ export interface McpServerWithStatus { transport: McpTransport url?: string headers?: Record - command?: string - args?: string[] - env?: Record timeout?: number retries?: number enabled?: boolean diff --git a/bun.lock b/bun.lock index f45b068342..5a43c341f4 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "name": "simstudio", "dependencies": { "@linear/sdk": "40.0.0", + "@modelcontextprotocol/sdk": "1.20.2", "@t3-oss/env-nextjs": "0.13.4", "cronstrue": "3.3.0", "drizzle-orm": "^0.44.5", @@ -654,7 +655,7 @@ "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], - "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.18.2", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-beedclIvFcCnPrYgHsylqiYJVJ/CI47Vyc4tY8no1/Li/O8U4BTlJfy6ZwxkYwx+Mx10nrgwSVrA7VBbhh4slg=="], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.20.2", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-6rqTdFt67AAAzln3NOKsXRmv5ZzPkgbfaebKBqUbts7vK1GZudqnrun5a8d3M/h955cam9RHZ6Jb4Y1XhnmFPg=="], "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.3.1", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg=="], @@ -1490,7 +1491,7 @@ "bluebird": ["bluebird@3.4.7", "", {}, "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="], - "body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="], + "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], @@ -1620,7 +1621,7 @@ "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], - "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], + "content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="], "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], @@ -1628,7 +1629,7 @@ "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], - "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], "copy-anything": ["copy-anything@3.0.5", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w=="], @@ -1862,7 +1863,7 @@ "expect-type": ["expect-type@1.2.2", "", {}, "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA=="], - "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], + "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], @@ -1900,7 +1901,7 @@ "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - "finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="], + "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], @@ -1922,7 +1923,7 @@ "framer-motion": ["framer-motion@12.23.22", "", { "dependencies": { "motion-dom": "^12.23.21", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-ZgGvdxXCw55ZYvhoZChTlG6pUuehecgvEAJz0BHoC5pQKW1EC5xf1Mul1ej5+ai+pVY0pylyFfdl45qnM1/GsA=="], - "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], @@ -2282,11 +2283,11 @@ "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], - "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "memory-pager": ["memory-pager@1.5.0", "", {}, "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="], - "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], @@ -2760,11 +2761,11 @@ "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], + "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], "seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="], - "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], + "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], @@ -2994,7 +2995,7 @@ "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], - "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], "typedarray": ["typedarray@0.0.6", "", {}, "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="], @@ -3188,6 +3189,8 @@ "@browserbasehq/sdk/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "@browserbasehq/stagehand/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.18.2", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-beedclIvFcCnPrYgHsylqiYJVJ/CI47Vyc4tY8no1/Li/O8U4BTlJfy6ZwxkYwx+Mx10nrgwSVrA7VBbhh4slg=="], + "@cerebras/cerebras_cloud_sdk/@types/node": ["@types/node@18.19.128", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-m7wxXGpPpqxp2QDi/rpih5O772APRuBIa/6XiGqLNoM1txkjI8Sz1V4oSXJxQLTz/yP5mgy9z6UXEO6/lP70Gg=="], "@cerebras/cerebras_cloud_sdk/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], @@ -3202,8 +3205,6 @@ "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "@modelcontextprotocol/sdk/express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], - "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], "@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], @@ -3390,14 +3391,6 @@ "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - - "body-parser/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], - - "body-parser/raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="], - "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "cheerio/htmlparser2": ["htmlparser2@10.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.1", "entities": "^6.0.0" } }, "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g=="], @@ -3422,20 +3415,12 @@ "execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], - "express/cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], - - "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "express/path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="], - - "express/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], + "express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "fetch-blob/web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], - "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], "fumadocs-mdx/zod": ["zod@4.1.11", "", {}, "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg=="], @@ -3512,6 +3497,8 @@ "nypm/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "oauth2-mock-server/express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], + "oauth2-mock-server/jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="], "openai/@types/node": ["@types/node@18.19.128", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-m7wxXGpPpqxp2QDi/rpih5O772APRuBIa/6XiGqLNoM1txkjI8Sz1V4oSXJxQLTz/yP5mgy9z6UXEO6/lP70Gg=="], @@ -3558,10 +3545,6 @@ "samlify/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - - "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], - "sim/@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], "sim/lucide-react": ["lucide-react@0.479.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-aBhNnveRhorBOK7uA4gDjgaf+YlHMdMhQ/3cupk6exM10hWlEU+2QtWYOfhXhjAsmdb6LeKR+NZnow4UxRRiTQ=="], @@ -3606,8 +3589,6 @@ "tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], - "type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "unicode-trie/pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="], "vite-tsconfig-paths/tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="], @@ -3686,26 +3667,6 @@ "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "@modelcontextprotocol/sdk/express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], - - "@modelcontextprotocol/sdk/express/body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], - - "@modelcontextprotocol/sdk/express/content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="], - - "@modelcontextprotocol/sdk/express/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], - - "@modelcontextprotocol/sdk/express/finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], - - "@modelcontextprotocol/sdk/express/fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], - - "@modelcontextprotocol/sdk/express/merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], - - "@modelcontextprotocol/sdk/express/send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], - - "@modelcontextprotocol/sdk/express/serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], - - "@modelcontextprotocol/sdk/express/type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], - "@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], "@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], @@ -3752,18 +3713,12 @@ "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "cli-truncate/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], "engine.io/@types/node/undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], - "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - - "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], @@ -3812,6 +3767,32 @@ "nypm/pkg-types/confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + "oauth2-mock-server/express/body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="], + + "oauth2-mock-server/express/content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], + + "oauth2-mock-server/express/cookie": ["cookie@0.7.1", "", {}, "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w=="], + + "oauth2-mock-server/express/cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], + + "oauth2-mock-server/express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "oauth2-mock-server/express/finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="], + + "oauth2-mock-server/express/fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + + "oauth2-mock-server/express/merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], + + "oauth2-mock-server/express/path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="], + + "oauth2-mock-server/express/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], + + "oauth2-mock-server/express/send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], + + "oauth2-mock-server/express/serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], + + "oauth2-mock-server/express/type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], + "openai/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], "openai/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], @@ -3832,8 +3813,6 @@ "restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], - "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "sim/@types/node/undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], "sim/tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], @@ -3850,8 +3829,6 @@ "test-exclude/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "@anthropic-ai/sdk/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "@anthropic-ai/sdk/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -3870,8 +3847,6 @@ "@cerebras/cerebras_cloud_sdk/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], - "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], - "@trigger.dev/core/@opentelemetry/exporter-logs-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g=="], "@trigger.dev/core/@opentelemetry/exporter-trace-otlp-http/@opentelemetry/otlp-transformer/@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.1", "", { "dependencies": { "@opentelemetry/core": "2.0.1", "@opentelemetry/resources": "2.0.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g=="], @@ -3926,6 +3901,18 @@ "log-update/wrap-ansi/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "oauth2-mock-server/express/body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + + "oauth2-mock-server/express/body-parser/raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="], + + "oauth2-mock-server/express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "oauth2-mock-server/express/send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + + "oauth2-mock-server/express/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + + "oauth2-mock-server/express/type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "openai/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "openai/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -3956,6 +3943,8 @@ "log-update/cli-cursor/restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + "oauth2-mock-server/express/type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "sim/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "lint-staged/listr2/cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], diff --git a/package.json b/package.json index 92ddda5b05..66b39c1e27 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ }, "dependencies": { "@linear/sdk": "40.0.0", + "@modelcontextprotocol/sdk": "1.20.2", "@t3-oss/env-nextjs": "0.13.4", "cronstrue": "3.3.0", "drizzle-orm": "^0.44.5",