MCP Connector 1.2 - 例

既存の API を使用して、MCP Connector を使用してエージェントを作成する方法の例を次にいくつか示します。

MCP サーバーとツールの作成

これらの例は、Mule アプリケーション内で MCP サーバーを作成し、MCP サーバーで公開される 2 つの個別のツールを定義するプロセスを示しています。1 つは、承認済みベンダーの動的リストを各ベンダーの商品カテゴリとともに取得するツールで、もう 1 つは、指定された詳細で購入注文の作成を開始するツールです。

これらの例は、MCP ツールの概念を呼び出し可能なリモートプロシージャーコール (RPC) として示しています。

MCP サーバー設定の作成

この例は、Streamable HTTP トランスポートを使用して Mule アプリケーション内で MCP サーバーを設定する方法を示しています。MCP クライアントとして機能する場合、MuleSoft では、AI エージェントがワークフロー内で単に別のシステムとして統合されるインテグレーションとオーケストレーションを容易に作成できます。

<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="b15f1eb5-468e-4170-8f59-62c9965e2a57" > <<1>>
	<http:listener-connection host="localhost" port="${https.port}" />
</http:listener-config>

<mcp:config name="MCP_Server" serverName="Mule MCP Server" serverVersion="1.0.0"> <<2>>
	<mcp:streamable-http-server-connection
        listenerConfig="HTTP_Listener_config"
        mcpEndpointPath="/mcp">
        <mcp:default-response-headers> <<3>>
            <mcp:default-response-header key="X-API-Version" value="1.0.0"/>
            <mcp:default-response-header key="X-Server-ID" value="${server.id}"/>
        </mcp:default-response-headers>
    </mcp:streamable-http-server-connection>
</mcp:config>

<configuration-properties file="mule-artifact.properties"/>

<flow name="mcp-connectorFlow" doc:id="a8cbbf9b-dfe7-4519-97e3-c832f8815267" >
    <http:listener doc:name="Listener" doc:id="53fb94b1-cbd6-4e5a-9bf7-d33e02284bb7" config-ref="HTTP_Listener_config" path="/path"/>
</flow> <<4>>
1 HTTP リスナー設定では、MCP サーバーが公開されるエンドポイントを定義します。
2 MCP サーバー設定では、Streamable HTTP トランスポートを使用します。
3 ヘッダーは、バージョン追跡とサーバー識別用にすべての応答に追加されます。
4 さまざまな環境をサポートするためにプロパティプレースホルダーが設定値で使用されます。

ベンダーのリストを提供するツールの作成

この例は、外部システム (この例では SAP Concur) から承認済みベンダーの動的リストを取得する MCP ツールを作成する方法を示しています.この例は、​<mcp:tool-listener>​ を使用してコール可能なツールを定義する方法と、データを処理し、​Custom19​ 項目からの割り当て済み商品カテゴリを含め、関連ベンダー情報をエージェントに提供する方法を示しています。

まず、再試行およびタイムアウト設定を使用して SAP Concur 設定を定義します。

<sap-concur:config name="SAP_Concur_Config"> <<1>>
	<sap-concur:oauth-connection clientId="${concur.client.id}" clientSecret="${concur.client.secret}">
		<oauth:token-manager-config tokenUrl="${concur.token.url}"/>
	</sap-concur:oauth-connection>
	<reconnection> <<2>>
		<reconnect-forever frequency="5000"/>
	</reconnection>
	<request-timeout>30</request-timeout> <<3>>
	<request-timeout-unit>SECONDS</request-timeout-unit>
</sap-concur:config>

<!-- Cache configuration for vendor data -->
<ee:cache-config name="Vendor_Cache_Config"> <<4>>
	<ee:cache-ttl>3600000</ee:cache-ttl>
	<ee:cache-ttl-unit>MILLISECONDS</ee:cache-ttl-unit>
</ee:cache-config>
1 SAP Concur 設定には、OAuth 認証設定が含まれます。
2 一時的な接続の問題を処理するために再接続戦略を設定します。
3 要求タイムアウトは、要求がハングしないように 30 秒に設定します。
4 キャッシュ設定を追加して、1 時間の TTL でパフォーマンスを向上します。

