Skip to content

Conversation

eli0shin
Copy link
Owner

Summary

  • Implement BUN_BE_BUN functionality to eliminate redundant bunx usage when running MCP servers
  • Transform user experience from bunx mcp-controller bunx server to bunx mcp-controller server
  • Leverage Bun's native BUN_BE_BUN=1 environment variable for direct npm package execution
  • Add comprehensive integration testing with real npm packages
  • Update documentation with usage examples and design rationale

Changes

Core Implementation

  • Modified src/target-server.ts: Complete rewrite of target server spawning logic
    • Use process.execPath with "x" command and BUN_BE_BUN=1 environment variable
    • Strip redundant bunx/npx prefixes from command arguments to prevent double-wrapping
    • Maintain full compatibility with existing command patterns while enabling cleaner syntax

Package Optimization

  • Modified package.json: Optimized dependency structure and metadata
    • Moved MCP SDK to devDependencies for smaller runtime footprint
    • Moved Zod to devDependencies as it's only used in tests
    • Updated description to better reflect controller functionality
    • Added author information

Documentation & Design

  • Updated README.md: Added clear usage example for npm-distributed MCP servers
  • Added docs/bunx-elimination-design.md: Comprehensive design document explaining:
    • Problem statement and motivation
    • Technical implementation approach using BUN_BE_BUN
    • Benefits and usage patterns
    • Detailed before/after examples

Test Coverage

  • Added tests/bunx-integration.test.ts: Real-world integration test
    • Tests actual npm package execution (@modelcontextprotocol/server-sequential-thinking)
    • Validates complete MCP initialization flow through BUN_BE_BUN
    • Uses MCP SDK types for proper response validation
    • Follows established testing patterns with complete object assertions

Technical Benefits

User Experience

  • Cleaner CLI: bunx mcp-controller server instead of bunx mcp-controller bunx server
  • Universal Compatibility: Works with npm packages, Docker commands, local scripts, and any CLI tool
  • Intuitive: Matches user expectations for how package runners should work

Performance & Reliability

  • Leverages Bun Speed: Inherits Bun's 100x performance improvement over npx
  • Global Caching: Benefits from Bun's efficient package caching system
  • Single Process: Eliminates extra process overhead from nested bunx calls

Implementation Quality

  • Zero Breaking Changes: Existing commands continue to work exactly as before
  • Robust: Handles edge cases like pre-stripped bunx/npx prefixes
  • Well-Tested: Integration tests with real npm packages ensure production reliability

Usage Examples

# Clean syntax for npm packages
bunx mcp-controller @modelcontextprotocol/server-sequential-thinking

# Local TypeScript servers  
bunx mcp-controller ./my-server.ts

# Python servers
bunx mcp-controller python -m my_mcp_server

# Docker containers
bunx mcp-controller docker run --rm some-mcp-image

# Traditional commands still work
bunx mcp-controller bun run server.ts

Implementation Details

BUN_BE_BUN Mechanism

  • Sets BUN_BE_BUN=1 environment variable to make compiled executable act like bun CLI
  • Uses process.execPath with "x" command to replicate bunx behavior
  • Automatically strips redundant bunx/npx prefixes to prevent double execution

Compatibility Strategy

  • Maintains full backward compatibility with existing usage patterns
  • Gracefully handles commands that already include bunx or npx prefixes
  • No changes required for existing integrations or workflows

Test Plan

  • Integration test passes with real npm package (@modelcontextprotocol/server-sequential-thinking)
  • MCP initialization flow works correctly through BUN_BE_BUN
  • Command argument stripping handles bunx/npx prefixes properly
  • All existing tests continue to pass without modification
  • Package dependency optimization doesn't break functionality
  • Documentation accurately reflects new capabilities

🤖 Generated with Claude Code

Co-Authored-By: Claude [email protected]

eli0shin and others added 2 commits August 27, 2025 08:25
- Move @modelcontextprotocol/sdk and zod to devDependencies as they are bundled
- Remove unnecessary peerDependencies and engines sections
- Update description to better reflect tool control functionality
- Add author field

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

