Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
14 changes: 7 additions & 7 deletions src/aws_mcp_proxy/server.py → aws_mcp_proxy/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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
""",
)

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/aws_mcp_proxy/utils.py → aws_mcp_proxy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -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]
Expand All @@ -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"]
Expand All @@ -155,4 +155,4 @@ exclude_also = [
]

[tool.coverage.run]
source = ["src"]
source = ["aws_mcp_proxy"]
16 changes: 0 additions & 16 deletions src/__init__.py

This file was deleted.

18 changes: 9 additions & 9 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,30 @@
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__')
Comment thread Dismissed

# Check that __version__ is a string
assert isinstance(src.aws_mcp_proxy.__version__, str)
assert isinstance(aws_mcp_proxy.__version__, str)
Comment thread Dismissed

# 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__), (
Comment thread Dismissed
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
Comment thread Dismissed
2 changes: 1 addition & 1 deletion tests/test_logging_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
12 changes: 6 additions & 6 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_mcp_proxy_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
38 changes: 19 additions & 19 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
):
Expand Down Expand Up @@ -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
):
Expand Down Expand Up @@ -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
):
Expand Down Expand Up @@ -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."""
Expand All @@ -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."""
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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')
Expand Down
18 changes: 9 additions & 9 deletions tests/test_sigv4_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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."""
Expand All @@ -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
Expand All @@ -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."""
Expand All @@ -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."""
Expand All @@ -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
Expand All @@ -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."""
Expand All @@ -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.
Expand Down
Loading