次に、ページネーションとキャッシュを使用してベンダーの取得を処理するメインフローを作成します。

<flow name="getVendorsFlow">
	<mcp:tool-listener config-ref="MCP_Server" name="get-vendors"> <<1>>
		<mcp:description>Get all approved vendors with optional pagination</mcp:description>
		<mcp:parameters-schema><![CDATA[{ <<2>>
			"$schema": "http://json-schema.org/draft-07/schema#",
			"type": "object",
			"properties": {
				"pageSize": {
					"type": "integer",
					"description": "Number of vendors to return per page",
					"minimum": 1,
					"maximum": 100,
					"default": 50
				},
				"pageNumber": {
					"type": "integer",
					"description": "Page number to retrieve",
					"minimum": 1,
					"default": 1
				}
			},
			"required": []
		}]]></mcp:parameters-schema>
		<mcp:responses>
			<mcp:text-tool-response-content text="#[payload.^raw]" />
		</mcp:responses>
		<mcp:on-error-responses>
			<mcp:text-tool-response-content text="#['Error retrieving vendors: $(error.description)']" />
		</mcp:on-error-responses>
	</mcp:tool-listener>

	<ee:cache config-ref="Vendor_Cache_Config" key="#[payload.pageNumber ++ '-' ++ payload.pageSize]"> <<3>>
		<sap-concur:get-vendors config-ref="SAP_Concur_Config">
			<sap-concur:query-params><![CDATA[#[output application/java
			---
			{
				limit: payload.pageSize default 50,
				offset: ((payload.pageNumber default 1) - 1) * (payload.pageSize default 50)
			}]]></sap-concur:query-params>
		</sap-concur:get-vendors>
	</ee:cache>

	<ee:transform> <<4>>
		<ee:message>
			<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
	vendors: payload.Vendor filter ($.Approved == "true") map {
		id: $.ID,
		name: $.VendorName,
		country: $.Country,
		city: $.City,
		productCategories: $.Custom19
	},
	pagination: {
		totalVendors: sizeOf(payload.Vendor),
		currentPage: payload.pageNumber default 1,
		pageSize: payload.pageSize default 50,
		totalPages: ceil(sizeOf(payload.Vendor) / (payload.pageSize default 50))
	}
}]]></ee:set-payload>
		</ee:message>
	</ee:transform>

	<error-handler> <<5>>
		<on-error-continue type="SAP-CONCUR:CONNECTIVITY">
			<set-payload value="#['Error connecting to SAP Concur: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="SAP-CONCUR:AUTHENTICATION">
			<set-payload value="#['Authentication error with SAP Concur: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="ANY">
			<set-payload value="#['Unexpected error: $(error.description)']"/>
		</on-error-continue>
	</error-handler>
</flow>
1 <mcp:tool-listener>​ では、ページネーションをサポートするベンダー取得ツールのインターフェースを定義します。
2 <mcp:parameters-schema>​ スキーマには、ページサイズとページ番号の検証が含まれます。
3 キャッシュコンポーネントは、結果を 1 時間保存することでパフォーマンスを向上します。
4 DataWeave 変換では、承認されたベンダーを絞り込み、ページネーションメタデータを追加します。
5 エラー処理では、接続エラー、認証エラー、予期しないエラーが対象となります。

購入注文を作成するツールの作成

この例は、エージェントが SAP Concur で購入注文の作成を開始するために使用できる MCP ツールの作成方法を示しています。この例では、JSON スキーマを使用してツールの入力パラメーターを定義する方法が強調されています。パラメーターごとに自然言語の説明が含まれており、これにより LLM は必要な情報を理解して入力することができます。

