diff --git a/src/aws_mcp_proxy/__init__.py b/aws_mcp_proxy/__init__.py similarity index 100% rename from src/aws_mcp_proxy/__init__.py rename to aws_mcp_proxy/__init__.py diff --git a/src/aws_mcp_proxy/logging_config.py b/aws_mcp_proxy/logging_config.py similarity index 100% rename from src/aws_mcp_proxy/logging_config.py rename to aws_mcp_proxy/logging_config.py diff --git a/src/aws_mcp_proxy/mcp_proxy_manager.py b/aws_mcp_proxy/mcp_proxy_manager.py similarity index 100% rename from src/aws_mcp_proxy/mcp_proxy_manager.py rename to aws_mcp_proxy/mcp_proxy_manager.py diff --git a/src/aws_mcp_proxy/server.py b/aws_mcp_proxy/server.py similarity index 91% rename from src/aws_mcp_proxy/server.py rename to aws_mcp_proxy/server.py index 0dd0a5f..059e025 100644 --- a/src/aws_mcp_proxy/server.py +++ b/aws_mcp_proxy/server.py @@ -26,14 +26,14 @@ import asyncio import logging import os -from fastmcp.server.server import FastMCP -from src.aws_mcp_proxy.logging_config import configure_logging -from src.aws_mcp_proxy.mcp_proxy_manager import McpProxyManager -from src.aws_mcp_proxy.utils import ( +from aws_mcp_proxy.logging_config import configure_logging +from aws_mcp_proxy.mcp_proxy_manager import McpProxyManager +from aws_mcp_proxy.utils import ( create_transport_with_sigv4, determine_service_name, normalize_endpoint_url, ) +from fastmcp.server.server import FastMCP from typing import Any @@ -79,13 +79,13 @@ def parse_args(): epilog=""" Examples: # Run with EKS MCP endpoint - src.aws-mcp-proxy --endpoint https://eks-mcp.us-west-2.api.aws + aws-mcp-proxy --endpoint https://eks-mcp.us-west-2.api.aws # Run with custom service and profile - src.aws-mcp-proxy --endpoint https://eks-mcp.us-west-2.api.aws --service eks-mcp --profile default + aws-mcp-proxy --endpoint https://eks-mcp.us-west-2.api.aws --service eks-mcp --profile default # Run with write permissions enabled - src.aws-mcp-proxy --endpoint https://eks-mcp.us-west-2.api.aws --allow-write + aws-mcp-proxy --endpoint https://eks-mcp.us-west-2.api.aws --allow-write """, ) diff --git a/src/aws_mcp_proxy/sigv4_helper.py b/aws_mcp_proxy/sigv4_helper.py similarity index 100% rename from src/aws_mcp_proxy/sigv4_helper.py rename to aws_mcp_proxy/sigv4_helper.py diff --git a/src/aws_mcp_proxy/utils.py b/aws_mcp_proxy/utils.py similarity index 97% rename from src/aws_mcp_proxy/utils.py rename to aws_mcp_proxy/utils.py index f484f32..9dc21ab 100644 --- a/src/aws_mcp_proxy/utils.py +++ b/aws_mcp_proxy/utils.py @@ -16,8 +16,8 @@ import httpx import re +from aws_mcp_proxy.sigv4_helper import create_sigv4_client from fastmcp.client.transports import StreamableHttpTransport -from src.aws_mcp_proxy.sigv4_helper import create_sigv4_client from typing import Dict, Optional from urllib.parse import urlparse diff --git a/pyproject.toml b/pyproject.toml index 3e4bbcb..a632b17 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ repository = "https://github.com/aws/aws-mcp-proxy.git" changelog = "https://github.com/aws/aws-mcp-proxy/blob/main/src/aws-mcp-proxy/CHANGELOG.md" [project.scripts] -"aws-mcp-proxy" = "src.aws_mcp_proxy.server:main" +"aws-mcp-proxy" = "aws_mcp_proxy.server:main" [dependency-groups] dev = [ @@ -118,7 +118,7 @@ line-ending = "auto" docstring-code-format = true [tool.pyright] -include = ["src", "tests"] +include = ["aws_mcp_proxy", "tests"] exclude = ["**/__pycache__", "**/.venv", "**/node_modules", "**/dist", "**/build"] [tool.commitizen] @@ -127,12 +127,12 @@ version = "0.0.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", - "src/aws_mcp_proxy/__init__.py:__version__" + "aws_mcp_proxy/__init__.py:__version__" ] update_changelog_on_bump = true [tool.hatch.build.targets.wheel] -packages = ["src"] +packages = ["aws_mcp_proxy"] [tool.bandit] exclude_dirs = ["venv", ".venv", "tests"] @@ -155,4 +155,4 @@ exclude_also = [ ] [tool.coverage.run] -source = ["src"] +source = ["aws_mcp_proxy"] diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index b6fbc42..0000000 --- a/src/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This file is part of the src namespace. -# It is intentionally minimal to support PEP 420 namespace packages. diff --git a/tests/test_init.py b/tests/test_init.py index e8fe978..513eaeb 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -24,30 +24,30 @@ class TestInit: def test_version(self): """Test that __version__ is defined and follows semantic versioning.""" # Import the module - import src.aws_mcp_proxy + import aws_mcp_proxy # Check that __version__ is defined - assert hasattr(src.aws_mcp_proxy, '__version__') + assert hasattr(aws_mcp_proxy, '__version__') # Check that __version__ is a string - assert isinstance(src.aws_mcp_proxy.__version__, str) + assert isinstance(aws_mcp_proxy.__version__, str) # Check that __version__ follows semantic versioning (major.minor.patch) version_pattern = r'^\d+\.\d+\.\d+$' - assert re.match(version_pattern, src.aws_mcp_proxy.__version__), ( - f"Version '{src.aws_mcp_proxy.__version__}' does not follow semantic versioning" + assert re.match(version_pattern, aws_mcp_proxy.__version__), ( + f"Version '{aws_mcp_proxy.__version__}' does not follow semantic versioning" ) def test_module_reload(self): """Test that the module can be reloaded.""" # Import the module - import src.aws_mcp_proxy + import aws_mcp_proxy # Store the original version - original_version = src.aws_mcp_proxy.__version__ + original_version = aws_mcp_proxy.__version__ # Reload the module - importlib.reload(src.aws_mcp_proxy) + importlib.reload(aws_mcp_proxy) # Check that the version is still the same - assert src.aws_mcp_proxy.__version__ == original_version + assert aws_mcp_proxy.__version__ == original_version diff --git a/tests/test_logging_config.py b/tests/test_logging_config.py index e46ae03..35f20d8 100644 --- a/tests/test_logging_config.py +++ b/tests/test_logging_config.py @@ -16,7 +16,7 @@ import logging import pytest -from src.aws_mcp_proxy.logging_config import configure_logging +from aws_mcp_proxy.logging_config import configure_logging def test_configure_logging_default_level(): diff --git a/tests/test_main.py b/tests/test_main.py index c8bb039..af5741a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -14,17 +14,17 @@ """Tests for the main function in server.py.""" -from src.aws_mcp_proxy.server import main +from aws_mcp_proxy.server import main from unittest.mock import AsyncMock, Mock, patch class TestMain: """Tests for the main function.""" - @patch('src.aws_mcp_proxy.server.asyncio.run') - @patch('src.aws_mcp_proxy.server.setup_mcp_mode') - @patch('src.aws_mcp_proxy.server.FastMCP') - @patch('sys.argv', ['src.aws-mcp-proxy', '--endpoint', 'https://test.example.com']) + @patch('aws_mcp_proxy.server.asyncio.run') + @patch('aws_mcp_proxy.server.setup_mcp_mode') + @patch('aws_mcp_proxy.server.FastMCP') + @patch('sys.argv', ['aws-mcp-proxy', '--endpoint', 'https://test.example.com']) def test_main_default(self, mock_fastmcp, mock_setup_mcp, mock_asyncio_run): """Test main function with default arguments.""" # Create mock FastMCP instance @@ -58,7 +58,7 @@ def test_module_execution(self): # Get the source code of the module import inspect - from src.aws_mcp_proxy import server + from aws_mcp_proxy import server # Get the source code source = inspect.getsource(server) diff --git a/tests/test_mcp_proxy_manager.py b/tests/test_mcp_proxy_manager.py index dfc80c9..9bf5f43 100644 --- a/tests/test_mcp_proxy_manager.py +++ b/tests/test_mcp_proxy_manager.py @@ -15,8 +15,8 @@ """Tests for mcp_proxy_manager module.""" import pytest +from aws_mcp_proxy.mcp_proxy_manager import McpProxyManager from fastmcp.server.server import FastMCP -from src.aws_mcp_proxy.mcp_proxy_manager import McpProxyManager from unittest.mock import AsyncMock, MagicMock diff --git a/tests/test_server.py b/tests/test_server.py index d0a11ca..11c5604 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -15,18 +15,18 @@ """Tests for the aws-mcp-proxy Server.""" import pytest -from src.aws_mcp_proxy.server import main, parse_args, setup_mcp_mode -from src.aws_mcp_proxy.sigv4_helper import create_sigv4_client -from src.aws_mcp_proxy.utils import determine_service_name +from aws_mcp_proxy.server import main, parse_args, setup_mcp_mode +from aws_mcp_proxy.sigv4_helper import create_sigv4_client +from aws_mcp_proxy.utils import determine_service_name from unittest.mock import AsyncMock, Mock, patch class TestServer: """Tests for the server module.""" - @patch('src.aws_mcp_proxy.server.McpProxyManager') - @patch('src.aws_mcp_proxy.server.create_transport_with_sigv4') - @patch('src.aws_mcp_proxy.server.FastMCP.as_proxy') + @patch('aws_mcp_proxy.server.McpProxyManager') + @patch('aws_mcp_proxy.server.create_transport_with_sigv4') + @patch('aws_mcp_proxy.server.FastMCP.as_proxy') async def test_setup_mcp_mode( self, mock_as_proxy, mock_create_transport, mock_proxy_manager_class ): @@ -59,9 +59,9 @@ async def test_setup_mcp_mode( mock_proxy_manager_class.assert_called_once_with(mock_mcp, False) mock_proxy_manager.add_proxy_content.assert_called_once_with(mock_proxy) - @patch('src.aws_mcp_proxy.server.McpProxyManager') - @patch('src.aws_mcp_proxy.server.create_transport_with_sigv4') - @patch('src.aws_mcp_proxy.server.FastMCP.as_proxy') + @patch('aws_mcp_proxy.server.McpProxyManager') + @patch('aws_mcp_proxy.server.create_transport_with_sigv4') + @patch('aws_mcp_proxy.server.FastMCP.as_proxy') async def test_setup_mcp_mode_with_tools( self, mock_as_proxy, mock_create_transport, mock_proxy_manager_class ): @@ -94,9 +94,9 @@ async def test_setup_mcp_mode_with_tools( mock_proxy_manager_class.assert_called_once_with(mock_mcp, False) mock_proxy_manager.add_proxy_content.assert_called_once_with(mock_proxy) - @patch('src.aws_mcp_proxy.server.McpProxyManager') - @patch('src.aws_mcp_proxy.server.create_transport_with_sigv4') - @patch('src.aws_mcp_proxy.server.FastMCP.as_proxy') + @patch('aws_mcp_proxy.server.McpProxyManager') + @patch('aws_mcp_proxy.server.create_transport_with_sigv4') + @patch('aws_mcp_proxy.server.FastMCP.as_proxy') async def test_setup_mcp_mode_tool_registration_error( self, mock_as_proxy, mock_create_transport, mock_proxy_manager_class ): @@ -133,7 +133,7 @@ def test_parse_args_default(self): args = parse_args() assert args.endpoint == 'https://test.example.com' - @patch('src.aws_mcp_proxy.server.asyncio.run') + @patch('aws_mcp_proxy.server.asyncio.run') @patch('sys.argv', ['test', '--endpoint', 'https://test.example.com']) def test_main_function(self, mock_asyncio_run): """Test that main function runs server correctly.""" @@ -146,7 +146,7 @@ def test_main_function(self, mock_asyncio_run): # Assert mock_asyncio_run.assert_called_once() - @patch('src.aws_mcp_proxy.server.asyncio.run') + @patch('aws_mcp_proxy.server.asyncio.run') @patch('sys.argv', ['test', '--endpoint', 'https://test.example.com']) def test_main_error_handling(self, mock_asyncio_run): """Test that main function handles errors gracefully.""" @@ -172,9 +172,9 @@ def test_validate_service_name_service_parsing(self): result = determine_service_name(endpoint) assert result == expected_service - @patch('src.aws_mcp_proxy.sigv4_helper.boto3.Session') - @patch('src.aws_mcp_proxy.sigv4_helper.httpx.AsyncClient') - @patch('src.aws_mcp_proxy.sigv4_helper.SigV4Auth') + @patch('aws_mcp_proxy.sigv4_helper.boto3.Session') + @patch('aws_mcp_proxy.sigv4_helper.httpx.AsyncClient') + @patch('aws_mcp_proxy.sigv4_helper.SigV4Auth') def test_create_sigv4_client(self, mock_sigv4_auth, mock_async_client, mock_session): """Test creating SigV4 authenticated client with HTTPX auth.""" # Arrange @@ -196,7 +196,7 @@ def test_create_sigv4_client(self, mock_sigv4_auth, mock_async_client, mock_sess mock_sigv4_auth.assert_called_once_with(mock_credentials, 'test-service', 'us-west-2') mock_async_client.assert_called_once() - @patch('src.aws_mcp_proxy.sigv4_helper.boto3.Session') + @patch('aws_mcp_proxy.sigv4_helper.boto3.Session') def test_create_sigv4_client_no_credentials(self, mock_session): """Test creating SigV4 client with no credentials.""" # Arrange @@ -213,7 +213,7 @@ def test_main_module_execution(self): """Test that main is called when module is executed directly.""" # This test is more complex because we need to test the actual module execution # We'll test by checking if the server module has the correct structure - import src.aws_mcp_proxy.server as server_module + import aws_mcp_proxy.server as server_module # Verify the module has the main function assert hasattr(server_module, 'main') diff --git a/tests/test_sigv4_helper.py b/tests/test_sigv4_helper.py index c217d60..bb7d486 100644 --- a/tests/test_sigv4_helper.py +++ b/tests/test_sigv4_helper.py @@ -18,7 +18,7 @@ import json import os import pytest -from src.aws_mcp_proxy.sigv4_helper import ( +from aws_mcp_proxy.sigv4_helper import ( SigV4HTTPXAuth, _handle_error_response, create_aws_session, @@ -225,7 +225,7 @@ def test_create_aws_session_creation_failure(self, mock_session_class): class TestCreateSigv4Auth: """Test cases for the create_sigv4_auth function.""" - @patch('src.aws_mcp_proxy.sigv4_helper.create_aws_session') + @patch('aws_mcp_proxy.sigv4_helper.create_aws_session') def test_create_sigv4_auth_default(self, mock_create_session): """Test creating SigV4 auth with default parameters.""" # Mock session and credentials @@ -246,7 +246,7 @@ def test_create_sigv4_auth_default(self, mock_create_session): assert result.region == 'us-west-2' # default region assert result.credentials == mock_credentials - @patch('src.aws_mcp_proxy.sigv4_helper.create_aws_session') + @patch('aws_mcp_proxy.sigv4_helper.create_aws_session') @patch.dict(os.environ, {'AWS_REGION': 'eu-west-1'}) def test_create_sigv4_auth_with_env_region(self, mock_create_session): """Test creating SigV4 auth with region from environment variable.""" @@ -268,7 +268,7 @@ def test_create_sigv4_auth_with_env_region(self, mock_create_session): assert result.region == 'eu-west-1' # from environment assert result.credentials == mock_credentials - @patch('src.aws_mcp_proxy.sigv4_helper.create_aws_session') + @patch('aws_mcp_proxy.sigv4_helper.create_aws_session') def test_create_sigv4_auth_with_explicit_region(self, mock_create_session): """Test creating SigV4 auth with explicit region parameter.""" # Mock session and credentials @@ -293,7 +293,7 @@ def test_create_sigv4_auth_with_explicit_region(self, mock_create_session): class TestCreateSigv4Client: """Test cases for the create_sigv4_client function.""" - @patch('src.aws_mcp_proxy.sigv4_helper.create_sigv4_auth') + @patch('aws_mcp_proxy.sigv4_helper.create_sigv4_auth') @patch('httpx.AsyncClient') def test_create_sigv4_client_default(self, mock_client_class, mock_create_auth): """Test creating SigV4 client with default parameters.""" @@ -318,7 +318,7 @@ def test_create_sigv4_client_default(self, mock_client_class, mock_create_auth): assert call_args[1]['headers']['Accept'] == 'application/json, text/event-stream' assert result == mock_client - @patch('src.aws_mcp_proxy.sigv4_helper.create_sigv4_auth') + @patch('aws_mcp_proxy.sigv4_helper.create_sigv4_auth') @patch('httpx.AsyncClient') def test_create_sigv4_client_with_custom_headers(self, mock_client_class, mock_create_auth): """Test creating SigV4 client with custom headers.""" @@ -341,7 +341,7 @@ def test_create_sigv4_client_with_custom_headers(self, mock_client_class, mock_c assert call_args[1]['headers'] == expected_headers assert result == mock_client - @patch('src.aws_mcp_proxy.sigv4_helper.create_sigv4_auth') + @patch('aws_mcp_proxy.sigv4_helper.create_sigv4_auth') @patch('httpx.AsyncClient') def test_create_sigv4_client_with_custom_service_and_region( self, mock_client_class, mock_create_auth @@ -362,7 +362,7 @@ def test_create_sigv4_client_with_custom_service_and_region( mock_create_auth.assert_called_once_with('custom-service', 'test-profile', 'us-east-1') assert result == mock_client - @patch('src.aws_mcp_proxy.sigv4_helper.create_sigv4_auth') + @patch('aws_mcp_proxy.sigv4_helper.create_sigv4_auth') @patch('httpx.AsyncClient') def test_create_sigv4_client_with_kwargs(self, mock_client_class, mock_create_auth): """Test creating SigV4 client with additional kwargs.""" @@ -381,7 +381,7 @@ def test_create_sigv4_client_with_kwargs(self, mock_client_class, mock_create_au assert call_args[1]['proxies'] == {'http': 'http://proxy:8080'} assert result == mock_client - @patch('src.aws_mcp_proxy.sigv4_helper.create_sigv4_auth') + @patch('aws_mcp_proxy.sigv4_helper.create_sigv4_auth') @patch('httpx.AsyncClient') def test_create_sigv4_client_with_prompt_context(self, mock_client_class, mock_create_auth): """Test creating SigV4 client when prompts exist in the system context. diff --git a/tests/test_utils.py b/tests/test_utils.py index 170fdd7..c3c9937 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -15,19 +15,19 @@ """Tests for utils module.""" import pytest -from fastmcp.client.transports import StreamableHttpTransport -from src.aws_mcp_proxy.utils import ( +from aws_mcp_proxy.utils import ( create_transport_with_sigv4, determine_service_name, normalize_endpoint_url, ) +from fastmcp.client.transports import StreamableHttpTransport from unittest.mock import MagicMock, patch class TestCreateTransportWithSigv4: """Test cases for create_transport_with_sigv4 function (line 129).""" - @patch('src.aws_mcp_proxy.utils.create_sigv4_client') + @patch('aws_mcp_proxy.utils.create_sigv4_client') def test_create_transport_with_sigv4(self, mock_create_sigv4_client): """Test creating StreamableHttpTransport with SigV4 authentication.""" mock_client = MagicMock() @@ -63,7 +63,7 @@ def test_create_transport_with_sigv4(self, mock_create_sigv4_client): # If we can't access the factory directly, just verify the transport was created assert result is not None - @patch('src.aws_mcp_proxy.utils.create_sigv4_client') + @patch('aws_mcp_proxy.utils.create_sigv4_client') def test_create_transport_with_sigv4_no_profile(self, mock_create_sigv4_client): """Test creating transport without profile.""" url = 'https://eks-mcp.us-west-2.api.aws/mcp'