Skip to content

fix: tool-version-check falls back to package.json for MCP servers that block on --version#3973

Merged
marcusquinn merged 3 commits intomarcusquinn:mainfrom
johnwaldo:fix/tool-version-check-mcp-servers
Mar 9, 2026
Merged

fix: tool-version-check falls back to package.json for MCP servers that block on --version#3973
marcusquinn merged 3 commits intomarcusquinn:mainfrom
johnwaldo:fix/tool-version-check-mcp-servers

Conversation

@johnwaldo
Copy link
Contributor

@johnwaldo johnwaldo commented Mar 9, 2026

Summary

  • MCP servers (macos-automator-mcp, claude-code-mcp) start a blocking server process when invoked with --version instead of printing a version string, causing timeout errors, "could not check latest" status, and server startup warnings leaking to the console
  • Added get_npm_pkg_version() fallback that reads the version from the npm global package.json when --version times out or produces unparseable output
  • Suppressed stderr on --version calls to prevent MCP server startup logs from leaking to console output

Before

[2026-03-09T12:19:53.773Z] [macos_automator_server] [INFO] Starting macos_automator MCP Server...
[2026-03-09T12:19:53.773Z] [macos_automator_server] [WARN] CRITICAL: Ensure macOS Automation...
?  macOS Automator MCP: unknown (could not check latest)
[Warning] Claude CLI not found at ~/.claude/local/claude...
?  Claude Code MCP: unknown (could not check latest)

After

✓  macOS Automator MCP: 0.4.1
✓  Claude Code MCP: 1.10.12

Summary by CodeRabbit

  • Bug Fixes
    • Improved tool version detection with a robust npm-package fallback when direct version checks fail or return unexpected output.
    • Better handling of timeouts and noisy errors during version checks: timeouts no longer surface stderr and trigger the npm fallback to recover a usable version string.

…at block on --version

MCP servers like macos-automator-mcp and claude-code-mcp start a blocking
server process when invoked with --version instead of printing a version
string. This caused timeout errors, 'could not check latest' status, and
server startup warnings leaking to the console.

Add get_npm_pkg_version() fallback that reads the version from the npm
global package.json when --version times out or produces unparseable
output. Suppress stderr on --version calls to prevent MCP server startup
logs from leaking.
@github-actions github-actions bot added the bug Auto-created from TODO.md tag label Mar 9, 2026
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves an issue where certain MCP servers, such as macos-automator-mcp and claude-code-mcp, would incorrectly initiate a blocking server process when queried for their version using the --version flag. This behavior led to timeouts, 'unknown' version statuses, and unwanted server startup logs appearing in the console. The solution introduces a robust fallback mechanism that, upon detecting a timeout or unparseable output from the --version command, attempts to retrieve the tool's version directly from its global npm package.json file. Additionally, stderr output during version checks is now suppressed, ensuring a cleaner and more accurate version reporting experience for these tools.

Highlights

  • Improved Version Checking for MCP Servers: Implemented a fallback mechanism for tool-version-check to correctly determine versions for MCP servers that block when invoked with --version, preventing timeouts and 'unknown' statuses.
  • NPM Package.json Fallback: Introduced a new get_npm_pkg_version() function that reads the version directly from the global npm package.json file when standard --version checks fail or time out.
  • Suppressed Stderr Output: Modified version checks to suppress stderr output, preventing server startup warnings and logs from leaking into the console during the version retrieval process.
Changelog
  • .agents/scripts/tool-version-check.sh
    • Added a new shell function get_npm_pkg_version to extract package versions from global npm package.json files.
    • Modified get_installed_version to accept an optional package name, redirect stderr to /dev/null during version command execution, and incorporate the get_npm_pkg_version as a fallback for timed-out or unparseable version outputs.
    • Updated check_tool to conditionally pass the npm package name to get_installed_version for tools identified as 'npm' category.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 9, 2026

Warning

Rate limit exceeded

@marcusquinn has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 31 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 99feceda-636d-4d2c-aba9-ae966728dcec

📥 Commits

Reviewing files that changed from the base of the PR and between 4a94ce1 and a8a3921.

📒 Files selected for processing (1)
  • .agents/scripts/tool-version-check.sh

Walkthrough

Adds an npm global package.json fallback to the tool-version-check script: if a tool's --version command times out or yields no parseable version, the script can read the version from npm's global package metadata when a package name is provided.

Changes

Cohort / File(s) Summary
Tool Version Check Enhancement
.agents/scripts/tool-version-check.sh
Removed OpenCode from NPM_TOOLS and added to BREW_TOOLS. Added get_npm_pkg_version() to read versions from npm global package.json. Extended get_installed_version(cmd, ver_flag, pkg) to accept optional pkg, suppress timeout stderr, return on success, and fallback to npm pkg version when timeouts or parse fail. check_tool() now passes pkg for npm-category tools.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested labels

