@@ -172,28 +172,6 @@ const enhanceToolsWithMCPMetadata = (tools, availableTools = {}) => {
172172 return enhancedTools ;
173173} ;
174174
175- /**
176- * Filter out MCP tools from enhanced tools array for agent duplication security
177- * @param {Array<string | Object> } tools - Enhanced tools array
178- * @returns {Array<string> } Array of non-MCP tools only
179- */
180- const filterOutMCPTools = ( tools ) => {
181- if ( ! Array . isArray ( tools ) ) {
182- return [ ] ;
183- }
184-
185- const nonMCPTools = [ ] ;
186-
187- for ( const tool of tools ) {
188- if ( typeof tool === 'string' ) {
189- // Keep regular/system tools
190- nonMCPTools . push ( tool ) ;
191- }
192- // Skip MCP tool objects (they have tool/server/type properties)
193- }
194-
195- return nonMCPTools ;
196- } ;
197175
198176/**
199177 * Creates an Agent.
@@ -383,137 +361,6 @@ const updateAgentHandler = async (req, res) => {
383361 return res . status ( 404 ) . json ( { error : 'Agent not found' } ) ;
384362 }
385363
386- // Check if this is a global agent that should be cloned instead of modified
387- const globalProject = await getProjectByName ( Constants . GLOBAL_PROJECT_NAME , 'agentIds' ) ;
388- const isGlobalAgent = globalProject && ( globalProject . agentIds ?. includes ( id ) ?? false ) ;
389- const shouldCloneInsteadOfUpdate =
390- isGlobalAgent && existingAgent . isCollaborative && ! isAuthor && ! isAdmin ;
391-
392- if ( shouldCloneInsteadOfUpdate ) {
393- // Instead of updating the global agent, create a duplicate for the user
394- const {
395- id : _id ,
396- _id : __id ,
397- author : _author ,
398- createdAt : _createdAt ,
399- updatedAt : _updatedAt ,
400- tool_resources : _tool_resources = { } ,
401- ...cloneData
402- } = existingAgent ;
403-
404- // Apply the updates to the clone data
405- Object . assign ( cloneData , updateData ) ;
406-
407- // Remove MCP tools from duplicated agents so users need to connect their own integrations
408- if ( cloneData . tools && Array . isArray ( cloneData . tools ) ) {
409- const originalToolCount = cloneData . tools . length ;
410- const { ToolMetadataUtils } = require ( 'librechat-data-provider' ) ;
411- const availableTools = req . app . locals . availableTools || { } ;
412-
413- const mcpTools = cloneData . tools . filter ( ( tool ) => {
414- if ( typeof tool === 'string' ) {
415- const toolDef = availableTools [ tool ] ;
416- return toolDef && ToolMetadataUtils . isMCPTool ( toolDef ) ;
417- }
418- return false ;
419- } ) ;
420-
421- cloneData . tools = cloneData . tools . filter ( ( tool ) => {
422- if ( typeof tool === 'string' ) {
423- // Check if this is an MCP tool using embedded metadata
424- const toolDef = availableTools [ tool ] ;
425- return ! ( toolDef && ToolMetadataUtils . isMCPTool ( toolDef ) ) ;
426- }
427- return true ;
428- } ) ;
429-
430- if ( mcpTools . length > 0 ) {
431- logger . info (
432- `[/agents/:id] Removed ${ mcpTools . length } MCP tools during auto-duplication for user ${ req . user . id } . User can add their own integrations. Tools removed: ${ mcpTools . join ( ', ' ) } ` ,
433- ) ;
434- }
435-
436- logger . info (
437- `[/agents/:id] Tool count: ${ originalToolCount } -> ${ cloneData . tools . length } (removed ${ originalToolCount - cloneData . tools . length } MCP tools)` ,
438- ) ;
439- }
440-
441- if ( _tool_resources ?. [ EToolResources . ocr ] ) {
442- cloneData . tool_resources = {
443- [ EToolResources . ocr ] : _tool_resources [ EToolResources . ocr ] ,
444- } ;
445- }
446-
447- const newAgentId = `agent_${ nanoid ( ) } ` ;
448- const newAgentData = Object . assign ( cloneData , {
449- id : newAgentId ,
450- author : req . user . id ,
451- originalAgentId : id ,
452- projectIds : [ ] , // Clear project associations - duplicated agents should be private
453- isCollaborative : false , // Make the private copy non-collaborative
454- tools : filterOutMCPTools ( originalAgent . tools ) , // Clear MCP tools for duplicated agents - users need to connect their own integrations
455- } ) ;
456-
457- // Handle actions duplication if the original agent has actions
458- const newActionsList = [ ] ;
459- const originalActions = ( await getActions ( { agent_id : id } , true ) ) ?? [ ] ;
460- const sensitiveFields = [ 'api_key' , 'oauth_client_id' , 'oauth_client_secret' ] ;
461- const promises = [ ] ;
462-
463- /**
464- * Duplicates an action and returns the new action ID.
465- * @param {Action } action
466- * @returns {Promise<string> }
467- */
468- const duplicateAction = async ( action ) => {
469- const newActionId = nanoid ( ) ;
470- const [ domain ] = action . action_id . split ( actionDelimiter ) ;
471- const fullActionId = `${ domain } ${ actionDelimiter } ${ newActionId } ` ;
472-
473- const newAction = await updateAction (
474- { action_id : newActionId } ,
475- {
476- metadata : action . metadata ,
477- agent_id : newAgentId ,
478- user : req . user . id ,
479- } ,
480- ) ;
481-
482- const filteredMetadata = { ...newAction . metadata } ;
483- for ( const field of sensitiveFields ) {
484- delete filteredMetadata [ field ] ;
485- }
486-
487- newAction . metadata = filteredMetadata ;
488- newActionsList . push ( newAction ) ;
489- return fullActionId ;
490- } ;
491-
492- for ( const action of originalActions ) {
493- promises . push (
494- duplicateAction ( action ) . catch ( ( error ) => {
495- logger . error ( '[/agents/:id] Error duplicating Action during auto-duplication:' , error ) ;
496- } ) ,
497- ) ;
498- }
499-
500- const agentActions = await Promise . all ( promises ) ;
501- newAgentData . actions = agentActions ;
502-
503- const newAgent = await createAgent ( newAgentData ) ;
504-
505- logger . info (
506- `[/agents/:id] Auto-duplicated global agent ${ id } to ${ newAgentId } for user ${ req . user . id } due to modification attempt` ,
507- ) ;
508-
509- return res . status ( 201 ) . json ( {
510- ...newAgent ,
511- actions : newActionsList ,
512- message : 'Global agent duplicated as your private copy with modifications' ,
513- duplicated : true ,
514- originalAgentId : id ,
515- } ) ;
516- }
517364
518365 const hasEditPermission = existingAgent . isCollaborative || isAdmin || isAuthor ;
519366
@@ -643,9 +490,7 @@ const duplicateAgentHandler = async (req, res) => {
643490 const newAgentData = Object . assign ( cloneData , {
644491 id : newAgentId ,
645492 author : userId ,
646- originalAgentId : id ,
647493 projectIds : [ ] , // Clear project associations - duplicated agents should be private
648- tools : filterOutMCPTools ( cloneData . tools ) , // Clear MCP tools for duplicated agents - users need to connect their own integrations
649494 } ) ;
650495
651496 const newActionsList = [ ] ;
0 commit comments