upload_tool
Upload custom tools to the Letta system for use with agents. Add tools to agents after creation and verify attachments.
Instructions
Upload a new tool to the Letta system. Use with attach_tool to add it to agents, or list_agent_tools to verify attachment.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of the tool | |
| description | Yes | Description of what the tool does | |
| source_code | Yes | Python source code for the tool | |
| category | No | Category/tag for the tool (e.g., "plane_api", "utility") | custom |
| agent_id | No | Optional agent ID to attach the tool to after creation |
Implementation Reference
- src/tools/tools/upload-tool.js:8-113 (handler)The handleUploadTool function implements the core logic of the upload_tool: validates inputs, deletes existing tool if present, creates a new tool via API, optionally attaches to an agent, and returns JSON with tool details.export async function handleUploadTool(server, args) { try { // Validate arguments if (!args.name || typeof args.name !== 'string') { throw new Error('Missing required argument: name (must be a string)'); } if (!args.description || typeof args.description !== 'string') { throw new Error('Missing required argument: description (must be a string)'); } if (!args.source_code || typeof args.source_code !== 'string') { throw new Error('Missing required argument: source_code (must be a string)'); } // Headers for API requests const headers = server.getApiHeaders(); // If agent_id is provided, set the user_id header if (args.agent_id) { headers['user_id'] = args.agent_id; } // Prepare category/tag const category = args.category || 'custom'; // Check if tool exists and delete if found const toolsResponse = await server.api.get('/tools/', { headers }); const existingTools = toolsResponse.data; let existingToolId = null; for (const tool of existingTools) { if (tool.name === args.name) { existingToolId = tool.id; logger.info( `Found existing tool ${args.name} with ID ${existingToolId}, will delete it first...`, ); break; } } if (existingToolId) { try { await server.api.delete(`/tools/${existingToolId}`, { headers }); logger.info(`Successfully deleted existing tool ${args.name}`); } catch (deleteError) { logger.info( `Failed to delete existing tool: ${deleteError}. Will try to continue anyway.`, ); } } // Prepare tool data const toolData = { source_code: args.source_code, description: args.description, tags: [category], source_type: 'python', }; // Create the tool logger.info(`Creating tool "${args.name}"...`); const createResponse = await server.api.post('/tools/', toolData, { headers }); const toolId = createResponse.data.id; // If agent_id is provided, attach the tool to the agent if (args.agent_id) { // Attach tool to agent const attachUrl = `/agents/${args.agent_id}/tools/attach/${toolId}`; await server.api.patch(attachUrl, {}, { headers }); // Get agent info const agentInfoResponse = await server.api.get(`/agents/${args.agent_id}`, { headers }); const agentName = agentInfoResponse.data.name || 'Unknown'; return { content: [ { type: 'text', text: JSON.stringify({ tool_id: toolId, tool_name: args.name, agent_id: args.agent_id, agent_name: agentName, category: category, }), }, ], }; } else { // Just return the created tool info return { content: [ { type: 'text', text: JSON.stringify({ tool_id: toolId, tool_name: args.name, category: category, }), }, ], }; } } catch (error) { server.createErrorResponse(error); } }
- Defines the tool schema including name, description, inputSchema with properties for name, description, source_code (required), optional category and agent_id.export const uploadToolToolDefinition = { name: 'upload_tool', description: 'Upload a new tool to the Letta system. Use with attach_tool to add it to agents, or list_agent_tools to verify attachment.', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Name of the tool', }, description: { type: 'string', description: 'Description of what the tool does', }, source_code: { type: 'string', description: 'Python source code for the tool', }, category: { type: 'string', description: 'Category/tag for the tool (e.g., "plane_api", "utility")', default: 'custom', }, agent_id: { type: 'string', description: 'Optional agent ID to attach the tool to after creation', }, }, required: ['name', 'description', 'source_code'], }, };
- src/tools/index.js:177-178 (registration)Registers the upload_tool in the MCP CallToolRequestSchema handler switch statement, dispatching calls to handleUploadTool.case 'upload_tool': return handleUploadTool(server, request.params.arguments);
- src/tools/index.js:58-58 (registration)Imports the handleUploadTool function and uploadToolToolDefinition from upload-tool.js.import { handleUploadTool, uploadToolToolDefinition } from './tools/upload-tool.js';
- src/tools/index.js:116-116 (registration)Includes uploadToolToolDefinition in the allTools array used for ListToolsRequestSchema and enhanced tool registration.uploadToolToolDefinition,