Skip to content

Conversation

@gulivan
Copy link
Collaborator

@gulivan gulivan commented Sep 24, 2025

Add comprehensive support for bunx (Bun) and pipx (Python) package managers in MCP server version detection alongside existing npx/uvx support.

Features:

  • Parse bunx commands (identical patterns to npx)
  • Parse pipx commands with --spec and --python flags
  • Query npm registry for JavaScript packages (npx/bunx)
  • Query PyPI registry for Python packages (pipx/uvx)
  • Extract versions directly from command strings when specified
  • Graceful fallback to "unknown" on network/parsing errors

Testing:

  • 17 unit tests for command parsing (no external dependencies)
  • 10 integration tests with mocked API calls (CI-safe)
  • Separate test:integration command for local testing with real tools
  • All existing tests pass (202 total)

CI Safety:

  • No external tool dependencies (npx/bunx/pipx/uvx not required)
  • Network requests mocked in tests for reliability
  • Main test command excludes integration directory
  • Version detection works purely through command parsing + HTTP APIs

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Displays actual package versions for compatible STDIO servers instead of "unknown" by resolving package versions from command or registries.
  • Tests

    • Added unit and integration suites covering command parsing and package-version resolution.
    • Test scripts updated: default excludes integration; new scripts for unit, integration, all, watch, and full test+type-check runs.
  • Documentation

    • Added integration tests README with prerequisites and run instructions.
  • Chores

    • Streamlined test workflow for CI and local development.

Add comprehensive support for bunx (Bun) and pipx (Python) package managers
in MCP server version detection alongside existing npx/uvx support.

Features:
- Parse bunx commands (identical patterns to npx)
- Parse pipx commands with --spec and --python flags
- Query npm registry for JavaScript packages (npx/bunx)
- Query PyPI registry for Python packages (pipx/uvx)
- Extract versions directly from command strings when specified
- Graceful fallback to "unknown" on network/parsing errors

Testing:
- 17 unit tests for command parsing (no external dependencies)
- 10 integration tests with mocked API calls (CI-safe)
- Separate test:integration command for local testing with real tools
- All existing tests pass (202 total)

CI Safety:
- No external tool dependencies (npx/bunx/pipx/uvx not required)
- Network requests mocked in tests for reliability
- Main test command excludes integration directory
- Version detection works purely through command parsing + HTTP APIs

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adds package-version resolution for STDIO MCP servers by parsing invocation commands and querying npm or PyPI; integrates resolved version into MCP connect/verify. Introduces src/core/packageVersionUtils, updates mcpClient to use it, adds unit and integration tests, and splits test scripts with integration tests documented.

Changes

Cohort / File(s) Summary
Test scripts & CI commands
package.json
Split test scripts: default test now excludes tests/integration; added test:all, test:unit, test:integration; updated test:watch and test_all to exclude integration by default.
MCP client integration
src/core/mcpClient.ts
Import and call getPackageVersion(...) to resolve and set serverInfo.version during connectAndVerify instead of hardcoding "unknown", preserving timeouts and error handling.
Package version utilities (new)
src/core/packageVersionUtils.ts
New module with PackageInfo, parsePackageFromCommand, isPythonPackageManager, fetchPackageVersionFromNpm, fetchPackageVersionFromPyPI, and getPackageVersion. Parses npx/bunx/pipx/uvx commands and queries registries with timeouts, returning versions or "unknown".
Unit tests for parsing
tests/core/packageVersion.test.ts
New unit tests covering parsing logic for npx/bunx/pipx/uvx patterns, scoped packages, explicit versions/tags, flags, and non-package commands.
Integration tests for resolution
tests/core/packageVersionIntegration.test.ts
New integration-style tests mocking fetch to validate registry requests/responses, direct-version extraction, error/rejection handling, and behavior for non-STDIO servers.
Integration testing docs
tests/integration/README.md
Added README explaining separation of integration tests, prerequisites, and commands to run integration / all / CI-safe unit tests.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant MCP as MCP Client
  participant Utils as packageVersionUtils
  participant NPM as npm Registry
  participant PyPI as PyPI Registry
  participant Server as STDIO Server

  Client->>MCP: connectAndVerify(server)
  MCP->>Utils: parsePackageFromCommand(server.command, server.args)
  alt explicit version found
    Utils-->>MCP: PackageInfo {name, version}
  else no explicit version
    MCP->>Utils: getPackageVersion(server)
    alt npm-style manager
      Utils->>NPM: GET /-/package/<pkg>/dist-tags (with timeout)
      NPM-->>Utils: dist-tags.latest or error
    else python-style manager
      Utils->>PyPI: GET /pypi/<pkg>/json (with timeout)
      PyPI-->>Utils: info.version or error
    end
    Utils-->>MCP: resolved version or null
  end
  MCP->>MCP: set serverInfo.version (resolved or "unknown")
  MCP->>Server: Initialize / request capabilities
  Server-->>MCP: Capabilities / info
  MCP-->>Client: Verified connection (includes serverInfo.version)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I hop through commands and registry glades,
