Conversation
Show update availability in server banner and `fastmcp version` command. Checks PyPI with 12-hour cache and 2-second timeout. New setting: FASTMCP_CHECK_FOR_UPDATES (stable/prerelease/off)
|
Warning Rate limit exceeded@jlowin has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 25 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughAdds a version-checking feature and UI to FastMCP: a new module provides cached PyPI lookups (stable/prerelease) and public functions Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 95670b4bef
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if not include_prereleases: | ||
| # Use the stable version from info | ||
| return data.get("info", {}).get("version") |
There was a problem hiding this comment.
Filter prereleases when stable-only is selected
With include_prereleases=False, _fetch_latest_version returns info.version directly. The PyPI JSON info.version reflects the most recently uploaded release, which can be a prerelease. When a prerelease is the latest upload, the default “stable” setting will still surface that prerelease, so users who opted into stable-only updates will get prerelease prompts. Consider selecting the highest non-prerelease version from releases instead of info.version when include_prereleases is false.
Useful? React with 👍 / 👎.
- Move fastmcp import inside functions to avoid circular imports - Filter prereleases from releases list instead of using info.version
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/fastmcp/utilities/version_check.py (1)
204-205: Consider startup latency on first run.On first run (no cache), this synchronous call adds up to 2 seconds of latency to banner display. While the timeout and caching mitigate this for subsequent runs, you may want to document this behavior or consider an async implementation if startup time is critical.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
tests/utilities/test_version_check.pyis excluded by none and included by none
📒 Files selected for processing (4)
src/fastmcp/cli/cli.pysrc/fastmcp/settings.pysrc/fastmcp/utilities/cli.pysrc/fastmcp/utilities/version_check.py
🧰 Additional context used
📓 Path-based instructions (1)
src/fastmcp/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
src/fastmcp/**/*.py: Python ≥ 3.10 with full type annotations required
Prioritize readable, understandable code - clarity over cleverness. Avoid obfuscated or confusing patterns even if shorter
Follow existing patterns and maintain consistency in code implementation
Be intentional about re-exports - don't blindly re-export everything to parent namespaces. Core types defining a module's purpose should be exported. Specialized features can live in submodules. Only re-export to fastmcp.* for most fundamental types
Never use bare except - be specific with exception types
Files:
src/fastmcp/utilities/version_check.pysrc/fastmcp/settings.pysrc/fastmcp/cli/cli.pysrc/fastmcp/utilities/cli.py
🧠 Learnings (2)
📚 Learning: 2025-12-25T15:53:07.656Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-25T15:53:07.656Z
Learning: Applies to src/fastmcp/**/*.py : Python ≥ 3.10 with full type annotations required
Applied to files:
src/fastmcp/utilities/version_check.pysrc/fastmcp/utilities/cli.py
📚 Learning: 2025-12-25T15:53:07.656Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-25T15:53:07.656Z
Learning: Applies to src/fastmcp/**/*.py : Be intentional about re-exports - don't blindly re-export everything to parent namespaces. Core types defining a module's purpose should be exported. Specialized features can live in submodules. Only re-export to fastmcp.* for most fundamental types
Applied to files:
src/fastmcp/utilities/version_check.py
🧬 Code graph analysis (3)
src/fastmcp/utilities/version_check.py (2)
src/fastmcp/cli/cli.py (1)
version(93-131)src/fastmcp/utilities/logging.py (1)
get_logger(14-26)
src/fastmcp/cli/cli.py (1)
src/fastmcp/utilities/version_check.py (1)
check_for_newer_version(124-151)
src/fastmcp/utilities/cli.py (1)
src/fastmcp/utilities/version_check.py (1)
check_for_newer_version(124-151)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Run tests: Python 3.10 on ubuntu-latest
- GitHub Check: Run tests: Python 3.13 on ubuntu-latest
- GitHub Check: Run tests with lowest-direct dependencies
- GitHub Check: Run tests: Python 3.10 on windows-latest
🔇 Additional comments (8)
src/fastmcp/utilities/version_check.py (2)
1-151: LGTM! Well-structured version checking implementation.The module is well-designed with appropriate separation of concerns, proper error handling, and clean type annotations. The caching strategy and timeout configuration are sensible for a non-critical background feature.
67-70: Exception handling is correct and complete.The current handler
except (httpx.HTTPError, json.JSONDecodeError, KeyError)successfully catches all relevant httpx exceptions. Bothhttpx.TimeoutExceptionandhttpx.ConnectErrorare subclasses ofhttpx.HTTPErrorthrough the inheritance chain (TransportError → RequestError → HTTPError), so they are properly covered.src/fastmcp/cli/cli.py (1)
32-32: LGTM!Clean import addition following the existing import structure.
src/fastmcp/settings.py (1)
337-350: LGTM! Well-documented configuration option.The new setting follows the established patterns in the Settings class with clear documentation and sensible defaults. The Literal type ensures type safety for the three allowed values.
src/fastmcp/utilities/cli.py (4)
20-20: LGTM!Import follows the existing pattern and module structure.
204-205: LGTM! Non-blocking version check.The version check is appropriately placed and will fail silently if network issues occur, ensuring the banner always displays regardless of PyPI availability.
238-242: LGTM! Enhanced text styling.The change from a simple Text object to Text.assemble provides better visual emphasis on the version constraint, making the notice more scannable.
260-280: LGTM! Clean output composition.The refactored output construction is well-structured with proper type annotations and clear conditional logic for the update notice. The update panel appears last for maximum visibility.
Test Failure AnalysisSummary: The test Root Cause: The test creates a JWT token with a 1-second expiration, verifies it immediately, then sleeps for 1.1 seconds and expects the token to be rejected as expired. However, the actual expiration check happened at exactly the boundary (token was issued at 22:53:51 with exp=1768085631, and validation failed at 22:53:51 showing "Token expired"), suggesting the token expired right at or slightly before the sleep completed. This is a classic timing-based test flakiness issue - the test assumes Note: This failure is unrelated to the PR changes (CLI update notifications). The test is part of the JWT authentication system, while this PR only adds version checking functionality to the CLI. Suggested Solution: Make the test more robust by using a larger expiration buffer: # In tests/server/auth/test_jwt_issuer.py, line 171
expires_in=2, # Changed from 1 to 2 secondsAnd adjust the sleep accordingly: # Line 179
time.sleep(2.5) # Changed from 1.1 to 2.5 secondsDetailed AnalysisTest Location: Failure Log: Why It Failed:
The issue is that Related Files
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/fastmcp/utilities/version_check.py (1)
59-95: LGTM! Solid PyPI fetch logic.The version fetching is well-implemented with appropriate error handling and version parsing. The synchronous
httpx.get()call is correct for CLI usage.One minor observation:
KeyErrorin the except clause at line 94 may be unnecessary sincedict.get("releases", {})at line 73 won't raiseKeyError. However, it's harmless defensive programming.♻️ Optional: Simplify exception handling
- except (httpx.HTTPError, json.JSONDecodeError, KeyError): + except (httpx.HTTPError, json.JSONDecodeError): return None
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
tests/utilities/test_version_check.pyis excluded by none and included by none
📒 Files selected for processing (1)
src/fastmcp/utilities/version_check.py
🧰 Additional context used
📓 Path-based instructions (1)
src/fastmcp/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
src/fastmcp/**/*.py: Python ≥ 3.10 with full type annotations required
Prioritize readable, understandable code - clarity over cleverness. Avoid obfuscated or confusing patterns even if shorter
Follow existing patterns and maintain consistency in code implementation
Be intentional about re-exports - don't blindly re-export everything to parent namespaces. Core types defining a module's purpose should be exported. Specialized features can live in submodules. Only re-export to fastmcp.* for most fundamental types
Never use bare except - be specific with exception types
Files:
src/fastmcp/utilities/version_check.py
🧠 Learnings (2)
📚 Learning: 2025-12-25T15:53:07.656Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-25T15:53:07.656Z
Learning: Applies to src/fastmcp/**/*.py : Python ≥ 3.10 with full type annotations required
Applied to files:
src/fastmcp/utilities/version_check.py
📚 Learning: 2025-12-25T15:53:07.656Z
Learnt from: CR
Repo: jlowin/fastmcp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-25T15:53:07.656Z
Learning: Applies to src/fastmcp/**/*.py : Be intentional about re-exports - don't blindly re-export everything to parent namespaces. Core types defining a module's purpose should be exported. Specialized features can live in submodules. Only re-export to fastmcp.* for most fundamental types
Applied to files:
src/fastmcp/utilities/version_check.py
🧬 Code graph analysis (1)
src/fastmcp/utilities/version_check.py (4)
src/fastmcp/cli/cli.py (1)
version(93-131)src/fastmcp/utilities/logging.py (1)
get_logger(14-26)src/fastmcp/server/server.py (1)
settings(414-422)src/fastmcp/server/context.py (1)
debug(468-482)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Run tests: Python 3.10 on windows-latest
🔇 Additional comments (3)
src/fastmcp/utilities/version_check.py (3)
1-18: LGTM! Clean module setup.The imports, logger initialization, and constants are well-structured. The 12-hour cache TTL and 2-second network timeout are sensible defaults for a CLI update checker.
21-56: LGTM! Robust cache management.The cache helper functions are well-implemented:
- Circular import handling via late import is appropriate
- Separate cache files for stable vs prerelease is clean
- Error handling is comprehensive and fails gracefully
- Silent OSError handling in
_write_cacheprevents permission issues from breaking functionality
98-153: LGTM! Public API is well-designed.Both public functions are correctly implemented:
get_latest_version: Cache-first strategy with stale fallback is robust for network failurescheck_for_newer_version: Settings integration and version comparison logic are soundThe implicit handling of unknown settings values (treating them as "stable") provides sensible default behavior. The circular import prevention through late binding is appropriate per your commit message.
Cherry-pick of #2839 for 3.x branch.
The CLI now notifies users when a newer version of FastMCP is available on PyPI.
Where it shows:
fastmcp versioncommand (simple text, excluded from--copy)Setting:
FASTMCP_CHECK_FOR_UPDATES"stable"- Check for stable releases (default)"prerelease"- Include alpha/beta/rc versions"off"- Disable12-hour cache, 2-second timeout, fails silently on network errors.