Skip to content

fix: auto-fallback MCP server port when already in use - #308

Open
jsmorabito wants to merge 7 commits into
eharris128:mainfrom
jsmorabito:fix/mcp-port-auto-fallback
Open

fix: auto-fallback MCP server port when already in use#308
jsmorabito wants to merge 7 commits into
eharris128:mainfrom
jsmorabito:fix/mcp-port-auto-fallback

Conversation

@jsmorabito

Copy link
Copy Markdown
Collaborator

Summary

  • Each vault runs its own built-in MCP server, but the port setting defaults identically across vaults, so enabling the server in a second or third open vault hit EADDRINUSE.
  • McpTransportServer.start() now walks forward to the next free port on EADDRINUSE (up to 20 attempts) instead of just failing.
  • The plugin persists whichever port actually got bound and surfaces a one-time Notice explaining the fallback, so multi-vault MCP setups (e.g. connecting Claude Desktop to several vaults at once) no longer require manually hunting for a free port before it'll start.

Test plan

  • npm run typecheck
  • npm run lint
  • npm run lint:css
  • npm run build
  • Manually verify: enable MCP server in two vaults simultaneously, confirm the second one auto-falls-back to the next port and shows the notice, and that the settings tab's port field + claude_desktop_config.json snippet reflect the actual bound port.

🤖 Generated with Claude Code

jsmorabito and others added 7 commits July 8, 2026 12:21
Adds a Streamable HTTP MCP server (127.0.0.1-bound, bearer-token
authenticated) so Claude Desktop or any other MCP client can list,
read, search, create, edit, move, and delete vault notes directly,
without a separate companion plugin. Writes go through a new
permission modal (create/edit/move/delete); reads run immediately.
Every path is resolved and validated against the vault root to
reject traversal attempts, including encoded/double-encoded variants.

The MCP SDK is loaded lazily (dynamic import, gated on
Platform.isDesktop && settings.mcpServerSettings.enabled) so its
node:http dependency chain never executes at plugin load on mobile.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add built-in MCP server for external vault access
esbuild's outfile pointed at ../large-language-models/ (this local dev
vault's live plugin folder) as the primary build target. That path
doesn't exist in a plain CI checkout, so release.yml's "Attest main.js"
step — which references the bare "main.js" path — couldn't find the
file (discovered while cutting the 0.24.24 release; CI's build step
itself silently succeeded because esbuild auto-creates its outfile's
parent directory one level above the checkout).

main.js/manifest.json/styles.css now build at the repo root first
(matching what release.yml expects and what CLAUDE.md documents), then
get mirrored to the sibling live-vault folder only when it exists —
a no-op in CI, unchanged local dev convenience otherwise.
Documents the lazy-load mobile-safety pattern (dynamic import gated on
Platform.isDesktop), the obsidianmd/no-nodejs-modules lint rule's
structural guard requirement, the McpPermissionModal vs. in-chat
permission gate distinction, and the mcp-remote bridge workaround for
clients that only accept command/args config entries.
# Conflicts:
#	.claude/rules/mcp-server.md
#	CLAUDE.md
#	manifest.json
#	package-lock.json
#	package.json
#	src/Settings/LLMSettingsModal.ts
#	src/main.ts
#	src/mcp/transport.ts
#	styles.css
#	versions.json
Each vault runs its own MCP server, but the port setting defaults
identically across vaults, so enabling the server in a second or third
vault hit EADDRINUSE. McpTransportServer.start() now walks forward to
the next free port on EADDRINUSE (up to 20 attempts), and the plugin
persists + surfaces whichever port actually got bound instead of just
erroring out.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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