From 5a7bf0b35fddde19c30599bb469f1b156d24d6f7 Mon Sep 17 00:00:00 2001 From: Dustin Healy Date: Fri, 27 Jun 2025 12:30:38 -0700 Subject: [PATCH] add update and delete mutations --- api/server/routes/agents/tools.js | 19 ++++++++- client/src/data-provider/Tools/mutations.ts | 42 +++++++++++++++++++ client/src/hooks/Plugins/useMCPSelect.ts | 7 +++- packages/api/src/index.ts | 2 +- packages/api/src/mcp/add.ts | 8 ---- packages/api/src/mcp/mcpOps.ts | 17 ++++++++ packages/data-provider/src/data-service.ts | 23 ++++++++++ packages/data-provider/src/types/mutations.ts | 7 ++++ 8 files changed, 114 insertions(+), 11 deletions(-) delete mode 100644 packages/api/src/mcp/add.ts create mode 100644 packages/api/src/mcp/mcpOps.ts diff --git a/api/server/routes/agents/tools.js b/api/server/routes/agents/tools.js index fbff6f6e43..b12e948f33 100644 --- a/api/server/routes/agents/tools.js +++ b/api/server/routes/agents/tools.js @@ -1,5 +1,5 @@ const express = require('express'); -const { addTool } = require('@librechat/api'); +const { addTool, updateTool, deleteTool } = require('@librechat/api'); const { callTool, verifyToolAuth, getToolCalls } = require('~/server/controllers/tools'); const { getAvailableTools } = require('~/server/controllers/PluginController'); const { toolCallLimiter } = require('~/server/middleware/limiters'); @@ -45,4 +45,21 @@ router.post('/:toolId/call', toolCallLimiter, callTool); */ router.post('/add', addTool); +/** + * Update an existing tool/MCP in the system + * @route PUT /agents/tools/:mcp_id + * @param {string} mcp_id - The ID of the MCP to update + * @param {object} req.body - Request body containing updated tool/MCP data + * @returns {object} Updated tool/MCP object + */ +router.put('/:mcp_id', updateTool); + +/** + * Delete a tool/MCP from the system + * @route DELETE /agents/tools/:mcp_id + * @param {string} mcp_id - The ID of the MCP to delete + * @returns {object} Deletion confirmation + */ +router.delete('/:mcp_id', deleteTool); + module.exports = router; diff --git a/client/src/data-provider/Tools/mutations.ts b/client/src/data-provider/Tools/mutations.ts index 7ed48f3cbc..c9935733ca 100644 --- a/client/src/data-provider/Tools/mutations.ts +++ b/client/src/data-provider/Tools/mutations.ts @@ -62,3 +62,45 @@ export const useCreateMCPMutation = ( }, ); }; + +export const useUpdateMCPMutation = ( + options?: t.UpdateMCPMutationOptions, +): UseMutationResult, Error, { mcp_id: string; data: t.MCP }> => { + const queryClient = useQueryClient(); + + return useMutation( + ({ mcp_id, data }: { mcp_id: string; data: t.MCP }) => { + return dataService.updateMCP({ mcp_id, data }); + }, + { + onMutate: (variables) => options?.onMutate?.(variables), + onError: (error, variables, context) => options?.onError?.(error, variables, context), + onSuccess: (data, variables, context) => { + // Invalidate tools list to trigger refetch + queryClient.invalidateQueries([QueryKeys.tools]); + return options?.onSuccess?.(data, variables, context); + }, + }, + ); +}; + +export const useDeleteMCPMutation = ( + options?: t.DeleteMCPMutationOptions, +): UseMutationResult, Error, { mcp_id: string }> => { + const queryClient = useQueryClient(); + + return useMutation( + ({ mcp_id }: { mcp_id: string }) => { + return dataService.deleteMCP({ mcp_id }); + }, + { + onMutate: (variables) => options?.onMutate?.(variables), + onError: (error, variables, context) => options?.onError?.(error, variables, context), + onSuccess: (data, variables, context) => { + // Invalidate tools list to trigger refetch + queryClient.invalidateQueries([QueryKeys.tools]); + return options?.onSuccess?.(data, variables, context); + }, + }, + ); +}; diff --git a/client/src/hooks/Plugins/useMCPSelect.ts b/client/src/hooks/Plugins/useMCPSelect.ts index a76ccdced5..9ea083703a 100644 --- a/client/src/hooks/Plugins/useMCPSelect.ts +++ b/client/src/hooks/Plugins/useMCPSelect.ts @@ -30,6 +30,8 @@ export function useMCPSelect({ conversationId }: UseMCPSelectOptions) { const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key)); const { data: mcpToolDetails, isFetched } = useAvailableToolsQuery(EModelEndpoint.agents, { select: (data: TPlugin[]) => { + console.log('🔍 Raw tools data received:', JSON.stringify(data, null, 2)); + const mcpToolsMap = new Map(); data.forEach((tool) => { const isMCP = tool.pluginKey.includes(Constants.mcp_delimiter); @@ -46,7 +48,10 @@ export function useMCPSelect({ conversationId }: UseMCPSelectOptions) { } } }); - return Array.from(mcpToolsMap.values()); + + const result = Array.from(mcpToolsMap.values()); + console.log('🔧 Processed MCP tools:', JSON.stringify(result, null, 2)); + return result; }, }); diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 4860200b16..c25d3184b6 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -2,7 +2,7 @@ export * from './mcp/manager'; export * from './mcp/oauth'; export * from './mcp/auth'; -export * from './mcp/add'; +export * from './mcp/mcpOps'; /* Utilities */ export * from './mcp/utils'; export * from './utils'; diff --git a/packages/api/src/mcp/add.ts b/packages/api/src/mcp/add.ts deleted file mode 100644 index e3d717ebd7..0000000000 --- a/packages/api/src/mcp/add.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { MCP } from 'librechat-data-provider'; -import { Response } from 'express'; - -// 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/api/src/mcp/mcpOps.ts b/packages/api/src/mcp/mcpOps.ts new file mode 100644 index 0000000000..605f423fae --- /dev/null +++ b/packages/api/src/mcp/mcpOps.ts @@ -0,0 +1,17 @@ +import { MCP } from 'librechat-data-provider'; +import { Response } from 'express'; + +export const addTool = (req: { body: MCP }, res: Response) => { + console.log('CREATE MCP:', JSON.stringify(req.body, null, 2)); + res.send('ok'); +}; + +export const updateTool = (req: { body: MCP; params: { mcp_id: string } }, res: Response) => { + console.log('UPDATE MCP:', req.params.mcp_id, JSON.stringify(req.body, null, 2)); + res.send('ok'); +}; + +export const deleteTool = (req: { params: { mcp_id: string } }, res: Response) => { + console.log('DELETE MCP:', req.params.mcp_id); + res.send('ok'); +}; diff --git a/packages/data-provider/src/data-service.ts b/packages/data-provider/src/data-service.ts index b230cf6a2e..eaa9c52933 100644 --- a/packages/data-provider/src/data-service.ts +++ b/packages/data-provider/src/data-service.ts @@ -841,3 +841,26 @@ export const createMCP = (mcp: ag.MCP): Promise> => { mcp, ); }; + +export const updateMCP = ({ + mcp_id, + data, +}: { + mcp_id: string; + data: ag.MCP; +}): Promise> => { + return request.put( + endpoints.agents({ + path: `tools/${mcp_id}`, + }), + data, + ); +}; + +export const deleteMCP = ({ mcp_id }: { mcp_id: string }): Promise> => { + return request.delete( + endpoints.agents({ + path: `tools/${mcp_id}`, + }), + ); +}; diff --git a/packages/data-provider/src/types/mutations.ts b/packages/data-provider/src/types/mutations.ts index 9c49f98ec2..7a9f5cf495 100644 --- a/packages/data-provider/src/types/mutations.ts +++ b/packages/data-provider/src/types/mutations.ts @@ -321,6 +321,13 @@ export type UpdatePluginAuthOptions = MutationOptions, MCP>; +export type UpdateMCPMutationOptions = MutationOptions< + Record, + { mcp_id: string; data: MCP } +>; + +export type DeleteMCPMutationOptions = MutationOptions, { mcp_id: string }>; + export type ToolParamsMap = { [Tools.execute_code]: { lang: string;