media-agent-mcp 2.6.13__py3-none-any.whl → 2.6.14__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.
- media_agent_mcp/async_server.py +24 -72
- {media_agent_mcp-2.6.13.dist-info → media_agent_mcp-2.6.14.dist-info}/METADATA +1 -1
- {media_agent_mcp-2.6.13.dist-info → media_agent_mcp-2.6.14.dist-info}/RECORD +6 -6
- {media_agent_mcp-2.6.13.dist-info → media_agent_mcp-2.6.14.dist-info}/WHEEL +0 -0
- {media_agent_mcp-2.6.13.dist-info → media_agent_mcp-2.6.14.dist-info}/entry_points.txt +0 -0
- {media_agent_mcp-2.6.13.dist-info → media_agent_mcp-2.6.14.dist-info}/top_level.txt +0 -0
media_agent_mcp/async_server.py
CHANGED
@@ -163,15 +163,15 @@ class SessionManager:
|
|
163
163
|
"""Get session object by ID."""
|
164
164
|
return self._sessions.get(session_id)
|
165
165
|
|
166
|
-
def remove_session(self, session_id: str):
|
166
|
+
def remove_session(self, session_id: str, remove_route_mapping: bool = True):
|
167
167
|
"""Remove a session."""
|
168
168
|
if session_id in self._sessions:
|
169
169
|
del self._sessions[session_id]
|
170
|
-
if session_id in self._session_routes:
|
170
|
+
if remove_route_mapping and session_id in self._session_routes:
|
171
171
|
del self._session_routes[session_id]
|
172
172
|
if session_id in self._session_timestamps:
|
173
173
|
del self._session_timestamps[session_id]
|
174
|
-
logger.info(f"Removed session: {session_id}")
|
174
|
+
logger.info(f"Removed session: {session_id} (route_mapping_removed: {remove_route_mapping})")
|
175
175
|
|
176
176
|
def cleanup_expired_sessions(self, max_age_seconds: int = 3600):
|
177
177
|
"""Clean up sessions older than max_age_seconds."""
|
@@ -209,70 +209,25 @@ class SessionManager:
|
|
209
209
|
# Global session manager
|
210
210
|
session_manager = SessionManager()
|
211
211
|
|
212
|
-
|
213
|
-
"""
|
212
|
+
def _extract_session_id_from_url(url: str) -> Optional[str]:
|
213
|
+
"""Extract session_id from URL."""
|
214
|
+
import re
|
215
|
+
from urllib.parse import urlparse, parse_qs
|
214
216
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
session_manager.add_route_mapping(session_id, new_session_id)
|
230
|
-
|
231
|
-
# Remove old session
|
232
|
-
session_manager.remove_session(session_id)
|
233
|
-
|
234
|
-
logger.info(f"Auto-generated new session {new_session_id} to replace expired session {session_id}")
|
235
|
-
|
236
|
-
# Create a JSON response with new session information
|
237
|
-
new_url = str(request.url).replace(f"session_id={session_id}", f"session_id={new_session_id}")
|
238
|
-
|
239
|
-
from starlette.responses import JSONResponse
|
240
|
-
return JSONResponse(
|
241
|
-
status_code=410, # Gone - indicates the resource is no longer available
|
242
|
-
content={
|
243
|
-
"error": "session_expired",
|
244
|
-
"message": "Session expired, please use the new session ID",
|
245
|
-
"old_session_id": session_id,
|
246
|
-
"new_session_id": new_session_id,
|
247
|
-
"redirect_url": new_url
|
248
|
-
}
|
249
|
-
)
|
250
|
-
|
251
|
-
# If no session_id found, re-raise the error
|
252
|
-
raise e
|
253
|
-
except Exception as e:
|
254
|
-
logger.error(f"Unexpected error in middleware: {e}")
|
255
|
-
raise e
|
256
|
-
|
257
|
-
def _extract_session_id(self, request: Request) -> Optional[str]:
|
258
|
-
"""Extract session_id from request URL or headers."""
|
259
|
-
# Try to get from query parameters
|
260
|
-
session_id = request.query_params.get('session_id')
|
261
|
-
if session_id:
|
262
|
-
return session_id
|
263
|
-
|
264
|
-
# Try to get from path parameters
|
265
|
-
if hasattr(request, 'path_params') and 'session_id' in request.path_params:
|
266
|
-
return request.path_params['session_id']
|
267
|
-
|
268
|
-
# Try to extract from URL path
|
269
|
-
import re
|
270
|
-
path = str(request.url.path)
|
271
|
-
match = re.search(r'session_id=([a-f0-9]+)', str(request.url))
|
272
|
-
if match:
|
273
|
-
return match.group(1)
|
274
|
-
|
275
|
-
return None
|
217
|
+
# Parse the URL
|
218
|
+
parsed = urlparse(url)
|
219
|
+
|
220
|
+
# Try to get from query parameters
|
221
|
+
query_params = parse_qs(parsed.query)
|
222
|
+
if 'session_id' in query_params:
|
223
|
+
return query_params['session_id'][0]
|
224
|
+
|
225
|
+
# Try to extract from URL path using regex
|
226
|
+
match = re.search(r'session_id=([a-f0-9]+)', url)
|
227
|
+
if match:
|
228
|
+
return match.group(1)
|
229
|
+
|
230
|
+
return None
|
276
231
|
|
277
232
|
# Global exception handler for ClosedResourceError
|
278
233
|
async def handle_closed_resource_error(request, exc):
|
@@ -288,7 +243,7 @@ async def handle_closed_resource_error(request, exc):
|
|
288
243
|
# Generate new session ID
|
289
244
|
new_session_id = session_manager.generate_session_id()
|
290
245
|
session_manager.add_route_mapping(session_id, new_session_id)
|
291
|
-
session_manager.remove_session(session_id)
|
246
|
+
session_manager.remove_session(session_id, remove_route_mapping=False)
|
292
247
|
|
293
248
|
logger.info(f"Global handler: Generated new session {new_session_id} to replace {session_id}")
|
294
249
|
|
@@ -834,16 +789,13 @@ def main():
|
|
834
789
|
mcp.settings.host = args.host
|
835
790
|
mcp.settings.port = args.port
|
836
791
|
|
837
|
-
# Get the SSE app and add
|
792
|
+
# Get the SSE app and add global exception handler
|
838
793
|
sse_app = mcp.sse_app()
|
839
794
|
|
840
|
-
# Add session error handling middleware
|
841
|
-
sse_app.add_middleware(SessionErrorHandlingMiddleware)
|
842
|
-
|
843
795
|
# Add global exception handler for ClosedResourceError
|
844
796
|
sse_app.add_exception_handler(anyio.ClosedResourceError, handle_closed_resource_error)
|
845
797
|
|
846
|
-
logger.info("Added
|
798
|
+
logger.info("Added global ClosedResourceError handler for automatic session recovery")
|
847
799
|
|
848
800
|
# Use uvicorn to run SSE app with extended keep-alive timeout (5 minutes)
|
849
801
|
uvicorn.run(
|
@@ -1,5 +1,5 @@
|
|
1
1
|
media_agent_mcp/__init__.py,sha256=4GfH0flV1CGHefl-eNXt-Gidk7aDXA6Jlh2uVDOXGSo,312
|
2
|
-
media_agent_mcp/async_server.py,sha256=
|
2
|
+
media_agent_mcp/async_server.py,sha256=3y1Xse4lavfzuNKUD9AU-REzhlAc3Po42GNn2el6Pn8,31091
|
3
3
|
media_agent_mcp/async_wrapper.py,sha256=hiiBhhz9WeVDfSBWVh6ovhf5jeP5ZbsieBbz9P-KPn0,15351
|
4
4
|
media_agent_mcp/ai_models/__init__.py,sha256=2kHzTYwjQw89U4QGDq0e2WqJScqDkDNlDaWHGak5JeY,553
|
5
5
|
media_agent_mcp/ai_models/omni_human.py,sha256=s_Ja4gEmHG_bgii1x4SoeV73lz0Zg_3iBRvu36goxVA,4643
|
@@ -43,8 +43,8 @@ media_agent_mcp/video/__init__.py,sha256=tfz22XEeFSeuKa3AggYCE0vCDt4IwXRCKW6avof
|
|
43
43
|
media_agent_mcp/video/processor.py,sha256=twfqmN5DbVryjDawZUcqTUcnglcBJYpUbAnApqHgD0c,12787
|
44
44
|
media_agent_mcp/video/stack.py,sha256=pyoJiJ9NhU1tjy2l3kARI9sWFoC00Fj97psxYOBi2NU,1736
|
45
45
|
media_agent_mcp/video/subtitle.py,sha256=TlrWVhWJqYTUJpnVz7eccwMAn8ixfrRzRxS6ETMY-DM,16323
|
46
|
-
media_agent_mcp-2.6.
|
47
|
-
media_agent_mcp-2.6.
|
48
|
-
media_agent_mcp-2.6.
|
49
|
-
media_agent_mcp-2.6.
|
50
|
-
media_agent_mcp-2.6.
|
46
|
+
media_agent_mcp-2.6.14.dist-info/METADATA,sha256=OrIMFu2iuILwbJ2sjRQp15v4Qm0_MnutbD7ocHDf5CU,11306
|
47
|
+
media_agent_mcp-2.6.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
48
|
+
media_agent_mcp-2.6.14.dist-info/entry_points.txt,sha256=qhOUwR-ORVf9GO7emhhl7Lgd6MISgqbZr8bEuSH_VdA,70
|
49
|
+
media_agent_mcp-2.6.14.dist-info/top_level.txt,sha256=WEa0YfchpTxZgiKn8gdxYgs-dir5HepJaTOrxAGx9nY,16
|
50
|
+
media_agent_mcp-2.6.14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|