Skip to content

feat: refactor HTTP transport to use dynamic port allocation#97

Merged
valebearzotti merged 3 commits intobasementstudio:canaryfrom
alejorrojas:find-available-port
Jul 27, 2025
Merged

feat: refactor HTTP transport to use dynamic port allocation#97
valebearzotti merged 3 commits intobasementstudio:canaryfrom
alejorrojas:find-available-port

Conversation

@alejorrojas
Copy link
Contributor

@alejorrojas alejorrojas commented Jul 25, 2025

Important: Please ensure your pull request is targeting the canary branch. PRs to other branches may be closed or require retargeting.

Summary

Refactors the HTTP transport to use dynamic port allocation, preventing port conflicts when multiple server instances are running. The implementation automatically finds the next available port when the default port is in use.

If the HTTP port is not explicitly configured, it searches for an available port starting from 3002 and incrementing upwards.

  • Updated HTTP transport to use dynamic port allocation
  • Created new port-utils.ts file to encapsulate port allocation logic
  • Made the start() method asynchronous to support port discovery
  • Added user-friendly console messages when port fallback occurs

Type of Change

  • Bug fixing
  • Adding a feature
  • Improving documentation
  • Adding or updating examples
  • Performance - bundle size improvement (if applicable)

Affected Packages

  • xmcp (core framework)
  • create-xmcp-app
  • init-xmcp
  • Documentation
  • Examples

Screenshots/Examples

Before (problematic behavior):

# Two processes already running on port 3002
$ pnpm run dev
 XMCP  Starting development mode...
✔ Compiled in 528ms
✔ Built HTTP server
❯ Starting http server
node:events:502
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE: address already in use 127.0.0.1:3002
    at Server.setupListenHandle [as _listen2] (node:net:1908:16)
    at listenInCluster (node:net:1965:12)
    at doListen (node:net:2139:7)
    at process.processTicksAndRejections (node:internal/process/task_queues:83:21)
Emitted 'error' event on Server instance at:
    at emitErrorNT (node:net:1944:8)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'EADDRINUSE',
  errno: -48,
  syscall: 'listen',
  address: '127.0.0.1',
  port: 3002
}

After (fixed behavior):

# Two processes already running on port 3002
$ pnpm run dev
 XMCP  Starting development mode...
✔ Compiled in 502ms
✔ Built HTTP server
❯ Starting http server
❯ Port 3002 is in use, trying 3003 instead.
✔ MCP Server running on http://127.0.0.1:3003/mcp
image

Related Issues

Resolves #89

@vercel
Copy link
Contributor

vercel bot commented Jul 25, 2025

@alejorrojas is attempting to deploy a commit to the basement Team on Vercel.

A member of the Team first needs to authorize it.

@alejorrojas
Copy link
Contributor Author

alejorrojas commented Jul 25, 2025

@valebearzotti This is my approach to solving the issue, let me know if there’s anything you’d like me to adjust

@valebearzotti
Copy link
Collaborator

Hey @alejorrojas !

Overall it's a good implementation, super clean 👏🏻

The only thing I'm concerned about is since we're changing the start method to be asynchronous if that should be handled when starting the transport. This means:

transport.start();

should be awaited (main function is already async)

startPort: number = 3002,
host: string = "127.0.0.1"
): Promise<number> {
return new Promise((resolve, reject) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

reject is unused, we can remove it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

totally right, I already removed it

@alejorrojas
Copy link
Contributor Author

Hi @valebearzotti!

Thanks for your time and the feedback.

About the await on transport.start();, you’re right. I’ve already added a new commit including the await on the method call.

Let me know if there’s anything else!

Copy link
Collaborator

@valebearzotti valebearzotti left a comment

Choose a reason for hiding this comment

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

👏🏻👏🏻

@valebearzotti valebearzotti merged commit 6061a81 into basementstudio:canary Jul 27, 2025
1 check failed
@matiasngf
Copy link
Contributor

Question, why did we changed the default port from 3001 to 3002?

The default url for the mcp inspector is localhost:3001, that was the reason we used that port

@valebearzotti
Copy link
Collaborator

@matiasngf that was my mistake when copying the config from one of the examples, that was setting it up to 3002 instead of 1

0xKoller pushed a commit that referenced this pull request Jan 7, 2026
feat: refactor HTTP transport to use dynamic port allocation
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.

3 participants