mirror of
https://github.com/imartinez/privateGPT.git
synced 2026-08-08 23:35:29 +00:00
fix: mcp oauth error (#2325)
* fix: rebuild httpx2 exceptions to an controllable exception * fix: avoid to create loop before to control the env * chore: enable verbose * chore: run all tests
This commit is contained in:
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
if: ${{ !startsWith(github.head_ref, 'release-please--branches--') }}
|
||||
env:
|
||||
GIT_TARGET: ${{ github.event_name == 'pull_request' && format('origin/{0}', github.base_ref) || 'HEAD^' }}
|
||||
run: make test-changed PYTEST_ARGS="--git-target $GIT_TARGET --junit-xml=tests-results.xml"
|
||||
run: make test PYTEST_ARGS="--git-target $GIT_TARGET --junit-xml=tests-results.xml"
|
||||
- name: Run full test suite with coverage
|
||||
if: ${{ startsWith(github.head_ref, 'release-please--branches--') }}
|
||||
run: make test-coverage
|
||||
|
||||
2
Makefile
2
Makefile
@@ -20,7 +20,7 @@ WIPE_LOCAL_DATA_DIR := $(WIPE_PGPT_HOME)/local_data
|
||||
|
||||
test:
|
||||
rm -rf "$(TEST_LOCAL_DATA_DIR)"/*
|
||||
PGPT_HOME=$(TEST_PGPT_HOME) PYTHONPATH=. uv run pytest tests $(PYTEST_ARGS)
|
||||
PGPT_HOME=$(TEST_PGPT_HOME) PYTHONPATH=. uv run pytest tests $(PYTEST_ARGS) -v
|
||||
|
||||
test-changed:
|
||||
rm -rf "$(TEST_LOCAL_DATA_DIR)"/*
|
||||
|
||||
@@ -369,12 +369,13 @@ class StatefulBackgroundTask(_BackgroundTask):
|
||||
async def _warm_async(cls) -> None:
|
||||
from private_gpt.eager_loading import warm
|
||||
|
||||
injector = create_loop_injector()
|
||||
profile = os.environ.get("PGPT_WORKER_WARM_PROFILE", "").strip()
|
||||
if not profile:
|
||||
raise ValueError(
|
||||
"PGPT_WORKER_WARM_PROFILE is required for stateful workers"
|
||||
)
|
||||
|
||||
injector = create_loop_injector()
|
||||
warm(injector, profile=profile)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import asyncio
|
||||
|
||||
from httpx import HTTPStatusError
|
||||
import httpx
|
||||
import httpx2
|
||||
from injector import inject, singleton
|
||||
|
||||
from private_gpt.components.chat.models.chat_config_models import (
|
||||
@@ -23,7 +24,7 @@ from private_gpt.server.mcp.mcp_service import McpService, mcp_tool_to_spec
|
||||
|
||||
|
||||
def _extract_original_exception(exc: BaseException) -> BaseException:
|
||||
if isinstance(exc, HTTPStatusError):
|
||||
if isinstance(exc, (httpx.HTTPStatusError, httpx2.HTTPStatusError)):
|
||||
if exc.response.status_code in (401, 403):
|
||||
return PermissionError(
|
||||
f"MCP server rejected the request with HTTP {exc.response.status_code}. "
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import httpx2
|
||||
from mcp import ClientSession, MCPError
|
||||
from mcp.types import (
|
||||
AudioContent,
|
||||
@@ -15,6 +16,7 @@ if TYPE_CHECKING:
|
||||
TextContent,
|
||||
)
|
||||
else:
|
||||
import httpx2
|
||||
from mcp import ClientSession, MCPError
|
||||
from mcp.client.sse import sse_client
|
||||
from mcp.client.stdio import StdioServerParameters, stdio_client
|
||||
@@ -54,6 +56,14 @@ def _prefer_sse(url: str) -> bool:
|
||||
return path.endswith("/sse") or "/sse/" in path
|
||||
|
||||
|
||||
async def _check_auth(url: str, headers: dict[str, Any]) -> None:
|
||||
"""Do a pre-flight POST to detect 401/403 before entering the MCP transport."""
|
||||
async with httpx2.AsyncClient(follow_redirects=True, timeout=10.0) as client:
|
||||
response = await client.post(url, headers=headers, content=b"{}")
|
||||
if response.status_code in (401, 403):
|
||||
response.raise_for_status()
|
||||
|
||||
|
||||
class PersistentMCPClient:
|
||||
"""Native MCP 2.x client with persistent session recovery.
|
||||
|
||||
@@ -107,6 +117,7 @@ class PersistentMCPClient:
|
||||
)
|
||||
)
|
||||
else:
|
||||
await _check_auth(self.command_or_url, self.headers)
|
||||
http_client = create_mcp_http_client()
|
||||
if self.headers:
|
||||
http_client.headers.update(self.headers)
|
||||
@@ -169,6 +180,9 @@ class PersistentMCPClient:
|
||||
)
|
||||
yield session
|
||||
return
|
||||
except httpx2.HTTPStatusError:
|
||||
await self._reset_session()
|
||||
raise
|
||||
except (MCPError, ConnectionError, TimeoutError, OSError) as e:
|
||||
last_exception = e
|
||||
logger.warning(
|
||||
|
||||
Reference in New Issue
Block a user