sniffing npx burrows and PyPI shades.
I fetch the tag, or read the line,
if all else fails, "unknown" is mine.
Thump—tests split, utilities sewn, carrots for versions grown!

Pre-merge checks and finishing touches

✅ 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 summarizes the principal change—adding package version detection for both bunx and pipx—and uses concise, descriptive language that aligns with conventional commit style. It matches the PR objectives and focuses on the key feature without extraneous details or ambiguity.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/add-bunx-pipx-version-detection

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

@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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/core/mcpClient.ts (1)

33-91: Consider extracting regex patterns as constants for maintainability.

The regex patterns are complex and repeated across multiple files. Consider extracting them as named constants to improve readability and maintainability.

+const PACKAGE_PATTERNS = {
+  NPX_VERSION: /npx\s+(?:-[ygc]\s+)?(?:--\S+\s+)*([^@\s]+)@([^\s]+)/,
+  NPX_SCOPED: /npx\s+(?:-[ygc]\s+)?(?:--\S+\s+)*(@[^/]+\/[^@\s]+)(?:@([^\s]+))?/,
+  NPX_BASIC: /npx\s+(?:-[ygc]\s+)?(?:--\S+\s+)*([^@\s]+)/,
+  BUNX_VERSION: /bunx\s+(?:-[ygc]\s+)?(?:--\S+\s+)*([^@\s]+)@([^\s]+)/,
+  BUNX_SCOPED: /bunx\s+(?:-[ygc]\s+)?(?:--\S+\s+)*(@[^/]+\/[^@\s]+)(?:@([^\s]+))?/,
+  BUNX_BASIC: /bunx\s+(?:-[ygc]\s+)?(?:--\S+\s+)*([^@\s]+)/,
+  PIPX_SPEC: /pipx\s+run\s+--spec\s+([^=\s]+)==([^\s]+)/,
+  PIPX_RUN: /pipx\s+run\s+(?:--python\s+[^\s]+\s+)?([^@\s]+)/,
+  UVX_BASIC: /uvx\s+(?:--from\s+[^\s]+\s+)?([^@\s]+)/
+};

 function parsePackageFromCommand(command: string, args: string[] = []): PackageInfo | null {
   const fullCommand = [command, ...args].join(' ');

   // Pattern 1: npx package-name@version
-  const npxVersionMatch = fullCommand.match(/npx\s+(?:-[ygc]\s+)?(?:--\S+\s+)*([^@\s]+)@([^\s]+)/);
+  const npxVersionMatch = fullCommand.match(PACKAGE_PATTERNS.NPX_VERSION);
   // ... apply similar changes to other patterns
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b39277 and 62df3b0.

📒 Files selected for processing (5)
  • package.json (1 hunks)
  • src/core/mcpClient.ts (2 hunks)
  • tests/core/packageVersion.test.ts (1 hunks)
  • tests/core/packageVersionIntegration.test.ts (1 hunks)
  • tests/integration/README.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write clean, maintainable code following TypeScript best practices
Use TypeScript for type safety when applicable
Follow consistent naming conventions
Add comments for complex logic
Maintain consistency with existing code style
Add appropriate error handling
Never expose sensitive information in code or logs
Follow security best practices for TypeScript
Validate all inputs
Use environment variables for configuration
Document all public APIs, functions, and classes with clear descriptions

Files:

  • tests/core/packageVersion.test.ts
  • tests/core/packageVersionIntegration.test.ts
  • src/core/mcpClient.ts
**/*.{test,spec}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{test,spec}.ts: Write unit tests for all business logic using Jest
Test edge cases and error scenarios
Update tests when modifying functionality

Files:

  • tests/core/packageVersion.test.ts
  • tests/core/packageVersionIntegration.test.ts
package.json

📄 CodeRabbit inference engine (CLAUDE.md)

Use npm for dependency management

Files:

  • package.json
🧠 Learnings (4)
📚 Learning: 2025-09-24T11:44:03.031Z
Learnt from: CR
PR: agentinit/agentinit#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-24T11:44:03.031Z
Learning: Include integration tests for critical paths

Applied to files:

  • tests/integration/README.md
📚 Learning: 2025-09-19T20:17:12.331Z
Learnt from: CR
PR: agentinit/agentinit#0
File: .cursorrules:0-0
Timestamp: 2025-09-19T20:17:12.331Z
Learning: Write both unit tests for individual components and integration tests

Applied to files:

  • tests/integration/README.md
📚 Learning: 2025-09-24T11:44:03.031Z
Learnt from: CR
PR: agentinit/agentinit#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-24T11:44:03.031Z
Learning: Applies to **/*.{test,spec}.ts : Update tests when modifying functionality

Applied to files:

  • tests/core/packageVersion.test.ts
  • package.json
📚 Learning: 2025-09-24T11:44:03.031Z
Learnt from: CR
PR: agentinit/agentinit#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-24T11:44:03.031Z
Learning: Applies to **/*.{test,spec}.ts : Test edge cases and error scenarios

Applied to files:

  • tests/core/packageVersion.test.ts
🧬 Code graph analysis (2)
tests/core/packageVersion.test.ts (1)
tests/core/packageVersionIntegration.test.ts (1)
  • parsePackageFromCommand (11-69)
src/core/mcpClient.ts (2)
tests/core/packageVersionIntegration.test.ts (5)
  • parsePackageFromCommand (11-69)
  • fetchPackageVersionFromNpm (71-93)
  • fetchPackageVersionFromPyPI (95-117)
  • isPythonPackageManager (119-122)
  • getPackageVersion (124-146)
src/types/index.ts (1)
  • MCPServerConfig (80-88)
🔇 Additional comments (14)
tests/core/packageVersion.test.ts (2)

6-63: LGTM! Comprehensive pattern matching for package managers.

The parsing logic correctly handles all the different package manager patterns including npx, bunx, pipx, and uvx with their various flag combinations and version specifications.


65-154: LGTM! Thorough test coverage for command parsing.

Excellent test coverage including edge cases, scoped packages, version specifications, and different flag combinations across all supported package managers.

src/core/mcpClient.ts (4)

96-118: LGTM! Robust npm registry integration.

The implementation includes proper timeout handling, error handling, and graceful fallback to null on failures.


123-145: LGTM! Clean PyPI registry integration.

Good implementation with proper error handling and consistent structure with the npm version.


156-191: LGTM! Well-documented version resolution logic.

The function has clear documentation explaining the resolution strategy and gracefully handles all edge cases. The comment explicitly notes that no external tools are required, which is important for CI compatibility.


414-419: LGTM! Clean integration into the MCP verification flow.

The package version resolution is properly integrated into the server connection flow, replacing the hardcoded "unknown" value with the actual resolved version.

tests/core/packageVersionIntegration.test.ts (6)

149-157: LGTM! Proper test setup and teardown.

Good practice using beforeEach to clear mocks and afterEach to restore all mocks.


158-225: LGTM! Comprehensive npm registry integration tests.

Excellent coverage of npm registry interactions including success cases, error handling, and proper URL construction verification.


227-290: LGTM! Thorough PyPI registry integration tests.

Good coverage of PyPI interactions including both pipx and uvx commands, with proper error handling tests.


292-318: LGTM! Version extraction tests validate command parsing.

Good tests confirming that versions specified in commands are used directly without API calls.


320-346: LGTM! Edge case handling for non-package commands.

Properly tests that non-package manager commands and non-STDIO servers return "unknown" without making unnecessary API calls.


8-10: Consider using a more robust approach for testing internal functions.

Similar to the unit tests, this creates another duplicate implementation of the parsing logic. This triples the maintenance burden.

package.json (1)

13-18: LGTM! Well-organized test script structure.

The test scripts are properly organized to separate unit and integration tests, with sensible defaults that exclude integration tests from CI runs. This aligns well with the goal of keeping CI fast while allowing comprehensive local testing.

tests/integration/README.md (1)

1-30: LGTM! Clear documentation for test organization.

The README clearly explains the rationale for separating integration tests and provides helpful commands for running different test suites. The categorization and goals are well-defined.

Copy link

@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.

Actionable comments posted: 2

🧹 Nitpick comments (8)
src/core/mcpClient.ts (1)

247-253: Avoid blocking server verification on registry lookups; add abort-aware, short-circuit fallback.

Fetching the package version here can add up to 5s latency and ignores the provided abortSignal. Prefer racing it with a short timeout and the abortSignal so verification isn't delayed by registry slowness.

Apply this diff to make version resolution non-blocking and abort-aware:

-      // Get server info and fetch package version
-      const packageVersion = await getPackageVersion(server);
+      // Get server info and fetch package version with a short cap and abort awareness
+      const packageVersion = await Promise.race<string>([
+        getPackageVersion(server),
+        new Promise<string>(resolve => setTimeout(() => resolve('unknown'), 1500)),
+        new Promise<string>(resolve => {
+          if (abortSignal?.aborted) return resolve('unknown');
+          abortSignal?.addEventListener('abort', () => resolve('unknown'), { once: true });
+        }),
+      ]);

If you want fuller cancellation, consider extending getPackageVersion to accept an AbortSignal and propagate it downstream. As per coding guidelines.

tests/core/packageVersion.test.ts (1)

1-92: Solid unit coverage; add UVX flag variants.

Great breadth across managers and scoped packages. Consider adding a UVX case with extra flags to guard future regex tweaks.

Apply this diff to extend coverage:

   it('should parse uvx with --from flag', () => {
     const result = parsePackageFromCommand('uvx', ['--from', 'git+https://github.com/user/repo.git', 'package-name']);
     expect(result).toEqual({ name: 'package-name' });
   });
+
+  it('should parse uvx with additional flags', () => {
+    const result = parsePackageFromCommand('uvx', ['-q', '--isolated', 'black']);
+    expect(result).toEqual({ name: 'black' });
+  });

Based on learnings

tests/core/packageVersionIntegration.test.ts (2)

1-8: Prefer stubbing globals via Vitest helpers.

Direct assignment works but is brittle across environments. Use vi.stubGlobal/vi.unstubAllGlobals for safer setup/teardown.

Example:

const mockFetch = vi.fn();

beforeAll(() => {
  vi.stubGlobal('fetch', mockFetch);
});

afterAll(() => {
  vi.unstubAllGlobals();
});

Based on learnings


18-88: Nice npm-path coverage; add ‘latest’ deref case.

You test direct versions and error paths. Add a case where the command specifies @latest to assert the registry is consulted.

Proposed test:

it('should dereference @latest via npm registry', async () => {
  mockFetch.mockResolvedValueOnce({ ok: true, json: async () => ({ 'dist-tags': { latest: '9.9.9' } }) });
  const server = { name: 'x', type: MCPServerType.STDIO, command: 'npx', args: ['pkg@latest'] };
  const version = await getPackageVersion(server);
  expect(version).toBe('9.9.9');
});
src/core/packageVersionUtils.ts (4)

129-132: Stricter manager detection to avoid false positives.

includes('uvx') could mis-route if 'uvx' appears in args. Check the first token instead.

Apply this diff:

-export function isPythonPackageManager(command: string, args: string[] = []): boolean {
-  const fullCommand = [command, ...args].join(' ');
-  return fullCommand.includes('pipx') || fullCommand.includes('uvx');
-}
+export function isPythonPackageManager(command: string, _args: string[] = []): boolean {
+  const firstToken = String(command || '').trim().split(/\s+/)[0];
+  return firstToken === 'pipx' || firstToken === 'uvx';
+}

63-67: UVX regex doesn’t handle additional flags.

Support generic long/short flags (with or without values) before the package name.

Apply this diff:

-  const uvxMatch = fullCommand.match(/uvx\s+(?:--from\s+[^\s]+\s+)?([^@\s]+)/);
+  const uvxMatch = fullCommand.match(/uvx\s+(?:--\S+(?:\s+[^\s]+)?\s+|-{1}\S+\s+)*([^@\s]+)/);

This skips sequences like: uvx -q --isolated --from https://... package-name


12-70: Reduce regex duplication for npx/bunx patterns (optional).

npx and bunx branches are identical. Consider a small helper to apply one set of patterns for a given manager to ease maintenance.

Sketch:

function matchJsManager(full: string, manager: 'npx'|'bunx'): PackageInfo | null { /* shared regex with variable */ }

