---
name: deploy-connect
description: "Connect a deployed Introspection agent (Recipe) to the MCP servers and data it declares, in each environment, or run it against local fakes with `introspection dev`. Use after deploy-runtime, when the version is ready; deploy-test follows. Needs `introspection login`."
---

# Deploy: connect

A version can be ready and still unable to do its job: every MCP server the Recipe declares (`package.json#pi.mcp.servers`) needs a connection in each environment that serves it. Find what's missing and get it connected, or test against fakes until it is.

## Before you start

- **Read only what you need.** Every `introspection` command takes `--query` (JMESPath): `bindings mcp list --runtime <slug> --environment staging --query "[].[mcp_server_id, connected, endpoint_id]"`, `connectors list --query "[].[slug, status]"`, `connectors connections list --connector <id> --query "[].[id, status]"`. A single string prints quoted: strip it with `| tr -d '"'` when you capture it.
- **Check the stage:** deploy-runtime recorded a runtime and a ready version. If not, go back to it.
- **List what's needed and what's there:** the Recipe's servers and whether each is `required`, the connectors the manifest names (`runtime.connectors` in the manifest the runtime was created from), the project's connectors (`introspection connectors list -o table`), and the version's bindings per environment (`introspection bindings mcp list --runtime-id <version-id> --environment staging -o table`, then `production`).
- <!-- rule: R-bindings-env-scoped --> **Each environment is its own.** A server bound in staging says nothing about production, and a binding is never copied from one environment to another without checking where it points and what credential it uses.

If every required server is bound in staging, say so in one line and hand over to deploy-test.

## What reaches what

Three kinds of run reach a server three different ways, so a server can be missing for one and fine for another:

| Run                             | Reaches a server through                                                                                                                               |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| A task in staging or production | that environment's binding, and nothing else                                                                                                           |
| A task in development           | the development binding, or a fake `introspection dev --mcp` serves while it stays attached                                                            |
| A Harbor trial                  | the servers its task declares (`[[environment.mcp_servers]]` in `task.toml`), which win over any binding; a task that declares none uses the Runtime's |

`dev` doesn't create a binding or configure staging or production: a fake it serves never reaches a staging task or a Harbor trial. Say this before the owner chooses, whenever the test they want is in staging.

## Steps

For each required server that isn't bound, ask the owner with the question tool how to connect it, one server per question, offering in this order. Ask before acting on their answer: creating a connector, binding it and authorizing it change the project, so each needs their yes, as the runtime did.

1. **Connect it in the dashboard.** `introspection open --runtime <slug> --wait` opens the Runtime's page, which shows **Connect <id>** for each environment missing a connector, its connection or its binding. The owner connects there with their own identity (a new authorization, or one they already have), clicks "Return to agent", and the command returns. With no browser on this machine, `--print` gives them the link instead; then wait for them to say they're done. Give only a link `introspection open` printed, never one you put together: the dashboard addresses a project by its slug, and a guessed path can lead nowhere.
2. **Connect it from here.** <!-- rule: R-authorize-url-clickable-pause --> When the connector exists, `introspection connectors authorize <connector> --runtime <slug>` opens the provider's sign-in and waits for the connection; with no browser here, `introspection connectors authorize-url <connector> --runtime <slug>` prints the link: give it to the owner as a link, wait until they say they've signed in, then list the bindings again. When the connector doesn't exist, agree its endpoint with the owner, then, with their yes:
   - create it: `introspection connectors create --name <id> --provider <id> --auth-mode <mode> --issuer <url> --api-host <host>` (`oauth-stored` for a server that signs the owner in);
   - bind it: `introspection bindings mcp connect --runtime <slug> --mcp-server-id <id> --endpoint-url <the server's MCP URL> --connector <id> --name <id>`, once per environment with `--environment staging` and `--environment production`, or once with no `--environment` to serve every environment. A CLI whose `bindings mcp connect --help` shows `--mcp-server-id` as optional takes the server id and URL from the connector: `bindings mcp connect --connector <id> --runtime <slug>`;
   - authorize it as above;
   - check it: `introspection connectors connections list --connector <id>` shows the connection active, `introspection connectors test <id> --connection <connection-id>` reaches the server with it, and `bindings mcp list` shows the server connected in each environment. The Runtime page's connect dialog shows its last check, which can predate the sign-in: tell the owner to use Re-check rather than trust an older failure. A repository that ships a setup script for this (`scripts/setup-introspection.sh`, say) shows the exact commands: read it, and run its steps one at a time with the owner's yes rather than the script whole. Never put a token or secret in a command; the owner enters it where the platform asks.
3. **Fake it from this machine, 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 in staging: say so in the question. Then:
   - Start the fake yourself, in the background: the Recipe's `fakes/` as `eval-fakes` says, or a server the repository ships (its README or `.pi/mcp.local.example.json` says where it listens). If the owner says one is already running, use theirs. Check it answers before going on.
   - <!-- rule: R-dev-mcp-name-must-match --> Attach it from the Recipe's repository, on the commit the version was built from, in the background with its output kept in a log: `introspection dev --runtime <slug> --mcp <id>=<local url>`. The id is exactly as `package.json` declares it. It routes that server to the local process only while `dev` stays attached, and no local secret is uploaded.
   - <!-- rule: R-dev-target-not-credential --> Read the development target from `dev`'s output (the `INTROSPECTION_DEV_TARGET` line it prints). deploy-test sets it on the development tasks it starts, so they route to this machine. It selects an attached session, never a credential or an environment, and is never set for staging or production.
   - <!-- rule: R-no-dev-handback-in-sandbox --> In a cloud Operator session, `dev` can't serve the owner's machine: don't offer this option there. Record the server as missing in each environment and what the owner must connect.
   - Stop `dev` and the fake when the tests are done. A pass here proves the agent against the fake, not the real service.
4. **Not now.** Record the server as not connected; deploy-test runs only the cases that don't need it.

<!-- 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`, as deploy-runtime wrote it): 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 in staging, faked through `dev` for development tests, or recorded as missing with the owner's decision.
- Hand over to `deploy-test`.
