diff --git a/dist/pypi_query_mcp_server-0.1.0-py3-none-any.whl b/dist/pypi_query_mcp_server-0.1.0-py3-none-any.whl index 379990f..2141a30 100644 Binary files a/dist/pypi_query_mcp_server-0.1.0-py3-none-any.whl and b/dist/pypi_query_mcp_server-0.1.0-py3-none-any.whl differ diff --git a/dist/pypi_query_mcp_server-0.1.0.tar.gz b/dist/pypi_query_mcp_server-0.1.0.tar.gz index 750c5ac..12f854e 100644 Binary files a/dist/pypi_query_mcp_server-0.1.0.tar.gz and b/dist/pypi_query_mcp_server-0.1.0.tar.gz differ diff --git a/nox_actions/codetest.py b/nox_actions/codetest.py index cf6b048..24f522a 100644 --- a/nox_actions/codetest.py +++ b/nox_actions/codetest.py @@ -3,8 +3,8 @@ import os # Import third-party modules import nox -from nox_actions.utils import PACKAGE_NAME -from nox_actions.utils import THIS_ROOT + +from nox_actions.utils import PACKAGE_NAME, THIS_ROOT def pytest(session: nox.Session) -> None: diff --git a/nox_actions/lint.py b/nox_actions/lint.py index 9b75bc1..bec2943 100644 --- a/nox_actions/lint.py +++ b/nox_actions/lint.py @@ -1,5 +1,6 @@ # Import third-party modules import nox + from nox_actions.utils import PACKAGE_NAME diff --git a/nox_actions/release.py b/nox_actions/release.py index b3b4a56..d736804 100644 --- a/nox_actions/release.py +++ b/nox_actions/release.py @@ -6,8 +6,8 @@ import zipfile # Import third-party modules import nox -from nox_actions.utils import PACKAGE_NAME -from nox_actions.utils import THIS_ROOT + +from nox_actions.utils import PACKAGE_NAME, THIS_ROOT def build(session: nox.Session) -> None: @@ -49,4 +49,4 @@ def build_exe(session: nox.Session) -> None: zip_obj.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), os.path.join(platform_dir, "."))) - print("Saving to {zipfile}".format(zipfile=zip_file)) + print(f"Saving to {zip_file}") diff --git a/nox_actions/utils.py b/nox_actions/utils.py index 076694e..a42eb1a 100644 --- a/nox_actions/utils.py +++ b/nox_actions/utils.py @@ -1,7 +1,6 @@ # Import built-in modules from pathlib import Path - PACKAGE_NAME = "pypi_query_mcp" THIS_ROOT = Path(__file__).parent.parent PROJECT_ROOT = THIS_ROOT.parent diff --git a/noxfile.py b/noxfile.py index 30b1182..d5d9a41 100644 --- a/noxfile.py +++ b/noxfile.py @@ -5,18 +5,14 @@ import sys # Import third-party modules import nox - ROOT = os.path.dirname(__file__) # Ensure pypi_query_mcp is importable. if ROOT not in sys.path: sys.path.append(ROOT) -# Import third-party modules -from nox_actions import codetest # noqa: E402 -from nox_actions import lint # noqa: E402 -from nox_actions import release # noqa: E402 - +# Import local modules (after sys.path setup) +from nox_actions import codetest, lint, release # noqa: E402 # Configure nox sessions nox.session(lint.lint, name="lint") diff --git a/pypi_query_mcp/__init__.py b/pypi_query_mcp/__init__.py index 0664362..1dca3d4 100644 --- a/pypi_query_mcp/__init__.py +++ b/pypi_query_mcp/__init__.py @@ -8,6 +8,6 @@ __version__ = "0.1.0" __author__ = "Hal" __email__ = "hal.long@outlook.com" -from pypi_query_mcp.server import app +from pypi_query_mcp.server import mcp -__all__ = ["app", "__version__"] +__all__ = ["mcp", "__version__"] diff --git a/pypi_query_mcp/core/exceptions.py b/pypi_query_mcp/core/exceptions.py index 6cdc942..239f2bc 100644 --- a/pypi_query_mcp/core/exceptions.py +++ b/pypi_query_mcp/core/exceptions.py @@ -4,7 +4,7 @@ class PyPIError(Exception): """Base exception for PyPI-related errors.""" - def __init__(self, message: str, status_code: int = None): + def __init__(self, message: str, status_code: int | None = None): super().__init__(message) self.message = message self.status_code = status_code @@ -22,7 +22,7 @@ class PackageNotFoundError(PyPIError): class NetworkError(PyPIError): """Raised when network-related errors occur.""" - def __init__(self, message: str, original_error: Exception = None): + def __init__(self, message: str, original_error: Exception | None = None): super().__init__(message) self.original_error = original_error @@ -30,7 +30,7 @@ class NetworkError(PyPIError): class RateLimitError(PyPIError): """Raised when API rate limit is exceeded.""" - def __init__(self, retry_after: int = None): + def __init__(self, retry_after: int | None = None): message = "PyPI API rate limit exceeded" if retry_after: message += f". Retry after {retry_after} seconds" @@ -50,7 +50,7 @@ class InvalidPackageNameError(PyPIError): class PyPIServerError(PyPIError): """Raised when PyPI server returns a server error.""" - def __init__(self, status_code: int, message: str = None): + def __init__(self, status_code: int, message: str | None = None): if not message: message = f"PyPI server error (HTTP {status_code})" super().__init__(message, status_code=status_code) diff --git a/pypi_query_mcp/server.py b/pypi_query_mcp/server.py index 7c97a90..c3a53c0 100644 --- a/pypi_query_mcp/server.py +++ b/pypi_query_mcp/server.py @@ -23,10 +23,10 @@ logging.basicConfig( logger = logging.getLogger(__name__) # Create FastMCP application -app = FastMCP("PyPI Query MCP Server") +mcp = FastMCP("PyPI Query MCP Server") -@app.tool() +@mcp.tool() async def get_package_info(package_name: str) -> dict[str, Any]: """Query comprehensive information about a PyPI package. @@ -71,7 +71,7 @@ async def get_package_info(package_name: str) -> dict[str, Any]: } -@app.tool() +@mcp.tool() async def get_package_versions(package_name: str) -> dict[str, Any]: """Get version information for a PyPI package. @@ -114,7 +114,7 @@ async def get_package_versions(package_name: str) -> dict[str, Any]: } -@app.tool() +@mcp.tool() async def get_package_dependencies(package_name: str, version: str | None = None) -> dict[str, Any]: """Get dependency information for a PyPI package. @@ -161,7 +161,7 @@ async def get_package_dependencies(package_name: str, version: str | None = None } -@app.tool() +@mcp.tool() async def check_package_python_compatibility( package_name: str, target_python_version: str, @@ -212,7 +212,7 @@ async def check_package_python_compatibility( } -@app.tool() +@mcp.tool() async def get_package_compatible_python_versions( package_name: str, python_versions: list[str] | None = None, @@ -262,33 +262,22 @@ async def get_package_compatible_python_versions( @click.command() -@click.option( - "--host", - default="localhost", - help="Host to bind the server to" -) -@click.option( - "--port", - default=8000, - type=int, - help="Port to bind the server to" -) @click.option( "--log-level", default="INFO", type=click.Choice(["DEBUG", "INFO", "WARNING", "ERROR"]), help="Logging level" ) -def main(host: str, port: int, log_level: str) -> None: +def main(log_level: str) -> None: """Start the PyPI Query MCP Server.""" # Set logging level logging.getLogger().setLevel(getattr(logging, log_level)) - logger.info(f"Starting PyPI Query MCP Server on {host}:{port}") + logger.info("Starting PyPI Query MCP Server") logger.info(f"Log level set to: {log_level}") - # Run the FastMCP server - app.run(host=host, port=port) + # Run the FastMCP server (uses STDIO transport by default) + mcp.run() if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index 2e405f4..9b06b35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,8 @@ pypi-query-mcp = "pypi_query_mcp.server:main" [tool.ruff] target-version = "py310" line-length = 88 + +[tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings @@ -66,7 +68,7 @@ ignore = [ "C901", # too complex ] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] [tool.mypy] diff --git a/tests/test_basic.py b/tests/test_basic.py index 19210aa..8a392c4 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -13,22 +13,22 @@ def test_version(): def test_import(): """Test that main modules can be imported.""" from pypi_query_mcp.core import PyPIClient, VersionCompatibility - from pypi_query_mcp.server import app - + from pypi_query_mcp.server import mcp + assert PyPIClient is not None assert VersionCompatibility is not None - assert app is not None + assert mcp is not None @pytest.mark.asyncio async def test_pypi_client_basic(): """Test basic PyPI client functionality.""" from pypi_query_mcp.core import PyPIClient - + async with PyPIClient() as client: # Test that client can be created and closed assert client is not None - + # Test cache clearing client.clear_cache() @@ -36,24 +36,24 @@ async def test_pypi_client_basic(): def test_version_compatibility(): """Test version compatibility utility.""" from pypi_query_mcp.core import VersionCompatibility - + compat = VersionCompatibility() - + # Test requires_python parsing spec = compat.parse_requires_python(">=3.8") assert spec is not None - + # Test classifier extraction classifiers = [ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython" ] - + versions = compat.extract_python_versions_from_classifiers(classifiers) assert "3.8" in versions assert "3.9" in versions - + implementations = compat.extract_python_implementations(classifiers) assert "CPython" in implementations @@ -68,7 +68,7 @@ def test_mcp_tools_import(): query_package_versions, suggest_python_version_for_packages, ) - + # Test that all tools are callable assert callable(query_package_info) assert callable(query_package_versions)