Skip to content

Add secure Wails project MCP server - #5896

Merged
leaanthony merged 10 commits into
masterfrom
feat/wails3-cli-mcp
Aug 16, 2026
Merged

Add secure Wails project MCP server#5896
leaanthony merged 10 commits into
masterfrom
feat/wails3-cli-mcp

Conversation

@leaanthony

@leaanthony leaanthony commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

  • add wails3 mcp for agent-assisted Wails project management
  • use automatic transport selection: stdio for agent-launched processes and loopback Streamable HTTP for interactive terminal use
  • add secure root confinement, symlink/traversal checks, session/bearer tokens, bounded jobs/output/arguments, and explicit approval for remote templates/Git remotes
  • expose project inspection, initialization, diagnostics, task discovery/execution, build/dev/binding jobs, and job status/stop tools
  • document the CLI MCP server in the main CLI and MCP guides

Validation

  • go test ./...
  • go vet ./internal/commands ./cmd/wails3
  • stdio MCP initialization smoke test
  • Streamable HTTP authentication and initialization smoke test
  • git diff --check

The documentation build was attempted but is blocked in this checkout because the available Node.js version is 20.20.2 while Astro requires Node.js >=22.12.0.

Summary by CodeRabbit

  • New Features

    • Added the wails3 mcp command for agent-assisted project management.
    • Supports automatic or explicitly selected stdio and authenticated loopback HTTP transport.
    • Provides project inspection, initialization, diagnostics, build, development, binding, and job-management tools.
    • Enforces project-root confinement and approval controls for external templates and Git remotes.
  • Documentation

    • Added CLI usage, configuration, available tools, transport, authentication, and security guidance.
    • Clarified the distinction between the project MCP server and the MCP server built into applications.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The pull request adds the wails3 mcp CLI command. It starts an authenticated project MCP server over stdio or loopback HTTP, provides project and job tools, enforces path and argument limits, and documents usage and restrictions.

Changes

Project MCP server

Layer / File(s) Summary
CLI entry and transport setup
v3/cmd/wails3/main.go, v3/internal/commands/mcp.go, v3/go.mod
The CLI registers wails3 mcp. The server selects stdio or authenticated loopback HTTP and manages its lifecycle.
Project tools and access controls
v3/internal/commands/mcp.go, v3/internal/commands/mcp_test.go
The server adds project inspection, initialization, diagnostics, and task tools. It enforces root confinement, token authorization, loopback checks, and explicit external-template approval.
Command jobs and bounded execution
v3/internal/commands/mcp.go, v3/internal/commands/mcp_test.go
The server adds build, development, binding, task, status, and stop operations with cancellation, bounded output, job retention, JSON decoding, and argument validation.
MCP usage documentation
docs/src/content/docs/guides/cli.mdx, docs/src/content/docs/guides/mcp-service.mdx, docs/src/content/docs/reference/cli.mdx, v3/cmd/wails3/README.md
The documentation describes transport selection, authentication, project confinement, available tools, and operation restrictions.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCPHost
  participant wails3
  participant commandsMCP
  participant ProjectProcess
  MCPHost->>wails3: Launch wails3 mcp
  wails3->>commandsMCP: Start project MCP server
  MCPHost->>commandsMCP: Send authenticated tool request
  commandsMCP->>ProjectProcess: Run validated Wails command
  ProjectProcess-->>commandsMCP: Return bounded output or job state
  commandsMCP-->>MCPHost: Return MCP response
Loading

Possibly related PRs

  • wailsapp/wails#5682: Adds the built-in application MCP server that this change distinguishes from the separate CLI project MCP server.

Suggested labels: size:XL

Poem