Co-Authored-By: Claude <[email protected]>
Eliminates redundant bunx usage by leveraging Bun's BUN_BE_BUN=1
environment variable to make the compiled executable behave like bunx.

This allows clean usage patterns:
- bunx mcp-controller @some/mcp-server (instead of bunx mcp-controller bunx @some/mcp-server)
- Works with any npm package, Docker command, or CLI tool
- Maintains backward compatibility with existing commands

Changes:
- Modified target-server.ts to use process.execPath with "x" command and BUN_BE_BUN=1
- Added automatic stripping of bunx/npx prefixes to avoid redundancy
- Added integration test with real npm package @modelcontextprotocol/server-sequential-thinking
- Updated README with npm package usage example
- Added comprehensive design documentation

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

Co-Authored-By: Claude <[email protected]>
@eli0shin eli0shin marked this pull request as ready for review August 27, 2025 13:12
@Copilot Copilot AI review requested due to automatic review settings August 27, 2025 13:12
@eli0shin eli0shin merged commit 3f6edb3 into main Aug 27, 2025
1 check passed
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements BUN_BE_BUN functionality to eliminate redundant bunx usage when running MCP servers, transforming the user experience from bunx mcp-controller bunx server to bunx mcp-controller server.

  • Leverages Bun's native BUN_BE_BUN=1 environment variable for direct npm package execution
  • Adds comprehensive integration testing with real npm packages
  • Optimizes package dependencies by moving MCP SDK and Zod to devDependencies

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/target-server.ts Implements BUN_BE_BUN mechanism to eliminate redundant bunx calls
tests/bunx-integration.test.ts Adds integration test with real npm package to validate BUN_BE_BUN functionality
package.json Optimizes dependencies and updates package metadata
docs/bunx-elimination-design.md Documents the design rationale and implementation approach
README.md Adds usage example for npm-distributed MCP servers

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines 10 to +13

const [command, ...args] = config.targetCommand;

const process = Bun.spawn([command, ...args], {
// Strip bunx/npx prefixes to avoid redundant calls
Copy link

Copilot AI Aug 27, 2025

Choose a reason for hiding this comment

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

This logic incorrectly handles the case when args is empty. If command is 'bunx' or 'npx' but args is empty, targetCommand will be an empty array, leading to an invalid spawn call. Should check args.length before destructuring.

Copilot uses AI. Check for mistakes.

Comment on lines +26 to +28
// Give the proxy time to start and install the npm package
await new Promise(resolve => setTimeout(resolve, 3000));

Copy link

Copilot AI Aug 27, 2025

Choose a reason for hiding this comment

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

[nitpick] Hard-coded 3-second timeout may be insufficient for slower systems or network conditions. Consider making this configurable or using a more robust waiting mechanism that checks for process readiness.

Suggested change
// Give the proxy time to start and install the npm package
await new Promise(resolve => setTimeout(resolve, 3000));
// Wait for the proxy process to be ready by reading the first line of stdout (with timeout)
async function waitForProcessReady(stream, timeoutMs = 10000) {
const reader = stream.getReader();
const decoder = new TextDecoder();
let ready = false;
let value;
const start = Date.now();
while (Date.now() - start < timeoutMs) {
const { value: chunk, done } = await Promise.race([
reader.read(),
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout waiting for process readiness')), 1000))
]);
if (done) break;
if (chunk) {
value = chunk;
ready = true;
break;
}
}
reader.releaseLock();
if (!ready) throw new Error('Process did not become ready in time');
return value;
}
// Wait for process to emit first stdout (as readiness signal)
if (!proxyProcess.stdout || typeof proxyProcess.stdout === 'number') {
throw new Error('Process stdout is not available');
}
await waitForProcessReady(proxyProcess.stdout);

Copilot uses AI. Check for mistakes.

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.

1 participant