How to Connect an LLM to an MCP Server in a Pipedream Workflow?

This topic was automatically generated from Slack. You can find the original thread here.

Hi, I’m exploring migrating a bunch of my work from n8n to Pipedream but am confused about using MCP servers with my Pipedream workflows. All of the documentation I’m coming across is related to using Pipedream’s MCP tooling to expose tooling to third party tools like Cursor, but is there a way to connect an LLM I’m using (e.g., Claude) to an MCP server in a workflow I’m creating in Pipedream?

Hi , you can use Claude Desktop to connect to Pipedream MCP servers.

Do you want a tool calling agent as a step of your workflow?

You can do that today with code. Here’s an example I built using String.com:

import { axios } from "/platform"
import anthropic from "@U080WU6G482/anthropic"

export default defineComponent({
  name: "Interact with MCP Server via Claude",
  description: "Use Claude to interact with a Model Context Protocol (MCP) server, enabling access to external tools and data sources",
  type: "action",
  props: {
    anthropic,
    message: {
      type: "string",
      label: "Message",
      description: "The message or query to send to Claude that will utilize the MCP server's capabilities"
    },
    mcpServerUrl: {
      type: "string",
      label: "MCP Server URL",
      description: "The HTTPS URL of the MCP server to connect to"
    },
    mcpServerName: {
      type: "string",
      label: "MCP Server Name",
      description: "A unique identifier for the MCP server",
      default: "mcp-server"
    },
    authToken: {
      type: "string",
      label: "Authorization Token",
      description: "OAuth authorization token if required by the MCP server",
      optional: true,
      secret: true
    },
    model: {
      type: "string",
      label: "Model",
      description: "The Claude model to use",
      options: [
        "claude-3-5-sonnet-20241022",
        "claude-3-5-haiku-20241022", 
        "claude-3-opus-20240229",
        "claude-3-sonnet-20240229",
        "claude-3-haiku-20240307"
      ],
      default: "claude-3-5-sonnet-20241022"
    },
    maxTokens: {
      type: "integer",
      label: "Max Tokens",
      description: "The maximum number of tokens to generate",
      default: 1024,
      min: 1,
      max: 4096
    },
    enableTools: {
      type: "boolean",
      label: "Enable MCP Tools",
      description: "Whether to enable tools from the MCP server",
      default: true
    },
    allowedTools: {
      type: "string[]",
      label: "Allowed Tools",
      description: "Specific tools to allow from the MCP server (leave empty to allow all)",
      optional: true
    }
  },
  async run({ $ }) {
    // Validate MCP server URL
    if (!this.mcpServerUrl.startsWith('https://')) {
      throw new Error('MCP server URL must start with https://');
    }

    // Construct MCP server configuration
    const mcpServerConfig = {
      type: "url",
      url: this.mcpServerUrl,
      name: this.mcpServerName,
      tool_configuration: {
        enabled: this.enableTools
      }
    };

    // Add allowed tools if specified
    if (this.allowedTools && this.allowedTools.length > 0) {
      mcpServerConfig.tool_configuration.allowed_tools = this.allowedTools;
    }

    // Add authorization token if provided
    if (this.authToken) {
      mcpServerConfig.authorization_token = this.authToken;
    }

    // Prepare the request payload
    const requestData = {
      model: this.model,
      max_tokens: this.maxTokens,
      messages: [
        {
          role: "user",
          content: this.message
        }
      ],
      mcp_servers: [mcpServerConfig]
    };

    try {
      // Make the API request to Claude with MCP server and beta header
      // Using axios directly to properly merge authentication headers with MCP beta header
      const response = await axios($, {
        url: `${this.anthropic._apiUrl()}/messages`,
        method: "post",
        headers: {
          "x-api-key": this.anthropic._apiKey(),
          "anthropic-version": "2023-06-01",
          "anthropic-beta": "mcp-client-2025-04-04"
        },
        data: requestData
      });

      // Extract and process the response
      const responseText = response.content
        .filter(block => block.type === 'text')
        .map(block => block.text)
        .join('\n');

      // Extract MCP tool usage information
      const mcpToolUses = response.content
        .filter(block => block.type === 'mcp_tool_use')
        .map(block => ({
          server: block.server,
          tool: block.name,
          input: block.input,
          id: block.id
        }));

      const mcpToolResults = response.content
        .filter(block => block.type === 'mcp_tool_result')
        .map(block => ({
          tool_use_id: block.tool_use_id,
          content: block.content,
          is_error: block.is_error
        }));

      // Create summary
      const toolsUsed = mcpToolUses.length;
      const serverName = this.mcpServerName;
      
      $.export("$summary", `Successfully processed message with Claude using MCP server "${serverName}". ${toolsUsed} tool${toolsUsed !== 1 ? 's' : ''} utilized.`);

      // Return comprehensive response data
      return {
        response_text: responseText,
        model_used: this.model,
        usage: response.usage,
        mcp_server: {
          name: this.mcpServerName,
          url: this.mcpServerUrl,
          tools_used: toolsUsed
        },
        mcp_tool_uses: mcpToolUses,
        mcp_tool_results: mcpToolResults,
        full_response: response
      };

    } catch (error) {
      // Handle specific MCP-related errors
      if (error.message?.includes('mcp_servers')) {
        throw new Error(`MCP Server Error: ${error.message}. Please check your MCP server URL and configuration.`);
      }
      
      if (error.message?.includes('authorization')) {
        throw new Error(`Authentication Error: ${error.message}. Please verify your authorization token.`);
      }

      // Handle general API errors
      throw new Error(`Claude API Error: ${error.message || 'Unknown error occurred'}`);
    }
  }
})

It used MCP tools to get data from RSS feeds:

I iterated with String to get there, but you can also start with a prompt I generated with the key details to develop that step (e.g., headers to set for Anthropic to enable MCP servers).

this is really helpful, thanks!