Skip to content

Conversation

@aaronlippold
Copy link
Contributor

@aaronlippold aaronlippold commented Dec 26, 2025

Description

Adds allowHeadless: true config option for MCP servers, enabling specific MCP tools to work in headless mode without requiring the --auto flag.

Problem: MCP tools are unavailable in headless mode, limiting automation scenarios where users want specific trusted MCP servers to work while still requiring approval for other tools.

Solution: Per-server allowHeadless option that allows enumeration and execution of tools from that server in headless mode.

Usage:

mcpServers:
  - name: Brave Search
    command: npx
    args: ["-y", "@modelcontextprotocol/server-brave-search"]
    allowHeadless: true  # Enable in headless mode

Changes

Commit 1: Feature (4062ff6)

  • Add allowHeadless to MCP config schema (packages/config-yaml)
  • Pass allowHeadless from connection config to Tool objects
  • Check allowHeadless in tool enumeration (getRequestTools)
  • Check allowHeadless in execution permission (checkToolPermissionApproval)
  • Security: allowHeadless respects explicit "exclude" permissions (won't override user denials)
  • Add 9 unit tests in mcp-headless.test.ts

Commit 2: Test Isolation Fix (4db8aa8)

  • Mock core/util/paths.js to read CONTINUE_GLOBAL_DIR dynamically
  • Fixes test isolation issue where GlobalContext singleton would leak state between parallel test files
  • Add interopDefault: true to vitest config for better CommonJS handling

AI Code Review

  • Team members only: AI review runs automatically when PR is opened or marked ready for review
  • Team members can also trigger a review by commenting @continue-review

Checklist

  • I've read the contributing guide
  • The relevant docs, if any, have been updated or created
  • The relevant tests, if any, have been updated or created

Screen recording or screenshot

N/A - This is a CLI/config change with no UI impact.

Tests

Added 9 unit tests in extensions/cli/src/stream/mcp-headless.test.ts:

Tool enumeration tests (4):

  • Exclude MCP tools by default in headless mode
  • Include MCP tools when allowHeadless=true in headless mode
  • Include all MCP tools in interactive mode regardless of allowHeadless
  • Handle multiple MCP servers with different allowHeadless settings

Execution permission tests (5):

  • Approve MCP tool with allowHeadless=true in headless mode
  • Deny MCP tool without allowHeadless in headless mode
  • Deny MCP tool with allowHeadless=undefined in headless mode
  • Approve explicitly allowed tools regardless of allowHeadless
  • Deny explicitly excluded tools even with allowHeadless=true (security test)

All existing tests continue to pass (1715 unit tests, 66 e2e tests).

@aaronlippold aaronlippold requested a review from a team as a code owner December 26, 2025 15:24
@aaronlippold aaronlippold requested review from Patrick-Erichsen and removed request for a team December 26, 2025 15:24
@continue
Copy link
Contributor

continue bot commented Dec 26, 2025

All Green - Keep your PRs mergeable

Learn more

All Green is an AI agent that automatically:

✅ Addresses code review comments

✅ Fixes failing CI checks

✅ Resolves merge conflicts


Unsubscribe from All Green comments

1 similar comment
@continue-development-app
Copy link

All Green - Keep your PRs mergeable

Learn more

All Green is an AI agent that automatically:

✅ Addresses code review comments

✅ Fixes failing CI checks

✅ Resolves merge conflicts


Unsubscribe from All Green comments

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Dec 26, 2025
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 7 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="extensions/cli/src/stream/mcp-headless.test.ts">

<violation number="1" location="extensions/cli/src/stream/mcp-headless.test.ts:238">
P2: Test claims to test `allowHeadless=undefined` but actually tests `allowHeadless=false` due to `?? false` coercion in the helper. To properly test undefined behavior, preserve the undefined value instead of defaulting to false.</violation>
</file>

<file name="extensions/cli/src/stream/handleToolCalls.ts">

<violation number="1" location="extensions/cli/src/stream/handleToolCalls.ts:206">
P1: The `allowMcpInHeadless` check doesn&#39;t respect explicit `&quot;exclude&quot;` permissions. If a tool is explicitly excluded in permissions but has `allowHeadless: true`, it will bypass the exclusion and be allowed in headless mode. The `allowHeadless` flag should only upgrade `&quot;ask&quot;` permissions to automatic approval, not override explicit exclusions.</violation>
</file>

Reply to cubic to teach it or ask questions. Tag @cubic-dev-ai to re-run a review.

@continue
Copy link
Contributor

continue bot commented Dec 26, 2025

📚 Documentation Updates Available

I've created documentation updates for this feature in a separate branch: docs/mcp-allow-headless-9327

Changes Overview

Reference Documentation (reference.mdx)

  • Added allowHeadless property to mcpServers configuration section
  • Added example showing usage with Brave Search MCP server

MCP Deep Dive (customize/deep-dives/mcp.mdx)

  • Added comprehensive section "How to Use MCP Servers in CLI Headless Mode"
  • Explained security rationale with Note and Warning components
  • Provided usage examples and best practices
  • Added CardGroup showing good candidates vs. cautionary use cases

CLI Overview (cli/overview.mdx)

  • Updated tool permissions Info box to mention MCP tools headless behavior
  • Linked to detailed documentation

Next Steps

You can:

  1. Review the changes in my branch: docs/mcp-allow-headless-9327
  2. Cherry-pick the documentation commit (8aff77c) into your PR branch
  3. Or I can create a separate PR to main after this PR merges

The documentation changes are scoped to explain the feature without adding unnecessary detail, using Mintlify components for effective information display.


View the commit: 8aff77c

@continue
Copy link
Contributor

continue bot commented Dec 26, 2025

📚 Documentation PR Created

I've created PR #9328 with documentation updates for the allowHeadless feature.

The PR adds comprehensive documentation covering:

  • ✅ Reference documentation for the allowHeadless property
  • ✅ Detailed explanation in the MCP deep dive guide
  • ✅ Updated CLI overview to mention MCP headless behavior
  • ✅ Security considerations and best practices
  • ✅ Usage examples with Mintlify components

The documentation PR is ready to merge once this PR is merged.

Preview: #9328

Adds `allowHeadless: true` config option for MCP servers, enabling
specific MCP tools to work in headless mode without requiring --auto flag.

Changes:
- Add allowHeadless to MCP config schema
- Pass allowHeadless from connection config to Tool objects
- Check allowHeadless in tool enumeration (getRequestTools)
- Check allowHeadless in execution permission (checkToolPermissionApproval)
- Respect explicit "exclude" permissions (allowHeadless cannot override)
- Add 9 tests covering enumeration, execution, and security scenarios

Usage:
```yaml
mcpServers:
  - name: Brave Search
    command: npx
    args: ["-y", "@modelcontextprotocol/server-brave-search"]
    allowHeadless: true  # Enable in headless mode
```

Authored by: Aaron Lippold<[email protected]>
@aaronlippold aaronlippold force-pushed the pr/mcp-allow-headless-option branch 2 times, most recently from f6cd721 to a054c6d Compare December 26, 2025 16:58
Mock core/util/paths.js to read CONTINUE_GLOBAL_DIR dynamically instead
of caching it at module load time. This fixes test isolation issues where
tests running in parallel would share the same GlobalContext file path.

Root cause: The CONTINUE_GLOBAL_DIR constant in core/util/paths.ts is
computed via an IIFE at module load time. When tests set different temp
directories in beforeEach, the module had already cached the original value.

Solution: Mock getContinueGlobalPath, getIndexFolderPath, and
getGlobalContextFilePath to read process.env.CONTINUE_GLOBAL_DIR on
each call, allowing proper test isolation.

Also adds interopDefault to vitest config for better CommonJS handling.

Authored by: Aaron Lippold<[email protected]>
@aaronlippold aaronlippold force-pushed the pr/mcp-allow-headless-option branch from a054c6d to 4db8aa8 Compare December 26, 2025 17:17
@aaronlippold
Copy link
Contributor Author

Review Comments Addressed

Both AI review comments have been resolved:

P1 (Security) - allowHeadless bypassing explicit exclusions ✅

Fixed in 4062ff6

The allowMcpInHeadless check now respects explicit "exclude" permissions:

const allowMcpInHeadless =
  !tool.isBuiltIn &&
  isHeadless &&
  tool.allowHeadless &&
  result.permission !== "exclude";  // ← Added this check

P2 (Test) - Helper coercing undefined to false

Fixed in 4062ff6

The test helper now preserves undefined instead of coercing to false:

// Before (bug):
allowHeadless: allowHeadless ?? false,

// After (fixed):
...(allowHeadless !== undefined && { allowHeadless }),

This ensures the test "should deny MCP tool with allowHeadless=undefined" actually tests undefined behavior, not false.


Both review threads are now outdated as the underlying code has been updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant