Tailscale-native MCP gateway with identity-based access control, audit logging, and session recording
Go 99.8%
Dockerfile 0.2%
1 1 0

Clone this repository

https://tangled.org/scottlanoue.com/turnscale https://tangled.org/did:plc:dy67wyyakm7u4v2lthy5zwbn/turnscale
git@tangled.org:scottlanoue.com/turnscale git@tangled.org:did:plc:dy67wyyakm7u4v2lthy5zwbn/turnscale

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

Turnscale#

tangled.sh

MCP gateway for Tailscale. Proxies Model Context Protocol requests to multiple backends, using Tailscale identity for access control. Single Go binary, no credentials to manage.

  • Identity from Tailscale WhoIs — no API keys or OAuth
  • Policy via tailnet ACL grants (or YAML fallback)
  • Per-tool deny globs (e.g. allow Gitea but deny delete_*)
  • Audit log and optional session recording
  • Dashboard with server health, request chart, tool discovery
  • Single binary, no CGO

Turnscale dashboard

Quick Start#

go build ./cmd/turnscale
cp gateway.example.yaml gateway.yaml  # edit with your servers + policies
./turnscale -config gateway.yaml

The gateway joins your tailnet as a node. Point MCP clients at https://{hostname}.{tailnet}.ts.net/{server}/mcp.

Configuration#

hostname: "mcp"
tailnet: "your-tailnet.ts.net"
state_dir: "~/.local/share/turnscale"

servers:
  github:
    url: "http://localhost:8091/mcp"
    transport: "streamable-http"
  slack:
    url: "http://localhost:8092/mcp"
    transport: "streamable-http"

policies:
  - name: "admin"
    match:
      identity: ["you@github"]
    allow: ["*"]

  - name: "ai-agents"
    match:
      tags: ["tag:ai-agent"]
    allow: ["github", "slack"]
    deny_tools: ["mcp__github__delete_*"]

  - name: "default-deny"
    match:
      identity: ["*"]
    deny: ["*"]

Servers can also be added, edited, and removed from the dashboard UI.

Connecting Clients#

Claude Code#

Add to ~/.claude/settings.local.json:

{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://mcp.your-tailnet.ts.net/github/mcp"
    },
    "slack": {
      "type": "http",
      "url": "https://mcp.your-tailnet.ts.net/slack/mcp"
    }
  }
}

Any MCP Client (Streamable HTTP)#

POST https://mcp.your-tailnet.ts.net/{server}/mcp   # JSON-RPC
GET  https://mcp.your-tailnet.ts.net/{server}/mcp   # SSE stream
DELETE https://mcp.your-tailnet.ts.net/{server}/mcp  # Session termination

No auth headers — identity comes from Tailscale.

Tailscale ACL Grants#

The recommended way to manage access. Add grants to your tailnet policy — the gateway reads them from WhoIs().CapMap at request time:

{
  "grants": [
    {
      "src": ["autogroup:member"],
      "dst": ["tag:server"],
      "app": {
        "your-tailnet.ts.net/cap/mcp": [{
          "servers": ["*"],
          "admin": true
        }]
      }
    },
    {
      "src": ["tag:ai-agent"],
      "dst": ["tag:server"],
      "app": {
        "your-tailnet.ts.net/cap/mcp": [{
          "servers": ["github", "slack"],
          "denyTools": ["mcp__github__delete_*"],
          "record": true
        }]
      }
    }
  ]
}
Field Description
servers Server names or ["*"] for all
denyTools Glob patterns for denied tools
admin Access to audit logs, server management, session recordings
record Capture full request/response bodies for this caller

Grants take priority over YAML policies. Multiple grants per caller are unioned.

Web UI#

All pages live under /ui/:

  • /ui/ — dashboard: request chart, server health, policies, recent activity
  • /ui/audit — full audit log with filtering by caller/server/tool/status
  • /ui/session/{id} — session recording viewer

Architecture#

┌──────────────┐     ┌──────────────────┐     ┌─────────────┐
│  Claude Code │────>│  Turnscale       │────>│ github-mcp  │
│              │     │  (tsnet node)    │────>│ slack-mcp   │
├──────────────┤     │                  │────>│ jira-mcp    │
│  AI Agents   │────>│  - WhoIs identity│────>│ ...         │
│  (tag:agent) │     │  - ACL grants    │     └─────────────┘
└──────────────┘     │  - Audit + Record│
                     │  - Tool discovery│
                     │  - Dashboard     │
                     └──────────────────┘

Development#

go build ./...           # Build
go test -race ./...      # Test (85 tests, race detector)
go test -cover ./...     # Coverage
go vet ./...             # Static analysis

Dependencies#

License#

MIT