---
name: mindset-connect
description: Use when connecting an outside system to Mindset (mindset.ai) so an agent can use it, through the mindset-admin MCP server. Covers choosing the connection type (HTTP API, MCP server, Postgres, Google Sheet, knowledge base), getting the credential in with request_capture or authorize_connection, enabling and governing operations, read versus write approval, and proving each read with real data.
metadata:
  title: Connect a system for an agent
  blurb: Connects an outside system, such as an API, database or MCP server, so an agent can use it.
  group: Mindset MCP
  order: 4
  docs: connections-and-operations, connection-types, connect-a-system, approve-what-an-agent-can-do, change-something-thats-already-live
  checked: d671041b6
  updated: 2026-10-19
---

# Connect a system so an agent can use it

When you finish, the outside system is a live **connection** in the person's environment, the operations the agent needs are enabled and offered to agents, each read has returned real data the person checked, and every write is either granted or visibly waiting for a person's approval.

## Mindset in brief

Mindset is a hosted platform for building, running and governing AI agents. An **agent** is configuration, not code: a prompt, a model, and the resources it may use. Those resources are **scripts** (steps that must wait or happen in order), **functions** (fixed steps with one right answer), **widgets** and **connections** (the only way data enters or leaves). People manage all of it in the Studio, a web app, or through Mindset's MCP servers.

## Where you are building: host, org, environment

Every Mindset call names three things. Get all three from the person before you write code or call a tool. Never guess or invent them.

| Value | What it is | Where the person finds it |
|---|---|---|
| **Host** | The Mindset deployment their org lives on, for example `https://eu.mindset.ai` | The address bar when they're signed in to the Studio, or an agent's **Embed** tab |
| **Org slug** | Their company's account. The org is the isolation boundary: members, model keys, settings and audit sit here, and one org can never see into another | An agent's **Embed** tab, or the address under **Settings → Systems → Connect an AI client** |
| **Environment slug** | A named partition inside the org, such as Sandbox, Test or Production | An agent's **Embed** tab, or the same address. The **Environment** switcher in the Studio shows which one is current |

How environments behave:

- **Agents, scripts, functions, connections, triggers, schedules, conversations, runs and API keys each belong to exactly one environment** and can't see anything in another.
- **Every org starts with one environment, Sandbox, whose slug is `original`.** A slug never changes, even when the environment is renamed. Use the slug, never the display name.
- **Nothing copies between environments.** To promote a change from Test to Production, make the same change again in Production.
- **Don't create an environment to hold your work.** Environments can't be deleted, and they're for stages such as Test and Production, not for projects. Work in the environment the person names. Create one only if the person asks you to.
- **Members, model keys and org settings are shared by every environment.** Changing an org setting changes it everywhere.

## Credentials for building in Mindset: sign in, never a key

You build inside Mindset through the **`mindset-admin` MCP server**. The person signs in with their own Mindset account in a browser, and they must be an org admin. There is no key or token, so never ask the person for one.

- **The server address names one environment**: `<host>/api/v1/orgs/<org-slug>/envs/<environment-slug>/mcp`. Every call goes to that environment unless the tool call passes `envSlug` to point that one call at another environment. Org-level tools refuse an `envSlug`.
- **No tool takes a secret value.** When a connection needs a credential, call `request_capture`. It returns a reference and a capture URL. Give the person the URL to open and paste the value into themselves, then use the reference. Capture links expire after 15 minutes. For a system that signs in with OAuth, `authorize_connection` returns a sign-in link the person opens the same way, and it expires after 10 minutes. If a link has expired, request a new one. Never ask the person to paste a credential into the conversation, even if they offer.
- **Errors come back structured.** Read `code` and `context` and act on them. Don't retry blind.

## Before you start

This skill works through the `mindset-admin` MCP server. Check that its tools (for example `get_information`) are available to you. If they aren't, set the server up first, following the `mindset-mcp` skill or https://docs.mindset.ai/docs/work-from-claude-code.md, then come back here.

Call `get_information` with no arguments for the platform's own topic index. Its guidance is current for the platform you're connected to. Where it and this skill disagree, follow `get_information`.

## Connections and operations

A **connection** links Mindset to one outside system and holds its address and credential. Mindset looks up the credential for each call. The agent never holds it, and it never reaches the model.

An **operation** is a single action an agent can take on a connection, with a fixed input and output. Each one is a **read** (fetches something) or a **write** (changes something). An agent is given operations, never "the finance system": for example `get_invoice`, `get_purchase_order_for_invoice` and `get_supplier` (reads) and `register_supplier_query` (a write) for the invoice exceptions agent.

