Skip to main content
Glama

clone_agent

Create a new agent by cloning an existing agent's configuration. Use to duplicate agent setups without manual recreation, then modify as needed.

Instructions

Creates a new agent by cloning the configuration of an existing agent. Use list_agents to find source agent ID. Alternative to export_agent + import_agent workflow. Modify the clone with modify_agent afterwards.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
source_agent_idYesThe ID of the agent to clone.
new_agent_nameYesThe name for the new cloned agent.
override_existing_toolsNoOptional: If set to True, existing tools can get their source code overwritten by the tool definitions from the source agent. Defaults to true.
project_idNoOptional: The project ID to associate the new cloned agent with.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
successYes
new_agent_idYes
new_agent_nameNo
original_agent_idNo

Implementation Reference

  • Core handler function for clone_agent tool. Exports source agent config from API, changes name, saves to temporary JSON file, imports as new agent using FormData POST to /agents/import endpoint, handles errors and cleanup.
    export async function handleCloneAgent(server, args) {
        if (!args?.source_agent_id) {
            server.createErrorResponse('Missing required argument: source_agent_id');
        }
        if (!args?.new_agent_name) {
            server.createErrorResponse('Missing required argument: new_agent_name');
        }
    
        const sourceAgentId = args.source_agent_id;
        const newAgentName = args.new_agent_name;
        const overrideTools = args.override_existing_tools ?? true; // Default override
        const projectId = args.project_id; // Optional project ID for the new agent
    
        let tempFilePath = '';
    
        try {
            const headers = server.getApiHeaders();
            const encodedSourceAgentId = encodeURIComponent(sourceAgentId);
    
            // --- Step 1: Export the source agent ---
            logger.info(`Exporting source agent ${sourceAgentId}...`);
            const exportResponse = await server.api.get(`/agents/${encodedSourceAgentId}/export`, {
                headers,
            });
            const agentConfig = exportResponse.data;
    
            if (!agentConfig || typeof agentConfig !== 'object') {
                throw new Error('Received invalid data from agent export endpoint.');
            }
            logger.info(`Source agent ${sourceAgentId} exported successfully.`);
    
            // --- Step 2: Modify the configuration for the new agent ---
            agentConfig.name = newAgentName; // Set the new name
            // Optionally clear fields that shouldn't be copied or might cause conflicts
            // delete agentConfig.id; // ID will be assigned on import
            // delete agentConfig.created_at;
            // delete agentConfig.updated_at;
            // Consider if message history should be copied or cleared
            // agentConfig.messages = [];
            // agentConfig.message_ids = [];
    
            const agentJsonString = JSON.stringify(agentConfig, null, 2);
    
            // --- Step 3: Save modified config to a temporary file ---
            // Use os.tmpdir() which should work inside Docker if /tmp is writable
            tempFilePath = path.join(os.tmpdir(), `agent_clone_temp_${Date.now()}.json`);
            logger.info(`Saving temporary config to ${tempFilePath}...`);
            await fs.writeFile(tempFilePath, agentJsonString);
            logger.info('Temporary config saved.');
    
            // --- Step 4: Import the modified configuration ---
            logger.info(`Importing new agent '${newAgentName}' from ${tempFilePath}...`);
            const importHeaders = server.getApiHeaders();
            delete importHeaders['Content-Type']; // Let FormData set the correct header
    
            const form = new FormData();
            form.append('file', await fs.readFile(tempFilePath), path.basename(tempFilePath)); // Read file content for FormData
    
            const importParams = {
                append_copy_suffix: false, // We explicitly set the name, don't append suffix
                override_existing_tools: overrideTools,
            };
            if (projectId) {
                importParams.project_id = projectId;
            }
    
            const importResponse = await server.api.post('/agents/import', form, {
                headers: {
                    ...importHeaders,
                    ...form.getHeaders(),
                },
                params: importParams,
            });
    
            const importedAgentState = importResponse.data;
            logger.info(
                `Agent '${newAgentName}' imported successfully with ID: ${importedAgentState.id}`,
            );
    
            // --- Step 5: Cleanup temporary file ---
            await fs.unlink(tempFilePath);
            logger.info(`Cleaned up temporary file ${tempFilePath}.`);
    
            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            new_agent: importedAgentState,
                        }),
                    },
                ],
            };
        } catch (error) {
            logger.error('Error:', error.response?.data || error.message);
            // Attempt cleanup even on error
            if (tempFilePath) {
                try {
                    await fs.unlink(tempFilePath);
                    logger.info(`Cleaned up temporary file ${tempFilePath} after error.`);
                } catch (cleanupError) {
                    logger.error(`Error cleaning up temporary file ${tempFilePath}:`, cleanupError);
                }
            }
    
            // Handle specific API errors
            if (error.response) {
                if (error.response.status === 404 && error.config.url.includes('/export')) {
                    server.createErrorResponse(`Source agent not found: ${sourceAgentId}`);
                }
                if (error.response.status === 422 && error.config.url.includes('/import')) {
                    server.createErrorResponse(
                        `Validation error importing cloned agent: ${JSON.stringify(error.response.data)}`,
                    );
                }
            }
            server.createErrorResponse(`Failed to clone agent ${sourceAgentId}: ${error.message}`);
        }
    }
  • Tool definition including name, description, and input schema with required parameters source_agent_id and new_agent_name.
    export const cloneAgentDefinition = {
        name: 'clone_agent',
        description:
            'Creates a new agent by cloning the configuration of an existing agent. Use list_agents to find source agent ID. Alternative to export_agent + import_agent workflow. Modify the clone with modify_agent afterwards.',
        inputSchema: {
            type: 'object',
            properties: {
                source_agent_id: {
                    type: 'string',
                    description: 'The ID of the agent to clone.',
                },
                new_agent_name: {
                    type: 'string',
                    description: 'The name for the new cloned agent.',
                },
                override_existing_tools: {
                    type: 'boolean',
                    description:
                        'Optional: If set to True, existing tools can get their source code overwritten by the tool definitions from the source agent. Defaults to true.',
                    default: true,
                },
                project_id: {
                    type: 'string',
                    description: 'Optional: The project ID to associate the new cloned agent with.',
                },
            },
            required: ['source_agent_id', 'new_agent_name'],
        },
    };
  • Registration of the handler in the central tool dispatch switch statement within registerToolHandlers function.
    case 'clone_agent':
        return handleCloneAgent(server, request.params.arguments);
  • Import of the handler function and tool definition from clone-agent.js.
    import { handleCloneAgent, cloneAgentDefinition } from './agents/clone-agent.js';
  • Output schema definition for structured responses from clone_agent tool.
    clone_agent: {
        type: 'object',
        properties: {
            success: { type: 'boolean' },
            original_agent_id: { type: 'string' },
            new_agent_id: { type: 'string' },
            new_agent_name: { type: 'string' },
        },
        required: ['success', 'new_agent_id'],
    },
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only provide a title, so the description carries the full burden. It discloses that this is a creation/mutation operation (implied by 'creates'), but lacks details on permissions, rate limits, or error conditions. It adds some context about the cloning process but doesn't fully compensate for the absence of annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured in three sentences: purpose, prerequisite, and alternatives/follow-up. Each sentence adds distinct value without redundancy, making it front-loaded and zero-waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the presence of an output schema (which handles return values), 100% schema coverage, and clear purpose/guidelines, the description is largely complete. However, as a mutation tool with no annotations, it could benefit from more behavioral context like error handling or side effects.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description doesn't add any additional meaning or clarification beyond what's in the schema, such as explaining interactions between parameters. Baseline 3 is appropriate when schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('creates a new agent by cloning') and resource ('configuration of an existing agent'), distinguishing it from siblings like create_agent (new from scratch) and export_agent/import_agent (separate workflow). It explicitly names the verb and target resource with precision.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use this tool: it names list_agents as a prerequisite for finding source IDs, positions it as an alternative to the export_agent + import_agent workflow, and suggests modify_agent for subsequent adjustments. This covers both prerequisites and alternatives clearly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oculairmedia/Letta-MCP-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server