Skip to main content
Glama

add_mcp_tool_to_letta

Register an MCP tool from a connected server and attach it to a specific agent in the Letta system for expanded functionality.

Instructions

Registers a tool from a connected MCP server as a native Letta tool AND attaches it to a specified agent. Use list_mcp_tools_by_server to find available tools, and list_agents to get agent IDs.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tool_nameYesThe name of the MCP tool to find, register, and attach.
agent_idYesThe ID of the agent to attach the newly registered tool to.

Implementation Reference

  • The primary handler function that implements the core logic of the 'add_mcp_tool_to_letta' tool. It validates inputs, locates the MCP server for the tool, registers the tool as a native Letta tool via API calls, attaches it to the specified agent, and returns structured results.
    export async function handleAddMcpToolToLetta(server, args) {
        try {
            // Validate arguments (new arguments: tool_name, agent_id)
            if (!args.tool_name) {
                throw new Error('Missing required argument: tool_name (MCP tool name)');
            }
            if (!args.agent_id) {
                throw new Error('Missing required argument: agent_id');
            }
    
            const { tool_name, agent_id } = args;
            const mcp_tool_name = tool_name;
    
            // Headers for API requests
            const headers = server.getApiHeaders();
    
            // --- Find the MCP Server Name for the given tool_name ---
            logger.info(`Searching for MCP server providing tool: ${mcp_tool_name}...`);
            let mcp_server_name = null;
            const serversResponse = await server.api.get('/tools/mcp/servers', { headers });
            if (!serversResponse.data || typeof serversResponse.data !== 'object') {
                throw new Error('Failed to list MCP servers or invalid response format.');
            }
            const serverNames = Object.keys(serversResponse.data);
    
            for (const serverName of serverNames) {
                logger.info(`Checking server: ${serverName}`);
                try {
                    const toolsResponse = await server.api.get(
                        `/tools/mcp/servers/${serverName}/tools`,
                        { headers },
                    );
                    if (toolsResponse.data && Array.isArray(toolsResponse.data)) {
                        const foundTool = toolsResponse.data.find(
                            (tool) => tool.name === mcp_tool_name,
                        );
                        if (foundTool) {
                            mcp_server_name = serverName;
                            logger.info(
                                `Found tool '${mcp_tool_name}' on server '${mcp_server_name}'.`,
                            );
                            break; // Stop searching once found
                        }
                    }
                } catch (toolListError) {
                    // Log error but continue searching other servers
                    logger.info(
                        `Could not list tools for server ${serverName}: ${toolListError.message}`,
                    );
                }
            }
    
            if (!mcp_server_name) {
                throw new Error(
                    `Could not find any MCP server providing the tool named '${mcp_tool_name}'.`,
                );
            }
            // --- End of Find MCP Server Name ---
    
            // Headers for API requests
            // Note: The API spec didn't explicitly require user_id for this endpoint,
            // but adding it might be necessary depending on Letta's auth setup.
    
            logger.info(
                `Attempting to register MCP tool ${mcp_server_name}/${mcp_tool_name} with Letta...`,
            );
            const registerUrl = `/tools/mcp/servers/${mcp_server_name}/${mcp_tool_name}`;
    
            // Make the POST request to register the tool
            logger.info(`DEBUG: Calling registration URL: POST ${registerUrl}`);
            const registerResponse = await server.api.post(registerUrl, {}, { headers });
    
            // Check registration response data for success and the new tool ID
            if (!registerResponse.data || !registerResponse.data.id) {
                throw new Error(
                    `Registration API call succeeded but did not return the expected tool ID. Response: ${JSON.stringify(registerResponse.data)}`,
                );
            }
    
            const lettaToolId = registerResponse.data.id;
            const lettaToolName = registerResponse.data.name || mcp_tool_name;
            logger.info(`Successfully registered tool. Letta Tool ID: ${lettaToolId}`);
    
            // Now, attempt to attach the newly registered tool to the agent
            logger.info(`Attempting to attach tool ${lettaToolId} to agent ${agent_id}...`);
            const attachUrl = `/agents/${agent_id}/tools/attach/${lettaToolId}`;
            let attachSuccess = false;
            let attachMessage = '';
            let attachError = null;
    
            try {
                // Use specific headers for the agent context if needed, otherwise reuse
                const attachHeaders = { ...headers };
    
                logger.info(`DEBUG: Calling attachment URL: PATCH ${attachUrl}`);
                const attachResponse = await server.api.patch(
                    attachUrl,
                    {},
                    { headers: attachHeaders },
                );
    
                // Verify attachment (optional but good practice)
                const attachedToolIds = attachResponse.data.tools?.map((t) => t.id) || [];
                if (attachedToolIds.includes(lettaToolId)) {
                    attachSuccess = true;
                    attachMessage = `Successfully attached tool '${lettaToolName}' (ID: ${lettaToolId}) to agent ${agent_id}.`;
                    logger.info(attachMessage);
                } else {
                    attachMessage = `Attachment API call succeeded, but tool ${lettaToolId} was not found in agent's tools list afterwards.`;
                    logger.info(attachMessage);
                    // Consider this a partial failure
                }
            } catch (error) {
                attachSuccess = false;
                attachMessage = `Failed to attach tool ${lettaToolId} to agent ${agent_id}.`;
                attachError = error.response?.data || error.message || error;
                logger.error(`${attachMessage} Error:`, attachError);
            }
    
            // Return combined result
            return {
                content: [
                    {
                        type: 'text',
                        text: JSON.stringify({
                            letta_tool_id: lettaToolId,
                            letta_tool_name: lettaToolName,
                            agent_id: agent_id,
                            attached: attachSuccess,
                            mcp_server_name: mcp_server_name,
                            mcp_tool_name: mcp_tool_name,
                            ...(attachError ? { error: attachError } : {}),
                        }),
                    },
                ],
                isError: !attachSuccess, // Consider it an error if attachment failed
            };
        } catch (error) {
            logger.error(`Error during MCP tool registration or attachment: ${error.message}`);
            // Ensure the error response includes context about which step failed if possible
            server.createErrorResponse(
                error,
                `Failed during registration/attachment of ${args.mcp_server_name || 'unknown_server'}/${args.mcp_tool_name || 'unknown_tool'}`,
            );
        }
    }
  • The tool definition including name, description, and input schema for validation.
    export const addMcpToolToLettaDefinition = {
        name: 'add_mcp_tool_to_letta',
        description:
            'Registers a tool from a connected MCP server as a native Letta tool AND attaches it to a specified agent. Use list_mcp_tools_by_server to find available tools, and list_agents to get agent IDs.',
        inputSchema: {
            type: 'object',
            properties: {
                tool_name: {
                    type: 'string',
                    description: 'The name of the MCP tool to find, register, and attach.',
                },
                agent_id: {
                    type: 'string',
                    description: 'The ID of the agent to attach the newly registered tool to.',
                },
            },
            required: ['tool_name', 'agent_id'], // Updated required fields
        },
    };
  • Registration of the tool handler in the central switch statement for dispatching tool calls within the MCP server request handler.
    case 'add_mcp_tool_to_letta':
        return handleAddMcpToolToLetta(server, request.params.arguments);
  • Import of the handler and definition from the implementation file into the central tools index for registration.
        handleAddMcpToolToLetta,
        addMcpToolToLettaDefinition,
    } from './mcp/add-mcp-tool-to-letta.js';
  • Output schema defining the expected structured response format for the tool.
    add_mcp_tool_to_letta: {
        type: 'object',
        properties: {
            success: { type: 'boolean' },
            tool_name: { type: 'string' },
            tool_id: { type: 'string' },
            attached_to_agent: { type: 'boolean' },
            agent_id: { type: 'string' },
        },
        required: ['success', 'tool_name'],
    },

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