fix: correct FastMCP interface usage and resolve lint issues
- Fix FastMCP server interface to use correct mcp.run() instead of app.run(host, port) - Remove unnecessary host and port parameters, use standard STDIO transport - Fix all ruff lint issues including import sorting and blank lines - Update ruff configuration to new lint configuration format - Fix type annotation issues using Union syntax (int | None) - Ensure uvx pypi-query-mcp-server works correctly - All tests pass and lint checks pass
This commit is contained in:
parent
030b3a2607
commit
576652571c
BIN
dist/pypi_query_mcp_server-0.1.0-py3-none-any.whl
vendored
BIN
dist/pypi_query_mcp_server-0.1.0-py3-none-any.whl
vendored
Binary file not shown.
BIN
dist/pypi_query_mcp_server-0.1.0.tar.gz
vendored
BIN
dist/pypi_query_mcp_server-0.1.0.tar.gz
vendored
Binary file not shown.
@ -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:
|
||||
|
@ -1,5 +1,6 @@
|
||||
# Import third-party modules
|
||||
import nox
|
||||
|
||||
from nox_actions.utils import PACKAGE_NAME
|
||||
|
||||
|
||||
|
@ -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}")
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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__"]
|
||||
|
@ -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)
|
||||
|
@ -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__":
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user