external-contributor

Poem

A script that listens when versions hide,
Falls back to npm where metadata bide;
Timeouts silenced, checks renewed,
A tiny helper, succinct and shrewd. 🚀

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a package.json fallback mechanism for MCP servers that block on --version invocations.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fallback mechanism to retrieve tool versions from package.json for MCP servers that hang when the --version flag is used. This is a solid improvement to handle problematic tools gracefully. The implementation is logical and correctly addresses the issue described. I've included a few suggestions to enhance the script's robustness and maintainability by using jq for JSON parsing, optimizing file reads, and simplifying conditional logic.

Comment on lines +121 to +122
grep -oE '"version"\s*:\s*"[0-9]+\.[0-9]+\.[0-9]+"' "$pkg_json" |
grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a chain of grep commands to parse a JSON file can be brittle. Since jq is a more robust and idiomatic tool for handling JSON, it should be preferred. This change will make the script more resilient to potential formatting variations in package.json files.

Suggested change
grep -oE '"version"\s*:\s*"[0-9]+\.[0-9]+\.[0-9]+"' "$pkg_json" |
grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1
jq -r '.version // empty' "$pkg_json" | head -1

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining this suggestion. While jq is more robust for arbitrary JSON, this script runs on diverse systems where jq may not be installed. The grep chain is sufficient for npm's well-structured package.json format — the "version" field is always a simple string. Adding a jq dependency for a single extraction is over-engineering for this use case.

Comment on lines 166 to 169
version=$(head -1 "$_ver_log" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "")
if [[ -z "$version" ]]; then
version=$(head -1 "$_ver_log" | grep -oE '[0-9]+\.[0-9]+' | head -1 || echo "unknown")
version=$(head -1 "$_ver_log" | grep -oE '[0-9]+\.[0-9]+' | head -1 || echo "")
fi

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block reads and parses the log file $_ver_log twice. To improve performance and readability, you can read the file's content into a variable once and then perform the grep operations on that variable.

Suggested change
version=$(head -1 "$_ver_log" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "")
if [[ -z "$version" ]]; then
version=$(head -1 "$_ver_log" | grep -oE '[0-9]+\.[0-9]+' | head -1 || echo "unknown")
version=$(head -1 "$_ver_log" | grep -oE '[0-9]+\.[0-9]+' | head -1 || echo "")
fi
local ver_output
ver_output=$(head -1 "$_ver_log")
version=$(echo "$ver_output" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
if [[ -z "$version" ]]; then
version=$(echo "$ver_output" | grep -oE '[0-9]+\.[0-9]+' | head -1)
fi

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in a8a3921. Reads the log file once into ver_output, then greps from the variable. Also moved rm -f before the grep operations so the temp file is cleaned up earlier.

echo "$version"

# If --version produced no parseable version, try npm package.json fallback
if [[ -z "$version" || "$version" == "unknown" ]] && [[ -n "$pkg" ]]; then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The check "$version" == "unknown" is redundant here. Based on the logic in the preceding lines (166-169), the $version variable will either contain a version string or be empty; it will not be the string "unknown". You can simplify this condition for better clarity.

Suggested change
if [[ -z "$version" || "$version" == "unknown" ]] && [[ -n "$pkg" ]]; then
if [[ -z "$version" ]] && [[ -n "$pkg" ]]; then

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in a8a3921. Correct analysis — $version can only be empty or a version string at this point, never the literal "unknown". Simplified to [[ -z "$version" ]]. CodeRabbit's nitpick about adding an empty npm_root guard was also applied in the same commit.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
.agents/scripts/tool-version-check.sh (2)

171-182: Minor cleanup opportunity in condition.

The condition "$version" == "unknown" on line 173 will never match because $version is populated from grep output (which would be empty, not "unknown"). The check is harmless but could be simplified:

♻️ Optional simplification
-		if [[ -z "$version" || "$version" == "unknown" ]] && [[ -n "$pkg" ]]; then
+		if [[ -z "$version" ]] && [[ -n "$pkg" ]]; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/tool-version-check.sh around lines 171 - 182, The
conditional that checks for an "unknown" literal is redundant because version
comes from grep output and will be empty when unparseable; update the fallback
condition in the tool-version-check logic to only test for an empty/undefined
version (e.g., use [[ -z "$version" ]] && [[ -n "$pkg" ]]) so the pkg fallback
via get_npm_pkg_version is reached correctly—look for the block referencing the
variables version and pkg and the call to get_npm_pkg_version to make this
change.

113-126: Well-designed fallback function for npm package version extraction.

The implementation correctly handles scoped packages (e.g., @steipete/macos-automator-mcp) and has appropriate error handling with early returns. The -f check prevents file-not-found errors gracefully.

Minor observation: If npm root -g succeeds but returns an empty string (rare edge case), the path would become //pkg/package.json. The -f check catches this safely, but an explicit empty-check could make intent clearer:

🛡️ Optional defensive enhancement
 get_npm_pkg_version() {
 	local pkg="$1"
 	local npm_root
 	npm_root="$(npm root -g 2>/dev/null)" || return 1
+	[[ -n "$npm_root" ]] || return 1
 	local pkg_json="${npm_root}/${pkg}/package.json"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/tool-version-check.sh around lines 113 - 126, The
get_npm_pkg_version function should explicitly guard against npm_root being
empty: after running npm_root="$(npm root -g ...)" check that npm_root is
non-empty before constructing pkg_json to avoid producing paths like
//pkg/package.json; update the function (referencing get_npm_pkg_version, the
npm_root variable and pkg_json) to return failure if npm_root is empty (or
trim/normalize it) before proceeding to the -f check and grep logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.agents/scripts/tool-version-check.sh:
- Around line 171-182: The conditional that checks for an "unknown" literal is
redundant because version comes from grep output and will be empty when
unparseable; update the fallback condition in the tool-version-check logic to
only test for an empty/undefined version (e.g., use [[ -z "$version" ]] && [[ -n
"$pkg" ]]) so the pkg fallback via get_npm_pkg_version is reached correctly—look
for the block referencing the variables version and pkg and the call to
get_npm_pkg_version to make this change.
- Around line 113-126: The get_npm_pkg_version function should explicitly guard
against npm_root being empty: after running npm_root="$(npm root -g ...)" check
that npm_root is non-empty before constructing pkg_json to avoid producing paths
like //pkg/package.json; update the function (referencing get_npm_pkg_version,
the npm_root variable and pkg_json) to return failure if npm_root is empty (or
trim/normalize it) before proceeding to the -f check and grep logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f1ad7953-abdf-497d-a54b-3bdce93c3c92