A rabbit checks the MCP gate,
Tokens guard each project state.
Stdio speaks and HTTP starts,
Safe roots guide the project parts.
Jobs return bounded output neat—
Wails tools hop on steady feet.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description summarizes the change and validation, but omits the required issue, change-type, test-configuration, and checklist sections. Complete the template by identifying the issue, selecting the change type, documenting test environments and wails doctor output, and completing the checklist.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: adding a secure Wails project MCP server.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wails3-cli-mcp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added Documentation Improvements or additions to documentation cli v3-alpha labels Aug 4, 2026
@leaanthony
leaanthony marked this pull request as ready for review August 4, 2026 12:25
Copilot AI lite review requested due to automatic review settings August 4, 2026 12:25

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

🧹 Nitpick comments (7)
v3/internal/commands/mcp.go (6)

550-561: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Accumulate job output in a byte slice.

j.output += string(p[:n]) reallocates and copies the whole buffer on every child write. For a verbose build that fills the 2 MiB cap through many small writes, the total copying is quadratic. cappedBuffer at Line 521 already uses the []byte append form. Reuse that type or switch output to []byte and convert only in snapshot.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/internal/commands/mcp.go` around lines 550 - 561, Update mcpJob.Write to
accumulate output as []byte using cappedBuffer or append semantics instead of
string concatenation, while preserving the maxMCPOutput cap and io.Writer return
behavior. Adjust snapshot to convert the byte slice to a string only when
producing its result.

403-460: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared job-tool preamble.

build, dev, bindings, and task repeat the same four steps: authorize, projectPath, validateMCPArgs, startJob. Only the leading command words differ. Extract one helper so a future change to the authorization or validation order applies to every tool.

♻️ Proposed refactor
+func (s *mcpServer) startCommandJob(ctx context.Context, in mcpCommandInput, command ...string) (*mcp.CallToolResult, mcpJobOutput, error) {
+	if err := s.authorize(in.Token); err != nil {
+		return nil, mcpJobOutput{}, err
+	}
+	if err := validateMCPArgs(in.Args); err != nil {
+		return nil, mcpJobOutput{}, err
+	}
+	path, err := s.projectPath(in.Path)
+	if err != nil {
+		return nil, mcpJobOutput{}, err
+	}
+	return s.startJob(ctx, path, append(command, in.Args...))
+}
+
 func (s *mcpServer) build(ctx context.Context, _ *mcp.CallToolRequest, in mcpCommandInput) (*mcp.CallToolResult, mcpJobOutput, error) {
-	if err := s.authorize(in.Token); err != nil {
-		return nil, mcpJobOutput{}, err
-	}
-	path, err := s.projectPath(in.Path)
-	if err != nil {
-		return nil, mcpJobOutput{}, err
-	}
-	if err := validateMCPArgs(in.Args); err != nil {
-		return nil, mcpJobOutput{}, err
-	}
-	return s.startJob(ctx, path, append([]string{"build"}, in.Args...))
+	return s.startCommandJob(ctx, in, "build")
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/internal/commands/mcp.go` around lines 403 - 460, Extract the repeated
authorization, project-path resolution, argument validation, and job startup
flow from mcpServer.build, dev, bindings, and task into a shared helper. Have
each command method supply its command words and retain task-specific validation
for in.Task before invoking the helper, preserving the current validation order
and error behavior.

383-401: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Return parsed JSON rather than a raw string.

The tool descriptions state that these tools return machine-readable JSON, but result is the raw child stdout and is embedded as a JSON string. The client receives a doubly encoded payload and must parse it again. Unmarshal the child output and return the decoded value, and fall back to the raw text when unmarshalling fails.

♻️ Proposed refactor
 	result, err := s.runSync(ctx, s.root, "doctor", "--json")
 	if err != nil {
 		return nil, nil, fmt.Errorf("doctor: %w: %s", err, result)
 	}
