Skip to content

(add): Add global MCP endpoint and Agent Tools management tools - #82

Open
ivanlopez wants to merge 1 commit into
mainfrom
feature/global-mcp-endpoint
Open

ivanlopez wants to merge 1 commit into
mainfrom
feature/global-mcp-endpoint

Conversation

@ivanlopez

Copy link
Copy Markdown

Adds /sites/mcp, a Local-wide MCP endpoint that is not bound to any site, alongside the existing per-site /sites/{siteId}/mcp routes. It can be configured once at user scope and used from any directory, which removes the bootstrap problem: previously the only way to reach the MCP server was to enable a site in Local's UI and then open that site's folder.

The route is collision-free — /sites/mcp is one path segment after /sites, so it cannot match the two-segment per-site pattern, and a site whose id is literally "mcp" still resolves at /sites/mcp/mcp.

Tool surface is now split in two. Site-scoped tools (wp_cli, the log readers, the wp-config tools, get_site_info, site_health_check) stay on the per-site endpoints, since they need a bound SiteConfig. Tools that address Local itself or take an explicit siteId are served on both. Sessions carry a nullable siteId and handleToolCall takes a nullable config, rejecting a site-scoped tool called globally with a message pointing at the per-site endpoint.

Three new tools wrap the setup and teardown paths that were previously reachable only through the renderer's IPC handlers:

  • enable_agent_tools registers a site, writes its MCP config and project context, and returns the site's own endpoint URL
  • disable_agent_tools tears down and is idempotent
  • agent_tools_status reports enablement, agents, project dir, registration and endpoint URL for one site or all of them

Two things surfaced while wiring those up:

setupSite only ever adds files, so it cannot be reused as-is for a site that is already enabled — moving the project dir would strand config at the old location, and narrowing the agent list would strand the dropped agents' files. enable_agent_tools now routes through changeProjectDir and updateAgents, which clean up after themselves, then regenerateConfig.

projectDir lands in path.join(sitePath, projectDir). That was safe coming from the UI's folder picker, but over MCP an absolute path or a .. segment would write agent config anywhere on disk, so it is now validated.

Adds 33 tests, including a real MCP handshake against the global endpoint covering the advertised tool list, a global tool call, the site-scoped refusal, and the /sites/mcp/mcp case.

Description of the Change

Closes #

How to test the Change

Changelog Entry

Added - New feature
Changed - Existing functionality
Deprecated - Soon-to-be removed feature
Removed - Feature
Fixed - Bug fix
Security - Vulnerability
Developer - Non-functional update

Credits

Props @username, ...

Checklist:

Adds /sites/mcp, a Local-wide MCP endpoint that is not bound to any site,
alongside the existing per-site /sites/{siteId}/mcp routes. It can be
configured once at user scope and used from any directory, which removes
the bootstrap problem: previously the only way to reach the MCP server was
to enable a site in Local's UI and then open that site's folder.

The route is collision-free — /sites/mcp is one path segment after /sites,
so it cannot match the two-segment per-site pattern, and a site whose id is
literally "mcp" still resolves at /sites/mcp/mcp.

Tool surface is now split in two. Site-scoped tools (wp_cli, the log
readers, the wp-config tools, get_site_info, site_health_check) stay on the
per-site endpoints, since they need a bound SiteConfig. Tools that address
Local itself or take an explicit siteId are served on both. Sessions carry
a nullable siteId and handleToolCall takes a nullable config, rejecting a
site-scoped tool called globally with a message pointing at the per-site
endpoint.

Three new tools wrap the setup and teardown paths that were previously
reachable only through the renderer's IPC handlers:

- enable_agent_tools registers a site, writes its MCP config and project
  context, and returns the site's own endpoint URL
- disable_agent_tools tears down and is idempotent
- agent_tools_status reports enablement, agents, project dir, registration
  and endpoint URL for one site or all of them

Two things surfaced while wiring those up:

setupSite only ever adds files, so it cannot be reused as-is for a site
that is already enabled — moving the project dir would strand config at
the old location, and narrowing the agent list would strand the dropped
agents' files. enable_agent_tools now routes through changeProjectDir and
updateAgents, which clean up after themselves, then regenerateConfig.

projectDir lands in path.join(sitePath, projectDir). That was safe coming
from the UI's folder picker, but over MCP an absolute path or a `..`
segment would write agent config anywhere on disk, so it is now validated.

Adds 33 tests, including a real MCP handshake against the global endpoint
covering the advertised tool list, a global tool call, the site-scoped
refusal, and the /sites/mcp/mcp case.
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🟢 Lines 59.11% (🎯 40%) 376 / 636
🟢 Statements 59.01% (🎯 40%) 396 / 671
🟢 Functions 70.58% (🎯 40%) 72 / 102
🟢 Branches 52.64% (🎯 25%) 229 / 435
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/mcp-server.ts 62.57% 52% 75% 62.73% 58-74, 82-105, 147-152, 159-164, 182-184, 270-280, 353-360, 363-375, 381-384, 397-402
src/tools/agent-tools.ts 81.69% 77.04% 100% 85.48% 149-150, 163, 166, 185, 191-192, 202-204, 211-212
src/tools/index.ts 87.87% 100% 55.55% 100% 58, 61, 64, 67
Generated in workflow #32 for commit 2456fa3 by the Vitest Coverage Report Action

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