请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

自己写的mcp工具遇到包管理问题

我遇到的问题是,这些mcp.tool函数和main函数必须写在同一个文件里面,导致这个文件太长了。如果分开写两个文件,就无法注册另外一个文件里的mcp.tool函数,智能体不能调用这些工具。感谢Sam老师解答。

老师写的代码是可以调通的,但我希望把mcp.tool的函数全部移到test_func.py文件里,我写的代码是这样的,是不是mcp.tool函数和main函数必须写在一起

import sys
from mcp.server.fastmcp import FastMCP

mcp = FastMCP()

dir = "D:\\GOPATH\\src\\cc\\testpy\\account\\mymcp"
sys.path.append(dir)

from test_func import register

if __name__ == '__main__':
    mcp.run(transport="stdio")

但是提示报错信息

{'account_tools': {'transport': 'stdio', 'command': 'python', 'args': ['D:\\GOPATH\\src\\cc\\testpy\\account\\mymcp\\account.py']}}
?[31mERROR?[0m:      + Exception Group Traceback (most recent call last):
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\starlette\routing.py", line 694, in lifespan
  |     async with self.lifespan_context(app) as maybe_state:
  |                ~~~~~~~~~~~~~~~~~~~~~^^^^^
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\starlette\routing.py", line 571, in __aenter__
  |     await self._router.startup()
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\starlette\routing.py", line 671, in startup
  |     await handler()
  |   File "D:\GOPATH\src\cc\testpy\account\web.py", line 82, in startup_event
  |     await initialize_agent()
  |   File "D:\GOPATH\src\cc\testpy\account\web.py", line 63, in initialize_agent
  |     account_tools = await get_stdio_account_tools()
  |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "D:\GOPATH\src\cc\testpy\account\tools\account_tools.py", line 26, in get_stdio_account_tools
  |     client, tools = await create_mcp_stdio_client("account_tools", params)
  |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "D:\GOPATH\src\cc\testpy\account\tools\account_tools.py", line 14, in create_mcp_stdio_client
  |     tools = await client.get_tools()
  |             ^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\langchain_mcp_adapters\client.py", line 142, in get_tools
  |     tools_list = await asyncio.gather(*load_mcp_tool_tasks)
  |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\langchain_mcp_adapters\tools.py", line 168, in load_mcp_tools
  |     async with create_session(connection) as tool_session:
  |                ~~~~~~~~~~~~~~^^^^^^^^^^^^
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\contextlib.py", line 235, in __aexit__
  |     await self.gen.athrow(value)
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\langchain_mcp_adapters\sessions.py", line 394, in create_session
  |     async with _create_stdio_session(**params) as session:
  |                ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\contextlib.py", line 235, in __aexit__
  |     await self.gen.athrow(value)
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\langchain_mcp_adapters\sessions.py", line 221, in _create_stdio_sess
ion
  |     stdio_client(server_params) as (read, write),
  |     ~~~~~~~~~~~~^^^^^^^^^^^^^^^
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\contextlib.py", line 235, in __aexit__
  |     await self.gen.athrow(value)
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\mcp\client\stdio\__init__.py", line 181, in stdio_client
  |     anyio.create_task_group() as tg,
  |     ~~~~~~~~~~~~~~~~~~~~~~~^^
  |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\anyio\_backends\_asyncio.py", line 772, in __aexit__
  |     raise BaseExceptionGroup(
  |         "unhandled errors in a TaskGroup", self._exceptions
  |     ) from None
  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
  +-+---------------- 1 ----------------
    | Exception Group Traceback (most recent call last):
    |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\mcp\client\stdio\__init__.py", line 187, in stdio_client
    |     yield read_stream, write_stream
    |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\langchain_mcp_adapters\sessions.py", line 222, in _create_stdio_se
ssion
    |     ClientSession(read, write, **(session_kwargs or {})) as session,
    |     ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\mcp\shared\session.py", line 218, in __aexit__
    |     return await self._task_group.__aexit__(exc_type, exc_val, exc_tb)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\anyio\_backends\_asyncio.py", line 772, in __aexit__
    |     raise BaseExceptionGroup(
    |         "unhandled errors in a TaskGroup", self._exceptions
    |     ) from None
    | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
    +-+---------------- 1 ----------------
      | Traceback (most recent call last):
      |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\langchain_mcp_adapters\sessions.py", line 224, in _create_stdio_
session
      |     yield session
      |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\langchain_mcp_adapters\sessions.py", line 395, in create_session

      |     yield session
      |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\langchain_mcp_adapters\tools.py", line 169, in load_mcp_tools
      |     await tool_session.initialize()
      |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\mcp\client\session.py", line 151, in initialize
      |     result = await self.send_request(
      |              ^^^^^^^^^^^^^^^^^^^^^^^^
      |     ...<16 lines>...
      |     )
      |     ^
      |   File "C:\Users\gaojun\AppData\Local\Programs\Python\Python313\Lib\site-packages\mcp\shared\session.py", line 286, in send_request
      |     raise McpError(response_or_error.error)
      | mcp.shared.exceptions.McpError: Connection closed
      +------------------------------------

?[31mERROR?[0m:    Application startup failed. Exiting.

正在回答 回答被采纳积分+3

1回答

Sam 2025-08-01 16:12:23

好的,我给你提供一个示例,你可以参考下。首先给你展示一下代码文件目录:

/Users/sam/Work/AI/coding_agent/test
├── __init__.py
├── test_938_2.py
├── test_func.py
├── test_mcp.py
└── test_tools.py

它们的关系是:

  • test_938_2 是智能体代码,调用 test_tools

  • test_tools 调用 test_mcp 生成 mcp 工具

  • test_mcp 包含工具的定义,调用 test_func

  • test_func 就是你刚才提到的要剥离的工具代码

下面分别提供这些文件的源码:

test_func

def do_read_file(file_name: str) -> str:
    return "file name is: " + file_name


test_mcp

import sys

from mcp.server.fastmcp import FastMCP

mcp = FastMCP()

dir = "/Users/sam/Work/AI/coding_agent/test"
sys.path.append(dir)

from test_func import do_read_file

@mcp.tool(name="read_file", description="read file")
def read_file(file_name: str) -> str:

    return do_read_file(file_name)

if __name__ == '__main__':
    mcp.run(transport="stdio")
    # print(read_file("test.txt"))

这里最关键的代码是:

dir = "/Users/sam/Work/AI/coding_agent/test"
sys.path.append(dir)

from test_func import do_read_file

这三行代码完成了三方库的加载


test_tools

from app.utils.mcp import create_mcp_stdio_client

async def get_stdio_test_tools():
    params = {
        "command": "python",
        "args": [
            "/Users/sam/Work/AI/coding_agent/test/test_mcp.py",
        ],
    }

    client, tools = await create_mcp_stdio_client("test", params)

    return tools

注意将路径替换为你本地的


test_938_2

import asyncio
import time

from langchain_core.messages import AIMessage, ToolMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableConfig
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent

from app.models.qwen import llm_qwen
from test.test_tools import get_stdio_test_tools


def format_debug_output(step_name: str, content: str, is_tool_call = False) -> None:
    if is_tool_call:
        print(f'🔄 【工具调用】 {step_name}')
        print("-" * 40)
        print(content.strip())
        print("-" * 40)
    else:
        print(f"💭 【{step_name}】")
        print("-" * 40)
        print(content.strip())
        print("-" * 40)


async def run_agent():
    memory = MemorySaver()

    test_tools = await get_stdio_test_tools()
    tools = test_tools

    prompt = ChatPromptTemplate(messages=[("system", "你是一位优秀的工程师,你的名字叫{name}")])

    agent = create_react_agent(
        model=llm_qwen,
        tools=tools,
        checkpointer=memory,
        debug=True,
        prompt=prompt.format(name="White怀特"),
    )

    config = RunnableConfig(configurable={"thread_id": 9})

    while True:
        user_input = input("用户: ")

        if user_input.lower() == "exit":
            break

        print("\n🤖 助手正在思考...")
        print("=" * 60)

        iteration_count = 0
        start_time = time.time()
        last_tool_time = start_time

        async for chunk in agent.astream(input={"name": "Bose", "messages": user_input}, config=config):
            iteration_count += 1

            print(f"\n📊 第 {iteration_count} 步执行:")
            print("-" * 30)

            items = chunk.items()

            for node_name, node_output in items:
                if "messages" in node_output:
                    for msg in node_output["messages"]:
                        if isinstance(msg, AIMessage):
                            if msg.content:
                                format_debug_output("AI思考", msg.content)
                            else:
                                for tool in msg.tool_calls:
                                    format_debug_output("工具调用", f"{tool['name']}: {tool['args']}")

                        elif isinstance(msg, ToolMessage):
                            tool_name = getattr(msg, "name", "unknown")
                            tool_content = msg.content

                            current_time = time.time()
                            tool_duration = current_time - last_tool_time
                            last_tool_time = current_time

                            tool_result = f"""🔧 工具:{tool_name}
📤 结果:
{tool_content}
✅ 状态:执行完成,可以开始下一个任务
️⏱️ 执行时间:{tool_duration:.2f}秒"""

                            format_debug_output("工具执行结果", tool_result, is_tool_call=True)

                        else:
                            format_debug_output("未实现", f"暂未实现的打印内容: {chunk}")

        print()


asyncio.run(run_agent())


0 回复 有任何疑惑可以回复我~
  • 提问者 工头 #1
    报错信息贴在问题里了
    回复 有任何疑惑可以回复我~ 2025-08-01 16:39:07
  • Sam 回复 提问者 工头 #2
    看起来在初始化mcp工具时报错了,方便的话,把整个源码打包上传,我用你的源码调试一下。或者传到github或gitee我下载一下也可以
    回复 有任何疑惑可以回复我~ 2025-08-02 13:43:46
  • 提问者 工头 回复 Sam #3
    回复 Sam:https://github.com/aadf0037-byte/test/  目前不报错,但智能体不能加载到mcp.tool工具函数
    回复 有任何疑惑可以回复我~ 2025-08-05 19:20:47
问题已解决,确定采纳
还有疑问,暂不采纳
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号