58 lines
2.1 KiB
Python
58 lines
2.1 KiB
Python
import requests
|
||
import uvicorn
|
||
from mcp.server.fastmcp.server import FastMCP
|
||
from typing import Optional
|
||
import logging
|
||
|
||
# 配置日志记录
|
||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||
|
||
# 1. 使用 FastMCP 创建一个 Server 实例
|
||
mcp = FastMCP(
|
||
"APICallerServer",
|
||
title="API Caller Server",
|
||
description="A server that provides a tool to call APIs.",
|
||
version="0.2.0" # a new version
|
||
)
|
||
|
||
# 2. 使用 @mcp.tool() 装饰器来定义一个工具
|
||
@mcp.tool()
|
||
def api_caller(method: str, url: str, headers: Optional[dict] = None, params: Optional[dict] = None, json_body: Optional[dict] = None) -> dict:
|
||
"""
|
||
一个通用的API调用工具,可以发送HTTP请求。
|
||
"""
|
||
logging.info(f"api_caller: Received request -> method={method}, url={url}, params={params}, json_body={json_body}")
|
||
try:
|
||
response = requests.request(
|
||
method=method,
|
||
url=url,
|
||
headers=headers,
|
||
params=params,
|
||
json=json_body
|
||
)
|
||
response.raise_for_status() # 如果状态码是 4xx 或 5xx,则引发HTTPError
|
||
|
||
logging.info(f"api_caller: Request to {url} successful with status code {response.status_code}")
|
||
|
||
# 尝试将响应解析为JSON,如果失败则作为纯文本返回
|
||
try:
|
||
response_body = response.json()
|
||
except requests.exceptions.JSONDecodeError:
|
||
response_body = response.text
|
||
|
||
return {
|
||
"status_code": response.status_code,
|
||
"headers": dict(response.headers),
|
||
"body": response_body
|
||
}
|
||
except requests.exceptions.RequestException as e:
|
||
logging.error(f"api_caller: Request to {url} failed. Error: {e}", exc_info=True)
|
||
return {
|
||
"error": "APIRequestError",
|
||
"message": str(e)
|
||
}
|
||
|
||
# 3. (可选) 如果直接运行此文件,则启动服务器
|
||
if __name__ == "__main__":
|
||
# FastMCP对象本身不是ASGI应用,但它的 streamable_http_app() 方法会返回一个
|
||
uvicorn.run(mcp.streamable_http_app(), host="127.0.0.1", port=8001) |