<flow name="createPurchaseOrderFlow">
	<mcp:tool-listener config-ref="MCP_Server" name="create-concur-purchase-order"> <<1>>
		<mcp:description>Create a new purchase order in SAP Concur with validation</mcp:description>
		<mcp:parameters-schema><![CDATA[{ <<2>>
			"$schema": "http://json-schema.org/draft-07/schema#",
			"type": "object",
			"properties": {
				"name": {
					"type": "string",
					"description": "Name for the purchase order.",
					"minLength": 1,
					"maxLength": 100
				},
				"description": {
					"type": "string",
					"description": "Purchase order description.",
					"minLength": 1,
					"maxLength": 500
				},
				"vendorCode": {
					"type": "string",
					"description": "Code that identifies the vendor.",
					"pattern": "^[A-Z0-9]{3,10}$"
				},
				"itemDescription": {
					"type": "string",
					"description": "Description of the item purchased in this order.",
					"minLength": 1,
					"maxLength": 200
				},
				"price": {
					"type": "number",
					"description": "Monetary amount of the purchase order.",
					"minimum": 0.01,
					"maximum": 999999.99
				},
				"currency": {
					"type": "string",
					"description": "Currency code for the purchase order monetary amount.",
					"pattern": "^[A-Z]{3}$"
				}
			},
			"required": ["name", "description", "vendorCode", "itemDescription", "price", "currency"]
		}]]></mcp:parameters-schema>
		<mcp:responses>
			<mcp:text-tool-response-content text="#['Created Purchase Order: $(payload.PurchaseOrderNumber)']" />
		</mcp:responses>
		<mcp:on-error-responses>
			<mcp:text-tool-response-content text="#['Error creating purchase order: $(error.description)']" />
		</mcp:on-error-responses>
	</mcp:tool-listener>

	<!-- Validate vendor exists -->
	<sap-concur:get-vendors config-ref="SAP_Concur_Config"> <<3>>
		<sap-concur:query-params><![CDATA[#[output application/java
		---
		{
			vendorCode: payload.vendorCode
		}]]></sap-concur:query-params>
	</sap-concur:get-vendors>

	<ee:transform> <<4>>
		<ee:message>
			<ee:set-payload><![CDATA[%dw 2.0
output application/java
---
if (isEmpty(payload.Vendor))
	throw "Vendor not found: " ++ payload.vendorCode
else
	payload]]></ee:set-payload>
		</ee:message>
	</ee:transform>

	<sap-concur:create-purchase-order config-ref="SAP_Concur_Config">
		<sap-concur:create-purchase-order-request-data><![CDATA[#[output application/json
		---
		{
			Name: payload.name,
			CurrencyCode: payload.currency,
			Description: payload.description,
			VendorCode: payload.vendorCode,
			LineItem: {
				Description: payload.itemDescription,
				ApprovedLineItemAmount: payload.price as String,
				TotalPrice: payload.price as String
			}
		}]]></sap-concur:create-purchase-order-request-data>
	</sap-concur:create-purchase-order>

	<error-handler> <<5>>
		<on-error-continue type="SAP-CONCUR:CONNECTIVITY">
			<set-payload value="#['Error connecting to SAP Concur: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="SAP-CONCUR:AUTHENTICATION">
			<set-payload value="#['Authentication error with SAP Concur: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="SAP-CONCUR:VALIDATION">
			<set-payload value="#['Validation error: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="ANY">
			<set-payload value="#['Unexpected error: $(error.description)']"/>
		</on-error-continue>
	</error-handler>
</flow>
1 Tool Listener では、包括的な入力規則を含む購入注文作成インターフェースを定義します。
2 パラメータースキーマには、長さ制限やパターンなど、すべての項目の入力規則が含まれます。
3 ベンダー存在チェックが購入注文の作成前に実行されます。
4 DataWeave 変換ではベンダーチェックの応答を検証します。
5 エラー処理では、接続エラー、認証エラー、検証エラー、予期しないエラーが対象となります。

サードパーティ MCP サーバーを使用する MCP クライアントの設定

前の例では、既存の Anypoint Connector から情報を取得するツールの作成方法が示されました。ここでは、サードパーティ MCP サーバーを使用する方法を見てみましょう。

複数の MCP サーバーを使用した天気サービスの作成