An agent can call an operation only when all five hold:

| | Question | Who settles it |
|---|---|---|
| 0 | Is the connection live (passed its probe, enabled)? | `publish_resource` |
| 1 | Is the operation enabled? | Creating it, or `govern_tool` |
| 2 | Is it offered to agents (`exposures` includes `agents`)? | `edit_resource` |
| 3 | For a write: is consent granted? | The org setting, or a person in the Studio. Never you |
| 4 | Is it on the agent's active version? | `agent_config_admin`, or the agent's **Resources** tab |

Questions 0 to 3 are checked on every call. Question 4 takes effect only when a version is activated.

## Ask the person for

- The host, org slug and environment slug, if your MCP address doesn't already settle them.
- What the agent must do with the system, in the person's own words. You turn that into the smallest set of named operations.
- The system's address, and what kind of system it is (an HTTP API, a remote MCP server, a Postgres database, a Google Sheet, or a search server holding documents).
- Who holds the credential, and that it's scoped to only what the operations need and pointed at the right account.
- One record they can check on their own screen (an invoice number, a supplier ID), so you can prove the reads.
- A safe target for any write you test: a test record, a test channel, their own address.

## Step 1: choose the connection type

`type` is required on every connection, and the platform can't infer it. It decides the protocol. Get it wrong for an MCP server (declaring `rest_api`) and the connection is created with zero operations and no error.

| `type` | Use it for | Credential | Operations come from |
|---|---|---|---|
| `rest_api` | Anything with an HTTP API. Most connections | Bearer token, up to three headers, HTTP Basic, or none | Authored, one per method and path |
| `mcp_server` | A **remote** MCP server. A local (stdio) one can't be connected | Token, headers, or an OAuth browser sign-in | Discovered from the server |
| `postgres_database` | Lookups and joins over more data than a sheet holds | A connection string (`dsn`) | Fixed parameterized queries you enable one at a time |
| `google_sheet` | A small table a person also edits | A Google Cloud service account key | Fixed: `get_range` (read), `append_row` (write) |
| `knowledge_base` | A search server holding the person's documents | As for an MCP server | Exactly one tool, `rag_search` |
| `model` | Letting functions and scripts call one AI model, under limits an admin sets | None | None. Functions and scripts name the connection |
| `stackone` | HR, recruiting and CRM systems, per end user through StackOne | None from you. Each end user signs in through StackOne | See the connection types page |

If the system fits none: does it have an HTTP API? Use `rest_api`. Is there a remote MCP server for it? Use `mcp_server`. Is it reachable only by clicking through a website? Mindset can't reach it. Say so.

An HTTP API that needs OAuth (browser sign-in or client credentials) can't be connected yet. Ask for an API key, or a vendor MCP server.

## Step 2: read the platform's recipe

Call `get_information` with `topic='authoring:connection'`. It's the generic flow, the adapter and config fields, and it names its other parts. Then read the guide for the type: `authoring:connection:api`, `authoring:connection:mcp`, `authoring:connection:database`, `authoring:connection:sheets` or `authoring:connection:llm`. For Slack, read `authoring:connection:provider:slack`. These are current for the platform. Follow them for field names and argument shapes.

## Step 3: probe the address

Call `probe_endpoint` with the URL before you create anything. It reports whether the far side speaks MCP, is plain HTTP, or is undetermined, and what authentication it declared.

- A `401` isn't a failure. For an MCP server it usually means it wants authorizing.
- `undetermined` is a real answer. Ask the person what the system is. Never guess the type from the URL.
- The probe decides nothing. You still state `type` and the adapter yourself.

## Step 4: get the credential in

You never see, hold or type a credential. There are exactly two routes:

- **A token, key, password, DSN or service account key:** call `request_capture` with the config `field` the adapter declares (for example `token`, `password`, `dsn`, `serviceAccountJson`), the `adapter`, and a `label` saying what it's for in the person's words ("the finance system's API key"). Give the person the `captureUrl`. Put the returned `secretRef` at `config.<field>` as `{ "secretRef": "<the ref>" }`. A secret captured under a field the adapter doesn't declare is never read, and the probe fails as if nothing were supplied.
- **An MCP server that signs in with OAuth:** create and publish the connection with no credential. It comes back `oauthRequired`. Call `authorize_connection` with the connection's uuid and give the person the authorization link. They sign in on the provider's own screen. The link is single use and expires after 10 minutes. Afterwards, read the connection back with `get_resource` and check `oauthConnected`. Don't assume it worked. The grant is one per connection, shared by every agent run and every user.

