Skip to content

fix(server): opt in to root MCP routing for Tailscale Funnel - #147

Open
dbc-hbin wants to merge 2 commits into
Waishnav:mainfrom
dbc-hbin:fix/tailscale-funnel-root-mcp
Open

fix(server): opt in to root MCP routing for Tailscale Funnel#147
dbc-hbin wants to merge 2 commits into
Waishnav:mainfrom
dbc-hbin:fix/tailscale-funnel-root-mcp

Conversation

@dbc-hbin

@dbc-hbin dbc-hbin commented Aug 8, 2026

Copy link
Copy Markdown

Problem

ChatGPT cannot connect to a DevSpace server exposed through a path-based Tailscale Funnel route.

Tailscale Funnel strips the configured path prefix before proxying to the backend. The MCP client requests the documented public /mcp endpoint, but a Funnel route targeting that prefix can forward the request to DevSpace as /. DevSpace only registers the MCP handler at /mcp, so the forwarded request returns 404.

This was verified empirically with a path-echo backend: a request to a configured Funnel prefix arrived with that prefix removed.

Change

  • Add an explicit DEVSPACE_TAILSCALE_FUNNEL=1 opt-in for path-stripping Funnel routes.
  • Pass that integration setting to the server as the provider-neutral mcpRootAlias capability.
  • Register the authenticated MCP handler at both /mcp and / only when the capability is enabled.
  • Do not infer Funnel mode from a .ts.net hostname, because Tailscale Serve uses the same hostname form.
  • Document the setting and add an authenticated HTTP integration regression test.

The default remains /mcp only. Tailscale Serve and ordinary reverse proxies do not expose the root alias unless explicitly configured.

Verification

  • npm run typecheck
  • npx tsx src/config.test.ts
  • npx tsx src/server.test.ts — 7/7 pass, including authenticated MCP initialize at / and /mcp
  • npm run build

The route regression test verifies:

  • opt-in enabled: authenticated MCP initialize at / returns 200;
  • opt-in disabled: / remains 404;
  • opt-in disabled: the existing /mcp endpoint still returns 200.

Development attribution

Built with the Codex desktop coding harness using deepseek/deepseek-v4-flash. The submitted changes were inspected and validated against the local repository checkout with the commands listed above.

Summary by CodeRabbit

  • New Features

    • Added an optional Tailscale Funnel setting that serves MCP requests at the root URL when enabled.
    • MCP requests remain available at /mcp regardless of the setting.
    • Added configuration guidance and an example environment variable for enabling the feature.
  • Tests

    • Added coverage for default behavior, explicit Funnel enablement, Tailscale URLs, regular URLs, and root MCP routing.

…host

Tailscale Funnel strips the configured path prefix before proxying to the
backend, so a server exposed at /mcp receives requests at /. Register the
MCP handler at the root path as well when publicBaseUrl is a *.ts.net
host so ChatGPT can reach DevSpace through Funnel. Non-Tailscale setups
keep the /mcp-only route unchanged.
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The server reads an explicit Funnel flag and registers MCP requests at / when enabled. The existing /mcp route remains available. Configuration and HTTP integration tests cover enabled and disabled behavior.

Changes

Tailscale Funnel MCP routing

Layer / File(s) Summary
Tailscale Funnel configuration detection
src/config.ts, src/config.test.ts, .env.example, docs/configuration.md
ServerConfig includes mcpRootAlias. loadConfig sets it from DEVSPACE_TAILSCALE_FUNNEL. Tests and documentation cover explicit opt-in and default behavior.
MCP route registration and integration coverage
src/server.ts, src/server.test.ts
The MCP request handler is extracted into handleMcpRequest. The server registers it at /mcp and at / when mcpRootAlias is enabled. Integration tests verify authenticated requests in both modes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TailscaleFunnel
  participant ServerRouter
  participant handleMcpRequest
  TailscaleFunnel->>ServerRouter: Forward authenticated MCP request with stripped path
  ServerRouter->>handleMcpRequest: Route / to MCP handler when mcpRootAlias is enabled
  handleMcpRequest-->>ServerRouter: Return MCP response or error
Loading

Suggested reviewers: waishnav

Poem

A rabbit sets the Funnel flag,
Then checks each MCP request path.
/mcp stays open,
/ works when enabled.
The burrow returns a response.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: optional root MCP routing for Tailscale Funnel.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown

