fix(server): 修复 API 模式失效的问题

1. 拆分 API 模式和 MCP 模式
2. 修改服务器模式启动命令
3. 修正示例代码错误

Closes #273
This commit is contained in:
Quan 2025-07-29 12:24:58 +08:00
parent 0c7f5eb32c
commit d5081f0ff9
6 changed files with 77 additions and 41 deletions

View File

@ -121,10 +121,10 @@
<hr>
<img src="static/screenshot/命令行模式截图CN2.png" alt="">
<h1>🖥 服务器模式</h1>
<p>⭐ 服务器模式同时支持 API 调用和 MCP 调用!</p>
<p><b>启动:</b>运行命令:<code>python .\main.py server</code></p>
<p>服务器模式包含 API 模式和 MCP 模式!</p>
<h2>API 模式</h2>
<p><b>启动:</b>运行命令:<code>python .\main.py api</code></p>
<p><b>关闭:</b>按下 <code>Ctrl</code> + <code>C</code> 关闭服务器</p>
<h2>API 调用</h2>
<p>访问 <code>http://127.0.0.1:5556/docs</code> 或者 <code>http://127.0.0.1:5556/redoc</code>;你会看到自动生成的交互式 API 文档!</p>
<p><b>请求接口:</b><code>/xhs/detail</code></p>
<p><b>请求方法:</b><code>POST</code></p>
@ -182,7 +182,7 @@
<pre>
async def example_api():
"""通过 API 设置参数,适合二次开发"""
server = "http://127.0.0.1:5556/xhs/"
server = "http://127.0.0.1:5556/xhs/detail"
data = {
"url": "", # 必需参数
"download": True,
@ -196,10 +196,14 @@ async def example_api():
response = post(server, json=data, timeout=10)
print(response.json())
</pre>
<h2>MCP 调用</h2>
<p><b>MCP URL</b><code>http://127.0.0.1:5556/xhs/mcp</code></p>
<p><b>MCP 传输机制:</b><code>可流式传输的 HTTP (streamableHttp)</code></p>
<h2>MCP 模式</h2>
<p><b>启动:</b>运行命令:<code>python .\main.py mcp</code></p>
<p><b>关闭:</b>按下 <code>Ctrl</code> + <code>C</code> 关闭服务器</p>
<h3>MCP 配置示例</h3>
[//]: # (<h4>STDIO</h4>)
<h4>Streamable HTTP</h4>
<p><b>MCP URL</b><code>http://127.0.0.1:5556/mcp/</code></p>
<img src="static/screenshot/MCP配置示例.png" alt="MCP配置示例">
<h3>MCP 调用示例</h3>
<h4><strong>获取小红书作品信息</strong></h4>

View File

@ -122,10 +122,10 @@
<hr>
<img src="static/screenshot/命令行模式截图EN2.png" alt="">
<h1>🖥 Server Mode</h1>
<p>⭐ Server mode supports both API calls and MCP calls!</p>
<p><b>Start:</b> Run the command: <code>python .\main.py server</code></p>
<p>Server modes include API mode and MCP mode!</p>
<h2>API Mode</h2>
<p><b>Start:</b> Run the command: <code>python .\main.py api</code></p>
<p><b>Stop:</b> Press <code>Ctrl</code> + <code>C</code> to stop the server</p>
<h2>API Calls</h2>
<p>Open <code>http://127.0.0.1:5556/docs</code> or <code>http://127.0.0.1:5556/redoc</code>; you will see automatically generated interactive API documentation!</p>
<p><b>Request endpoint:</b>
<code>/xhs/detail</code></p>
@ -186,7 +186,7 @@
<pre>
async def example_api():
"""通过 API 设置参数,适合二次开发"""
server = "http://127.0.0.1:5556/xhs/"
server = "http://127.0.0.1:5556/xhs/detail"
data = {
"url": "", # 必需参数
"download": True,
@ -200,10 +200,14 @@ async def example_api():
response = post(server, json=data, timeout=10)
print(response.json())
</pre>
<h2>MCP Calls</h2>
<p><b>MCP URL:</b><code>http://127.0.0.1:5556/xhs/mcp</code></p>
<p><b>MCP Transmission Mechanism:</b><code>streamableHttp</code></p>
<h2>MCP Mode</h2>
<p><b>Start:</b> Run the command: <code>python .\main.py mcp</code></p>
<p><b>Stop:</b> Press <code>Ctrl</code> + <code>C</code> to stop the server</p>
<h3>MCP Configuration Example</h3>
[//]: # (<h4>STDIO</h4>)
<h4>Streamable HTTP</h4>
<p><b>MCP URL:</b><code>http://127.0.0.1:5556/mcp/</code></p>
<img src="static/screenshot/MCP配置示例.png" alt="MCP Configuration Example">
<h3>MCP Invocation Example</h3>
<h4><strong>Retrieve RedNote Works Information</strong></h4>

View File

@ -76,7 +76,7 @@ async def example():
async def example_api():
"""通过 API 设置参数,适合二次开发"""
server = "http://127.0.0.1:5556/xhs/"
server = "http://127.0.0.1:5556/xhs/detail"
data = {
"url": "", # 必需参数
"download": True,

31
main.py
View File

@ -14,27 +14,46 @@ async def app():
await xhs.run_async()
async def server(
async def api_server(
host="0.0.0.0",
port=5556,
log_level="info",
):
async with XHS(**Settings().run()) as xhs:
await xhs.run_server(
await xhs.run_api_server(
host,
port,
log_level,
)
async def mcp_server(
transport="streamable-http",
host="0.0.0.0",
port=5556,
log_level="INFO",
):
async with XHS(**Settings().run()) as xhs:
await xhs.run_mcp_server(
transport=transport,
host=host,
port=port,
log_level=log_level,
)
if __name__ == "__main__":
with suppress(
KeyboardInterrupt,
CancelledError,
KeyboardInterrupt,
CancelledError,
):
# TODO: 重构优化
if len(argv) == 1:
run(app())
elif argv[1] == "server":
run(server())
elif argv[1] == "api":
run(api_server())
elif argv[1] == "mcp":
run(mcp_server())
# run(mcp_server("stdio"))
else:
cli()

View File

@ -154,9 +154,6 @@ class XHS:
self.clipboard_cache: str = ""
self.queue = Queue()
self.event = Event()
# self.runner = self.init_server()
# self.site = None
self.server = None
def __extract_image(self, container: dict, data: Namespace):
container["下载地址"], container["动图地址"] = self.image.get_image_link(
@ -528,23 +525,20 @@ class XHS:
# await self.runner.cleanup()
# logging(log, _("Web API 服务器已关闭!"))
async def run_server(
async def run_api_server(
self,
host="0.0.0.0",
port=5556,
log_level="info",
):
mcp = self.init_mcp_server()
self.server = FastAPI(
api = FastAPI(
debug=self.VERSION_BETA,
title="XHS-Downloader",
version=__VERSION__,
lifespan=mcp.lifespan,
)
self.server.mount("/xhs", mcp)
self.setup_routes()
self.setup_routes(api)
config = Config(
self.server,
api,
host=host,
port=port,
log_level=log_level,
@ -552,8 +546,11 @@ class XHS:
server = Server(config)
await server.serve()
def setup_routes(self):
@self.server.get(
def setup_routes(
self,
server: FastAPI,
):
@server.get(
"/",
summary=_("访问项目 GitHub 仓库"),
description=_("重定向至项目 GitHub 仓库主页"),
@ -562,7 +559,7 @@ class XHS:
async def index():
return RedirectResponse(url=REPOSITORY)
@self.server.post(
@server.post(
"/xhs/detail",
summary=_("获取作品数据及下载地址"),
description=_(
@ -601,7 +598,13 @@ class XHS:
msg = _("获取小红书作品数据失败")
return ExtractData(message=msg, params=extract, data=data)
def init_mcp_server(self):
async def run_mcp_server(
self,
transport="streamable-http",
host="0.0.0.0",
port=5556,
log_level="INFO",
):
mcp = FastMCP(
"XHS-Downloader",
instructions=dedent("""
@ -631,6 +634,9 @@ class XHS:
- data作品信息数据不需要返回作品信息数据时固定为 None
"""),
version=__VERSION__,
host=host,
port=port,
log_level=log_level,
)
@mcp.tool(
@ -749,7 +755,9 @@ class XHS:
case _:
raise ValueError
return mcp.http_app(path="/mcp")
await mcp.run_async(
transport=transport,
)
async def deal_detail_mcp(
self,

View File

@ -2,12 +2,13 @@
1. 修复作品类型判断失败时异常退出的问题
2. 修改服务器模式请求路径为 `/xhs/detail`
3. 服务器模式支持通过 MCP 调用
4. 修改服务器模式默认端口为 `5556`
3. 修改服务器模式默认端口为 `5556`
4. 服务器模式新增 MCP 模式
5. 优化提取链接的正则表达式
6. 支持更多作品链接格式
7. 支持音乐图集作品下载
8. 其他细节优化
6. 修改服务器模式启动命令
7. 支持更多作品链接格式
8. 支持音乐图集作品下载
9. 其他细节优化
*****