Custom MCP server
Connecting a data source the catalog does not cover — a local command over stdio, or a remote HTTP endpoint — and what the catalog gives you that this does not.
Anything speaking the Model Context Protocol can be configured by hand. In the Add shared data source dialog, switch from Catalog integration to Custom MCP server and pick a transport.
Prefer a catalog entry where one exists
A catalog entry derives its package, arguments, transport, read-only flags and health check server-side, so upgrades and new flags reach existing configurations on their next restart. A custom row is a frozen snapshot of whatever you typed: nothing updates it, nothing pins its read-only mode, and nothing proves the credential beyond the server starting.
Command (stdio)
For a server distributed as a package you run locally.
| Field | Notes |
|---|---|
| Command | The runner: npx, uvx, docker, or an absolute path to a binary. It must exist on every member's machine — the same prerequisite rule as the catalog. |
| Arguments | Space-separated. -y some-mcp-server@1.4.0 — pin a version; an unpinned npx follows silent major bumps and will break the row without warning. |
| Environment variables | Key/value pairs passed to the spawned process. This is where connection details go. |
Arguments support ${VAR} interpolation from the environment map, and an argument
that interpolates to an empty string is dropped — which is how an optional flag can
be present in the template and vanish when its variable is unset.
URL (HTTP)
For a hosted or self-hosted server you reach over HTTPS. Nothing is installed locally, so members need outbound network access to that host instead of a runtime.
| Field | Notes |
|---|---|
| Server URL | The streamable-HTTP endpoint, e.g. https://mcp.example.com/mcp. |
| Headers | Key/value pairs sent on every request, e.g. Authorization: Bearer …. |
Servers that require an interactive OAuth authorization flow cannot be configured here: there is no browser and no callback URL in this path. Only endpoints that accept a static header work.
Where secrets can and cannot go
A shared custom server has no encrypted path for a secret
For catalog integrations, credential fields are encrypted at rest and returned masked. For a custom row, the spawned process is built from its environment variables (stdio) or headers (HTTP) — and org-side those two are stored unencrypted. The separate Credentials box on the custom form is stored encrypted but is not read when the server is started, so a token placed there does not reach the process at all.
So: do not put a production secret on a shared custom server. Either add a catalog entry for that system, or have each member configure the custom server in their own desktop app, where its environment is encrypted locally.
What you give up
| Catalog entry | Custom server | |
|---|---|---|
| Package and flags | Derived server-side, update on restart | Frozen as typed |
| Read-only mode | Pinned on, not exposed as a switch | Yours to get right |
| Credential validation | Per-field, before saving | Shape only |
| Health check | A real read-only call proves the credential | Start-check only |
| Failure diagnostics | Mapped to the field that fixes them | Raw error text |
| Secret storage | Encrypted, masked | See the warning above |
Keys and tool names
A custom row gets a key like any other — org- prefixed when shared — and that key
prefixes its tool names, so a playbook can scope to it exactly as it would to a
catalog integration. See
Anatomy of a playbook for how allowedServers uses keys.
If it will not start
The portal cannot test-connect anything, so the first real signal is the status a desktop reports back. The common causes, in order:
| Symptom | Cause |
|---|---|
| Degraded, naming the runner | Command isn't installed on that machine, or isn't on the PATH the app resolves. |
| Degraded immediately on stdio | Wrong arguments — run the same command by hand in a terminal on that machine to see the real error. |
| Degraded with a 401 on HTTP | The header is missing, malformed, or the endpoint wants OAuth. |
| Starts, but the tool count is 0 | It connected to something that is not an MCP server, or to one whose tools are all gated behind configuration it did not get. |