158-169: Tag semantics: consider dereferencing non-semver tags (e.g., next, beta).

Current logic returns non-'latest' tags verbatim. Optionally, detect non-semver tags and resolve via registry for a concrete version.

Example:

const isSemver = /^\d+\.\d+\.\d+(-[\w.-]+)?$/.test(packageInfo.version);
if (packageInfo.version && isSemver) return packageInfo.version;
// else fall through to registry lookup
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62df3b0 and a00b1d8.

📒 Files selected for processing (4)
  • src/core/mcpClient.ts (2 hunks)
  • src/core/packageVersionUtils.ts (1 hunks)
  • tests/core/packageVersion.test.ts (1 hunks)
  • tests/core/packageVersionIntegration.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write clean, maintainable code following TypeScript best practices
Use TypeScript for type safety when applicable
Follow consistent naming conventions
Add comments for complex logic
Maintain consistency with existing code style
Add appropriate error handling
Never expose sensitive information in code or logs
Follow security best practices for TypeScript
Validate all inputs
Use environment variables for configuration
Document all public APIs, functions, and classes with clear descriptions

Files:

  • src/core/mcpClient.ts
  • tests/core/packageVersion.test.ts
  • src/core/packageVersionUtils.ts
  • tests/core/packageVersionIntegration.test.ts
