@@ -41,7 +41,7 @@ import type { ActorMcpTool, ActorTool, HelperTool, ToolEntry } from '../types.js
4141import { buildActorResponseContent } from '../utils/actor-response.js' ;
4242import { buildMCPResponse } from '../utils/mcp.js' ;
4343import { createProgressTracker } from '../utils/progress.js' ;
44- import { getToolPublicFieldOnly } from '../utils/tools.js' ;
44+ import { cloneToolEntry , getToolPublicFieldOnly } from '../utils/tools.js' ;
4545import { connectMCPClient } from './client.js' ;
4646import { EXTERNAL_TOOL_CALL_TIMEOUT_MSEC , LOG_LEVEL_MAP } from './const.js' ;
4747import { processParamsGetTools } from './utils.js' ;
@@ -262,31 +262,42 @@ export class ActorsMcpServer {
262262 * @returns Array of added/updated tool wrappers
263263 */
264264 public upsertTools ( tools : ToolEntry [ ] , shouldNotifyToolsChangedHandler = false ) {
265- for ( const wrap of tools ) {
266- this . tools . set ( wrap . tool . name , wrap ) ;
267- }
268- // Handle Skyfire mode modifications once per tool upsert
265+ // Handle Skyfire mode modifications before storing tools
269266 if ( this . options . skyfireMode ) {
270267 for ( const wrap of tools ) {
271268 if ( wrap . type === 'actor'
272269 || ( wrap . type === 'internal' && wrap . tool . name === HelperTools . ACTOR_CALL )
273270 || ( wrap . type === 'internal' && wrap . tool . name === HelperTools . ACTOR_OUTPUT_GET ) ) {
271+ // Clone the tool before modifying it to avoid affecting shared objects
272+ const clonedWrap = cloneToolEntry ( wrap ) ;
273+
274274 // Add Skyfire instructions to description if not already present
275- if ( ! wrap . tool . description . includes ( SKYFIRE_TOOL_INSTRUCTIONS ) ) {
276- wrap . tool . description += `\n\n${ SKYFIRE_TOOL_INSTRUCTIONS } ` ;
275+ if ( ! clonedWrap . tool . description . includes ( SKYFIRE_TOOL_INSTRUCTIONS ) ) {
276+ clonedWrap . tool . description += `\n\n${ SKYFIRE_TOOL_INSTRUCTIONS } ` ;
277277 }
278278 // Add skyfire-pay-id property if not present
279- if ( wrap . tool . inputSchema && 'properties' in wrap . tool . inputSchema ) {
280- const props = wrap . tool . inputSchema . properties as Record < string , unknown > ;
279+ if ( clonedWrap . tool . inputSchema && 'properties' in clonedWrap . tool . inputSchema ) {
280+ const props = clonedWrap . tool . inputSchema . properties as Record < string , unknown > ;
281281 if ( ! props [ 'skyfire-pay-id' ] ) {
282282 props [ 'skyfire-pay-id' ] = {
283283 type : 'string' ,
284284 description : SKYFIRE_PAY_ID_PROPERTY_DESCRIPTION ,
285285 } ;
286286 }
287287 }
288+
289+ // Store the cloned and modified tool
290+ this . tools . set ( clonedWrap . tool . name , clonedWrap ) ;
291+ } else {
292+ // Store unmodified tools as-is
293+ this . tools . set ( wrap . tool . name , wrap ) ;
288294 }
289295 }
296+ } else {
297+ // No skyfire mode - store tools as-is
298+ for ( const wrap of tools ) {
299+ this . tools . set ( wrap . tool . name , wrap ) ;
300+ }
290301 }
291302 if ( shouldNotifyToolsChangedHandler ) this . notifyToolsChangedHandler ( ) ;
292303 return tools ;
0 commit comments