mirror of
https://github.com/GH05TCREW/pentestagent.git
synced 2026-03-07 22:33:38 +00:00
mcp: wait/attempt discovery of POST messages endpoint before POST to avoid 405
This commit is contained in:
@@ -229,6 +229,15 @@ class SSETransport(MCPTransport):
|
||||
if not self.session:
|
||||
raise RuntimeError("Transport not connected")
|
||||
|
||||
# Ensure we have a POST endpoint. If discovery hasn't completed yet,
|
||||
# try a quick synchronous discovery attempt before posting so we don't
|
||||
# accidentally POST to the SSE listen endpoint which returns 405.
|
||||
if not self._post_url:
|
||||
try:
|
||||
await self._discover_post_url(timeout=2.0)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
post_target = self._post_url or self.url
|
||||
|
||||
try:
|
||||
@@ -258,6 +267,44 @@ class SSETransport(MCPTransport):
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"SSE request failed: {e}") from e
|
||||
|
||||
async def _discover_post_url(self, timeout: float = 2.0) -> None:
|
||||
"""Attempt a short GET to the SSE endpoint to find the advertised POST URL.
|
||||
|
||||
This is a fallback used when the background listener hasn't yet
|
||||
extracted the `endpoint` event. It reads a few lines with a short
|
||||
timeout and sets `self._post_url` if found.
|
||||
"""
|
||||
if not self.session:
|
||||
return
|
||||
|
||||
try:
|
||||
async with self.session.get(self.url, timeout=timeout) as resp:
|
||||
if resp.status != 200:
|
||||
return
|
||||
# Read up to a few lines looking for `data:`
|
||||
for _ in range(20):
|
||||
line = await resp.content.readline()
|
||||
if not line:
|
||||
break
|
||||
try:
|
||||
text = line.decode(errors="ignore").strip()
|
||||
except Exception:
|
||||
continue
|
||||
if text.startswith("data:"):
|
||||
endpoint = text.split("data:", 1)[1].strip()
|
||||
from urllib.parse import urlparse
|
||||
|
||||
p = urlparse(self.url)
|
||||
if endpoint.startswith("http"):
|
||||
self._post_url = endpoint
|
||||
elif endpoint.startswith("/"):
|
||||
self._post_url = f"{p.scheme}://{p.netloc}{endpoint}"
|
||||
else:
|
||||
self._post_url = f"{p.scheme}://{p.netloc}/{endpoint.lstrip('/')}"
|
||||
return
|
||||
except Exception:
|
||||
return
|
||||
|
||||
async def disconnect(self):
|
||||
"""Close the HTTP session."""
|
||||
# Cancel listener and close SSE response
|
||||
|
||||
Reference in New Issue
Block a user