この例は、MCP クライアントを設定し、​Call Tool​ 操作を使用することで、Streamable HTTP トランスポートを使用して Mule アプリケーションを既存のサードパーティ MCP サーバーと統合する方法を示しています。

サードパーティ MCP サーバーに接続する場合、その MCP サーバーで Streamable HTTP トランスポートがサポートされることを確認してください。サードパーティサーバーで SSE トランスポートのみがサポートされる場合、SSE クライアント接続を使用するか、サービスプロバイダーに連絡して Streamable HTTP についてのサポートを受ける必要があります。

まず、タイムアウトおよび再試行設定を使用してクライアント設定を定義します。

<http:request-config name="Weather_API_Config" basePath="/v1"> <<1>>
	<http:request-connection host="api.open-meteo.com" protocol="HTTPS"/>
	<http:request-timeout>30</http:request-timeout>
	<http:request-timeout-unit>SECONDS</http:request-timeout-unit>
	<reconnection>
		<reconnect-forever frequency="5000"/>
	</reconnection>
</http:request-config>

<mcp:client-config name="Google_Maps_Client" clientName="Mule MCP Maps Client" clientVersion="1.0.0"> <<2>>
	<mcp:streamable-http-client-connection
		serverUrl="http://google-maps-mcp-streamable-f5ebe64f8456.herokuapp.com"
		mcpEndpointPath="/mcp">
		<mcp:default-request-headers >
			<mcp:default-request-header key="X-Client-Version" value="1.0.0" />
		</mcp:default-request-headers>
	</mcp:streamable-http-client-connection>
	<reconnection>
		<reconnect-forever frequency="5000"/>
	</reconnection>
</mcp:client-config>

<mcp:server-config name="Weather_MCP_Server" serverName="Weather MCP Server" serverVersion="1.0.0"> <<3>>
	<mcp:streamable-http-server-connection
		listenerConfig="HTTP_Listener_config"
		mcpEndpointPath="/weather/mcp">
		<mcp:default-response-headers>
			<mcp:default-response-headers key="X-API-Version" value="1.0.0"/>
			<mcp:default-response-headers key="X-Service-Type" value="weather"/>
		</mcp:default-response-headers>
	</mcp:streamable-http-server-connection>
</mcp:server-config>
1 HTTP 要求の設定には、天気 API のタイムアウト設定と再試行設定が含まれます。
2 Google マップ MCP クライアントの設定では、カスタムヘッダーと再接続設定と共に Streamable HTTP トランスポートを使用します。
3 天気 MCP サーバーの設定では、Streamable HTTP トランスポートを使用し、カスタムヘッダーを使用して天気サービスエンドポイントを公開します。

次に、エラー処理とキャッシュを含む天気サービスフローを作成します。

<!-- Cache configuration for weather data -->
<ee:cache-config name="Weather_Cache_Config"> <<1>>
	<ee:cache-ttl>900000</ee:cache-ttl>
	<ee:cache-ttl-unit>MILLISECONDS</ee:cache-ttl-unit>
</ee:cache-config>