📥 Commits

Reviewing files that changed from the base of the PR and between 254e22f and 1c3eae1.

📒 Files selected for processing (1)
  • .agents/scripts/tool-version-check.sh

OpenCode is installed via Homebrew (anomalyco/tap/opencode) but was listed
under NPM_TOOLS, causing false 'outdated' warnings when the brew tap
lagged behind npm releases. Move to BREW_TOOLS so the latest version is
checked against the brew tap instead.
@marcusquinn
Copy link
Owner

This PR is from an external contributor (@johnwaldo). Auto-merge is disabled for external PRs — a maintainer must review and approve manually.


To approve or decline, comment on this PR:

  • approved — removes the review gate and allows merge (CI permitting)
  • declined: <reason> — closes this PR (include your reason after the colon)

@marcusquinn marcusquinn added external-contributor PR from external contributor, requires maintainer review needs-maintainer-review needs-review-fixes labels Mar 9, 2026
@marcusquinn
Copy link
Owner

Dispatching worker to address unresolved review suggestions before merge.

  • Model: opus (anthropic/claude-opus-4-6) — default tier
  • Branch: fix/tool-version-check-mcp-servers
  • Scope: Address 3 unresolved inline review suggestions from CodeRabbit
  • Attempt: 1 of 1
  • Direction: Apply valid suggestions, dismiss invalid ones with explanation

@marcusquinn
Copy link
Owner

Review suggestions addressed (a8a3921)

Applied (3 of 4):

  1. Read log file once (Gemini) — Read $_ver_log into ver_output variable once, then grep from the variable. Avoids double file read.
  2. Remove redundant "unknown" check (Gemini + CodeRabbit) — $version can only be empty or a version string after the grep operations, never the literal "unknown". Simplified condition.
  3. Guard empty npm_root (CodeRabbit) — Added [[ -n "$npm_root" ]] || return 1 after npm root -g to explicitly handle the rare case where it succeeds but returns empty.

Declined (1 of 4):

  1. Use jq instead of grep chain (Gemini) — This script runs on diverse systems where jq may not be installed. The grep chain is sufficient for npm's well-structured package.json format. Adding a jq dependency for a single version extraction is over-engineering.

All changes verified: ShellCheck clean, script tested and producing correct output for MCP servers.

@marcusquinn marcusquinn merged commit 9550315 into marcusquinn:main Mar 9, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Auto-created from TODO.md tag external-contributor PR from external contributor, requires maintainer review needs-maintainer-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants