.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "tutorial/task_mcp.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_tutorial_task_mcp.py: .. _mcp: MCP ========================= The tutorial covers the following features of AgentScope in support of the MCP (Model Context Protocol): - Support both **HTTP** (streamable HTTP and SSE) and **StdIO** MCP servers - Provide both **stateful** and **stateless** MCP clients - Provide both **server-level** and **function-level** MCP tool management Here the stateful/stateless distinction refers to whether the client maintains a persistent session with the MCP server or not. The table below summarizes the supported MCP client types and protocols: .. list-table:: Supported MCP client types and protocols :header-rows: 1 * - Client Type - HTTP (Streamable HTTP and SSE) - StdIO * - Stateful Client - ``HttpStatefulClient`` - ``HttpStatelessClient`` * - Stateless Client - ``StdIOStatefulClient`` - .. GENERATED FROM PYTHON SOURCE LINES 31-38 .. code-block:: Python import asyncio import json import os from agentscope.mcp import HttpStatefulClient, HttpStatelessClient from agentscope.tool import Toolkit .. GENERATED FROM PYTHON SOURCE LINES 39-59 MCP Client ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In AgentScope, MCP clients are responsible for - connecting to the MCP server, - obtaining tool functions from the server, and - calling tool functions in the MCP server. There are two types of MCP clients in AgentScope: **Stateful** and **Stateless**. They only differ in how to manage the session with the MCP server. - Stateful Client: The stateful MCP client **maintains a persistent session** with the MCP server within its lifetime. The developers should explicitly call ``connect()`` and ``close()`` methods to manage the connection lifecycle. - Stateless Client: The stateless MCP client creates a new session when calling the tool function, and destroys the session right after the tool function call, which is much more lightweight. .. note:: - The StdIO MCP server only has stateful client, when ``connect()`` is called, it will start the MCP server locally and then connect to it. - For stateful clients, developers must ensure the client is connected when calling the tool functions. Taking Gaode map MCP server as an example, the creation of stateful and stateless clients are very similar: .. GENERATED FROM PYTHON SOURCE LINES 59-74 .. code-block:: Python stateful_client = HttpStatefulClient( # The name to identify the MCP name="mcp_services_stateful", transport="streamable_http", url=f"https://mcp.amap.com/mcp?key={os.environ['GAODE_API_KEY']}", ) stateless_client = HttpStatelessClient( # The name to identify the MCP name="mcp_services_stateless", transport="streamable_http", url=f"https://mcp.amap.com/mcp?key={os.environ['GAODE_API_KEY']}", ) .. GENERATED FROM PYTHON SOURCE LINES 75-97 Both stateful and stateless clients provide the following methods: .. list-table:: MCP Client Methods :header-rows: 1 * - Method - Description * - ``list_tools`` - List all tools available in the MCP server. * - ``get_callable_function`` - Get a callable function object from the MCP server by its name. MCP as Tool ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AgentScope provides fine-grained management of MCP tools, including both server-level and function-level management. Server-Level Management -------------------------------- You can register all tools from an MCP server into ``Toolkit`` as follows. .. tip:: Optionally, you can specify a group name to organize the tools. Refer to :ref:`tool` section for group-wise tools management. .. GENERATED FROM PYTHON SOURCE LINES 97-131 .. code-block:: Python toolkit = Toolkit() async def example_register_stateless_mcp() -> None: """Example of registering MCP tools from a stateless client.""" # Register all tools from the MCP server await toolkit.register_mcp_client( stateless_client, # group_name="map_services", # Optional group name ) print( "Total number of MCP tools registered:", len(toolkit.get_json_schemas()), ) maps_geo = next( tool for tool in toolkit.get_json_schemas() if tool["function"]["name"] == "maps_geo" ) print("\nThe example ``maps_geo`` function:") print( json.dumps( maps_geo, indent=4, ensure_ascii=False, ), ) asyncio.run(example_register_stateless_mcp()) .. rst-class:: sphx-glr-script-out .. code-block:: none Total number of MCP tools registered: 15 The example ``maps_geo`` function: { "type": "function", "function": { "name": "maps_geo", "description": "将详细的结构化地址转换为经纬度坐标。支持对地标性名胜景区、建筑物名称解析为经纬度坐标", "parameters": { "type": "object", "properties": { "address": { "type": "string", "description": "待解析的结构化地址信息" }, "city": { "type": "string", "description": "指定查询的城市" } }, "required": [ "address" ] } } } .. GENERATED FROM PYTHON SOURCE LINES 132-134 To remove the registered tools, you can use the ``remove_tool_function`` to remove a specific tool function, or ``remove_mcp_clients`` to remove all tools from a specific MCP. .. GENERATED FROM PYTHON SOURCE LINES 134-154 .. code-block:: Python async def example_remove_mcp_tools() -> None: """Example of removing MCP tools.""" print( "Total number of tools before removal: ", len(toolkit.get_json_schemas()), ) # Remove a specific tool function by its name toolkit.remove_tool_function("maps_geo") print("Number of tools: ", len(toolkit.get_json_schemas())) # Remove all tools from the MCP client by its name await toolkit.remove_mcp_clients(client_names=["mcp_services_stateless"]) print("Number of tools: ", len(toolkit.get_json_schemas())) asyncio.run(example_remove_mcp_tools()) .. rst-class:: sphx-glr-script-out .. code-block:: none Total number of tools before removal: 15 Number of tools: 14 Number of tools: 0 .. GENERATED FROM PYTHON SOURCE LINES 155-169 Function-Level Management -------------------------------- We notice the demand for more fine-grained control over MCP tools, such as post-processing the tool results, or use them to create a more complex tool function. Therefore, AgentScope supports to obtain the callable function object from MCP by its name, so that you can - call it directly, - wrap it into your own function, or anyway you like. Additionally, you can specify whether to wrap the tool result into ``ToolResponse`` object in AgentScope, so that you can use it seamlessly with the ``Toolkit``. If you set ``wrap_tool_result=False``, the raw result type ``mcp.types.CallToolResult`` will be returned. Taking the ``maps_geo`` function as an example, you can obtain it as a callable function object as follows: .. GENERATED FROM PYTHON SOURCE LINES 169-198 .. code-block:: Python async def example_function_level_usage() -> None: """Example of using function-level MCP tool.""" func_obj = await stateless_client.get_callable_function( func_name="maps_geo", # Whether to wrap the tool result into ToolResponse in AgentScope wrap_tool_result=True, ) # You can obtain its name, description and json schema print("Function name:", func_obj.name) print("Function description:", func_obj.description) print( "Function JSON schema:", json.dumps(func_obj.json_schema, indent=4, ensure_ascii=False), ) # Call the function object directly res = await func_obj( address="Tiananmen Square", city="Beijing", ) print("\nFunction call result:") print(res) asyncio.run(example_function_level_usage()) .. rst-class:: sphx-glr-script-out .. code-block:: none Function name: maps_geo Function description: 将详细的结构化地址转换为经纬度坐标。支持对地标性名胜景区、建筑物名称解析为经纬度坐标 Function JSON schema: { "type": "function", "function": { "name": "maps_geo", "description": "将详细的结构化地址转换为经纬度坐标。支持对地标性名胜景区、建筑物名称解析为经纬度坐标", "parameters": { "type": "object", "properties": { "address": { "type": "string", "description": "待解析的结构化地址信息" }, "city": { "type": "string", "description": "指定查询的城市" } }, "required": [ "address" ] } } } Function call result: ToolResponse(content=[{'type': 'text', 'text': '{"results":[{"country":"中国","province":"北京市","city":"北京市","citycode":"010","district":"东城区","street":[],"number":[],"adcode":"110101","location":"116.397455,39.909187","level":"兴趣点"}]}'}], metadata=None, stream=False, is_last=True, is_interrupted=False, id='2025-08-15 10:12:33.112_619af4') .. GENERATED FROM PYTHON SOURCE LINES 199-207 Further Reading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For more details, see: - :ref:`tool` - :ref:`agent` .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 7.628 seconds) .. _sphx_glr_download_tutorial_task_mcp.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: task_mcp.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: task_mcp.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: task_mcp.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_