test: Fix oauth2 token extract from starlette requests

This commit is contained in:
Chris Coutinho
2025-10-13 18:07:58 +02:00
parent b3b7c90bd0
commit f58a9883a6
3 changed files with 32 additions and 11 deletions
+13 -3
View File
@@ -30,9 +30,19 @@ def get_client_from_context(ctx: Context, base_url: str) -> NextcloudClient:
ValueError: If username cannot be extracted from token
"""
try:
logger.info(f"Inspecting session object: {dir(ctx.request_context.session)}")
# Get AccessToken from MCP session (set by TokenVerifier)
access_token: AccessToken = ctx.request_context.session.access_token
# In Starlette with FastMCP OAuth, the authenticated user info is stored in request.user
# The FastMCP auth middleware sets request.user to an AuthenticatedUser object
# which contains the access_token
if hasattr(ctx.request_context.request, "user") and hasattr(
ctx.request_context.request.user, "access_token"
):
access_token: AccessToken = ctx.request_context.request.user.access_token
logger.debug("Retrieved access token from request.user for OAuth request")
else:
logger.error(
"OAuth authentication failed: No access token found in request"
)
raise AttributeError("No access token found in OAuth request context")
# Extract username from resource field (RFC 8707)
# We stored the username here during token verification
+10 -3
View File
@@ -136,13 +136,20 @@ async def nc_mcp_client() -> AsyncGenerator[ClientSession, Any]:
@pytest.fixture(scope="session")
async def nc_mcp_oauth_client() -> AsyncGenerator[ClientSession, Any]:
async def nc_mcp_oauth_client(
interactive_oauth_token: str,
) -> AsyncGenerator[ClientSession, Any]:
"""
Fixture to create an MCP client session for OAuth integration tests using streamable-http.
Connects to the OAuth-enabled MCP server on port 8001.
Connects to the OAuth-enabled MCP server on port 8001 with OAuth authentication.
"""
logger.info("Creating Streamable HTTP client for OAuth MCP server")
streamable_context = streamablehttp_client("http://127.0.0.1:8001/mcp")
# Pass OAuth token as Bearer token in headers
headers = {"Authorization": f"Bearer {interactive_oauth_token}"}
streamable_context = streamablehttp_client(
"http://127.0.0.1:8001/mcp", headers=headers
)
session_context = None
try:
+9 -5
View File
@@ -119,15 +119,19 @@ async def test_mcp_oauth_tool_execution(nc_mcp_oauth_client):
"""Test executing a tool on the OAuth-enabled MCP server."""
import json
# Example: Execute the 'nc_tables_list_tables' tool
result = await nc_mcp_oauth_client.call_tool("nc_tables_list_tables")
# Example: Execute the 'nc_notes_search_notes' tool
result = await nc_mcp_oauth_client.call_tool(
"nc_notes_search_notes", arguments={"query": ""}
)
assert result.isError is False, f"Tool execution failed: {result.content}"
assert result.content is not None
notes_list = json.loads(result.content[0].text)
response_data = json.loads(result.content[0].text)
assert isinstance(notes_list, list)
# The search response should have a 'results' field containing the list
assert "results" in response_data
assert isinstance(response_data["results"], list)
logger.info(
f"Successfully executed 'nc_tables_list_tables' tool on OAuth MCP server and got {len(notes_list)} notes."
f"Successfully executed 'nc_notes_search_notes' tool on OAuth MCP server and got {len(response_data['results'])} notes."
)