From 568ec2f7d5fa49b15c86608b4bf8519ecbf8e694 Mon Sep 17 00:00:00 2001 From: Dustin Healy Date: Fri, 27 Jun 2025 11:53:42 -0700 Subject: [PATCH] nicely refactored mcp add done --- .../src/components/SidePanel/MCP/MCPPanel.tsx | 23 +-- client/src/data-provider/Tools/mutations.ts | 30 +--- packages/api/src/mcp/add.ts | 158 +----------------- packages/data-provider/src/data-service.ts | 47 +----- packages/data-provider/src/types/mutations.ts | 4 +- 5 files changed, 22 insertions(+), 240 deletions(-) diff --git a/client/src/components/SidePanel/MCP/MCPPanel.tsx b/client/src/components/SidePanel/MCP/MCPPanel.tsx index 88a3aad54a..32f652d61e 100644 --- a/client/src/components/SidePanel/MCP/MCPPanel.tsx +++ b/client/src/components/SidePanel/MCP/MCPPanel.tsx @@ -1,17 +1,17 @@ -import React, { useState, useCallback, useMemo, useEffect } from 'react'; import { ChevronLeft } from 'lucide-react'; import { Constants } from 'librechat-data-provider'; import { useForm, Controller } from 'react-hook-form'; +import React, { useState, useCallback, useMemo, useEffect } from 'react'; import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query'; import type { TUpdateUserPlugins } from 'librechat-data-provider'; import type { MCP } from 'librechat-data-provider'; +import { useCreateMCPMutation } from '~/data-provider'; import { Button, Input, Label } from '~/components/ui'; import { useGetStartupConfig } from '~/data-provider'; -import { useAddToolMutation } from '~/data-provider/Tools/mutations'; import MCPPanelSkeleton from './MCPPanelSkeleton'; import { useToastContext } from '~/Providers'; -import { useLocalize } from '~/hooks'; import MCPFormPanel from './MCPFormPanel'; +import { useLocalize } from '~/hooks'; interface ServerConfigWithVars { serverName: string; @@ -61,7 +61,7 @@ export default function MCPPanel() { }, }); - const createMCPMutation = useAddToolMutation({ + const create = useCreateMCPMutation({ onSuccess: () => { showToast({ message: localize('com_ui_update_mcp_success'), @@ -119,20 +119,7 @@ export default function MCPPanel() { }; const handleSaveMCP = (mcp: MCP) => { - // Transform MCP data to match the expected format - const mcpData = { - name: mcp.metadata.name || '', - description: mcp.metadata.description || '', - url: mcp.metadata.url || '', - icon: mcp.metadata.icon || '', - tools: mcp.metadata.tools || [], - trust: mcp.metadata.trust ?? false, - customHeaders: mcp.metadata.customHeaders || [], - requestTimeout: mcp.metadata.requestTimeout, - connectionTimeout: mcp.metadata.connectionTimeout, - }; - - createMCPMutation.mutate(mcpData); + create.mutate(mcp); }; if (showMCPForm) { diff --git a/client/src/data-provider/Tools/mutations.ts b/client/src/data-provider/Tools/mutations.ts index 2501eecbb0..7ed48f3cbc 100644 --- a/client/src/data-provider/Tools/mutations.ts +++ b/client/src/data-provider/Tools/mutations.ts @@ -41,32 +41,14 @@ export const useToolCallMutation = ( ); }; -interface CreateToolData { - name: string; - description: string; - metadata?: Record; - // MCP-specific fields - url?: string; - icon?: string; - tools?: string[]; - trust?: boolean; - customHeaders?: Array<{ - id: string; - name: string; - value: string; - }>; - requestTimeout?: number; - connectionTimeout?: number; -} - -export const useAddToolMutation = ( - options?: t.MutationOptions, CreateToolData>, -): UseMutationResult, Error, CreateToolData> => { +export const useCreateMCPMutation = ( + options?: t.CreateMCPMutationOptions, +): UseMutationResult, Error, t.MCP> => { const queryClient = useQueryClient(); return useMutation( - (toolData: CreateToolData) => { - return dataService.createTool(toolData); + (mcp: t.MCP) => { + return dataService.createMCP(mcp); }, { onMutate: (variables) => options?.onMutate?.(variables), @@ -74,7 +56,7 @@ export const useAddToolMutation = ( onSuccess: (data, variables, context) => { // Invalidate tools list to trigger refetch queryClient.invalidateQueries([QueryKeys.tools]); - queryClient.invalidateQueries([QueryKeys.mcpTools]); + // queryClient.invalidateQueries([QueryKeys.mcpTools]); return options?.onSuccess?.(data, variables, context); }, }, diff --git a/packages/api/src/mcp/add.ts b/packages/api/src/mcp/add.ts index ed17c59991..e3d717ebd7 100644 --- a/packages/api/src/mcp/add.ts +++ b/packages/api/src/mcp/add.ts @@ -1,154 +1,8 @@ -import { Request, Response } from 'express'; -import { logger } from '@librechat/data-schemas'; +import { MCP } from 'librechat-data-provider'; +import { Response } from 'express'; -interface MCPCreateRequest extends Request { - body: { - name: string; - description: string; - url: string; - icon?: string; - tools?: string[]; - trust: boolean; - customHeaders?: Array<{ - id: string; - name: string; - value: string; - }>; - requestTimeout?: number; - connectionTimeout?: number; - }; - user?: { - id: string; - }; -} - -export interface MCPCreateResponse { - mcp_id: string; - metadata: { - name: string; - description: string; - url: string; - icon?: string; - tools?: string[]; - trust: boolean; - customHeaders?: Array<{ - id: string; - name: string; - value: string; - }>; - requestTimeout?: number; - connectionTimeout?: number; - }; - created_at: string; - updated_at: string; -} - -export interface MCPCreateError { - error: string; - message?: string; -} - -/** - * Add a new tool/MCP to the system - * @route POST /agents/tools/add - * @param {object} req.body - Request body containing tool/MCP data - * @param {string} req.body.name - Tool/MCP name - * @param {string} req.body.description - Tool/MCP description - * @param {string} req.body.url - Tool/MCP server URL - * @param {string} [req.body.icon] - Tool/MCP icon (base64) - * @param {string[]} [req.body.tools] - Available tools - * @param {boolean} req.body.trust - Trust flag - * @param {string[]} [req.body.customHeaders] - Custom headers - * @param {string} [req.body.requestTimeout] - Request timeout - * @param {string} [req.body.connectionTimeout] - Connection timeout - * @returns {object} Created tool/MCP object - */ -export const addTool = async (req: MCPCreateRequest, res: Response) => { - try { - const { - name, - description, - url, - icon, - tools, - trust, - customHeaders, - requestTimeout, - connectionTimeout, - } = req.body; - - // Log the raw request body for debugging - logger.info('Raw request body: ' + JSON.stringify(req.body, null, 2)); - - // Log the incoming tool/MCP request for development - const logData = { - name, - description, - url, - icon: icon ? 'base64_icon_provided' : 'no_icon', - tools: tools || [], - trust, - customHeaders: customHeaders || [], - timeouts: { - requestTimeout: requestTimeout || 'default', - connectionTimeout: connectionTimeout || 'default', - }, - userId: req.user?.id, - timestamp: new Date().toISOString(), - }; - - logger.info('Add Tool/MCP Request: ' + JSON.stringify(logData, null, 2)); - - // Validate required fields - if (!name || !description || !url) { - return res.status(400).json({ - error: 'Missing required fields: name, description, and url are required', - }); - } - - // Validate URL format - try { - new URL(url); - } catch { - return res.status(400).json({ - error: 'Invalid URL format', - }); - } - - // Validate trust flag - if (typeof trust !== 'boolean') { - return res.status(400).json({ - error: 'Trust flag must be a boolean value', - }); - } - - // For now, return a mock successful response - // TODO: Implement actual tool/MCP creation logic - const mockTool = { - mcp_id: `mcp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, - metadata: { - name, - description, - url, - icon: icon || undefined, - tools: tools || [], - trust, - customHeaders: customHeaders || [], - requestTimeout, - connectionTimeout, - }, - created_at: new Date().toISOString(), - updated_at: new Date().toISOString(), - }; - - logger.info('Tool/MCP created successfully:', JSON.stringify(mockTool, null, 2)); - - res.status(201).json(mockTool); - } catch (error) { - logger.error('Error adding tool/MCP:', error); - res.status(500).json({ - error: 'Internal server error while adding tool/MCP', - message: error instanceof Error ? error.message : 'Unknown error', - }); - } +// just log the request +export const addTool = (req: { body: MCP }, res: Response) => { + console.log(JSON.stringify(req.body, null, 2)); + res.send('ok'); }; diff --git a/packages/data-provider/src/data-service.ts b/packages/data-provider/src/data-service.ts index 49ce568021..b230cf6a2e 100644 --- a/packages/data-provider/src/data-service.ts +++ b/packages/data-provider/src/data-service.ts @@ -833,54 +833,11 @@ export const createMemory = (data: { return request.post(endpoints.memories(), data); }; -export const createTool = (toolData: { - name: string; - description: string; - metadata?: Record; - // MCP-specific fields - url?: string; - icon?: string; - tools?: string[]; - trust?: boolean; - customHeaders?: Array<{ - id: string; - name: string; - value: string; - }>; - requestTimeout?: number; - connectionTimeout?: number; -}): Promise<{ - id?: string; - mcp_id?: string; - type?: string; - function?: { - name: string; - description: string; - }; - metadata: - | Record - | { - name: string; - description: string; - url?: string; - icon?: string; - tools?: string[]; - trust?: boolean; - customHeaders?: Array<{ - id: string; - name: string; - value: string; - }>; - requestTimeout?: number; - connectionTimeout?: number; - }; - created_at: string; - updated_at: string; -}> => { +export const createMCP = (mcp: ag.MCP): Promise> => { return request.post( endpoints.agents({ path: 'tools/add', }), - toolData, + mcp, ); }; diff --git a/packages/data-provider/src/types/mutations.ts b/packages/data-provider/src/types/mutations.ts index cd6cae75c8..9c49f98ec2 100644 --- a/packages/data-provider/src/types/mutations.ts +++ b/packages/data-provider/src/types/mutations.ts @@ -12,7 +12,7 @@ import { AgentCreateParams, AgentUpdateParams, } from './assistants'; -import { Action, ActionMetadata } from './agents'; +import { Action, ActionMetadata, MCP } from './agents'; export type MutationOptions< Response, @@ -319,6 +319,8 @@ export type AcceptTermsMutationOptions = MutationOptions< /* Tools */ export type UpdatePluginAuthOptions = MutationOptions; +export type CreateMCPMutationOptions = MutationOptions, MCP>; + export type ToolParamsMap = { [Tools.execute_code]: { lang: string;