**/*.{test,spec}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{test,spec}.ts: Write unit tests for all business logic using Jest
Test edge cases and error scenarios
Update tests when modifying functionality

Files:

  • tests/core/packageVersion.test.ts
  • tests/core/packageVersionIntegration.test.ts
🧠 Learnings (2)
📚 Learning: 2025-09-24T11:44:03.031Z
Learnt from: CR
PR: agentinit/agentinit#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-24T11:44:03.031Z
Learning: Applies to **/*.{test,spec}.ts : Update tests when modifying functionality

Applied to files:

  • tests/core/packageVersion.test.ts
  • tests/core/packageVersionIntegration.test.ts
📚 Learning: 2025-09-24T11:44:03.046Z
Learnt from: CR
PR: agentinit/agentinit#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-24T11:44:03.046Z
Learning: Applies to **/*.{test,spec}.ts : Test edge cases and error scenarios

Applied to files:

  • tests/core/packageVersion.test.ts
🧬 Code graph analysis (4)
src/core/mcpClient.ts (1)
src/core/packageVersionUtils.ts (1)
  • getPackageVersion (148-170)
tests/core/packageVersion.test.ts (1)
src/core/packageVersionUtils.ts (1)
  • parsePackageFromCommand (12-70)
src/core/packageVersionUtils.ts (1)
src/types/index.ts (1)
  • MCPServerConfig (80-88)
tests/core/packageVersionIntegration.test.ts (1)
src/core/packageVersionUtils.ts (1)
  • getPackageVersion (148-170)
🔇 Additional comments (1)
src/core/mcpClient.ts (1)

9-12: Import looks good.

Brings in the new utility cleanly with correct type import grouping.

- Fix timer cleanup in fetchPackageVersionFromNpm/PyPI using try/finally blocks
- Add non-blocking version resolution with 1.5s timeout and abort awareness in mcpClient
- Improve isPythonPackageManager detection to avoid false positives
- Fix UVX regex to handle additional flags properly
- Reduce code duplication by creating shared matchJsManager helper for npx/bunx
- Add semver detection for better tag handling (resolve non-semver tags via registry)
- Add comprehensive tests for all changes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copy link

@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.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a00b1d8 and 04a4426.

📒 Files selected for processing (3)
  • src/core/mcpClient.ts (2 hunks)
  • src/core/packageVersionUtils.ts (1 hunks)
  • tests/core/packageVersion.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/core/mcpClient.ts
  • tests/core/packageVersion.test.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write clean, maintainable code following TypeScript best practices
Use TypeScript for type safety when applicable
Follow consistent naming conventions
Add comments for complex logic
Maintain consistency with existing code style
Add appropriate error handling
Never expose sensitive information in code or logs
Follow security best practices for TypeScript
Validate all inputs
Use environment variables for configuration
Document all public APIs, functions, and classes with clear descriptions

Files:

  • src/core/packageVersionUtils.ts
🧬 Code graph analysis (1)
src/core/packageVersionUtils.ts (1)
src/types/index.ts (1)
  • MCPServerConfig (80-88)
🪛 ast-grep (0.39.5)
src/core/packageVersionUtils.ts

[warning] 13-13: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(${manager}\\s+(?:-[ygc]\\s+)?(?:--\\S+\\s+)*([^@\\s]+)@([^\\s]+))
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 19-19: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(${manager}\\s+(?:-[ygc]\\s+)?(?:--\\S+\\s+)*(@[^/]+\\/[^@\\s]+)(?:@([^\\s]+))?)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 25-25: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(${manager}\\s+(?:-[ygc]\\s+)?(?:--\\S+\\s+)*([^@\\s]+))
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

Copy link

@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.

Actionable comments posted: 0

🧹 Nitpick comments (6)
tests/core/packageVersionIntegration.test.ts (2)

1-1: Stabilize fetch mocking: type-safe assignment and restore original fetch

Avoid leaking the mocked fetch across files and fix TS typing by assigning/restoring in hooks.

Apply this diff:

-import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
+import { describe, it, expect, vi, beforeEach, afterEach, beforeAll, afterAll } from 'vitest';
@@
-// Mock fetch globally
-const mockFetch = vi.fn();
-global.fetch = mockFetch;
+// Mock fetch globally
+const mockFetch = vi.fn() as unknown as typeof fetch;
+let originalFetch: typeof global.fetch;
+
+beforeAll(() => {
+  originalFetch = global.fetch;
+});
@@
 afterEach(() => {
   vi.restoreAllMocks();
 });
+
+afterAll(() => {
+  // Restore original fetch to avoid leaking mocks to other test files
+  global.fetch = originalFetch;
+});

And ensure we set the mock per test run (so we don’t rely on file-load timing):

   beforeEach(() => {
-    mockFetch.mockClear();
+    mockFetch.mockClear();
+    global.fetch = mockFetch;
   });

As per coding guidelines

Also applies to: 5-8, 14-16


261-273: Add a scoped package test for npx -p to verify encoding

We currently don’t cover scoped packages for the npm registry path. Add a case like @scope/cli to ensure encodeURIComponent handling is correct.

Example test to add after this block:

it('should handle scoped packages with npx -p without API calls', async () => {
  const server = {
    name: 'test-server',
    type: MCPServerType.STDIO,
    command: 'npx',
    args: ['-p', '@scope/[email protected]', 'cli', '--help']
  };

  const version = await getPackageVersion(server);
  expect(mockFetch).not.toHaveBeenCalled();
  expect(version).toBe('2.1.0');
});
src/core/packageVersionUtils.ts (4)

90-115: Broaden timeout type for Node/browser parity

Use ReturnType instead of NodeJS.Timeout to keep types portable across environments.

Apply this diff in both functions:

-export async function fetchPackageVersionFromNpm(packageName: string, timeoutMs = 5000): Promise<string | null> {
-  let timeoutId: NodeJS.Timeout | undefined;
+export async function fetchPackageVersionFromNpm(packageName: string, timeoutMs = 5000): Promise<string | null> {
+  let timeoutId: ReturnType<typeof setTimeout> | undefined;
@@
 export async function fetchPackageVersionFromPyPI(packageName: string, timeoutMs = 5000): Promise<string | null> {
-  let timeoutId: NodeJS.Timeout | undefined;
+  let timeoutId: ReturnType<typeof setTimeout> | undefined;

As per coding guidelines

Also applies to: 120-145


150-153: Detect Python managers from args too (env wrappers, absolute paths)

When command is an interpreter or env shim, we may still have pipx/uvx in args. Check both for robustness.

Apply this diff:

-export function isPythonPackageManager(command: string, _args: string[] = []): boolean {
-  const firstToken = String(command || '').trim().split(/\s+/)[0];
-  return firstToken === 'pipx' || firstToken === 'uvx';
-}
+export function isPythonPackageManager(command: string, args: string[] = []): boolean {
+  const tokens = [String(command || '').trim(), ...(args ?? [])].filter(Boolean);
+  // Match exact tokens only to avoid false positives on similarly named binaries
+  return tokens.some(t => t === 'pipx' || t === 'uvx');
+}

169-207: Prefer cached lookups for “latest” registry queries

Repeated same-package lookups can be memoized to reduce latency and registry load. Cache only when we perform a registry fetch (i.e., when no version is specified or it’s a dist tag).

Apply this diff around the fetch call:

-  const usePyPI = isPythonPackageManager(server.command, server.args);
-  const latestVersion = usePyPI
-    ? await fetchPackageVersionFromPyPI(packageInfo.name)
-    : await fetchPackageVersionFromNpm(packageInfo.name);
-
-  return latestVersion || "unknown";
+  const usePyPI = isPythonPackageManager(server.command, server.args);
+  const cacheKey = `${usePyPI ? 'pypi' : 'npm'}:${packageInfo.name}`;
+  const cached = versionCache.get(cacheKey);
+  if (cached) return cached;
+
+  const latestVersion = usePyPI
+    ? await fetchPackageVersionFromPyPI(packageInfo.name)
+    : await fetchPackageVersionFromNpm(packageInfo.name);
+
+  if (latestVersion) {
+    versionCache.set(cacheKey, latestVersion);
+    return latestVersion;
+  }
+  return "unknown";

Add this at module scope:

const versionCache = new Map<string, string>();

Note: For long-running processes, consider a small TTL or size cap if package churn is expected.


27-41: Dynamic RegExp is safe here but consider literals for clarity

The interpolated manager is a closed union ('npx' | 'bunx'), so ReDoS risk is negligible. If you want to quiet scanners and improve readability, duplicate the patterns as regex literals for each manager or prebuild them once.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04a4426 and 7a11194.

📒 Files selected for processing (3)
  • src/core/packageVersionUtils.ts (1 hunks)
  • tests/core/packageVersion.test.ts (1 hunks)
  • tests/core/packageVersionIntegration.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/core/packageVersion.test.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write clean, maintainable code following TypeScript best practices
Use TypeScript for type safety when applicable
Follow consistent naming conventions
Add comments for complex logic
Maintain consistency with existing code style
Add appropriate error handling
Never expose sensitive information in code or logs
Follow security best practices for TypeScript
Validate all inputs
Use environment variables for configuration
Document all public APIs, functions, and classes with clear descriptions

Files:

  • src/core/packageVersionUtils.ts
  • tests/core/packageVersionIntegration.test.ts
**/*.{test,spec}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{test,spec}.ts: Write unit tests for all business logic using Jest
Test edge cases and error scenarios
Update tests when modifying functionality

