We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jmagar/homelab-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
# Synapse Transport Modes
Synapse supports multiple secure transport patterns, depending on whether you run local-only or remote.
## Transport Options
1. `stdio` (local process, default)
2. HTTP (`/mcp`) with API key auth
3. `stdio` tunneled over SSH (remote, zero-extra infra)
4. HTTP behind Tailscale Serve auth (tailnet identity headers)
## 1) Local `stdio` (Default)
Best for local development and local CLI clients.
Example MCP client config:
```json
{
"mcpServers": {
"synapse": {
"command": "node",
"args": ["/path/to/synapse-mcp/dist/index.js"]
}
}
}
```
## 2) HTTP with API Key Auth
Use HTTP when you need remote access via a network endpoint.
### Required hardening for HTTP deployments
If deploying Synapse via HTTP, use at least one of:
1. API key auth (`SYNAPSE_API_KEY`)
2. Tailscale Serve auth (tailnet identity headers)
You can also use both together for defense in depth.
### API key setup
```bash
export SYNAPSE_HOST=127.0.0.1
export SYNAPSE_PORT=53000
export SYNAPSE_API_KEY="replace-with-strong-secret"
node /path/to/synapse-mcp/dist/index.js --transport http
```
Request requirements:
- `X-Synapse-Client` header is required for CSRF protection.
- `X-API-Key` is required when `SYNAPSE_API_KEY` is set.
Example request:
```bash
curl -X POST "http://127.0.0.1:53000/mcp" \
-H "Content-Type: application/json" \
-H "X-Synapse-Client: mcp" \
-H "X-API-Key: replace-with-strong-secret" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```
## 3) Remote `stdio` Over SSH
This is usually the easiest secure remote setup with near-zero extra infrastructure.
Prerequisite:
- SSH key-based auth between client machine and Synapse host
Then run Synapse remotely via SSH as your MCP command:
```json
{
"mcpServers": {
"synapse-remote-ssh-stdio": {
"command": "ssh",
"args": ["my-server", "node", "/path/to/synapse-mcp/dist/index.js"]
}
}
}
```
Why this is strong:
- Reuses battle-tested SSH transport and host auth
- Isolated remote process execution
- No HTTP endpoint required
- Minimal setup beyond SSH keys
## 4) Tailscale Serve Auth for HTTP MCP
Zero-OAuth auth pattern for internal MCP servers on a tailnet.
Tailscale Serve proxies to localhost and injects identity headers. Your server trusts those headers only when traffic comes through Serve.
### Security model
- Keep Synapse bound to `127.0.0.1` only.
- Expose via `tailscale serve`, not direct LAN/public bind.
- Tailscale identity headers are for tailnet traffic (not public Funnel traffic).
- Tagged-device traffic may not populate user identity headers.
- If service is reachable directly, headers can be spoofed outside Serve path.
### Headers injected by Tailscale Serve
| Header | Value |
| ---------------------------- | -------------------- |
| `Tailscale-User-Login` | `user@example.com` |
| `Tailscale-User-Name` | `Display Name` |
| `Tailscale-User-Profile-Pic` | URL to profile image |
### Prerequisites
- Tailscale installed and logged in on Synapse host
- HTTPS certificates enabled in tailnet
- MagicDNS enabled
### Step 1: Add middleware
```typescript
// src/middleware/tailscale-auth.ts
import type { NextFunction, Request, Response } from "express"
export interface TailscaleIdentity {
login: string
name: string
profilePic?: string
}
export function tailscaleAuth(req: Request, res: Response, next: NextFunction): void {
const login = req.headers["tailscale-user-login"] as string | undefined
const name = req.headers["tailscale-user-name"] as string | undefined
if (!login) {
res.status(401).json({
error: "unauthorized",
message: "No Tailscale identity. Connect through tailnet Serve."
})
return
}
;(req as Request & { tailscaleUser: TailscaleIdentity }).tailscaleUser = {
login,
name: name ?? login,
profilePic: req.headers["tailscale-user-profile-pic"] as string | undefined
}
next()
}
export function getIdentity(req: Request): TailscaleIdentity {
return (req as Request & { tailscaleUser: TailscaleIdentity }).tailscaleUser
}
```
### Step 2: Wire middleware and bind localhost
```typescript
import { tailscaleAuth } from "./middleware/tailscale-auth.js"
app.use("/mcp", tailscaleAuth)
app.listen(53000, "127.0.0.1")
```
### Step 3: Configure Tailscale Serve
```bash
tailscale serve --bg https+insecure://127.0.0.1:53000
tailscale serve status
```
MCP URL becomes:
```text
https://<hostname>.<tailnet-name>.ts.net/mcp
```
Stop serving:
```bash
tailscale serve --bg off
```
### Step 4: Client config (HTTP MCP)
```json
{
"mcpServers": {
"synapse-tailscale": {
"type": "http",
"url": "https://myserver.tailnet.ts.net/mcp"
}
}
}
```
### Optional: ACL lockdown
Use Tailscale ACLs/tags so only approved users/devices can reach the MCP host.
Example policy:
```json
{
"acls": [
{
"action": "accept",
"src": ["autogroup:admin"],
"dst": ["tag:mcp-servers:*"]
}
],
"tagOwners": {
"tag:mcp-servers": ["autogroup:admin"]
}
}
```
Tag host:
```bash
tailscale up --advertise-tags=tag:mcp-servers
```
### Optional: LocalAPI fallback (dual-mode)
If you need tailnet identity without using Serve, query Tailscale LocalAPI `whois` from connection metadata. This is useful for direct tailnet-IP traffic.
If running behind Serve, requests usually appear as `127.0.0.1` to your app, so LocalAPI `whois` for remote peer identity is not the right mechanism. In that case, use Serve headers.
## Quick Reference
| What | Where |
| --------------------- | ----------------------------------------------------------- |
| Tailscale Serve docs | https://tailscale.com/kb/1312/serve |
| Serve CLI reference | https://tailscale.com/kb/1242/tailscale-serve |
| Identity headers blog | https://tailscale.dev/blog/id-headers-tailscale-serve-flask |
| Tailnet ACLs | https://tailscale.com/kb/1018/acls |
| HTTPS certificates | https://tailscale.com/kb/1153/enabling-https |
| MCP TypeScript SDK | https://github.com/modelcontextprotocol/typescript-sdk |
## TL;DR
1. Bind Synapse to `127.0.0.1` only.
2. Use `tailscale serve` to publish `https://<host>.<tailnet>.ts.net/mcp`.
3. Read `Tailscale-User-*` headers for caller identity.
4. Keep ACLs tight so only approved users/devices can reach the host.
5. For HTTP deployments, require API key auth and/or Tailscale Serve auth.
With this setup, Synapse listens on localhost and only tailnet-connected devices can reach it through Tailscale.
## Recommended Defaults
1. Local-only usage: `stdio`
2. Remote single-user/admin usage: `stdio` over SSH
3. Remote team/internal usage: HTTP behind Tailscale Serve
4. Any direct HTTP deployment: set `SYNAPSE_API_KEY` at minimum