- Fix version parameter being ignored - now properly fetches specified versions - Enhance PyPIClient with version-specific URL construction - Add version format validation with regex patterns - Improve error handling for non-existent versions - Test with Django 4.2.0, FastAPI 0.100.0, NumPy 1.20.0
7.4 KiB
Version Parameter Fix Summary
Problem Description
The get_package_dependencies
tool in the PyPI Query MCP Server had a critical issue where the version parameter was completely ignored. When users requested dependencies for a specific version of a package (e.g., Django 4.2.0), the tool would:
- Accept the version parameter but ignore it
- Always fetch the latest version of the package instead
- Return dependencies for the latest version, not the requested version
- Only log a warning message about the unimplemented functionality
This made the tool unreliable for users who needed to analyze dependencies for specific package versions.
Root Cause Analysis
The issue was located in the query_package_dependencies
function in /tmp/a/fix-version-parameter/pypi_query_mcp/tools/package_query.py
:
# Old problematic code (lines 250-261)
async with PyPIClient() as client:
package_data = await client.get_package_info(package_name) # No version passed!
# TODO: In future, support querying specific version dependencies
# For now, we return dependencies for the latest version
if version and version != package_data.get("info", {}).get("version"):
logger.warning(
f"Specific version {version} requested but not implemented yet. "
f"Returning dependencies for latest version."
)
The underlying PyPI client's get_package_info
method also did not support version-specific queries, always fetching the latest package information.
Implementation Changes
1. Enhanced PyPIClient to Support Version-Specific Queries
File: /tmp/a/fix-version-parameter/pypi_query_mcp/core/pypi_client.py
Changes:
- Modified
get_package_info
method signature to accept optionalversion
parameter - Added URL construction logic to query specific versions using PyPI's API pattern:
https://pypi.org/pypi/{package}/{version}/json
- Enhanced cache key generation to include version information
- Improved error handling with specific messages for version-not-found cases
Before:
async def get_package_info(self, package_name: str, use_cache: bool = True) -> dict[str, Any]:
# Always fetched latest version
url = f"{self.base_url}/{quote(normalized_name)}/json"
After:
async def get_package_info(self, package_name: str, version: str | None = None, use_cache: bool = True) -> dict[str, Any]:
# Version-aware URL construction
if version:
url = f"{self.base_url}/{quote(normalized_name)}/{quote(version)}/json"
else:
url = f"{self.base_url}/{quote(normalized_name)}/json"
2. Fixed query_package_dependencies Function
File: /tmp/a/fix-version-parameter/pypi_query_mcp/tools/package_query.py
Changes:
- Removed TODO comment and warning about unimplemented functionality
- Added version parameter validation using regex patterns
- Simplified function logic to actually pass the version parameter to PyPIClient
Before:
async with PyPIClient() as client:
package_data = await client.get_package_info(package_name) # No version!
# TODO: In future, support querying specific version dependencies
if version and version != package_data.get("info", {}).get("version"):
logger.warning("Specific version requested but not implemented yet...")
After:
async with PyPIClient() as client:
# Pass the version parameter to get_package_info
package_data = await client.get_package_info(package_name, version=version)
return format_dependency_info(package_data)
3. Added Version Format Validation
File: /tmp/a/fix-version-parameter/pypi_query_mcp/tools/package_query.py
New Function:
def validate_version_format(version: str | None) -> bool:
"""Validate that a version string follows a reasonable format."""
if version is None:
return True
# Supports: 1.0.0, 1.0, 1.0.0a1, 1.0.0b2, 1.0.0rc1, 1.0.0.dev1, etc.
version_pattern = r"^[0-9]+(?:\.[0-9]+)*(?:[\.\-]?(?:a|b|rc|alpha|beta|dev|pre|post|final)[0-9]*)*$"
return bool(re.match(version_pattern, version.strip(), re.IGNORECASE))
4. Enhanced Error Handling
- Added proper validation that raises
InvalidPackageNameError
for malformed version strings - Improved PyPIClient error messages to distinguish between package-not-found and version-not-found errors
- Maintained existing error handling patterns for consistency
Test Results
Comprehensive testing was performed to verify the fix works correctly:
Successful Test Cases
- Django 4.2.0: ✅ Successfully retrieved 4 runtime dependencies
- FastAPI 0.100.0: ✅ Successfully retrieved 3 runtime dependencies
- NumPy 1.20.0: ✅ Successfully retrieved 0 runtime dependencies (NumPy has minimal deps)
- Requests 2.25.1: ✅ Successfully retrieved 4 runtime dependencies
- Pre-release versions (Django 5.0a1): ✅ Successfully handled
Verification of Fix
- Version-specific queries now return different results than latest version queries
- Django 4.2.0 returns different dependencies than Django 5.2.5 (latest)
- Dependency counts differ between versions (Django 4.2.0: 4 deps, Django latest: 3 deps)
- Dependency specifications updated between versions (e.g.,
asgiref (<4,>=3.6.0)
vsasgiref>=3.8.1
)
Error Handling Test Cases
- Invalid version format (
invalid.version!
): ✅ Correctly rejected withInvalidPackageNameError
- Non-existent version (Django 999.999.999): ✅ Correctly rejected with
PackageNotFoundError
- Non-existent package: ✅ Correctly handled with appropriate error
Version Validation Test Cases
1.0.0
,2.1
,1.0.0a1
,1.0.0b2
,1.0.0rc1
,2.0.0.dev1
: ✅ All validinvalid.version!
, empty string: ✅ Correctly rejectedNone
(latest version): ✅ Correctly accepted
Impact and Benefits
Before the Fix
- Users requesting
get_package_dependencies("django", "4.2.0")
would get dependencies for Django 5.2.5 (latest) - No way to analyze dependencies for specific historical versions
- Misleading results that could lead to incorrect dependency analysis
- Function parameter was essentially non-functional
After the Fix
- Users can reliably get dependencies for any specific version available on PyPI
- Proper error handling for non-existent versions
- Accurate dependency analysis for historical versions
- Full compatibility with PyPI's version-specific API endpoints
Backward Compatibility
The fix maintains full backward compatibility:
- Existing calls without version parameter continue to work identically
- Error handling patterns remain consistent
- Return value structure unchanged
- All existing functionality preserved
Files Modified
-
/tmp/a/fix-version-parameter/pypi_query_mcp/core/pypi_client.py
- Enhanced
get_package_info
method with version support - Updated
get_package_versions
andget_latest_version
calls
- Enhanced
-
/tmp/a/fix-version-parameter/pypi_query_mcp/tools/package_query.py
- Fixed
query_package_dependencies
to use version parameter - Added
validate_version_format
function - Updated other query functions for consistency
- Fixed
Conclusion
The version parameter fix resolves a significant functional gap in the PyPI Query MCP Server. Users can now reliably query dependencies for specific package versions, enabling accurate dependency analysis for any version available on PyPI. The implementation follows best practices for error handling, validation, and maintains full backward compatibility.