-	return nil, map[string]any{"root": s.root, "report": result}, nil
+	var report any
+	if jsonErr := json.Unmarshal([]byte(result), &report); jsonErr != nil {
+		report = result
+	}
+	return nil, map[string]any{"root": s.root, "report": report}, nil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/internal/commands/mcp.go` around lines 383 - 401, Update doctor and
taskList to unmarshal the successful runSync result from JSON and return the
decoded value in the report or tasks field instead of the raw string. If
unmarshalling fails, preserve the raw result as the field value; keep existing
command-error handling unchanged.

84-86: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Validate the transport flags before doing work.

The mutual-exclusion check runs after resolveMCPRoot, token generation, and signal-handler installation. Move it to the top of MCP so an invalid flag combination fails immediately.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/internal/commands/mcp.go` around lines 84 - 86, The mutual-exclusion
validation for HTTP and Stdio flags in the MCP function currently runs after
resolveMCPRoot, token generation, and signal-handler installation. Move the
check that returns the error for choosing both --http and --stdio flags to the
beginning of the MCP function so invalid flag combinations fail immediately
before any initialization work is performed.

37-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fix the stale transport comment.

The comment states that stdio is the only transport and that no network listener is opened. runHTTP opens a loopback TCP listener, and the struct exposes HTTP and Port. Correct the comment so the documented security model matches the code.

📝 Proposed comment update
-// MCPOptions configures the local project MCP server. Stdio is intentionally
-// the only transport exposed by this command: a caller that can launch the
-// process already owns the pipe, and no network listener is opened.
+// MCPOptions configures the local project MCP server. Two transports are
+// supported: stdio, where the caller that launched the process owns the pipe,
+// and Streamable HTTP, which binds only to loopback and requires a bearer
+// token.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/internal/commands/mcp.go` around lines 37 - 46, Update the comment block
for the MCPOptions struct to accurately reflect the supported transports. The
current comment states that stdio is the only transport and no network listener
is opened, but the struct fields HTTP and Port along with runHTTP functionality
contradict this. Revise the comment to document that both stdio and HTTP
transports are supported, and clarify that when HTTP transport is selected, a
loopback TCP listener is opened on the configured port.

132-139: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Security Misconfiguration (CWE-350)

Reachability path
● Entry
  v3/cmd/wails3/main.go:49
  MCP
│
▼
● Sink
  v3/internal/commands/mcp.go

Add Origin/Host validation and an IdleTimeout to the loopback HTTP server.

