---
name: deploy-connect
description: "The first step of deploy: check the CLI, login and scopes, then connect the MCP servers a Recipe declares, or fake them with `introspection dev`. Use to deploy a new agent, a change, or an existing Recipe."
metadata:
  min-cli-version: "0.76.0"
  next: "deploy-create deploy-test"
---

# Deploy: connect

Deploy always starts here. This step makes sure the agent can reach every MCP server its Recipe declares (`package.json#pi.mcp.servers`): a ready version can't do its job without them.

## Before you start

**Check the CLI.** It must be at least this skill's `metadata.min-cli-version`, and only one may be installed:

```sh
introspection --version
which -a introspection
```

Otherwise stop and tell the owner to run `npm i -g @introspection-ai/cli@latest` and remove the older one from their `PATH`.

**Check the login:**

```sh
introspection whoami
```

Not signed in: ask the owner to run `introspection login` in their own terminal. Any other error from `whoami`, `runtimes list` or `repositories list` (a 404, connection refused, a server error): show it to the owner and stop, since every later choice depends on reading the platform.

<!-- rule: R-deploy-scopes-stop-before-register -->

**Check the scopes** in that output:

| To                          | Needs                                                  |
| --------------------------- | ------------------------------------------------------ |
| create a runtime            | `recipes:write`, `repositories:read`, `runtimes:write` |
| push to a hosted repository | `git:push`                                             |

If one is missing, name it and stop before creating anything.

**Check the stage.** After build, `pr/<name>` has approved cases in `evals/cases/` and `docs/PULL_REQUEST.md`; if not, go back to build-review. An existing Recipe the owner asks to deploy needs neither: run `introspection check`, say in one line what it lacks, and carry on from `main`.

**Find out which deploy this is:**

```sh
introspection runtimes list --query "[].[slug, id]"
```

None named as in `.introspection/<name>.yaml` means a **first deploy**; one means a **change** to a deployed agent (a later build, or optimize's branch; improve's branch goes to `deploy-try` instead).

## The order

| Step | First deploy                                                             | A change                                             |
| ---- | ------------------------------------------------------------------------ | ---------------------------------------------------- |
| 1    | Here: connect the required servers project-wide                          | Here: connect what the change added, per environment |
| 2    | deploy-create: choose the repository, push to `main`, create the runtime | deploy-create: push the branch, pin staging to it    |
| 3    | Here again: connect what needs the runtime (BYOK, a chat connector)      | —                                                    |
| 4    | deploy-test                                                              | deploy-test                                          |

A server connected project-wide before the runtime exists serves its first version. One connected after leaves that version failing until a new one is made; nothing is wrong with the Recipe then: connect, then make a new version.

**Approvals.** Creating a repository, a connector or a binding, authorizing, pushing and creating a runtime each need the owner's yes, asked with the question tool. A choice and the go-ahead are two questions, choice first; picking an option isn't a yes. deploy-create's record keeps each approval.

## What's needed

```sh
introspection connectors list -o table
# once a runtime exists, per environment:
introspection bindings mcp list --runtime <slug> --environment staging -o table
introspection bindings mcp list --runtime <slug> --environment production -o table
```

Compare them with the Recipe's servers and whether each is `required`.

<!-- rule: R-bindings-env-scoped -->

**Each environment is its own.** A server bound in staging says nothing about production. Never copy a binding from one environment to another without checking where it points and what credential it uses.

If every required server is connected, say so in one line and go to the next step.

## Find the connector

Look in this order, and create one only when none fits:

1. The project's connectors: `introspection connectors list -o table`, a `provider` or `slug` matching the server id.
2. What the platform supports, listed on the project's connectors page: built-in providers, MCP servers it knows, apps through Pipedream.
3. A new custom MCP connector, added by the server's URL.

Then read how it signs in; never guess from the provider's name:

```sh
introspection connectors get <slug> --query auth_mode
```

`oauth_*`: the owner signs in. `static`: the owner pastes a key in the dashboard. The Recipe's `pi.mcp` server id is the connector's slug and its URL the connector's; nothing goes under `runtime.connectors`. When the Recipe names the server differently, change the Recipe first (a Conventional Commit, `introspection check`, the owner's yes before pushing).

## Connect each missing server

Ask the owner how, one server per question, offering in this order:

### 1. In the dashboard

With the `introspection_open` tool, on its own in a turn:

```json
{
  "kind": "binding",
  "runtime": "<slug>",
  "name": "<server id>",
  "environment": "<environment>"
}
```

with `wait: true`. The owner connects with their own identity, or pastes a `static` connector's key into its dialog; the result is `connected`, `failed: <reason>` or a decline. Without the tool:

```sh
introspection open --runtime <slug> --wait   # --print gives a link when there's no browser here
```

Before a runtime exists, the owner connects project-wide on the project's Bindings page instead (give the link `introspection open` prints, never one you put together). A key goes only into that dialog, never into the conversation or a command. `connected` is what the owner did, not proof: list the bindings again before recording it.

### 2. From here

`introspection connectors authorize <connector> --runtime <slug>` opens the provider's sign-in and waits. To create, bind, authorize and check a connector from the CLI, follow [connecting from here](references/from-here.md).

### 3. Fake it, for development tasks only

When the real service isn't ready or the owner doesn't want real data touched yet; it tests the agent in development, not staging, so say so in the question. Follow [faking a server](references/fakes.md), which also says what each kind of run reaches.

### 4. Not now

Record the server as not connected; deploy-test runs only the cases that don't need it.

## After a first runtime

Come back here from deploy-create for what needs the runtime:

- **BYOK:** the owner adds their key on the Runtime's page, for staging and for production; a key never passes through you. Open it with `introspection open --runtime <slug> --wait`, ask them to add an LLM endpoint with their key and click Return to agent, then check it:

  ```sh
  introspection bindings endpoints list --kind llm
  ```

  Until an environment has one, report it missing there: a version without it can't answer.

- **A chat connector** such as Slack (`requires_runtime: true` in `introspection connectors get`): its connection names the agent that answers, so connect it now, as above.
- **A per-environment binding** the owner wants different in staging and production.

<!-- rule: R-new-binding-needs-new-task -->

A task's connections are fixed when it starts, so a server connected while a conversation is open is used only by tasks started afterwards. Check the bindings again after each change, and record what each environment has in the deploy record (Part B and `docs/PULL_REQUEST.md`): connected, faked through `dev` for development, or missing.

## Guardrails

- **The owner connects:** they sign in, authorize and enter secrets. You find what's missing and say where.
- **Never run a task in an environment missing a required connection,** unless `dev` supplies it for that development task.
- **A fake proves the fake:** say which servers were faked, and in which environment, whenever you report a result.

## Done when

- Every required server is connected (project-wide before the runtime exists, or in staging), faked through `dev` for development tests, or recorded missing with the owner's decision.
- Go to `deploy-create`, or, back here after a first runtime, to `deploy-test`.
