Skip to content

fix(mcp): default to disabled, matching docs and least privilege#1377

Open
sam-fakhreddine wants to merge 4 commits into
emdash-cms:mainfrom
sam-fakhreddine:fix/mcp-default-false
Open

fix(mcp): default to disabled, matching docs and least privilege#1377
sam-fakhreddine wants to merge 4 commits into
emdash-cms:mainfrom
sam-fakhreddine:fix/mcp-default-false

Conversation

@sam-fakhreddine

@sam-fakhreddine sam-fakhreddine commented Jun 7, 2026

Copy link
Copy Markdown

What does this PR do?

Changes the MCP route injection guard from resolvedConfig.mcp !== false (opt-out) to resolvedConfig.mcp === true (opt-in), so the MCP endpoint at /_emdash/api/mcp and its OAuth discovery metadata are only injected when explicitly enabled.

This matches the AI Tools documentation which states "The MCP server is disabled by default. Enable it in your Astro configuration: emdash({ mcp: true })."

Without this fix, every EmDash deployment that omits the mcp config key gets a live MCP endpoint plus public OAuth discovery at /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server/_emdash. The endpoint requires auth (401 without credentials), but it exposes unnecessary attack surface and allows fingerprinting the site as an EmDash instance. Confirmed independently by @Vallhalen on a production instance.

Closes #1228

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable). Do not include messages.po changes except in translation PRs — a workflow extracts catalogs on merge to main.
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: https://github.com/emdash-cms/emdash/discussions/...

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.6 via Claude Code

Changes

packages/core/src/astro/integration/index.ts

  • Changed resolvedConfig.mcp !== falseresolvedConfig.mcp === true
  • Updated comment from "always on" to "only when explicitly opted in"

packages/core/src/astro/integration/runtime.ts

  • Updated JSDoc on mcp config field: @default true@default false, "Enabled by default" → "Disabled by default"

packages/core/tests/unit/mcp/mcp-default-disabled.test.ts

  • Regression test verifying the guard uses === true not !== false

.changeset/mcp-default-false.md

  • Patch changeset for the fix

The MCP guard checked `resolvedConfig.mcp !== false`, injecting the
endpoint on every site that didn't explicitly disable it. Changed to
`resolvedConfig.mcp === true` so the endpoint is opt-in only.

Closes emdash-cms#1228
Copilot AI review requested due to automatic review settings June 7, 2026 22:07
@changeset-bot

changeset-bot Bot commented Jun 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f3d3d85

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/admin Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@github-actions github-actions Bot added review/needs-review No maintainer or bot review yet cla: needed labels Jun 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Makes MCP route injection opt-in to match documentation and the principle of least privilege.

Changes:

  • Change MCP route injection from default-on (mcp !== false) to explicit opt-in (mcp === true)
  • Update EmDashConfig.mcp docs to reflect default disabled and @default false
  • Add a regression test and a changeset documenting the behavior change

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
packages/core/src/astro/integration/index.ts Switches MCP route injection guard to explicit opt-in
packages/core/src/astro/integration/runtime.ts Updates config documentation to “disabled by default” (@default false)
packages/core/tests/unit/mcp/mcp-default-disabled.test.ts Adds regression test ensuring opt-in behavior
.changeset/mcp-default-false.md Adds release note describing the behavior correction

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/tests/unit/mcp/mcp-default-disabled.test.ts Outdated
Comment thread packages/core/tests/unit/mcp/mcp-default-disabled.test.ts Outdated
Comment thread packages/core/src/astro/integration/runtime.ts Outdated

@emdashbot emdashbot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is the correct security fix: switching MCP from opt-out to opt-in aligns with the documented behavior and the principle of least privilege. The core logic change (!== false=== true) is correct, the JSDoc update is consistent, and the regression test covers the specific bug.

However, the PR's stated scope includes eliminating the public OAuth discovery metadata that fingerprints EmDash instances, and that part is incomplete. The /.well-known/oauth-protected-resource endpoint is injected unconditionally in injectBuiltinAuthRoutes (not behind the new mcp === true guard). It returns resource: ${origin}/_emdash/api/mcp, so it still advertises MCP capability even when the MCP route itself is disabled. The changeset description is therefore overstated. The /.well-known/oauth-authorization-server/_emdash endpoint can remain unconditional because it serves the general OAuth infrastructure (CLI, device code, etc.), not just MCP.

Comment thread packages/core/src/astro/integration/index.ts
@sam-fakhreddine

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA.

github-actions Bot added a commit that referenced this pull request Jun 7, 2026
The /.well-known/oauth-protected-resource endpoint advertises the MCP
resource URL, fingerprinting EmDash instances even when MCP is disabled.
Move it into injectMcpRoute so both the API and its discovery metadata
are conditional on mcp: true.

Addresses review feedback from emdashbot and Copilot.
Also fixes import.meta.dirname portability and improves JSDoc clarity.
@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review size/M and removed review/needs-review No maintainer or bot review yet size/S labels Jun 7, 2026
@sam-fakhreddine

Copy link
Copy Markdown
Author

@copilot recheck please

@sam-fakhreddine sam-fakhreddine requested a review from Copilot June 7, 2026 23:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread packages/core/tests/unit/mcp/mcp-default-disabled.test.ts Outdated
Comment thread packages/core/tests/unit/mcp/mcp-default-disabled.test.ts Outdated
Comment thread packages/core/src/astro/integration/routes.ts
Addresses Copilot review feedback — the test now exercises injectMcpRoute
with a stubbed injectRoute and asserts on collected route patterns instead
of scanning source code strings. Also verifies oauth-protected-resource
is co-located with the MCP route.
@sam-fakhreddine sam-fakhreddine force-pushed the fix/mcp-default-false branch from de80e49 to f3d3d85 Compare June 7, 2026 23:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core cla: signed review/needs-rereview Author pushed changes since the last review size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(mcp): MCP server is enabled by default, docs say "disabled by default"

2 participants