auth.RequireBearerToken returns 401 no bearer token for requests without a valid Bearer ... header, and the bearer verifier rejects bad tokens before tools are called. Harden DNS rebinding for Streamable HTTP by rejecting non-loopback Origin values and non-loopback Host values on loopback transport, and add an IdleTimeout so abandoned keep-alive connections do not exhaust resources.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v3/internal/commands/mcp.go` around lines 132 - 139, Update the loopback HTTP
server setup around NewStreamableHTTPHandler and http.Server to validate Origin
and Host headers, rejecting values that are not loopback addresses before
requests reach the MCP handler or bearer authentication path. Preserve the
existing token verifier, and configure the server’s IdleTimeout to close
abandoned keep-alive connections.
docs/src/content/docs/guides/mcp-service.mdx (1)

21-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a root-relative Starlight link for the CLI MCP section.

The target heading exists at docs/src/content/docs/guides/cli.mdx:210, but this docs tree uses root-relative links with locale prefixes, such as /guides/build/obfuscation and /id/guides/build/obfuscation. Change ./cli/#mcp to /guides/cli/#mcp so it resolves on every locale page consistently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/src/content/docs/guides/mcp-service.mdx` around lines 21 - 26, Update
the CLI MCP documentation link in the project lifecycle paragraph to use the
root-relative `/guides/cli/#mcp` target instead of `./cli/#mcp`, preserving the
existing link text and surrounding content.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/src/content/docs/guides/cli.mdx`:
- Around line 230-243: Update the MCP flags documentation to include
WAILS_MCP_TOKEN as the supported token source, matching the existing README
documentation. Also align the documented -http and -stdio flag notation with the
runtime error wording in the MCP command, consistently using the double-dash
style throughout this section.

In `@v3/cmd/wails3/README.md`:
- Around line 45-50: Update the README’s available-tools description to replace
“bounded job status/log/stop operations” with wording that names only the
registered tools wails_job_status and wails_job_stop, noting that status returns
bounded output.

In `@v3/internal/commands/mcp_test.go`:
- Around line 21-32: In TestMCPProjectPathRejectsEscapes, resolve the root path
using filepath.EvalSymlinks before assigning it to the mcpServer initialization
so the test root matches how projectPath resolves paths in production (via
resolveMCPRoot). Additionally, add a positive assertion after the existing error
checks to confirm that projectPath accepts a legitimate nested path within the
root directory, ensuring the escape checks do not incorrectly reject valid
paths.

In `@v3/internal/commands/mcp.go`:
- Around line 331-342: Update the marker comparisons in the file-scanning logic
to use the already computed slash-normalized path value used for Files instead
of platform-specific rel. Ensure the build/config.yml and frontend/package.json
checks match correctly on Windows while preserving the existing Taskfile and
go.mod detection behavior.
- Around line 584-599: Update mcpJobs.add and related job lifecycle handling so
completed jobs are reaped when the map reaches maxMCPJobs, while preserving the
cap for active jobs. Record completion time in mcpJob.finish and expose a small
accessor; use a reapLocked helper to remove the oldest finished jobs without
reading mcpJob fields outside its lock, then admit the new job.
- Around line 474-479: Update the job stop flow around job.cancel() and
job.snapshot() to mark the job as stopping before taking the snapshot. Ensure
wails_job_stop returns the transitional stopping state immediately, while
preserving the existing cancellation and unknown-job behavior.
- Around line 283-291: The projectPath method skips symlink resolution for
non-existent paths because the EvalSymlinks call is gated behind the os.Stat
check, allowing a symlinked ancestor to bypass root confinement. Refactor the
symlink validation to find the nearest existing ancestor directory before
applying EvalSymlinks, then verify that the resolved ancestor path remains
within cleanRoot and its prefix. Apply this resolution logic regardless of
whether cleanPath itself exists, so symlinked parents of missing leaf paths are
caught before being passed to child processes or used in paths like wails3 init.

---

Nitpick comments:
In `@docs/src/content/docs/guides/mcp-service.mdx`:
- Around line 21-26: Update the CLI MCP documentation link in the project
lifecycle paragraph to use the root-relative `/guides/cli/#mcp` target instead
of `./cli/#mcp`, preserving the existing link text and surrounding content.

In `@v3/internal/commands/mcp.go`:
- Around line 550-561: Update mcpJob.Write to accumulate output as []byte using
cappedBuffer or append semantics instead of string concatenation, while
preserving the maxMCPOutput cap and io.Writer return behavior. Adjust snapshot
to convert the byte slice to a string only when producing its result.
- Around line 403-460: Extract the repeated authorization, project-path
resolution, argument validation, and job startup flow from mcpServer.build, dev,
bindings, and task into a shared helper. Have each command method supply its
command words and retain task-specific validation for in.Task before invoking
the helper, preserving the current validation order and error behavior.
- Around line 383-401: Update doctor and taskList to unmarshal the successful
runSync result from JSON and return the decoded value in the report or tasks
field instead of the raw string. If unmarshalling fails, preserve the raw result
as the field value; keep existing command-error handling unchanged.
- Around line 84-86: The mutual-exclusion validation for HTTP and Stdio flags in
the MCP function currently runs after resolveMCPRoot, token generation, and
signal-handler installation. Move the check that returns the error for choosing
both --http and --stdio flags to the beginning of the MCP function so invalid
flag combinations fail immediately before any initialization work is performed.
- Around line 37-46: Update the comment block for the MCPOptions struct to
accurately reflect the supported transports. The current comment states that
stdio is the only transport and no network listener is opened, but the struct
fields HTTP and Port along with runHTTP functionality contradict this. Revise
the comment to document that both stdio and HTTP transports are supported, and
clarify that when HTTP transport is selected, a loopback TCP listener is opened
on the configured port.
- Around line 132-139: Update the loopback HTTP server setup around
NewStreamableHTTPHandler and http.Server to validate Origin and Host headers,
rejecting values that are not loopback addresses before requests reach the MCP
handler or bearer authentication path. Preserve the existing token verifier, and
configure the server’s IdleTimeout to close abandoned keep-alive connections.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8462ff2d-8038-4209-87da-77727a7d1636