Greptile Summary

The PR detects Tailscale-hosted public URLs and exposes the existing MCP request handler at the backend root to accommodate Funnel path-prefix stripping.

  • Adds isTailscaleFunnel to loaded server configuration.
  • Extracts the MCP route callback into a reusable handler and conditionally mounts it at both /mcp and /.
  • Adds configuration tests for Tailscale and non-Tailscale hostnames.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking issue identified.

The conditional root route reuses the existing authenticated MCP handler only for the intended Tailscale-host configuration, while repository callers consistently obtain the new flag through loadConfig().

Important Files Changed

Filename Overview
src/config.ts Adds a derived boolean identifying *.ts.net public hostnames for conditional Funnel routing.
src/server.ts Extracts the existing MCP callback and additionally mounts it at / for detected Tailscale hosts without changing its protocol or authorization logic.
src/config.test.ts Covers the new configuration value for default, Tailscale, and ordinary public URLs.

Sequence Diagram

sequenceDiagram
    participant Client as MCP Client
    participant Funnel as Tailscale Funnel
    participant Server as DevSpace Server
    Client->>Funnel: Request /mcp
    Funnel->>Server: Forward request /
    Server->>Server: Authenticate and handle MCP request
    Server-->>Funnel: MCP response
    Funnel-->>Client: MCP response
Loading

Reviews (1): Last reviewed commit: "fix(server): serve MCP at root when publ..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/server.ts (1)

1874-1878: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add an integration regression test for the proxy-stripped MCP path.

isTailscaleFunnel is only covered through loadConfig. Exercise the real createServer(...) app for Funnel and non-Funnel configs: send an authenticated MCP initialize request to / with Funnel enabled, and assert that root remains unavailable without Funnel.

🤖 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 `@src/server.ts` around lines 1874 - 1878, Add an integration regression test
around createServer that sends an authenticated MCP initialize request to / with
isTailscaleFunnel enabled and verifies it succeeds, then runs the same request
with Funnel disabled and verifies root remains unavailable while /mcp behavior
is unchanged.

Source: Coding guidelines

🤖 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 `@src/config.ts`:
- Around line 21-28: Remove the Tailscale-specific isTailscaleFunnel field and
ChatGPT routing documentation from ServerConfig. Move the hostname/path-prefix
translation into the Tailscale adapter, then pass createServer a generic MCP
route capability or explicit integration mode while keeping DevSpace policy in
the core configuration.
- Line 241: Update the isTailscaleFunnel configuration in the publicBaseUrl
setup so it is not inferred from a .ts.net hostname; instead, derive it from an
explicit Tailscale Funnel mode/capability setting or other Funnel-only
configuration, while preserving false for Tailscale Serve deployments.

---

Nitpick comments:
In `@src/server.ts`:
- Around line 1874-1878: Add an integration regression test around createServer
that sends an authenticated MCP initialize request to / with isTailscaleFunnel
enabled and verifies it succeeds, then runs the same request with Funnel
disabled and verifies root remains unavailable while /mcp behavior is unchanged.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cf294c1c-4c4c-46ed-87bc-fd11f223adad

📥 Commits

Reviewing files that changed from the base of the PR and between 3bd0378 and 5b7dd36.

📒 Files selected for processing (3)
  • src/config.test.ts
  • src/config.ts
  • src/server.ts

Comment thread src/config.ts Outdated
Comment thread src/config.ts Outdated
@dbc-hbin dbc-hbin changed the title fix(server): serve MCP at root when public URL is a Tailscale Funnel host fix(server): opt in to root MCP routing for Tailscale Funnel Aug 10, 2026
@dbc-hbin

Copy link
Copy Markdown
Author

Addressed the review feedback in 28e7544.

  • Removed .ts.net hostname inference, so Tailscale Serve remains /mcp-only by default.
  • Replaced the provider-specific isTailscaleFunnel server field with the generic mcpRootAlias route capability.
  • Added explicit DEVSPACE_TAILSCALE_FUNNEL=1 opt-in and documentation.
  • Added an authenticated HTTP integration test covering / enabled, / disabled, and unchanged /mcp behavior.

Validated with typecheck, focused config/server tests, and a production build.

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