<flow name="getWeatherByCoordinatesFlow">
	<mcp:tool-listener config-ref="Weather_MCP_Server" name="get-weather-by-coordinates"> <<2>>
		<mcp:description>Provides the weather at given coordinates expressed as latitude and longitude</mcp:description>
		<mcp:parameters-schema><![CDATA[{
			"$schema": "http://json-schema.org/draft-07/schema#",
			"type": "object",
			"properties": {
				"latitude": {
					"type": "number",
					"description": "The latitude component of a location's coordinates",
					"minimum": -90,
					"maximum": 90
				},
				"longitude": {
					"type": "number",
					"description": "The longitude component of a location's coordinates",
					"minimum": -180,
					"maximum": 180
				}
			},
			"required": ["latitude", "longitude"]
		}]]></mcp:parameters-schema>
		<mcp:responses>
			<mcp:text-tool-response-content text="#['Current temperature at location is $(payload.current.temperature_2m)°C']"/>
		</mcp:responses>
		<mcp:on-error-responses>
			<mcp:text-tool-response-content text="#['Error getting weather: $(error.description)']"/>
		</mcp:on-error-responses>
	</mcp:tool-listener>

	<ee:cache config-ref="Weather_Cache_Config" key="#[payload.latitude ++ '-' ++ payload.longitude]">
		<http:request config-ref="Weather_API_Config" method="GET" path="/forecast">
			<http:query-params><![CDATA[#[output application/java
			---
			{
				latitude: payload.latitude,
				longitude: payload.longitude,
				current: 'temperature_2m'
			}]]></http:query-params>
		</http:request>
	</ee:cache>

	<error-handler> <<3>>
		<on-error-continue type="HTTP:CONNECTIVITY">
			<set-payload value="#['Error connecting to weather service: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="HTTP:TIMEOUT">
			<set-payload value="#['Weather service request timed out: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="ANY">
			<set-payload value="#['Unexpected error: $(error.description)']"/>
		</on-error-continue>
	</error-handler>
</flow>

<flow name="getWeatherByAddressFlow">
	<mcp:tool-listener config-ref="Weather_MCP_Server" name="get-weather-by-address"> <<4>>
		<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",
					"minLength": 1,
					"maxLength": 200
				}
			},
			"required": ["address"]
		}]]></mcp:parameters-schema>
		<mcp:responses>
			<mcp:text-tool-response-content text="#[payload]"/>
		</mcp:responses>
		<mcp:on-error-responses>
			<mcp:text-tool-response-content text="#['Error getting weather for address: $(error.description)']"/>
		</mcp:on-error-responses>
	</mcp:tool-listener>

	<!-- First get coordinates from Google Maps MCP -->
	<mcp:call-tool config-ref="Google_Maps_Client" toolName="maps_geocode">
		<mcp:arguments><![CDATA[#[output application/java
		---
		{
			address: payload.address
		}]]></mcp:arguments>
	</mcp:call-tool>

	<ee:transform>
		<ee:message>
			<ee:set-payload><![CDATA[%dw 2.0
output application/java
---
if (isEmpty(payload.contents))
	throw "Address not found: " ++ payload.address
else
	{
		latitude: read(payload.contents[0].text!, 'json').location.lat as Number,
		longitude: read(payload.contents[0].text!, 'json').location.lng as Number
	}]]></ee:set-payload>
		</ee:message>
	</ee:transform>

	<!-- Then get weather using our coordinates tool -->
	<mcp:call-tool config-ref="Weather_MCP_Server" toolName="get-weather-by-coordinates">
		<mcp:arguments><![CDATA[#[output application/java
		---
		{
			latitude: payload.latitude,
			longitude: payload.longitude
		}]]></mcp:arguments>
	</mcp:call-tool>

	<error-handler> <<5>>
		<on-error-continue type="MCP:CONNECTIVITY">
			<set-payload value="#['Error connecting to Google Maps service: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="MCP:TIMEOUT">
			<set-payload value="#['Google Maps service request timed out: $(error.description)']"/>
		</on-error-continue>
		<on-error-continue type="ANY">
			<set-payload value="#['Unexpected error: $(error.description)']"/>
		</on-error-continue>
	</error-handler>
</flow>
1 キャッシュ設定では、API コールを減らすために天気データを 15 分保存します。
2 座標ベースの天気フローには、入力規則とキャッシュが含まれます。
3 住所ベースの天気フローではツールの構成が示されています。
  • まず、Google マップを使用して住所を座標に変換します。

  • 次に、その座標を使用して天気を取得します。

4 両方のフローに、さまざまなシナリオの包括的なエラー処理が含まれます。
5 DataWeave 変換では、続行する前に Google マップの応答を検証します。

LLM でこれらのツールを直接オーケストレーションできますが、Mule での手動構成が望まれる次のような場合もあります。

  • すべての MCP サーバーへの保証されたアクセスが必要な場合

  • 認証をセキュアに処理する必要がある場合

  • 強力なガバナンス機能とトレース機能が必要な場合