http-mcp-client-server 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ """HTTP MCP Client-Server for video enhancement API."""
2
+
3
+ __version__ = "0.1.0"
4
+ __all__ = ["__version__"]
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ HTTP MCP Server - 提供视频增强功能的 MCP 服务
4
+
5
+ 通过 MCP 协议暴露 tools,内部调用 FastAPI HTTP Server。
6
+ 支持 URL 上传和本地文件上传(base64)。
7
+ """
8
+
9
+ import argparse
10
+ import asyncio
11
+ import json
12
+ import os
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ import httpx
17
+ from mcp.server import Server
18
+ from mcp.server.stdio import stdio_server
19
+ from mcp.types import TextContent, Tool
20
+
21
+
22
+ class VideoEnhancementMCPServer:
23
+ """MCP Server for video enhancement"""
24
+
25
+ def __init__(self, base_url: str, api_key: str):
26
+ self.base_url = base_url.rstrip("/")
27
+ self.api_key = api_key
28
+ self.server = Server("video-enhancement")
29
+
30
+ # 注册 tools
31
+ self.server.list_tools()(self.list_tools)
32
+ self.server.call_tool()(self.call_tool)
33
+
34
+ # HTTP 客户端
35
+ self._client = httpx.AsyncClient(
36
+ base_url=self.base_url,
37
+ headers={
38
+ "Authorization": f"Bearer {api_key}",
39
+ "Content-Type": "application/json",
40
+ },
41
+ timeout=60.0,
42
+ )
43
+
44
+ async def list_tools(self) -> list[Tool]:
45
+ """列出所有可用的 tools"""
46
+ return [
47
+ Tool(
48
+ name="create_task",
49
+ description="""创建视频增强任务(异步)
50
+
51
+ 支持两种上传方式:
52
+ 1. URL 上传:提供视频 URL
53
+ 2. 本地上传:提供本地文件路径,MCP Server 自动读取并转为 base64
54
+
55
+ 参数说明:
56
+ - video_source: 视频 URL 或本地文件路径
57
+ - type: "url" 或 "local"
58
+ - resolution: 目标分辨率
59
+ """,
60
+ inputSchema={
61
+ "type": "object",
62
+ "properties": {
63
+ "video_source": {
64
+ "type": "string",
65
+ "description": "视频URL地址或本地文件路径",
66
+ },
67
+ "type": {
68
+ "type": "string",
69
+ "enum": ["url", "local"],
70
+ "default": "url",
71
+ "description": "上传类型:url=网络视频,local=本地文件",
72
+ },
73
+ "resolution": {
74
+ "type": "string",
75
+ "enum": ["480p", "540p", "720p", "1080p", "2k"],
76
+ "default": "720p",
77
+ "description": "目标分辨率,默认720p",
78
+ },
79
+ },
80
+ "required": ["video_source"],
81
+ },
82
+ ),
83
+ Tool(
84
+ name="get_task_status",
85
+ description="查询视频增强任务状态",
86
+ inputSchema={
87
+ "type": "object",
88
+ "properties": {
89
+ "task_id": {
90
+ "type": "string",
91
+ "description": "任务ID",
92
+ },
93
+ },
94
+ "required": ["task_id"],
95
+ },
96
+ ),
97
+ Tool(
98
+ name="enhance_video_sync",
99
+ description="""同步增强视频(阻塞等待完成)
100
+
101
+ 支持两种上传方式:
102
+ 1. URL 上传:提供视频 URL
103
+ 2. 本地上传:提供本地文件路径,MCP Server 自动读取并转为 base64
104
+
105
+ 参数说明:
106
+ - video_source: 视频 URL 或本地文件路径
107
+ - type: "url" 或 "local"
108
+ - resolution: 目标分辨率
109
+ - poll_interval: 轮询间隔(秒)
110
+ - timeout: 超时时间(秒)
111
+ """,
112
+ inputSchema={
113
+ "type": "object",
114
+ "properties": {
115
+ "video_source": {
116
+ "type": "string",
117
+ "description": "视频URL地址或本地文件路径",
118
+ },
119
+ "type": {
120
+ "type": "string",
121
+ "enum": ["url", "local"],
122
+ "default": "url",
123
+ "description": "上传类型:url=网络视频,local=本地文件",
124
+ },
125
+ "resolution": {
126
+ "type": "string",
127
+ "enum": ["480p", "540p", "720p", "1080p", "2k"],
128
+ "default": "720p",
129
+ "description": "目标分辨率,默认720p",
130
+ },
131
+ "poll_interval": {
132
+ "type": "number",
133
+ "default": 5,
134
+ "description": "轮询间隔(秒),默认5",
135
+ },
136
+ "timeout": {
137
+ "type": "number",
138
+ "default": 600,
139
+ "description": "超时时间(秒),默认600",
140
+ },
141
+ },
142
+ "required": ["video_source"],
143
+ },
144
+ ),
145
+ ]
146
+
147
+ async def call_tool(self, name: str, arguments: dict[str, Any]) -> list[TextContent]:
148
+ """调用 tool"""
149
+ try:
150
+ if name == "create_task":
151
+ result = await self._create_task(
152
+ video_source=arguments["video_source"],
153
+ source_type=arguments.get("type", "url"),
154
+ resolution=arguments.get("resolution", "720p"),
155
+ )
156
+ elif name == "get_task_status":
157
+ result = await self._get_task_status(
158
+ task_id=arguments["task_id"],
159
+ )
160
+ elif name == "enhance_video_sync":
161
+ result = await self._enhance_video_sync(
162
+ video_source=arguments["video_source"],
163
+ source_type=arguments.get("type", "url"),
164
+ resolution=arguments.get("resolution", "720p"),
165
+ poll_interval=arguments.get("poll_interval", 5),
166
+ timeout=arguments.get("timeout", 600),
167
+ )
168
+ else:
169
+ result = {"success": False, "error": f"未知工具: {name}"}
170
+
171
+ return [TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
172
+
173
+ except Exception as e:
174
+ return [
175
+ TextContent(
176
+ type="text", text=json.dumps({"success": False, "error": str(e)}, ensure_ascii=False, indent=2)
177
+ )
178
+ ]
179
+
180
+ def _read_local_file(self, file_path: str) -> tuple[str, str]:
181
+ """
182
+ 读取本地文件并转为 base64
183
+
184
+ Args:
185
+ file_path: 本地文件路径
186
+
187
+ Returns:
188
+ (base64_data, file_name)
189
+ """
190
+ import base64
191
+
192
+ path = Path(file_path)
193
+ if not path.exists():
194
+ raise FileNotFoundError(f"文件不存在: {file_path}")
195
+
196
+ # 检查文件大小(最大 100MB)
197
+ max_size = 100 * 1024 * 1024
198
+ file_size = path.stat().st_size
199
+ if file_size > max_size:
200
+ raise ValueError("文件大小超过 100MB 限制")
201
+
202
+ # 读取并编码
203
+ with open(path, "rb") as f:
204
+ file_data = f.read()
205
+
206
+ base64_data = base64.b64encode(file_data).decode("utf-8")
207
+ return base64_data, path.name
208
+
209
+ async def _create_task(self, video_source: str, source_type: str, resolution: str) -> dict:
210
+ """创建任务"""
211
+ # 根据类型构建请求
212
+ if source_type == "local":
213
+ # 本地上传:读取文件转 base64
214
+ file_data, file_name = self._read_local_file(video_source)
215
+ content_item = {
216
+ "type": "video_file",
217
+ "file_data": file_data,
218
+ "file_name": file_name,
219
+ }
220
+ else:
221
+ # URL 上传
222
+ content_item = {
223
+ "type": "video_url",
224
+ "video_url": {"url": video_source},
225
+ }
226
+
227
+ payload = {
228
+ "model": "avc-enhance",
229
+ "content": [content_item],
230
+ "resolution": resolution,
231
+ }
232
+
233
+ response = await self._client.post(
234
+ "/api/v3/contents/generations/tasks",
235
+ json=payload,
236
+ )
237
+ response.raise_for_status()
238
+
239
+ data = response.json()
240
+ if data.get("code", 0) != 0:
241
+ return {"success": False, "error": data.get("message", "Unknown error")}
242
+
243
+ return {
244
+ "success": True,
245
+ "task_id": data["data"]["task_id"],
246
+ "status": data["data"]["status"],
247
+ }
248
+
249
+ async def _get_task_status(self, task_id: str) -> dict:
250
+ """查询任务状态"""
251
+ response = await self._client.get(
252
+ f"/api/v3/contents/generations/tasks/{task_id}",
253
+ )
254
+ response.raise_for_status()
255
+
256
+ data = response.json()
257
+ if data.get("code", 0) != 0:
258
+ return {"success": False, "error": data.get("message", "Unknown error")}
259
+
260
+ result = data["data"]
261
+ return {
262
+ "success": True,
263
+ "task_id": result["task_id"],
264
+ "status": result["status"],
265
+ "progress": result.get("progress", 0),
266
+ "video_url": result.get("video_url"),
267
+ "error_message": result.get("error_message"),
268
+ "created_at": result.get("created_at"),
269
+ "updated_at": result.get("updated_at"),
270
+ }
271
+
272
+ async def _enhance_video_sync(
273
+ self,
274
+ video_source: str,
275
+ source_type: str,
276
+ resolution: str,
277
+ poll_interval: int,
278
+ timeout: int,
279
+ ) -> dict:
280
+ """同步增强视频"""
281
+ # 创建任务
282
+ create_result = await self._create_task(video_source, source_type, resolution)
283
+ if not create_result["success"]:
284
+ return create_result
285
+
286
+ task_id = create_result["task_id"]
287
+
288
+ # 轮询等待完成
289
+ start_time = asyncio.get_event_loop().time()
290
+ while True:
291
+ status = await self._get_task_status(task_id)
292
+ if not status["success"]:
293
+ return status
294
+
295
+ if status["status"] in ("completed", "failed"):
296
+ return status
297
+
298
+ elapsed = asyncio.get_event_loop().time() - start_time
299
+ if elapsed >= timeout:
300
+ return {
301
+ "success": False,
302
+ "error": f"任务超时: {task_id}",
303
+ "task_id": task_id,
304
+ }
305
+
306
+ await asyncio.sleep(poll_interval)
307
+
308
+ async def run(self):
309
+ """运行 MCP Server (stdio mode)"""
310
+ async with stdio_server() as (read_stream, write_stream):
311
+ await self.server.run(
312
+ read_stream,
313
+ write_stream,
314
+ self.server.create_initialization_options(),
315
+ )
316
+
317
+ async def close(self):
318
+ """关闭客户端"""
319
+ await self._client.aclose()
320
+
321
+
322
+ def main():
323
+ """主入口"""
324
+ parser = argparse.ArgumentParser(description="HTTP MCP Server for video enhancement")
325
+ parser.add_argument(
326
+ "--base-url",
327
+ default=os.getenv("HTTP_API_BASE_URL", "http://localhost:8000"),
328
+ help="FastAPI HTTP Server base URL",
329
+ )
330
+ parser.add_argument(
331
+ "--api-key",
332
+ default=os.getenv("HTTP_API_KEY", ""),
333
+ help="API key for authentication",
334
+ )
335
+
336
+ args = parser.parse_args()
337
+
338
+ if not args.api_key:
339
+ print("错误: 需要提供 --api-key 或设置 HTTP_API_KEY 环境变量", flush=True)
340
+ exit(1)
341
+
342
+ server = VideoEnhancementMCPServer(
343
+ base_url=args.base_url,
344
+ api_key=args.api_key,
345
+ )
346
+
347
+ try:
348
+ asyncio.run(server.run())
349
+ except KeyboardInterrupt:
350
+ print("\n服务已停止", flush=True)
351
+ finally:
352
+ asyncio.run(server.close())
353
+
354
+
355
+ if __name__ == "__main__":
356
+ main()
@@ -0,0 +1,272 @@
1
+ Metadata-Version: 2.4
2
+ Name: http-mcp-client-server
3
+ Version: 0.1.0
4
+ Summary: HTTP MCP Client-Server for video enhancement API
5
+ Project-URL: Homepage, https://github.com/yourusername/http-mcp-client-server
6
+ Project-URL: Repository, https://github.com/yourusername/http-mcp-client-server
7
+ Project-URL: Issues, https://github.com/yourusername/http-mcp-client-server/issues
8
+ Author-email: Your Name <your.email@example.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: client,enhancement,fastapi,http,mcp,server,video
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Multimedia :: Video
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: httpx>=0.27.0
23
+ Requires-Dist: mcp>=1.0.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: build>=1.0.0; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.6.0; extra == 'dev'
30
+ Requires-Dist: twine>=5.0.0; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # http-mcp-client-server (Python)
34
+
35
+ [![PyPI version](https://badge.fury.io/py/http-mcp-client-server.svg)](https://pypi.org/project/http-mcp-client-server/)
36
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
38
+
39
+ 基于 MCP 协议的视频增强服务,作为 MCP Client-Server 与 FastAPI HTTP Server 交互。
40
+
41
+ ## 功能
42
+
43
+ 提供以下 MCP Tools:
44
+ - `create_task` - 创建视频增强任务(支持 URL 或本地文件上传)
45
+ - `get_task_status` - 查询任务状态
46
+ - `enhance_video_sync` - 同步增强视频(阻塞等待)
47
+
48
+ ## 安装
49
+
50
+ ### 从 PyPI 安装(推荐)
51
+
52
+ ```bash
53
+ # 使用 pip 安装
54
+ pip install http-mcp-client-server
55
+
56
+ # 或使用 uv 安装
57
+ uv pip install http-mcp-client-server
58
+ ```
59
+
60
+ ### 从源码安装
61
+
62
+ ```bash
63
+ git clone https://github.com/yourusername/http-mcp-client-server.git
64
+ cd python_client
65
+
66
+ # 使用 uv 安装(推荐)
67
+ uv pip install -e ".[dev]"
68
+
69
+ # 或使用 pip 安装
70
+ pip install -e ".[dev]"
71
+ ```
72
+
73
+ ## 使用方法
74
+
75
+ ### 1. 命令行启动
76
+
77
+ ```bash
78
+ # 直接运行(安装后)
79
+ http-mcp-client-server --base-url http://localhost:8000 --api-key your-api-key
80
+
81
+ # 或使用环境变量
82
+ export HTTP_API_BASE_URL=http://localhost:8000
83
+ export HTTP_API_KEY=your-api-key
84
+ http-mcp-client-server
85
+ ```
86
+
87
+ ### 2. 在 Claude Desktop 中配置
88
+
89
+ 编辑 Claude Desktop 配置文件:
90
+
91
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
92
+
93
+ **Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "video-enhancement": {
99
+ "command": "http-mcp-client-server",
100
+ "args": [
101
+ "--base-url",
102
+ "http://localhost:8000",
103
+ "--api-key",
104
+ "your-api-key"
105
+ ]
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### 3. 使用 uv run 运行(开发模式)
112
+
113
+ ```bash
114
+ uv run http-mcp-client-server --base-url http://localhost:8000 --api-key your-api-key
115
+ ```
116
+
117
+ ## 提供的 Tools
118
+
119
+ ### create_task
120
+
121
+ 创建视频增强任务(异步)。
122
+
123
+ **参数:**
124
+ - `video_source` (string, required): 视频 URL 或本地文件路径
125
+ - `type` (string, optional): 上传类型,默认 "url"
126
+ - 可选值: `"url"` - 网络视频URL, `"local"` - 本地文件路径
127
+ - `resolution` (string, optional): 目标分辨率,默认 720p
128
+ - 可选值: 480p, 540p, 720p, 1080p, 2k
129
+
130
+ **使用示例:**
131
+
132
+ ```python
133
+ # URL 方式
134
+ {
135
+ "video_source": "https://example.com/video.mp4",
136
+ "type": "url",
137
+ "resolution": "1080p"
138
+ }
139
+
140
+ # 本地文件方式
141
+ {
142
+ "video_source": "/path/to/local/video.mp4",
143
+ "type": "local",
144
+ "resolution": "1080p"
145
+ }
146
+ ```
147
+
148
+ **返回值:**
149
+ ```json
150
+ {
151
+ "success": true,
152
+ "task_id": "xxx",
153
+ "status": "wait"
154
+ }
155
+ ```
156
+
157
+ ### get_task_status
158
+
159
+ 查询任务状态。
160
+
161
+ **参数:**
162
+ - `task_id` (string, required): 任务ID
163
+
164
+ **使用示例:**
165
+ ```python
166
+ {
167
+ "task_id": "task-123-abc"
168
+ }
169
+ ```
170
+
171
+ **返回值:**
172
+ ```json
173
+ {
174
+ "success": true,
175
+ "task_id": "xxx",
176
+ "status": "completed",
177
+ "progress": 100,
178
+ "video_url": "https://...",
179
+ "error_message": null,
180
+ "created_at": "2024-01-01T00:00:00Z",
181
+ "updated_at": "2024-01-01T00:01:00Z"
182
+ }
183
+ ```
184
+
185
+ ### enhance_video_sync
186
+
187
+ 同步增强视频(阻塞等待完成)。
188
+
189
+ **参数:**
190
+ - `video_source` (string, required): 视频 URL 或本地文件路径
191
+ - `type` (string, optional): 上传类型,默认 "url"
192
+ - 可选值: `"url"` - 网络视频URL, `"local"` - 本地文件路径
193
+ - `resolution` (string, optional): 目标分辨率,默认 720p
194
+ - `poll_interval` (number, optional): 轮询间隔(秒),默认 5
195
+ - `timeout` (number, optional): 超时时间(秒),默认 600
196
+
197
+ **使用示例:**
198
+ ```python
199
+ {
200
+ "video_source": "https://example.com/video.mp4",
201
+ "type": "url",
202
+ "resolution": "1080p",
203
+ "poll_interval": 5,
204
+ "timeout": 600
205
+ }
206
+ ```
207
+
208
+ **返回值:**
209
+ ```json
210
+ {
211
+ "success": true,
212
+ "task_id": "xxx",
213
+ "status": "completed",
214
+ "progress": 100,
215
+ "video_url": "https://..."
216
+ }
217
+ ```
218
+
219
+ ## 文件上传说明
220
+
221
+ 当 `type` 设置为 `"local"` 时,MCP Server 会:
222
+ 1. 读取本地文件
223
+ 2. 将文件转为 base64 编码
224
+ 3. 上传到视频增强服务
225
+
226
+ **限制:**
227
+ - 最大文件大小:100MB
228
+
229
+ ## 环境变量
230
+
231
+ | 变量名 | 说明 | 默认值 |
232
+ |--------|------|--------|
233
+ | `HTTP_API_BASE_URL` | FastAPI HTTP Server 地址 | `http://localhost:8000` |
234
+ | `HTTP_API_KEY` | API 认证密钥 | 无 |
235
+
236
+ ## 开发
237
+
238
+ ```bash
239
+ # 克隆仓库
240
+ git clone https://github.com/yourusername/http-mcp-client-server.git
241
+ cd python_client
242
+
243
+ # 安装开发依赖
244
+ uv pip install -e ".[dev]"
245
+
246
+ # 运行测试
247
+ pytest
248
+
249
+ # 代码格式化
250
+ ruff format .
251
+ ruff check --fix .
252
+ ```
253
+
254
+ ## 发布到 PyPI
255
+
256
+ ```bash
257
+ # 安装构建工具
258
+ uv pip install build twine
259
+
260
+ # 构建分发包
261
+ python -m build
262
+
263
+ # 上传到 PyPI(测试)
264
+ python -m twine upload --repository testpypi dist/*
265
+
266
+ # 上传到 PyPI(正式)
267
+ python -m twine upload dist/*
268
+ ```
269
+
270
+ ## License
271
+
272
+ MIT License - 详见 [LICENSE](LICENSE) 文件
@@ -0,0 +1,7 @@
1
+ http_mcp_client/__init__.py,sha256=K7O3bmQwEKwkYvMsIwxLexqH4Kz2TzpsWTrGeSj8dkE,105
2
+ http_mcp_client/server.py,sha256=J8f98ldu_EcfYcxadOcnwm_1oRloQB27Jyy7qDBB4vU,11916
3
+ http_mcp_client_server-0.1.0.dist-info/METADATA,sha256=X6Y0BeiHXZrSNwdms0k2rUBXK6rNttCWf910GCsG3P0,6298
4
+ http_mcp_client_server-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
5
+ http_mcp_client_server-0.1.0.dist-info/entry_points.txt,sha256=gnHpFJTKA7FGjMB1MqRALn6iD87wA7LO3Cv9dS0MIhw,71
6
+ http_mcp_client_server-0.1.0.dist-info/licenses/LICENSE,sha256=QvyDolqEVJoMgCxrNb823xH5hJDH0ifntw7vzN-VGD4,1079
7
+ http_mcp_client_server-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ http-mcp-client-server = http_mcp_client.server:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 http-mcp-client-server
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.