Files:

  • tests/core/packageVersionIntegration.test.ts
🧠 Learnings (1)
📚 Learning: 2025-09-24T11:44:03.046Z
Learnt from: CR
PR: agentinit/agentinit#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-24T11:44:03.046Z
Learning: Applies to **/*.{test,spec}.ts : Update tests when modifying functionality

Applied to files:

  • tests/core/packageVersionIntegration.test.ts
🧬 Code graph analysis (2)
src/core/packageVersionUtils.ts (1)
src/types/index.ts (1)
  • MCPServerConfig (80-88)
tests/core/packageVersionIntegration.test.ts (1)
src/core/packageVersionUtils.ts (1)
  • getPackageVersion (169-207)
🪛 ast-grep (0.39.5)
src/core/packageVersionUtils.ts

[warning] 13-13: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(${manager}\\s+(?:-[ygc]\\s+)?(?:--\\S+\\s+)*-p\\s+([^\\s]+))
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 27-27: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(${manager}\\s+(?:-[ygc]\\s+)?(?:--\\S+\\s+)*([^@\\s]+)@([^\\s]+))
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 33-33: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(${manager}\\s+(?:-[ygc]\\s+)?(?:--\\S+\\s+)*(@[^/]+\\/[^@\\s]+)(?:@([^\\s]+))?)
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)


[warning] 39-39: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(${manager}\\s+(?:-[ygc]\\s+)?(?:--\\S+\\s+)*([^@\\s]+))
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🔇 Additional comments (3)
tests/core/packageVersionIntegration.test.ts (1)

289-301: Good coverage for pipx global flags with --python

This validates the relaxed regex for pipx global flags. Looks solid.

src/core/packageVersionUtils.ts (2)

12-45: JS manager parsing covers -p and scoped/inline specs well

The preinstall -p pattern and scoped package handling close the gap for npx/bunx flows. Nice.


67-75: pipx regex now tolerates global flags before run — addressed prior review

The relaxed patterns handle --python and other globals correctly. This resolves the earlier match failure.

Also applies to: 79-82

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants