media-agent-mcp 0.3.8__tar.gz → 0.3.10__tar.gz
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.
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/PKG-INFO +2 -1
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/pyproject.toml +2 -1
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/__init__.py +3 -1
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/async_server.py +42 -37
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/async_wrapper.py +9 -9
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp.egg-info/PKG-INFO +2 -1
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp.egg-info/requires.txt +1 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/README.md +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/setup.cfg +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/ai_models/__init__.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/ai_models/seed16.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/ai_models/seedance.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/ai_models/seededit.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/ai_models/seedream.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/media_selectors/__init__.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/media_selectors/image_selector.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/media_selectors/video_selector.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/server.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/storage/__init__.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/storage/tos_client.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/video/__init__.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/video/processor.py +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp.egg-info/SOURCES.txt +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp.egg-info/dependency_links.txt +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp.egg-info/entry_points.txt +0 -0
- {media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: media-agent-mcp
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.10
|
4
4
|
Summary: A Model Context Protocol server for media processing with AI tools
|
5
5
|
Author-email: Media Agent Team <team@mediaagent.com>
|
6
6
|
Keywords: mcp,ai,media,video,image,processing
|
@@ -22,6 +22,7 @@ Requires-Dist: numpy>=1.24.0
|
|
22
22
|
Requires-Dist: python-dotenv>=1.0.0
|
23
23
|
Requires-Dist: volcengine-python-sdk>=1.0.0
|
24
24
|
Requires-Dist: volcengine>=1.0.194
|
25
|
+
Requires-Dist: tenacity>=8.2.3
|
25
26
|
|
26
27
|
# Media Agent MCP
|
27
28
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "media-agent-mcp"
|
3
|
-
version = "0.3.
|
3
|
+
version = "0.3.10"
|
4
4
|
description = "A Model Context Protocol server for media processing with AI tools"
|
5
5
|
readme = "README.md"
|
6
6
|
requires-python = ">=3.12"
|
@@ -27,6 +27,7 @@ dependencies = [
|
|
27
27
|
"python-dotenv>=1.0.0",
|
28
28
|
"volcengine-python-sdk>=1.0.0",
|
29
29
|
"volcengine>=1.0.194",
|
30
|
+
"tenacity>=8.2.3",
|
30
31
|
]
|
31
32
|
|
32
33
|
[project.scripts]
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
from . import ai_models, media_selectors, storage, video
|
4
4
|
from .server import main
|
5
|
+
from .async_server import main as async_main
|
6
|
+
from . import async_wrapper
|
5
7
|
|
6
8
|
__version__ = "0.1.0"
|
7
|
-
__all__ = ['ai_models', 'media_selectors', 'storage', 'video', 'main']
|
9
|
+
__all__ = ['ai_models', 'media_selectors', 'storage', 'video', 'main', 'async_main', 'async_wrapper']
|
@@ -22,6 +22,17 @@ from typing import List, Optional
|
|
22
22
|
import json
|
23
23
|
from dotenv import load_dotenv
|
24
24
|
import uvicorn
|
25
|
+
from tenacity import retry, stop_after_attempt, wait_fixed
|
26
|
+
|
27
|
+
def _is_result_error(result):
|
28
|
+
"""Return True if the result is a dictionary with status 'error'."""
|
29
|
+
if isinstance(result, str):
|
30
|
+
try:
|
31
|
+
data = json.loads(result)
|
32
|
+
return isinstance(data, dict) and data.get('status') == 'error'
|
33
|
+
except json.JSONDecodeError:
|
34
|
+
return False
|
35
|
+
return isinstance(result, dict) and result.get('status') == 'error'
|
25
36
|
|
26
37
|
from mcp.server.fastmcp import FastMCP
|
27
38
|
|
@@ -49,7 +60,8 @@ mcp = FastMCP("Media-Agent-MCP-Async")
|
|
49
60
|
|
50
61
|
|
51
62
|
@mcp.tool()
|
52
|
-
|
63
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
64
|
+
async def video_concat_tool(video_urls: List[str]) -> dict:
|
53
65
|
"""
|
54
66
|
Asynchronously concatenate multiple videos from URLs and upload to TOS.
|
55
67
|
|
@@ -57,13 +69,14 @@ async def video_concat_tool_async(video_urls: List[str]) -> str:
|
|
57
69
|
video_urls: List of video URLs to concatenate in order
|
58
70
|
|
59
71
|
Returns:
|
60
|
-
|
72
|
+
Dictionary with status, data, and message
|
61
73
|
"""
|
62
74
|
return await async_video_concat_tool(video_urls)
|
63
75
|
|
64
76
|
|
65
77
|
@mcp.tool()
|
66
|
-
|
78
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
79
|
+
async def video_last_frame_tool(video_url: str) -> dict:
|
67
80
|
"""
|
68
81
|
Asynchronously extract the last frame from a video file and upload to TOS.
|
69
82
|
|
@@ -71,13 +84,14 @@ async def video_last_frame_tool_async(video_url: str) -> str:
|
|
71
84
|
video_url: URL or path to the video file
|
72
85
|
|
73
86
|
Returns:
|
74
|
-
|
87
|
+
Dictionary with status, data, and message
|
75
88
|
"""
|
76
89
|
return await async_video_last_frame_tool(video_url)
|
77
90
|
|
78
91
|
|
79
92
|
@mcp.tool()
|
80
|
-
|
93
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
94
|
+
async def seedream_generate_image_tool(prompt: str, size: str = "1024x1024") -> dict:
|
81
95
|
"""
|
82
96
|
Asynchronously generate an image using Seedream AI model.
|
83
97
|
|
@@ -86,15 +100,16 @@ async def seedream_generate_image_tool_async(prompt: str, size: str = "1024x1024
|
|
86
100
|
size: Size of the image (e.g., "1024x1024")
|
87
101
|
|
88
102
|
Returns:
|
89
|
-
|
103
|
+
Dictionary with status, data, and message
|
90
104
|
"""
|
91
105
|
return await async_seedream_generate_image_tool(prompt, size)
|
92
106
|
|
93
107
|
|
94
108
|
@mcp.tool()
|
95
|
-
|
109
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
110
|
+
async def seedance_generate_video_tool(prompt: str, first_frame_image: str,
|
96
111
|
last_frame_image: str = None, duration: int = 5,
|
97
|
-
resolution: str = "720p") ->
|
112
|
+
resolution: str = "720p") -> dict:
|
98
113
|
"""
|
99
114
|
Asynchronously generate a video using Seedance AI model with first/last frame images.
|
100
115
|
|
@@ -106,14 +121,15 @@ async def seedance_generate_video_tool_async(prompt: str, first_frame_image: str
|
|
106
121
|
resolution: Video resolution (480p, 720p)
|
107
122
|
|
108
123
|
Returns:
|
109
|
-
|
124
|
+
Dictionary with status, data, and message
|
110
125
|
"""
|
111
126
|
return await async_seedance_generate_video_tool(prompt, first_frame_image, last_frame_image, duration, resolution)
|
112
127
|
|
113
128
|
|
114
129
|
@mcp.tool()
|
115
|
-
|
116
|
-
|
130
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
131
|
+
async def seededit_tool(image_url: str, prompt: str, seed: int = -1,
|
132
|
+
scale: float = 0.5, charactor_keep: bool = False) -> dict:
|
117
133
|
"""
|
118
134
|
Asynchronously edit an image using Seededit model.
|
119
135
|
|
@@ -125,13 +141,14 @@ async def seededit_tool_async(image_url: str, prompt: str, seed: int = -1,
|
|
125
141
|
charactor_keep: whether to keep the main character in this image, if you wanna change the main character, please keep False
|
126
142
|
|
127
143
|
Returns:
|
128
|
-
|
144
|
+
Dictionary with status, data, and message
|
129
145
|
"""
|
130
146
|
return await async_seededit_tool(image_url, prompt, seed, scale, charactor_keep)
|
131
147
|
|
132
148
|
|
133
149
|
@mcp.tool()
|
134
|
-
|
150
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
151
|
+
async def vlm_vision_task_tool(messages: List) -> dict:
|
135
152
|
"""
|
136
153
|
Asynchronously perform vision-language tasks using VLM model.
|
137
154
|
|
@@ -139,13 +156,14 @@ async def vlm_vision_task_tool_async(messages: List) -> str:
|
|
139
156
|
messages: OpenAI-compatible messages format
|
140
157
|
|
141
158
|
Returns:
|
142
|
-
|
159
|
+
Dictionary with status, data, and message
|
143
160
|
"""
|
144
161
|
return await async_vlm_vision_task_tool(messages)
|
145
162
|
|
146
163
|
|
147
164
|
@mcp.tool()
|
148
|
-
|
165
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
166
|
+
async def image_selector_tool(image_paths: List[str], prompt: str) -> dict:
|
149
167
|
"""
|
150
168
|
Asynchronously select the best image from multiple options using VLM model.
|
151
169
|
|
@@ -154,13 +172,14 @@ async def image_selector_tool_async(image_paths: List[str], prompt: str) -> str:
|
|
154
172
|
prompt: Selection criteria prompt
|
155
173
|
|
156
174
|
Returns:
|
157
|
-
|
175
|
+
Dictionary with status, data, and message
|
158
176
|
"""
|
159
177
|
return await async_image_selector_tool(image_paths, prompt)
|
160
178
|
|
161
179
|
|
162
180
|
@mcp.tool()
|
163
|
-
|
181
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
182
|
+
async def video_selector_tool(video_paths: List[str], prompt: str) -> dict:
|
164
183
|
"""
|
165
184
|
Asynchronously select the best video from multiple options using VLM model.
|
166
185
|
|
@@ -169,14 +188,15 @@ async def video_selector_tool_async(video_paths: List[str], prompt: str) -> str:
|
|
169
188
|
prompt: Selection criteria prompt
|
170
189
|
|
171
190
|
Returns:
|
172
|
-
|
191
|
+
Dictionary with status, data, and message
|
173
192
|
"""
|
174
193
|
return await async_video_selector_tool(video_paths, prompt)
|
175
194
|
|
176
195
|
|
177
196
|
@mcp.tool()
|
178
|
-
|
179
|
-
|
197
|
+
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
|
198
|
+
async def tos_save_content_tool(content: str, file_extension: str = "txt",
|
199
|
+
object_key: Optional[str] = None) -> dict:
|
180
200
|
"""
|
181
201
|
Asynchronously save content to TOS and return URL.
|
182
202
|
|
@@ -186,7 +206,7 @@ async def tos_save_content_tool_async(content: str, file_extension: str = "txt",
|
|
186
206
|
object_key: Optional key to use for the object in TOS
|
187
207
|
|
188
208
|
Returns:
|
189
|
-
|
209
|
+
Dictionary with status, data, and message
|
190
210
|
"""
|
191
211
|
return await async_tos_save_content_tool(content, file_extension, object_key)
|
192
212
|
|
@@ -205,21 +225,6 @@ async def run_multiple_tools_concurrently(*coroutines):
|
|
205
225
|
return await asyncio.gather(*coroutines, return_exceptions=True)
|
206
226
|
|
207
227
|
|
208
|
-
# Example usage function
|
209
|
-
async def example_concurrent_usage():
|
210
|
-
"""
|
211
|
-
Example of how to use multiple tools concurrently.
|
212
|
-
"""
|
213
|
-
# Example: Generate image and process video concurrently
|
214
|
-
image_task = seedream_generate_image_tool_async("A beautiful sunset", "1024x1024")
|
215
|
-
video_task = video_last_frame_tool_async("https://example.com/video.mp4")
|
216
|
-
|
217
|
-
# Run both tasks concurrently
|
218
|
-
results = await run_multiple_tools_concurrently(image_task, video_task)
|
219
|
-
|
220
|
-
return results
|
221
|
-
|
222
|
-
|
223
228
|
def main():
|
224
229
|
"""Main entry point for the Async MCP server."""
|
225
230
|
# Parse command line arguments
|
@@ -229,7 +234,7 @@ def main():
|
|
229
234
|
parser.add_argument('--host', type=str, default='127.0.0.1',
|
230
235
|
help='Host for SSE transport (default: 127.0.0.1)')
|
231
236
|
parser.add_argument('--port', type=int, default=8000,
|
232
|
-
help='Port for SSE transport (default:
|
237
|
+
help='Port for SSE transport (default: 8000)')
|
233
238
|
parser.add_argument('--version', action='store_true',
|
234
239
|
help='Show version information')
|
235
240
|
|
@@ -85,28 +85,28 @@ def json_response_wrapper(func: Callable) -> Callable:
|
|
85
85
|
# Async wrapped functions
|
86
86
|
@async_wrapper
|
87
87
|
@json_response_wrapper
|
88
|
-
def
|
88
|
+
def _sync_video_concat(video_urls: List[str]) -> str:
|
89
89
|
"""Synchronous video concatenation wrapper."""
|
90
90
|
return concat_videos(video_urls)
|
91
91
|
|
92
92
|
|
93
93
|
@async_wrapper
|
94
94
|
@json_response_wrapper
|
95
|
-
def
|
95
|
+
def _sync_video_last_frame(video_url: str) -> str:
|
96
96
|
"""Synchronous video last frame extraction wrapper."""
|
97
97
|
return extract_last_frame(video_url)
|
98
98
|
|
99
99
|
|
100
100
|
@async_wrapper
|
101
101
|
@json_response_wrapper
|
102
|
-
def
|
102
|
+
def _sync_seedream_generate_image(prompt: str, size: str = "1024x1024") -> str:
|
103
103
|
"""Synchronous image generation wrapper."""
|
104
104
|
return generate_image(prompt, size=size)
|
105
105
|
|
106
106
|
|
107
107
|
@async_wrapper
|
108
108
|
@json_response_wrapper
|
109
|
-
def
|
109
|
+
def _sync_seedance_generate_video(prompt: str, first_frame_image: str,
|
110
110
|
last_frame_image: str = None, duration: int = 5,
|
111
111
|
resolution: str = "720p") -> str:
|
112
112
|
"""Synchronous video generation wrapper."""
|
@@ -128,7 +128,7 @@ def seedance_generate_video_tool(prompt: str, first_frame_image: str,
|
|
128
128
|
|
129
129
|
@async_wrapper
|
130
130
|
@json_response_wrapper
|
131
|
-
def
|
131
|
+
def _sync_seededit(image_url: str, prompt: str, seed: int = -1,
|
132
132
|
scale: float = 0.5, charactor_keep: bool = False) -> str:
|
133
133
|
"""Synchronous image editing wrapper."""
|
134
134
|
return seededit(
|
@@ -143,14 +143,14 @@ def seededit_tool(image_url: str, prompt: str, seed: int = -1,
|
|
143
143
|
|
144
144
|
@async_wrapper
|
145
145
|
@json_response_wrapper
|
146
|
-
def
|
146
|
+
def _sync_vlm_vision_task(messages: List) -> str:
|
147
147
|
"""Synchronous VLM vision task wrapper."""
|
148
148
|
from media_agent_mcp.ai_models.seed16 import process_vlm_task
|
149
149
|
return process_vlm_task(messages)
|
150
150
|
|
151
151
|
|
152
152
|
@async_wrapper
|
153
|
-
def
|
153
|
+
def _sync_image_selector(image_paths: List[str], prompt: str) -> str:
|
154
154
|
"""Synchronous image selector wrapper."""
|
155
155
|
try:
|
156
156
|
result = select_best_image(image_paths, prompt)
|
@@ -168,7 +168,7 @@ def image_selector_tool(image_paths: List[str], prompt: str) -> str:
|
|
168
168
|
|
169
169
|
|
170
170
|
@async_wrapper
|
171
|
-
def
|
171
|
+
def _sync_video_selector(video_paths: List[str], prompt: str) -> str:
|
172
172
|
"""Synchronous video selector wrapper."""
|
173
173
|
try:
|
174
174
|
result = select_best_video(video_paths, prompt)
|
@@ -186,7 +186,7 @@ def video_selector_tool(video_paths: List[str], prompt: str) -> str:
|
|
186
186
|
|
187
187
|
|
188
188
|
@async_wrapper
|
189
|
-
def
|
189
|
+
def _sync_tos_save_content(content: str, file_extension: str = "txt",
|
190
190
|
object_key: Optional[str] = None) -> str:
|
191
191
|
"""Synchronous TOS content save wrapper."""
|
192
192
|
import tempfile
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: media-agent-mcp
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.10
|
4
4
|
Summary: A Model Context Protocol server for media processing with AI tools
|
5
5
|
Author-email: Media Agent Team <team@mediaagent.com>
|
6
6
|
Keywords: mcp,ai,media,video,image,processing
|
@@ -22,6 +22,7 @@ Requires-Dist: numpy>=1.24.0
|
|
22
22
|
Requires-Dist: python-dotenv>=1.0.0
|
23
23
|
Requires-Dist: volcengine-python-sdk>=1.0.0
|
24
24
|
Requires-Dist: volcengine>=1.0.194
|
25
|
+
Requires-Dist: tenacity>=8.2.3
|
25
26
|
|
26
27
|
# Media Agent MCP
|
27
28
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp/media_selectors/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp.egg-info/dependency_links.txt
RENAMED
File without changes
|
{media_agent_mcp-0.3.8 → media_agent_mcp-0.3.10}/src/media_agent_mcp.egg-info/entry_points.txt
RENAMED
File without changes
|
File without changes
|