📥 Commits

Reviewing files that changed from the base of the PR and between 2014eb6 and ec5fbf0.

⛔ Files ignored due to path filters (1)
  • v3/go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • docs/src/content/docs/guides/cli.mdx
  • docs/src/content/docs/guides/mcp-service.mdx
  • docs/src/content/docs/reference/cli.mdx
  • v3/cmd/wails3/README.md
  • v3/cmd/wails3/main.go
  • v3/go.mod
  • v3/internal/commands/mcp.go
  • v3/internal/commands/mcp_test.go

Comment thread docs/src/content/docs/guides/cli.mdx
Comment thread v3/cmd/wails3/README.md
Comment thread v3/internal/commands/mcp_test.go
Comment thread v3/internal/commands/mcp.go Outdated
Comment thread v3/internal/commands/mcp.go Outdated
Comment thread v3/internal/commands/mcp.go
Comment thread v3/internal/commands/mcp.go

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

Adds a new wails3 mcp subcommand that runs a local Model Context Protocol (MCP) server for agent-assisted Wails project lifecycle management, with automatic transport selection (stdio vs loopback Streamable HTTP), job management, and documentation updates so the capability is discoverable from the CLI guides.

Changes:

  • Introduces a new CLI-side MCP server with project inspection/init, doctor, task listing/execution, build/dev/bindings jobs, plus job status/stop.
  • Adds a child-process mode (WAILS_MCP_CHILD=1) to suppress CLI footer output so spawned CLI subprocesses don’t corrupt protocol/log output.
  • Documents the new wails3 mcp command across CLI docs and adds the required Go module dependencies.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
v3/internal/commands/mcp.go New MCP server implementation: transport selection, root confinement checks, token auth, job orchestration, and tool registration.
v3/internal/commands/mcp_test.go Adds unit tests for root resolution, token generation, token auth, and basic path escape checks.
v3/cmd/wails3/main.go Registers the mcp subcommand and disables the footer for MCP child subprocesses.
v3/cmd/wails3/README.md Documents the project MCP server usage, transport behavior, and security constraints.
docs/src/content/docs/reference/cli.mdx Adds wails3 mcp to the CLI reference table.
docs/src/content/docs/guides/mcp-service.mdx Points readers to the CLI MCP server for project lifecycle automation (separate from app MCP server).
docs/src/content/docs/guides/cli.mdx Adds a dedicated mcp command section and flag documentation.
v3/go.mod Adds MCP SDK dependency (and indirect deps).
v3/go.sum Adds checksums for new dependencies.
Suppressed comments (1)

v3/internal/commands/mcp.go:58

  • The function doc for MCP states it starts a local stdio-only server, but the implementation can also run Streamable HTTP (auto-selected in terminal mode or via --http). Keeping this comment accurate matters because stdout/stderr handling and security assumptions differ by transport.
// MCP starts a local, stdio MCP server. The token is returned in the MCP
// initialize instructions so an agent can use it without contaminating the
// JSON-RPC stdout stream. It is also written to stderr for humans debugging a
// manually launched server.

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

Comment thread v3/internal/commands/mcp.go Outdated
Comment thread v3/internal/commands/mcp.go Outdated
Comment thread v3/internal/commands/mcp.go Outdated
Comment thread v3/internal/commands/mcp.go Outdated
Comment thread v3/internal/commands/mcp.go Outdated
Comment thread v3/internal/commands/mcp.go Outdated
@leaanthony

Copy link
Copy Markdown
Member Author

