# Integrations

> Shared data sources for the whole organization. The catalog, credentials, keys, and how health is reported.

Source: https://triagic.com/docs/admin/integrations

**Integrations** holds the data sources your organization shares. Credentials are
entered once, encrypted here, and pulled down by every member's desktop app on sync,
instead of every member pasting in their own copy of the same production connection
string.

## Adding one [#adding-one]

**Add shared data source** opens the form.

| Field             | Notes                                                                                                          |
| ----------------- | -------------------------------------------------------------------------------------------------------------- |
| **Display name**  | Human label, e.g. *Billing Postgres*. Auto-suggested from the integration you pick.                            |
| **Key**           | The stable identifier. Auto-allocated with an `org-` prefix; you rarely need to set it.                        |
| **Integration**   | The catalog entry, grouped by category. Determines which credential fields you get.                            |
| Credential fields | Per-integration. See [Connecting data sources](/docs/integrations) for step-by-step instructions for each one. |
| **Environment**   | `production`, `staging` or `development`. Defaults to production.                                              |
| **Teams**         | Optional tags for organizing the list.                                                                         |

Pick the catalog entry and the form becomes that integration's real credential form
(*Connection URL* for Postgres, *Access token* and *Organization slug* for Sentry,
a pasted *Kubeconfig* for Kubernetes) with per-field help, rather than a generic
name/value editor.

For anything the catalog does not cover, choose **Custom MCP server** and supply a
command, arguments and environment, or a remote HTTP URL.

### The `org-` key convention [#the-org--key-convention]

Every shared integration's key is prefixed `org-` (`org-postgres`, `org-sentry`), and
personal keys are barred from that prefix.

This matters because a key prefixes its tool names. A member's own `postgres`
integration and the organization's shared `org-postgres` produce distinct tools
(`postgres__query` vs `org-postgres__query`) that never collide, in the tool list the
agent sees or in a playbook's allowlist.

### Multiple instances of one integration [#multiple-instances-of-one-integration]

A production database and a replica, staging and prod OpenSearch: pick the same
catalog entry again. Each instance is its own configuration with its own key
(`org-postgres`, `org-postgres-2`), which is what lets a playbook be scoped to exactly
one of them.

The **copy** control on a configured card starts a new instance from that one's
non-secret fields.

Two configurations that resolve to the *same* connection are rejected. A second
instance has to differ in at least one connection detail. Otherwise it would spawn
the same server twice and double the tool count for nothing.

### The environment tag [#the-environment-tag]

Every integration carries an environment tag saying which deployment tier it points
at. It is **a label, and only a label**: nothing routes on it, nothing is blocked
because of it, and the agent does not treat a `development` source differently from a
`production` one. What it buys you is that a list holding four Postgres connections
says which is which, at a glance, on the card.

The tag rides along with the rest of the configuration: it is set here, shown as a
badge here and in the desktop's data-source list, and mirrored down on sync, so the
two never disagree about which database is production.

Every pre-existing integration is `production`, because that is the safe assumption to
make about a source somebody configured before the field existed.

## What members can do here [#what-members-can-do-here]

Configuration stays admin-only: only an org admin can add, edit or delete a shared
data source, and members never see credential fields at all.

Two things are **operational** rather than configuration, and any member may do them
on a shared data source they can already reach:

* **Restart** it. A restart moves no credentials and changes no configuration: it
  re-runs exactly what an admin already saved. It is audited (`org.server.restart`),
  because a shared server going down and up is visible to the whole org and "who did
  that" has to have an answer.
* **Read its connection log**, meaning the server process's own lifecycle events and stderr.
  "Why is this data source degraded" is the whole organization's question, not just
  the admin's, and the log is where it is answered.

> **Note:** Connection logs are scrubbed
>
> An MCP server that prints the connection string it was handed is a thing we do not
> control, so the values of that configuration's stored secrets are stripped out of the
> log lines before they are returned, for admins too. Nobody needs to read a password
> out of a log line to operate a server.

"Reach" means the same team-tag rule the list itself uses: a member can only act on
rows they can already see, and a row they cannot see answers *not found* rather than
*forbidden*, so this cannot be used to discover another team's data sources.

## Secrets [#secrets]

Stored secrets are returned masked as `•••` and never in plaintext.

In the edit form, a saved secret shows as set and keeps the mask as its value. Saving
with the mask untouched means *keep the stored secret*; typing a new value replaces
it. You cannot read a secret back out, from the UI or the API.

## Health [#health]

The column of counts at the top of the page (`3/4`) and each card's status are the
**last thing a desktop install reported**, not a live check.

> **Note:** Saving here validates shape, not connectivity
>
> The portal never test-connects an integration; it has no long-lived process to do it
> from. A configuration that saves cleanly can still be wrong. The truth arrives when a
> desktop tries to start it and reports back.

So the loop for a new integration is: save it, wait for a member's desktop to sync,
then come back and look at the reported status. A degraded entry carries the error
text, and it is nearly always a wrong credential, an expired token, or a host that is
not reachable from that machine's network.

## Pre-adding data sources for members [#pre-adding-data-sources-for-members]

On the **Organization** page, **Pre-add data sources for members** lets you select
catalog integrations that members' desktop apps will pre-provision as *disabled
placeholder rows* in their own personal data-source list.

This is for the case where each member needs their **own** credential for something
(their own Sentry token, their own kubeconfig) and you want the row waiting for them
rather than making them find it in the catalog.

Shared data sources need no selection here. They already work for everyone.

The options offered are the provider ids already in use by this organization's
configured integrations, so configure something on this page before expecting choices
there.

## Deleting [#deleting]

Deleting a shared integration removes it for everyone on the next sync. Any playbook
scoped to its key keeps the key visible as a stale pill in the editor so you can clear
it deliberately. See [Managing playbooks](/docs/admin/playbooks#data-sources).

## Use read-only credentials [#use-read-only-credentials]

Write protection is enforced at the MCP server level, but that guarantee is only as
good as the MCP server's own code. Pointing these credentials at read-only database
users and read-scoped tokens makes it independent of any bug in that layer. See
[Security model](/docs/admin/security).
