MCP
Let AI clients like Claude drive your Synq server as tools, over the Model Context Protocol. The endpoint on your panel's host, OAuth or token sign-in, what agents can do, and how to limit and review them.
MCP (Model Context Protocol) is a standard way for AI clients (Claude, Cursor, VS Code Copilot and others) to call an app's features as tools. Point one of those clients at Synq and it can list your projects, kick off deployments, check logs, add domains, look at a server's disk usage, check that panel backups run, and more, using the exact same permissions you'd have yourself.
The important part: it's not a second, looser door into Synq. Every tool call re-runs the full auth and permission stack, so an agent can only ever see and do what its credential is allowed to, nothing more.
Where this lives in the dashboard
Everything below is set up under Settings, MCP. That tab shows the exact endpoint for your install, a per-client "add" recipe (Claude Code, Codex, Cursor, VS Code, Claude Desktop, Windsurf, Zed), and the list of clients you've already connected.
The endpoint
The endpoint lives on your panel's host, the address in SYNQ_PUBLIC_URL:
https://app.<domain>/api/mcpapp.<domain> stands for the host you open the panel on, for example panel.example.com. A few things worth
knowing up front:
- It's a stateless Streamable-HTTP JSON-RPC 2.0 endpoint: request in, response out.
- It's
POST-only. An authenticatedGETreturns405(there's no server-to-client stream to open); an unauthenticatedGETreturns401with the pointer OAuth clients use to find the sign-in. - No batching: send one JSON-RPC message per request, not an array.
- The OAuth discovery documents are on the same host:
/.well-known/oauth-authorization-serverand/.well-known/oauth-protected-resource/api/mcp.
You rarely type this URL by hand. Settings, MCP shows it pre-filled under Endpoint, with a copy button.
Connect a client
There are two ways to authenticate, and most clients pick one for you. Use the tab that matches your client.
Synq is a standards-compliant OAuth 2.1 MCP server, so capable clients need nothing but the URL.
Paste the endpoint into your client
Give the client your endpoint, https://app.<domain>/api/mcp. In Claude Code that's one command:
claude mcp add --transport http synq https://app.<domain>/api/mcpCodex registers the server and authorizes it as two commands:
codex mcp add synq --url https://app.<domain>/api/mcp
codex mcp login synqOther clients take it through their own UI; Settings, MCP has the exact snippet for each one (Add to your client).
Approve it in the browser
For most clients this happens on the first connect: a browser window opens by itself. With Codex it's the explicit
codex mcp login synq above: the server is registered without it, but every call comes back unauthorized until you
run it.
Either way, that browser page is where you choose what the client may do: read-only or full control, and either all resources or a specific set of projects, servers and repositories. No credential to copy or paste.
You're connected
The client can now call tools within exactly the scope you approved. The connection shows up under Settings, MCP, Connected clients, where you can change or disconnect it at any time.
The scope you pick is enforced, not advisory
Your choices are stored as the client's grant, the same grant model as a scoped personal access token. The client can never exceed what you granted, or what you can access yourself.
Codex: local surfaces share one config; hosted tasks don't
The Codex CLI, desktop app, and IDE extension all read the same local MCP configuration, so adding Synq once covers all three. Restart any of them that were already running: they read the config at startup.
A hosted Codex task is a different environment. It doesn't inherit your machine's MCP config, and it can only
reach https://app.<domain>/api/mcp if that environment has network access to your server. For a private or
LAN-only install, it won't: the endpoint has to be reachable from wherever the agent actually runs. A Synq install on
a public hostname (the panel at https://app.<domain>) is reachable; a localhost or private-network endpoint is
not. See Installation for putting an install on a public domain.
For clients without OAuth support, or when you want a fixed, narrowly-scoped credential in a config file, authenticate with a personal access token as a bearer credential. There's no separate MCP credential.
Create the token under Settings, API tokens (see Authentication), then drop the endpoint and token into your client's config:
{
"mcpServers": {
"synq": {
"url": "https://app.<domain>/api/mcp",
"headers": { "Authorization": "Bearer synq_pat_…" }
}
}
}For Claude Code, add the header on the command:
claude mcp add --transport http synq https://app.<domain>/api/mcp \
--header "Authorization: Bearer synq_pat_…"Give an agent a narrow token
Mint a read-only or scoped token for agents rather than handing over your full access. A read-only token limits the agent to read tools; a scoped token confines it to exactly the projects, servers and repositories you grant, even below your own role.
Every call is re-checked
This is the heart of the security model, and it's why MCP access is as safe as your token:
- Authenticating once resolves your capability, but that's used only to filter
tools/list, so a client isn't shown tools its token could never use. - The real gate runs on every
tools/call: the endpoint builds an internal request, forwards your bearer, and dispatches it through the same routes, validation, auth middleware and per-resource permission check as a normal HTTP call.
The practical upshot: a read-only token can only reach read tools, and a scoped token stays boxed into its granted
resources. A scoped token isn't even shown the org-wide list and create tools: get_projects (list every project)
simply won't appear in its tools/list; it sees only the per-resource tools for the resource types it was granted.
And if a tools/call touches something outside that scope, it comes back 404: the scope doing its job. For the
full protocol details (JSON-RPC methods, negotiation, error codes), see the MCP API reference.
The organization boundary applies to MCP exactly as it does to a browser session: because every call runs
through the same per-resource permission check, an MCP client acts only within organizations you belong to and can
never reach another org's projects, servers or secrets. A resource outside your membership comes back 404, just as
it would in the dashboard. See Isolation.
Instance-wide operations (panel backups, a Docker cleanup, the certificate contact email, system jobs) additionally need an instance administrator's credential, as they do in the dashboard.
Which tools map to which API
Tools aren't a separate feature set: each one maps onto a permission-tagged REST route, and the tool name is
built from that route's method and path, without the /api prefix. So get_projects is GET /api/projects,
post_domains is POST /api/domains, and patch_projects_by_id is PATCH /api/projects/:id. Call tools/list to
see the exact set your token can use.
Not every route is a tool: a route becomes one only when it opts in, so the set is a curated slice of the API
rather than the whole surface. Each exposed tool also carries two hints a client can surface: readOnlyHint (the
tool only reads) and destructiveHint (it deletes or tears something down), so an agent UI can flag a destructive
call before it runs.
| Tool name (examples) | REST route | Reference |
|---|---|---|
get_projects, patch_projects_by_id | /api/projects | Projects API |
get_deployments, post_deployments_build_access | /api/deployments | Deployments API |
get_projects_by_id_services, post_projects_by_id_services | /api/projects/:id/services | Services API |
get_domains, post_domains, get_domains_acme, put_domains_acme_email | /api/domains | Domains API |
get_github_repos | /api/github | GitHub API |
get_analytics | /api/analytics | Analytics API |
get_notifications_channels | /api/notifications | Notifications API |
get_settings, patch_settings_build_mode | /api/settings | Settings API |
get_projects_by_projectId_backup_policies, post_backup_policies_by_policyId_run | /api/backups | Backups API |
get_system_servers_by_id_docker_disk_usage, post_system_servers_by_id_docker_cleanup_preview, get_system_servers_by_id_cpu_reservations | /api/system/servers/:id/... | Servers API |
get_system_panel_backup, post_system_panel_backup_run, get_system_docker_cleanup_schedule | /api/system/... | System API |
get_jobs, post_jobs_by_key_run | /api/jobs | Jobs guide |
get_apps_catalog, post_apps | /api/apps | App catalog |
get_updates, post_updates_scan | /api/updates | Updating Synq |
Credentials and auth are never exposed
The tokens, auth and mcp modules are hard-blocked from ever becoming tools: a full-access MCP token can't mint
itself a fresh credential or escape its own scope. Manage tokens and connected clients from the dashboard or the
Tokens API, not from an agent.
Guided flows
Some tasks are a chain of calls in a specific order: deploying a repo, uploading a folder, installing a catalog app.
The server ships a small set of prompts (prompts/list / prompts/get) that spell those chains out step by
step, referencing the exact tools to call. Compatible clients surface them as slash-commands or starters, so an agent
can pick a flow and follow it rather than reverse-engineering the order from the flat tool list. See the
MCP API reference for the full catalog.
Verify from the terminal
To confirm a token works and see what it can do, ask for the tool list:
curl -s https://app.<domain>/api/mcp \
-H "Authorization: Bearer synq_pat_…" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'This returns exactly the tools that token is allowed to call.
Manage connected clients
Every OAuth client you've approved is listed under Settings, MCP, Connected clients, tagged Read-only or Full control, with All resources or how many resources it can reach, when it was authorized, when it was last used and how many calls it made.
- Edit access changes what the client can reach. Changes apply on the agent's next request; it doesn't need to reconnect. Removing every restriction asks for a second confirmation.
- Activity opens the audit log filtered to that client, so you see exactly what it did. Everything an agent changes is recorded with the source AI assistant.
- Disconnect revokes the client's issued tokens immediately and drops its consent, so it has to re-authorize next time.
The same list and controls are available programmatically via the Tokens API.
After the panel moves
OAuth tokens are issued for one endpoint address. If you move the panel to another host (see
Domains for the panel and your apps), the old
tokens are refused at the new address: remove Synq from each OAuth client, add https://<new host>/api/mcp, and
approve it again. Clients that use a static token only need the new URL.
Troubleshooting
401: Missing or invalid access token
There's no bearer credential, or it's expired or revoked. The response includes a WWW-Authenticate header so OAuth
clients can start discovery; if you're using a static token, mint a fresh one under Settings, API tokens and
update your client config.
401: Access token was issued for a different resource
The client reached a different address than the one it was authorized for, typically after the panel moved or when
the client uses the website's host. Point the client at https://app.<domain>/api/mcp and authorize it again.
405 on a GET request
Expected. This is a request/response server with no server-to-client stream, so GET /api/mcp isn't supported.
Always POST your JSON-RPC message.
A tool call returns 404 for a project, server, or repo
tools/list worked but a specific tools/call reports 404: that's the token's scope working as intended. It
wasn't granted that resource. Re-authorize the client (or mint a token) with the resource included, or use Edit
access on the connected client.