To replace a credential that already exists (rotated, leaked, wrong value), read its existing `secretRef` from the connection's config and pass it to `request_capture`. The reference stays the same, so don't edit the connection afterwards. Capturing a fresh one instead leaves the old secret live and orphaned.

## Step 5: create and publish the connection

1. Propose a short name and a one-line description to the person. The description is what later lets someone pick the right connection.
2. Call `create_resource` with `type: "connection"`, an `input` carrying the name, description, address, `type`, adapter and `config`, and an `idempotencyKey`. If the call errors, retry with the **same** key: a create that reported an error may already have committed, and a fresh key makes a second connection holding its own credential.
3. Call `publish_resource`. It probes the connection on its own host and makes it live only on a pass.

For an MCP server or knowledge base, publishing discovers the tools. Every discovered tool arrives switched off. A knowledge base with anything other than exactly one `rag_search` tool is refused. Connect a multi-tool search server as `mcp_server` instead. A tool left out because another operation on the connection already has its name is listed in the answer's `toolsLeftOut`, with the operation that holds the name.

## Step 6: set up the operations

**HTTP API.** Call `introspect_api` on the connection. It tries standard OpenAPI and Swagger paths and GraphQL on the API's own host. Finding nothing is a normal answer. Then ask the person to paste the relevant documentation into the conversation, or name the parameters. No tool here fetches a link, so don't ask for one. Register each operation with `create_resource` and `type: "connection_operation"`, including `sampleArgs` that name a real record. A read (`GET`) makes one real call and enables only if it worked, and its output shape comes from the real response, not the documentation. A required path parameter without a real value is refused.

**Postgres.** Each operation is one parameterized SQL statement. Enabling first checks the login's privileges (a refusal gives the `GRANT` statement for the database owner), then runs the query inside a rolled-back transaction. Read versus write follows the login's privileges, not the SQL, so a connection that must never write needs a login that can't write. An agent's call returns at most 100 rows, and a function's or script's 1,000. Every result stops at 5 MB of whole rows, and `truncatedBy` says which limit cut it.

**Google Sheet.** Ask the person to share the spreadsheet with the service account's email address. Register `get_range` and `append_row` as operations.

**MCP server.** Call `govern_tool` with the connection's uuid and the tool's original name to `enable` each tool the workflow needs. Leave the rest off.

Then, for every operation:

- **Descriptions.** The operation and every parameter need a description written for tool choice. The model picks the tool and fills its parameters from them. Fix wording with `edit_resource`, not `govern_tool`.
- **Labels.** Each operation also carries `labels`, `{ doing, done }`: the line a person sees in the chat while it runs and once it has. They're generated for you. To change them, `edit_resource` with a `path_set` on `labels` (one line each, at most 60 characters), or `null` to go back to the generated pair.
- **Offer it to agents.** Read the operation with `get_resource`, then `edit_resource` with a `path_set` on `exposures` to the full set you want (for example `["functions", "agents"]`). This is refused while any description is missing. Enabling never offers it to agents: an operation you register starts offered to functions only, and a discovered MCP tool to nobody. Until it's offered to agents, its record carries a `reachNotice` saying so.
- **Check read or write.** On an MCP tool, the marking comes from an admin's choice, then the server's hints, then a model's reading, and anything unknown counts as a write. Correct a wrong marking with `govern_tool` and `access`. If in doubt, mark it a write.
- **Other governance** through `govern_tool`: `disable` (kept, not callable), `hide` / `unhide` (hiding also disables), `adminOnly`, and `eraseOutputSamples`.

## Step 7: prove each read with real data

A probe proves the credential, not the data. Before any agent uses a read:

1. Call `test_resource` with `type: "connection"`, the connection, and the operation plus its arguments. It refuses a write operation, so it can't change the system.
2. Show the person one value from the response, and have them check it against what they see in the system itself. A credential pointed at the wrong account returns valid data and no error.
3. Report each operation you registered as **Tested** or **Untested**, by name. Activating an agent version whose script calls an untested operation can be refused.

## Step 8: writes wait for a person

Read the result when you create or enable a write:

- **Org setting on (the default):** a new write is granted at once, recorded as granted by the org policy. It's callable but untested. Say plainly what it would really do.
- **Org setting off:** it comes back `needs_approval`, with an `approvalUrl`. It's registered, not rejected. Give the person the link: an admin approves it on the connection's **Operations** tab (or **Tools** for an MCP server). Report it verbatim. Never tell anyone the agent can use it yet.

No tool argument approves a write, and you can't approve one. To test a write, call `test_resource` with `input.mode: "invoke"` against the safe target. It's first refused with `write_go_ahead_required` and what it would write. Tell the person what it would write, and call again with `goAhead` only once they say go, quoting their instruction.

## Step 9: give it to the agent

Give the operations to the agent with `agent_config_admin` verb `set_assignments`, `assignments: { connection_operations: [<every operation id the agent should hold>] }` and `activation`: `"stage"` if the agent already has an active version, `"activate"` if it never has. A knowledge base is assigned whole, under `connections`. If a connection you assign gives the agent no tool, the reply's `assignmentWarnings` says why. A write still waiting for approval can be assigned; it runs nothing until a person approves it. Nothing reaches the agent until a version holding it is active. If you aren't building the agent, tell the person to add the operations on the agent's **Resources** tab.

## Rules

- Never ask for a credential in the conversation, a tool argument or anywhere else, even if the person offers. If a capture can't be completed, say so and stop.
- Never write the literal `{ "secretRef": "captured" }`. That placeholder belongs to the in-app builder and resolves to nothing here.
- Give an agent the fewest operations it needs. Assign named operations rather than the whole connection, except for a knowledge base.
- Never call a test write without the person's go-ahead for that exact write.
- Deleting a connection can't be undone. `delete_resource` is refused first with `has_dependents` naming each dependent. Show the person the list. To stop a connection for now, disable it instead.
- Rotating a credential or changing the address makes the operations untested again.
- Don't put a probe path such as `/ping` on the base URL to make a probe pass. Operation paths are appended to it, so every operation breaks.

## Check it works

- `get_resource` on the connection shows it enabled and live.
- `list_resources` with `type: "connection_operation"` and the connection as filter shows each operation you need, enabled, with `agents` in `exposures` where an agent calls it.
- One `test_resource` read per operation returned a value the person confirmed.
- Every write is reported as granted (by the org setting or a named person) or waiting, with the approval link.

## When it fails

| What you see | Cause and fix |
|---|---|
| An MCP server connection has no operations and no error | It was created as `rest_api`. `edit_resource` the `type` to `mcp_server`, then `publish_resource` again |
| `probe_endpoint` or publish returns `401` on an MCP server | It wants OAuth. Use `authorize_connection` |
| Publish fails after a capture | The secret went under a field the adapter doesn't read, or the value is wrong. Replace it through `request_capture` with the existing `secretRef` |
| A capture or authorization link no longer works | It expired. Request a new one |
| Enabling a read fails with an authorization error | The credential is scoped narrower than the operation needs. The person widens it at the provider |
| `edit_resource` refuses `agents` in `exposures` | The operation or a parameter has no description. Add them |
| An operation comes back with a `blockedReason` | It's offered but not callable yet, usually a write awaiting approval. Report it verbatim |
| `needs_approval`, or `govern_tool` leaves a write un-enabled | A person must approve it in the Studio. Pass on the `approvalUrl` |
| `credential_binding_required` | An operator-published connection needs this org's own credential. Capture one, then call `bind_connection_credential` |
| Knowledge base discovery refused | The server doesn't expose exactly one `rag_search` tool. Connect it as `mcp_server` |
| The sheet reads as empty or refuses access | The spreadsheet isn't shared with the service account's email |
| The data is right but from the wrong place | Check the account the credential reaches, not the connection |
| `name_taken` | Another operation on that connection already has that name. Pick another, or rename that one first |
| Registering an HTTP operation refuses a header parameter | The connection's credential already sets that header, such as `Authorization`. Remove the parameter: Mindset sends the credential |

## Read more

Fetch these as Markdown when you need more than this skill gives you. If one disagrees with this skill, the page is newer: follow it.

- https://docs.mindset.ai/docs/connections-and-operations.md: read for the five questions and how to check you reached the right account.
- https://docs.mindset.ai/docs/connection-types.md: read when a system doesn't obviously fit a type, or for the model and StackOne types.
- https://docs.mindset.ai/docs/connect-a-system.md: read for choosing a connection type, auth options, OAuth sign-in and how tools are marked read or write.
- https://docs.mindset.ai/docs/troubleshooting.md: read when enabling a database operation fails on a privilege, or a Google Sheet reads as empty.
- https://docs.mindset.ai/docs/approve-what-an-agent-can-do.md: read for consent states, withdrawing approval, and per-action approval in Slack.
- https://docs.mindset.ai/docs/change-something-thats-already-live.md: read when a connection must be stopped or deleted, or a system stops returning a field.
