diff --git a/autogpt_platform/backend/backend/blocks/mcp/block.py b/autogpt_platform/backend/backend/blocks/mcp/block.py index 3369d75d19..5620864e01 100644 --- a/autogpt_platform/backend/backend/blocks/mcp/block.py +++ b/autogpt_platform/backend/backend/blocks/mcp/block.py @@ -129,9 +129,7 @@ class MCPToolBlock(Block): return validate_with_jsonschema(tool_schema, tool_arguments) class Output(BlockSchemaOutput): - result: Any = SchemaField( - description="The result returned by the MCP tool" - ) + result: Any = SchemaField(description="The result returned by the MCP tool") error: str = SchemaField(description="Error message if the tool call failed") def __init__(self): diff --git a/autogpt_platform/backend/backend/blocks/mcp/client.py b/autogpt_platform/backend/backend/blocks/mcp/client.py index ef6eb98128..0d7860132e 100644 --- a/autogpt_platform/backend/backend/blocks/mcp/client.py +++ b/autogpt_platform/backend/backend/blocks/mcp/client.py @@ -229,9 +229,7 @@ class MCPClient: # Try standard metadata endpoints (RFC 8414 and OpenID Connect) candidates = [] if path and path != "/": - candidates.append( - f"{base}/.well-known/oauth-authorization-server{path}" - ) + candidates.append(f"{base}/.well-known/oauth-authorization-server{path}") candidates.append(f"{base}/.well-known/oauth-authorization-server") candidates.append(f"{base}/.well-known/openid-configuration") diff --git a/autogpt_platform/backend/backend/blocks/mcp/oauth.py b/autogpt_platform/backend/backend/blocks/mcp/oauth.py index 1f5755d0c4..72c6cd39b2 100644 --- a/autogpt_platform/backend/backend/blocks/mcp/oauth.py +++ b/autogpt_platform/backend/backend/blocks/mcp/oauth.py @@ -14,8 +14,8 @@ from typing import ClassVar, Optional from pydantic import SecretStr from backend.data.model import OAuth2Credentials -from backend.integrations.providers import ProviderName from backend.integrations.oauth.base import BaseOAuthHandler +from backend.integrations.providers import ProviderName from backend.util.request import Requests logger = logging.getLogger(__name__) diff --git a/autogpt_platform/backend/backend/blocks/mcp/test_mcp.py b/autogpt_platform/backend/backend/blocks/mcp/test_mcp.py index dc532e86e6..e256a05e70 100644 --- a/autogpt_platform/backend/backend/blocks/mcp/test_mcp.py +++ b/autogpt_platform/backend/backend/blocks/mcp/test_mcp.py @@ -8,7 +8,11 @@ from unittest.mock import AsyncMock, patch import pytest from pydantic import SecretStr -from backend.blocks.mcp.block import MCPToolBlock, TEST_CREDENTIALS, TEST_CREDENTIALS_INPUT +from backend.blocks.mcp.block import ( + TEST_CREDENTIALS, + TEST_CREDENTIALS_INPUT, + MCPToolBlock, +) from backend.blocks.mcp.client import MCPCallResult, MCPClient, MCPClientError from backend.data.model import APIKeyCredentials, OAuth2Credentials from backend.util.test import execute_block_test @@ -257,9 +261,7 @@ class TestMCPClient: } with ( - patch.object( - client, "_send_request", return_value=mock_result - ) as mock_req, + patch.object(client, "_send_request", return_value=mock_result) as mock_req, patch.object(client, "_send_notification") as mock_notif, ): result = await client.initialize() @@ -357,9 +359,7 @@ class TestMCPToolBlock: credentials=TEST_CREDENTIALS_INPUT, # type: ignore ) outputs = [] - async for name, data in block.run( - input_data, credentials=TEST_CREDENTIALS - ): + async for name, data in block.run(input_data, credentials=TEST_CREDENTIALS): outputs.append((name, data)) assert outputs == [("error", "MCP server URL is required")] @@ -372,9 +372,7 @@ class TestMCPToolBlock: credentials=TEST_CREDENTIALS_INPUT, # type: ignore ) outputs = [] - async for name, data in block.run( - input_data, credentials=TEST_CREDENTIALS - ): + async for name, data in block.run(input_data, credentials=TEST_CREDENTIALS): outputs.append((name, data)) assert outputs == [ ("error", "No tool selected. Please select a tool from the dropdown.") @@ -400,9 +398,7 @@ class TestMCPToolBlock: block._call_mcp_tool = mock_call # type: ignore outputs = [] - async for name, data in block.run( - input_data, credentials=TEST_CREDENTIALS - ): + async for name, data in block.run(input_data, credentials=TEST_CREDENTIALS): outputs.append((name, data)) assert len(outputs) == 1 @@ -424,9 +420,7 @@ class TestMCPToolBlock: block._call_mcp_tool = mock_call # type: ignore outputs = [] - async for name, data in block.run( - input_data, credentials=TEST_CREDENTIALS - ): + async for name, data in block.run(input_data, credentials=TEST_CREDENTIALS): outputs.append((name, data)) assert outputs[0][0] == "error" @@ -534,9 +528,7 @@ class TestMCPToolBlock: patch.object(MCPClient, "call_tool", mock_call), ): with pytest.raises(MCPClientError, match="returned an error"): - await block._call_mcp_tool( - "https://mcp.example.com", "test_tool", {} - ) + await block._call_mcp_tool("https://mcp.example.com", "test_tool", {}) @pytest.mark.asyncio async def test_call_mcp_tool_image_content(self): @@ -612,25 +604,31 @@ class TestMCPOAuth2Support: def test_extract_auth_token_from_api_key(self): creds = APIKeyCredentials( - id="test", provider="mcp", - api_key=SecretStr("my-api-key"), title="test", + id="test", + provider="mcp", + api_key=SecretStr("my-api-key"), + title="test", ) token = MCPToolBlock._extract_auth_token(creds) assert token == "my-api-key" def test_extract_auth_token_from_oauth2(self): creds = OAuth2Credentials( - id="test", provider="mcp", + id="test", + provider="mcp", access_token=SecretStr("oauth2-access-token"), - scopes=["read"], title="test", + scopes=["read"], + title="test", ) token = MCPToolBlock._extract_auth_token(creds) assert token == "oauth2-access-token" def test_extract_auth_token_empty_skipped(self): creds = APIKeyCredentials( - id="test", provider="mcp", - api_key=SecretStr(""), title="test", + id="test", + provider="mcp", + api_key=SecretStr(""), + title="test", ) token = MCPToolBlock._extract_auth_token(creds) assert token is None @@ -646,9 +644,11 @@ class TestMCPOAuth2Support: ) oauth2_creds = OAuth2Credentials( - id="test-id", provider="mcp", + id="test-id", + provider="mcp", access_token=SecretStr("real-oauth2-token"), - scopes=["read", "write"], title="MCP OAuth", + scopes=["read", "write"], + title="MCP OAuth", ) captured_tokens = [] diff --git a/autogpt_platform/backend/backend/blocks/mcp/test_server.py b/autogpt_platform/backend/backend/blocks/mcp/test_server.py index a6861681ec..a6732932bc 100644 --- a/autogpt_platform/backend/backend/blocks/mcp/test_server.py +++ b/autogpt_platform/backend/backend/blocks/mcp/test_server.py @@ -7,6 +7,7 @@ with a few sample tools. Runs on localhost with a random available port. import json import logging + from aiohttp import web logger = logging.getLogger(__name__) @@ -149,9 +150,7 @@ async def handle_mcp_request(request: web.Request) -> web.Response: ) result = handler(params) - return web.json_response( - {"jsonrpc": "2.0", "result": result, "id": request_id} - ) + return web.json_response({"jsonrpc": "2.0", "result": result, "id": request_id}) def create_test_mcp_app(auth_token: str | None = None) -> web.Application: