mcp测试案例
This commit is contained in:
91
examples/mcp_adapters/inject_to_langgraph.py
Normal file
91
examples/mcp_adapters/inject_to_langgraph.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
Full example: Start a FastMCP-style HTTP MCP server, then use
|
||||
langchain-mcp-adapters to inject MCP tools into a LangGraph + Qwen agent.
|
||||
|
||||
Steps:
|
||||
1) Start the local HTTP MCP server (fallback minimal):
|
||||
- uv pip install fastapi uvicorn
|
||||
- uvicorn examples.mcp_adapters.fastmcp_server:http_app --host 127.0.0.1 --port 8010
|
||||
|
||||
The MCP endpoint is available at: http://127.0.0.1:8010/mcp/
|
||||
|
||||
2) Install mcp-adapters:
|
||||
- uv pip install -e '.[mcp-adapters]'
|
||||
|
||||
3) Configure adapter entry + config (choose one):
|
||||
A) Explicit entry (recommended):
|
||||
export MCP_ADAPTER_ENTRY='langchain_mcp_adapters:create_tools'
|
||||
export MCP_CONFIG_JSON='{"servers":{"local":{"url":"http://127.0.0.1:8010/mcp/","transport":"streamable_http"}}}'
|
||||
|
||||
B) If your adapter provides a different function:
|
||||
export MCP_ADAPTER_ENTRY='your_module:your_entry'
|
||||
export MCP_CONFIG_JSON='{}'
|
||||
|
||||
4) Qwen env (or .env auto-loaded):
|
||||
- QWEN_API_KEY, QWEN_BASE_URL, QWEN_MODEL, ...
|
||||
|
||||
5) Run this example:
|
||||
- python examples/mcp_adapters/inject_to_langgraph.py
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import importlib
|
||||
from typing import Any, Dict, List
|
||||
|
||||
import asyncio
|
||||
from langchain_core.messages import HumanMessage
|
||||
from langgraph_qwen.chat_model import ChatQwenOpenAICompat
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
def _env(name: str, default: str = "") -> str:
|
||||
v = os.getenv(name)
|
||||
return v if v else default
|
||||
|
||||
async def _load_tools_via_client() -> List[Any]:
|
||||
try:
|
||||
from langchain_mcp_adapters.client import MultiServerMCPClient # type: ignore
|
||||
except Exception as e:
|
||||
raise RuntimeError("Please install langchain-mcp-adapters: uv pip install -e '.[mcp-adapters]'") from e
|
||||
|
||||
weather_url = _env("WEATHER_MCP_URL", "http://localhost:8000/mcp")
|
||||
weather_transport = _env("WEATHER_TRANSPORT", "streamable_http")
|
||||
|
||||
client = MultiServerMCPClient(
|
||||
{
|
||||
"weather": {
|
||||
"url": weather_url,
|
||||
"transport": weather_transport,
|
||||
}
|
||||
}
|
||||
)
|
||||
tools = await client.get_tools()
|
||||
# Best-effort cleanup if client exposes a close method
|
||||
try:
|
||||
if hasattr(client, "close") and callable(getattr(client, "close")):
|
||||
await client.close() # type: ignore
|
||||
elif hasattr(client, "close_all_sessions") and callable(getattr(client, "close_all_sessions")):
|
||||
await client.close_all_sessions() # type: ignore
|
||||
except Exception:
|
||||
pass
|
||||
return tools
|
||||
|
||||
async def main():
|
||||
tools = await _load_tools_via_client()
|
||||
print("Discovered tools:")
|
||||
for t in tools:
|
||||
print(" -", getattr(t, "name", "<noname>"))
|
||||
|
||||
model = ChatQwenOpenAICompat(temperature=0).bind(tool_choice="auto")
|
||||
# 或直接:model = ChatQwenOpenAICompat(temperature=0).bind_tools(tools).bind(tool_choice="auto")
|
||||
agent = create_react_agent(model, tools)
|
||||
|
||||
prompt = (
|
||||
"请先列出可用工具名,然后选择一个合理的工具做一次演示调用,并用简洁中文总结结果。"
|
||||
)
|
||||
res = await agent.ainvoke({"messages": [HumanMessage(content=prompt)]})
|
||||
print("=== Final ===")
|
||||
print(res["messages"][-1].content)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
98
examples/mcp_adapters/server/fastmcp_server.py
Normal file
98
examples/mcp_adapters/server/fastmcp_server.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
FastMCP-style minimal MCP server for local testing (HTTP JSON-RPC 2.0).
|
||||
|
||||
This script prefers running with FastMCP if installed; otherwise it falls back
|
||||
to a tiny FastAPI JSON-RPC server that implements initialize/tools.list/tools.call.
|
||||
|
||||
Usage (fallback HTTP server):
|
||||
uv pip install fastapi uvicorn
|
||||
uvicorn examples.mcp_adapters.fastmcp_server:http_app --host 127.0.0.1 --port 8010
|
||||
|
||||
The MCP endpoint will be: http://127.0.0.1:8010/mcp/
|
||||
|
||||
If you have FastMCP server utilities available, you can replace the fallback
|
||||
with your real FastMCP server.
|
||||
"""
|
||||
|
||||
try:
|
||||
# If you have a real FastMCP server implementation, import and expose here.
|
||||
# Example (pseudo):
|
||||
# from fastmcp import MCPServer, tool
|
||||
# ... define @tool functions ...
|
||||
# fastmcp_app = MCPServer(...)
|
||||
# Then you can provide an ASGI http_app = fastmcp_app.asgi_app()
|
||||
fastmcp_app = None # placeholder; fallback below
|
||||
except Exception: # pragma: no cover
|
||||
fastmcp_app = None
|
||||
|
||||
# Fallback: FastAPI JSON-RPC 2.0 minimal server
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
http_app = FastAPI()
|
||||
|
||||
|
||||
def _rpc_result(result, id_):
|
||||
return {"jsonrpc": "2.0", "result": result, "id": id_}
|
||||
|
||||
|
||||
def _rpc_error(message, id_=None, code=-32000):
|
||||
return {"jsonrpc": "2.0", "error": {"code": code, "message": message}, "id": id_}
|
||||
|
||||
|
||||
@http_app.post("/mcp/")
|
||||
async def mcp_endpoint(request: Request):
|
||||
try:
|
||||
data = await request.json()
|
||||
except Exception:
|
||||
return JSONResponse(_rpc_error("Invalid JSON"), status_code=400)
|
||||
|
||||
method = data.get("method")
|
||||
id_ = data.get("id")
|
||||
params = data.get("params") or {}
|
||||
|
||||
if method == "initialize":
|
||||
return JSONResponse(_rpc_result({"sessionId": "demo-session"}, id_))
|
||||
|
||||
if method in ("tools/list", "tool/list", "tools.list"):
|
||||
tools = [
|
||||
{
|
||||
"name": "echo",
|
||||
"description": "Echo back provided text.",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {"text": {"type": "string"}},
|
||||
"required": ["text"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "add",
|
||||
"description": "Add two integers a and b.",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {"a": {"type": "integer"}, "b": {"type": "integer"}},
|
||||
"required": ["a", "b"],
|
||||
},
|
||||
},
|
||||
]
|
||||
return JSONResponse(_rpc_result({"tools": tools}, id_))
|
||||
|
||||
if method in ("tools/call", "tool/call", "tools.call"):
|
||||
name = params.get("name") or params.get("tool")
|
||||
arguments = params.get("arguments") or params.get("params") or {}
|
||||
if name == "echo":
|
||||
text = arguments.get("text", "")
|
||||
result = {"content": [{"type": "text", "text": text}]}
|
||||
return JSONResponse(_rpc_result(result, id_))
|
||||
if name == "add":
|
||||
try:
|
||||
a = int(arguments.get("a", 0))
|
||||
b = int(arguments.get("b", 0))
|
||||
result = {"content": [{"type": "text", "text": str(a + b)}]}
|
||||
return JSONResponse(_rpc_result(result, id_))
|
||||
except Exception:
|
||||
return JSONResponse(_rpc_error("Invalid arguments for add", id_=id_), status_code=400)
|
||||
return JSONResponse(_rpc_error("Unknown tool", id_=id_), status_code=400)
|
||||
|
||||
return JSONResponse(_rpc_error("Method not found", id_=id_), status_code=400)
|
||||
|
||||
34
examples/mcp_adapters/server/weather_server.py
Normal file
34
examples/mcp_adapters/server/weather_server.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from fastapi import FastAPI
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
import asyncio
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
# 创建 FastAPI 应用
|
||||
app = FastAPI()
|
||||
|
||||
# 创建 FastMCP 服务器
|
||||
mcp = FastMCP("Weather")
|
||||
|
||||
# 定义工具:获取天气
|
||||
@mcp.tool()
|
||||
async def get_weather(location: str) -> str:
|
||||
"""返回指定位置的天气情况"""
|
||||
return f"The weather in {location} is sunny!"
|
||||
|
||||
# 使用 FastAPI 的 lifespan 来启动 MCP 服务器
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# 在应用启动时启动 MCP 服务
|
||||
loop = asyncio.get_event_loop()
|
||||
task = loop.create_task(mcp.run_streamable_http_async())
|
||||
yield
|
||||
# 在应用关闭时停止 MCP 服务
|
||||
task.cancel()
|
||||
|
||||
# 将 lifespan 事件添加到 FastAPI 应用
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
# 启动 FastAPI 应用
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
Reference in New Issue
Block a user