Reading Time: 6 minutes

We previously discussed creating secure MCP servers using the MCP Connector. Now, let’s shift our focus to using Mule as an MCP client.

What is the MCP Client?

MCP is gaining incredible traction in the market. https://mcpservers.org/ has a large, growing list of MCP servers already implemented and ready to use. Enter the MCP Client:

This example shows a Google Maps MCP server from the internet deployed in Heroku. We then created an MCP Client config to consume it and configured it, per the screenshot. The connector also offers the Call Tool operation, which invokes tools in the target server. The connector integrates with Anypoint Code Builder and displays all the tools available in the target server: 

Full DataSense support is also available, offering auto-completion and graphical representation of the arguments required by each tool and the produced update. The following shows the DataSense information for the maps_distance_matrix tool which takes three input arguments.

Build a sample application 

Let’s build a Weather Agent. We start with a simple weather tool:

<flow name="getWeatherByAddressToolFlow">
  <mcp:tool-listener doc:name="Call Tool Listener" config-ref="MCP_Server" name="get-weather-by-address">
   <mcp:description>Provides the weather at a specific address</mcp:description>
  <mcp:parameters-schema ><![CDATA[{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "address": {
      "type": "string",
      "description": "The address we want to learn the weather for"
    }
  },
  "required": ["address"]
}]]></mcp:parameters-schema>
    <mcp:responses >
    <mcp:text-tool-response-content text="#[payload.contents[0].text]" />
</mcp:responses>
 </mcp:tool-listener>
 <mcp:call-tool config-ref="MCP_GMaps_Client" toolName="maps_geocode">
	<mcp:arguments ><![CDATA[#[output application/java
---
{
	address: payload.address
}]]]>
</mcp:arguments>
 </mcp:call-tool>
 <mcp:call-tool config-ref="MCP_Client" toolName="get-weather-by-coordinates">
    <mcp:arguments ><![CDATA[#[output application/java
---
{
	latitude: read(payload.contents[0].text!, 'json').location.lat as Number,
	longitude: read(payload.contents[0].text!, 'json').location.lng as Number
}]]]>
</mcp:arguments>
 </mcp:call-tool>
</flow>

We saw how to write a tool that draws from existing Anypoint connectors, here we can see how we can define a tool that leverages other MCP servers, whether they were written with Mule or not. 

But we don’t need to actually write that composition. We can just feed the agent with all of those tools individually and it will figure the composition out automatically. The LLM will figure it out, but it also means that it needs to:

  • Have access to all those MCP servers
  • Be able to securely authenticate to all of them

Plus, because the LLM is in charge of the orchestration, things like governance and tracing just became quite complicated.

The most advanced LLMs can only currently handle around 20 to 25 tools. Once that threshold is surpassed, the context becomes too big and bad results start to happen. Composing tools into higher level abstractions such as this is a way of dealing with that problem. In some use cases, letting the LLM be in charge of the entire orchestration is awesome and makes total sense. In others, the invisible human touch still applies.

Apply security 

For securing clients we took the exact same approach as with the server: reuse all the security components we already have. In the client, the authentication parameter accepts all the Authentication strategies defined in the HTTP Connector, and the OAuth Module as well if it’s added to the project:

Also operations like Call Tool also accept additional properties, which will map to request headers. This makes it possible to add custom authentication headers like API keys:

Powerful, secure, and strategic 

The connector’s client capabilities not only allows your integrations to leverage MCP servers like any other external resource or APIs, it can also be a strategic piece that reduces the amount of external endpoints and total amount of tools that your agent has to reason about.