@copilot Fix the code for all comments in this review thread.

When a review comment includes a suggested change, apply the suggestion exactly.

Do not make changes beyond what is described in the linked review thread.

…ymlink, path flags)

Co-authored-by: leaanthony <1943904+leaanthony@users.noreply.github.com>

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 8 out of 9 changed files in this pull request and generated no new comments.

Suppressed comments (4)

v3/internal/commands/mcp.go:628

  • validateMCPArgs blocks --output, but wails3 task uses --output to select the output style (not a filesystem path). This prevents legitimate wails_project_task_run usage. At the same time, the path-valued --taskfile flag is not blocked, which can bypass the intended root confinement by pointing at a Taskfile outside the allowed root.
	pathFlags := map[string]bool{
		"-d": true, "--dir": true,
		"-o": true, "--output": true,
		"--config": true,
	}

v3/internal/commands/mcp.go:293

  • The symlink-escape check repeats the same string prefix comparison against realPath. For the same reasons as above (case-insensitive filesystems and general robustness), prefer a filepath.Rel-based containment check here too.
		if _, err := os.Lstat(check); err == nil {
			realPath, err := filepath.EvalSymlinks(check)
			if err != nil || (realPath != cleanRoot && !strings.HasPrefix(realPath, cleanRoot+string(filepath.Separator))) {
				return "", fmt.Errorf("path %q resolves outside the allowed MCP root", input)
			}

v3/internal/commands/mcp_test.go:34

  • The test name claims the token check is "constant time", but crypto/subtle.ConstantTimeCompare returns immediately when slice lengths differ. Consider renaming the test to assert the actual property being validated (exact match required).
func TestMCPAuthorizeUsesExactConstantTimeToken(t *testing.T) {

v3/internal/commands/mcp.go:283

  • Root confinement uses a string prefix check on cleaned absolute paths. On case-insensitive filesystems (notably Windows), this can incorrectly reject paths that are actually within the root when the path casing differs. Using filepath.Rel avoids case/prefix pitfalls and keeps the intent clear.

This issue also appears on line 289 of the same file.

	cleanRoot := filepath.Clean(s.root)
	cleanPath := filepath.Clean(p)
	if cleanPath != cleanRoot && !strings.HasPrefix(cleanPath, cleanRoot+string(filepath.Separator)) {
		return "", fmt.Errorf("path %q is outside the allowed MCP root", input)
	}

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@v3/internal/commands/mcp.go`:
- Around line 142-153: Add a finite ReadTimeout to the http.Server configuration
used around the protectedHandler and loopback validation, ensuring request body
reads cannot continue indefinitely. Keep the existing ReadHeaderTimeout and
IdleTimeout values, and do not add a global WriteTimeout so long-lived
Streamable HTTP responses remain supported.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e3cce99d-ff36-4b34-b64a-490ad86fdb61

📥 Commits

Reviewing files that changed from the base of the PR and between e961782 and e903b74.

📒 Files selected for processing (3)
  • docs/src/content/docs/guides/mcp-service.mdx
  • v3/internal/commands/mcp.go
  • v3/internal/commands/mcp_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/src/content/docs/guides/mcp-service.mdx

Comment thread v3/internal/commands/mcp.go
@leaanthony
leaanthony merged commit 1196be0 into master Aug 16, 2026
49 checks passed
@leaanthony
leaanthony deleted the feat/wails3-cli-mcp branch August 16, 2026 12:01
overlordtm pushed a commit to overlordtm/wails that referenced this pull request Aug 18, 2026
* Add secure Wails project MCP server

* fix: address MCP review feedback (comments, init dir, job ID error, symlink, path flags)

Co-authored-by: leaanthony <1943904+leaanthony@users.noreply.github.com>

* fix: address MCP PR review feedback

* fix: address remaining MCP review feedback

* fix: bound MCP HTTP request reads

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: taliesin-ai <bot@taliesin.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli Documentation Improvements or additions to documentation v3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants