media-agent-mcp 0.3.9__py3-none-any.whl → 0.3.11__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.
@@ -22,6 +22,27 @@ from typing import List, Optional
22
22
  import json
23
23
  from dotenv import load_dotenv
24
24
  import uvicorn
25
+ from functools import wraps
26
+
27
+ def async_retry(max_retries=3, delay=2):
28
+ def decorator(func):
29
+ @wraps(func)
30
+ async def wrapper(*args, **kwargs):
31
+ for attempt in range(max_retries):
32
+ try:
33
+ result = await func(*args, **kwargs)
34
+ if isinstance(result, dict) and result.get('status') == 'error':
35
+ logger.warning(f"Attempt {attempt + 1} of {max_retries} failed for {func.__name__}. Error: {result.get('message')}. Retrying in {delay}s...")
36
+ await asyncio.sleep(delay)
37
+ continue
38
+ return result
39
+ except Exception as e:
40
+ logger.error(f"Attempt {attempt + 1} of {max_retries} failed for {func.__name__} with exception: {e}. Retrying in {delay}s...")
41
+ await asyncio.sleep(delay)
42
+ logger.error(f"Function {func.__name__} failed after {max_retries} retries.")
43
+ return {"status": "error", "data": None, "message": f"Function {func.__name__} failed after {max_retries} retries."}
44
+ return wrapper
45
+ return decorator
25
46
 
26
47
  from mcp.server.fastmcp import FastMCP
27
48
 
@@ -49,7 +70,8 @@ mcp = FastMCP("Media-Agent-MCP-Async")
49
70
 
50
71
 
51
72
  @mcp.tool()
52
- async def video_concat_tool(video_urls: List[str]) -> str:
73
+ @async_retry()
74
+ async def video_concat_tool(video_urls: List[str]) -> dict:
53
75
  """
54
76
  Asynchronously concatenate multiple videos from URLs and upload to TOS.
55
77
 
@@ -57,13 +79,14 @@ async def video_concat_tool(video_urls: List[str]) -> str:
57
79
  video_urls: List of video URLs to concatenate in order
58
80
 
59
81
  Returns:
60
- JSON string with status, data, and message
82
+ Dictionary with status, data, and message
61
83
  """
62
84
  return await async_video_concat_tool(video_urls)
63
85
 
64
86
 
65
87
  @mcp.tool()
66
- async def video_last_frame_tool(video_url: str) -> str:
88
+ @async_retry()
89
+ async def video_last_frame_tool(video_url: str) -> dict:
67
90
  """
68
91
  Asynchronously extract the last frame from a video file and upload to TOS.
69
92
 
@@ -71,13 +94,14 @@ async def video_last_frame_tool(video_url: str) -> str:
71
94
  video_url: URL or path to the video file
72
95
 
73
96
  Returns:
74
- JSON string with status, data, and message
97
+ Dictionary with status, data, and message
75
98
  """
76
99
  return await async_video_last_frame_tool(video_url)
77
100
 
78
101
 
79
102
  @mcp.tool()
80
- async def seedream_generate_image_tool(prompt: str, size: str = "1024x1024") -> str:
103
+ @async_retry()
104
+ async def seedream_generate_image_tool(prompt: str, size: str = "1024x1024") -> dict:
81
105
  """
82
106
  Asynchronously generate an image using Seedream AI model.
83
107
 
@@ -86,15 +110,16 @@ async def seedream_generate_image_tool(prompt: str, size: str = "1024x1024") ->
86
110
  size: Size of the image (e.g., "1024x1024")
87
111
 
88
112
  Returns:
89
- JSON string with status, data, and message
113
+ Dictionary with status, data, and message
90
114
  """
91
115
  return await async_seedream_generate_image_tool(prompt, size)
92
116
 
93
117
 
94
118
  @mcp.tool()
119
+ @async_retry()
95
120
  async def seedance_generate_video_tool(prompt: str, first_frame_image: str,
96
121
  last_frame_image: str = None, duration: int = 5,
97
- resolution: str = "720p") -> str:
122
+ resolution: str = "720p") -> dict:
98
123
  """
99
124
  Asynchronously generate a video using Seedance AI model with first/last frame images.
100
125
 
@@ -106,14 +131,15 @@ async def seedance_generate_video_tool(prompt: str, first_frame_image: str,
106
131
  resolution: Video resolution (480p, 720p)
107
132
 
108
133
  Returns:
109
- JSON string with status, data, and message
134
+ Dictionary with status, data, and message
110
135
  """
111
136
  return await async_seedance_generate_video_tool(prompt, first_frame_image, last_frame_image, duration, resolution)
112
137
 
113
138
 
114
139
  @mcp.tool()
140
+ @async_retry()
115
141
  async def seededit_tool(image_url: str, prompt: str, seed: int = -1,
116
- scale: float = 0.5, charactor_keep: bool = False) -> str:
142
+ scale: float = 0.5, charactor_keep: bool = False) -> dict:
117
143
  """
118
144
  Asynchronously edit an image using Seededit model.
119
145
 
@@ -125,13 +151,14 @@ async def seededit_tool(image_url: str, prompt: str, seed: int = -1,
125
151
  charactor_keep: whether to keep the main character in this image, if you wanna change the main character, please keep False
126
152
 
127
153
  Returns:
128
- JSON string with status, data, and message
154
+ Dictionary with status, data, and message
129
155
  """
130
156
  return await async_seededit_tool(image_url, prompt, seed, scale, charactor_keep)
131
157
 
132
158
 
133
159
  @mcp.tool()
134
- async def vlm_vision_task_tool(messages: List) -> str:
160
+ @async_retry()
161
+ async def vlm_vision_task_tool(messages: List) -> dict:
135
162
  """
136
163
  Asynchronously perform vision-language tasks using VLM model.
137
164
 
@@ -139,13 +166,14 @@ async def vlm_vision_task_tool(messages: List) -> str:
139
166
  messages: OpenAI-compatible messages format
140
167
 
141
168
  Returns:
142
- JSON string with status, data, and message
169
+ Dictionary with status, data, and message
143
170
  """
144
171
  return await async_vlm_vision_task_tool(messages)
145
172
 
146
173
 
147
174
  @mcp.tool()
148
- async def image_selector_tool(image_paths: List[str], prompt: str) -> str:
175
+ @async_retry()
176
+ async def image_selector_tool(image_paths: List[str], prompt: str) -> dict:
149
177
  """
150
178
  Asynchronously select the best image from multiple options using VLM model.
151
179
 
@@ -154,13 +182,14 @@ async def image_selector_tool(image_paths: List[str], prompt: str) -> str:
154
182
  prompt: Selection criteria prompt
155
183
 
156
184
  Returns:
157
- JSON string with status, data, and message
185
+ Dictionary with status, data, and message
158
186
  """
159
187
  return await async_image_selector_tool(image_paths, prompt)
160
188
 
161
189
 
162
190
  @mcp.tool()
163
- async def video_selector_tool(video_paths: List[str], prompt: str) -> str:
191
+ @async_retry()
192
+ async def video_selector_tool(video_paths: List[str], prompt: str) -> dict:
164
193
  """
165
194
  Asynchronously select the best video from multiple options using VLM model.
166
195
 
@@ -169,14 +198,15 @@ async def video_selector_tool(video_paths: List[str], prompt: str) -> str:
169
198
  prompt: Selection criteria prompt
170
199
 
171
200
  Returns:
172
- JSON string with status, data, and message
201
+ Dictionary with status, data, and message
173
202
  """
174
203
  return await async_video_selector_tool(video_paths, prompt)
175
204
 
176
205
 
177
206
  @mcp.tool()
207
+ @async_retry()
178
208
  async def tos_save_content_tool(content: str, file_extension: str = "txt",
179
- object_key: Optional[str] = None) -> str:
209
+ object_key: Optional[str] = None) -> dict:
180
210
  """
181
211
  Asynchronously save content to TOS and return URL.
182
212
 
@@ -186,7 +216,7 @@ async def tos_save_content_tool(content: str, file_extension: str = "txt",
186
216
  object_key: Optional key to use for the object in TOS
187
217
 
188
218
  Returns:
189
- JSON string with status, data, and message
219
+ Dictionary with status, data, and message
190
220
  """
191
221
  return await async_tos_save_content_tool(content, file_extension, object_key)
192
222
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: media-agent-mcp
3
- Version: 0.3.9
3
+ Version: 0.3.11
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
@@ -1,5 +1,5 @@
1
1
  media_agent_mcp/__init__.py,sha256=4kV5u8kHrsdjpMHDNUhc8h4U6AwOyw1mNptFPd2snrQ,365
2
- media_agent_mcp/async_server.py,sha256=QYOcX0X3vFJ4elOwb1FzFItHC9YVpjA9DCg9CBanSiw,9238
2
+ media_agent_mcp/async_server.py,sha256=IpXezeefilGukutgBqOU7RvCDp-t9_j11A2OOqiu2z0,10524
3
3
  media_agent_mcp/async_wrapper.py,sha256=bHi0cCKxv6R9oHcNcNq8tV0AyKrTDV47s8BuWetqlIg,8992
4
4
  media_agent_mcp/server.py,sha256=-mTeNcJXIlgByCG2HhaqV6zSbhjrQIEv_ssLN47KAzM,13759
5
5
  media_agent_mcp/ai_models/__init__.py,sha256=WN8JDSJbj2-sNwaQg3MDwmm9mvJTC1mqpWliac3sHoc,427
@@ -14,8 +14,8 @@ media_agent_mcp/storage/__init__.py,sha256=eio7ZiSeLjCxICSZwZisiR7wKJfXlT2PV7aDE
14
14
  media_agent_mcp/storage/tos_client.py,sha256=9c3GPmQe2stvxgZzsWYjVqKzVyvluZqYneCXYj-FQ3M,3174
15
15
  media_agent_mcp/video/__init__.py,sha256=4ILnqYaUaYKI4GWOSg2SNZqt10UM1Y-8Q2SVvjoijqY,277
16
16
  media_agent_mcp/video/processor.py,sha256=5ABPyj1IoD2xyIiB8dkEx4ZssPTXKHtuoFjy-dmnFks,11866
17
- media_agent_mcp-0.3.9.dist-info/METADATA,sha256=HgLx9BJINu6TANDbAZT4qX4adNFegiJDR6BYqm9OwSM,10975
18
- media_agent_mcp-0.3.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
- media_agent_mcp-0.3.9.dist-info/entry_points.txt,sha256=qhOUwR-ORVf9GO7emhhl7Lgd6MISgqbZr8bEuSH_VdA,70
20
- media_agent_mcp-0.3.9.dist-info/top_level.txt,sha256=WEa0YfchpTxZgiKn8gdxYgs-dir5HepJaTOrxAGx9nY,16
21
- media_agent_mcp-0.3.9.dist-info/RECORD,,
17
+ media_agent_mcp-0.3.11.dist-info/METADATA,sha256=92jf-Ti8koiMfQqYbpcFNwNVQ4sntuCz0XrRTnBe0rI,10976
18
+ media_agent_mcp-0.3.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ media_agent_mcp-0.3.11.dist-info/entry_points.txt,sha256=qhOUwR-ORVf9GO7emhhl7Lgd6MISgqbZr8bEuSH_VdA,70
20
+ media_agent_mcp-0.3.11.dist-info/top_level.txt,sha256=WEa0YfchpTxZgiKn8gdxYgs-dir5HepJaTOrxAGx9nY,16
21
+ media_agent_mcp-0.3.11.dist-info/RECORD,,