Skip to main content
A connection links a managed deep agent to an external service such as GitHub, Notion, or Tavily. The credential lives in your LangSmith workspace. Use connections.get(...) in an authored tool or MCP server definition to resolve it at runtime. Connections let you:
  • Keep credentials out of your project: mda deploy collects .env values as deployment secrets on every deploy. A connection value stays in the workspace instead.
  • Give each caller their own identity: A user-owned connection resolves the credential of the person who made the request, so the agent reads that person’s documents and acts under their name. An environment variable holds one value for everyone.
  • Skip the OAuth plumbing: Managed Deep Agents runs the authorization round-trip, so a project needs no callback route, token store, or consent screen. These flows are handled automatically by your Managed Deep Agent.
  • Reuse one slug across agents: Connections belong to the workspace, so several deployments can resolve the same slug. Each deployment holds its own credential under that slug: run mda connections create <slug> once from each project root. Rotating a deployment’s value takes effect on its next run, with no redeploy.
Storing a credential in LangSmith to use across your Managed Deep Agents takes one command:
The rest of this page covers the two choices around those steps: who owns the credential, and how the service authenticates.
Managed Deep Agents is in public beta and available on LangSmith Cloud in the US region only.

Choose a credential owner

Every connections.get(...) call names who owns the credential it resolves:
connections.get(...) resolves to the credential value as a string. A connection is a container, and it belongs to the workspace rather than to an owner. The credentials inside it have owners. There is no --owner flag: the create mode you use sets the owner. connections.get(...) selects an owner. It does not create one. Asking for an owner with no credential of its own fails the run for agent, and raises a credential_authorization_required interrupt for user. A credential stored under the same slug for a different owner does not satisfy the lookup. Agent-owned credentials belong to the project’s deployment, so create them after at least one successful mda deploy. A deployment reads only the credential it owns. To resolve the same slug from a second deployment, run mda connections create <slug> again from that project root: on an existing slug the command attaches a new agent-owned credential instead of failing.

Identify the caller

A user-owned connection resolves against the caller identity that Managed Deep Agents attaches to the run. Where that identity comes from depends on how the agent is called: The default identity declaration verifies a LangSmith API key. That key authenticates the calling client, not an individual person, so every caller who presents it resolves to the same identity. To give each signed-in person their own credentials, declare Supabase identity. Code never passes a user ID to connections.get(...). The runtime resolves the caller and returns that person’s credential.
Slack and Studio complete the authorization round-trip for the caller. First-class support for custom channels is in development. To build a custom frontend against caller identity today, see Handle the authorization interrupt and contact the LangChain team.

Choose a create mode

Ownership decides what the agent does with a credential. The create mode decides how that credential reaches the workspace, and depends on how the external service authenticates: For example:
Do not mix modes in one command. For example, --mcp cannot combine with --oauth, custom endpoints, --client-id, or a secret value.

Name a connection

The first argument to mda connections create is a slug: your name for the connection, and the name your code passes to connections.get(...). It is not the provider name, which goes to --oauth:
Slugs are unique within a workspace. Use lowercase letters, numbers, and single hyphens, and pick a name that identifies which account the connection points at, such as organization-tavily or engineering-notion.

Create an opaque secret

Store a fixed secret for the agent. Read the value from an environment variable, a file, stdin, or a prompt. This mode fits API keys for custom tools, such as a Tavily search key. Opaque secrets created with the CLI are agent-owned. Put the source value in the shell environment or project .env file, then create the connection from that variable. Run the command from the project root. The CLI requires a LangSmith API key and workspace ID.
This stores the value from TAVILY_API_KEY as an agent-owned secret. Runtime code resolves it with connections.get(...). Other ways to supply the value:
  • --secret-from-file PATH: Read one value from a file that contains only the secret.
  • stdin: Pipe or redirect the value, for example printf '%s' "$ACME_API_KEY" | mda connections create acme-api.
  • Interactive prompt: Omit a value flag on a TTY. The CLI hides the input so the secret does not appear on screen or in shell history.
Opaque secrets created with the CLI are always agent-owned. For per-caller credentials, use an OAuth connection. Issue a key that belongs to the agent rather than reusing a personal key. A dedicated key can be scoped, rotated, and revoked without affecting anything else that shares it.

Use an opaque secret in a custom tool

The following tool resolves the organization-tavily connection for the agent, then sends it to the Tavily API:
tools/search-web.ts
See Custom tools to add the tool to the agent.

Create a general OAuth connection

Register a bring-your-own-app (BYOT) OAuth client so callers can grant the agent access to a provider API. Use this mode for REST or GraphQL APIs where you own the OAuth app registration. For MCP servers that discover and register clients automatically, use MCP OAuth instead.

Use the OAuth catalog

Every OAuth provider needs the same five settings: an authorization URL, a token URL, a token endpoint authentication method, authorization parameters, and default scopes. A catalog entry supplies all five, so --oauth <service> plus your own client ID and secret is the whole configuration. The catalog is not a gate on which providers you can use. For a service it does not cover, pass the endpoints yourself. List the catalog with:
The command prints each service’s default scopes and the page where you register an app. It does not call LangSmith, so it needs no workspace ID or API key. Pass a value from the first column to --oauth. A service with no default scopes requires --scope.
Notion is one of them. --oauth notion-api registers an app against Notion’s REST API, and that app does not authorize Notion’s MCP server. To use the MCP server, create an MCP OAuth connection instead. Check the provider’s documentation when a service offers both.
GitHub requires an OAuth client ID and client secret. Set GITHUB_CLIENT_SECRET, then create the connection. Replace ******** with the client ID:
On create, the CLI prints the redirect URI to register with the provider. Register that URI on the provider’s app settings page before callers authorize. The URI follows your LangSmith host, for example https://api.smith.langchain.com/v1/agent-auth/oauth/callback on production. Optional flags:
  • --scope SCOPE: Replace the catalog defaults. Repeat for each scope.
  • --allowed-scope SCOPE: Ceiling any later authorization may request. Defaults to the --scope values and must cover every --scope.
  • --authorization-param KEY=VALUE: Extra authorization query parameter. Repeat for each parameter.
  • --auth-method METHOD: How the client authenticates to the token endpoint: client_secret_basic, client_secret_post, or none for a public client. Defaults to the catalog service’s method.

Register a provider with custom endpoints

For a service the catalog does not cover, pass both endpoints plus a client ID and scopes:
Most providers reject an authorization request with no scope parameter. Pass --scope for manual registrations, or use --oauth <service> when the catalog covers the provider.

Authorize an agent-owned OAuth account

When a provider issues its own application credential, such as a Slack bot token, a GitHub App installation token, or a Notion internal integration token, prefer that credential stored as an agent-owned secret. An application credential is scoped to the application, is revocable on its own, and does not depend on any person’s account. Use --authorize when the provider offers no application identity and its API authenticates only as a person. By default, an OAuth connection collects a grant from each caller at runtime. Pass --authorize to sign in once yourself and store the grant for the deployment. Every caller then acts as that one account, and no caller sees an authorization prompt:
The CLI starts an authorization flow for the account you sign in with and stores the resulting grant for the deployment. Runtime code resolves it as an agent-owned credential:
--authorize applies to OAuth connections only. Combine it with --oauth, custom endpoints, or --mcp. Run it from the project directory, because the grant belongs to that project’s deployment. Use an agent-owned OAuth account when every caller should act as one shared account rather than as themselves. A company Notion account that grants read access to a question-answering agent is one example.
Authorize a dedicated account that your team owns, not your own. The account you sign in with becomes the identity behind every action the agent takes, for every caller. Using a personal account costs you three things:
  • The agent gets your full access at that provider.
  • The provider’s audit log shows your name for what the agent did.
  • The agent stops working when your own access changes.
A grant made this way stays tied to the account that authorized it, even a dedicated one. A password reset, a revoked session, or a deactivated account ends the grant, so treat that account as production infrastructure.Give the dedicated account the narrowest --scope values the agent needs. Set --allowed-scope to cap what any later authorization can request.

Access an OAuth token in a custom tool

This tool resolves the authenticated caller’s GitHub connection and calls the GitHub REST API:
tools/get-github-user.ts

Create an MCP OAuth connection

For remote MCP servers that support OAuth client registration, Managed Deep Agents discovers the server’s OAuth metadata and registers a client automatically. You do not supply a client ID or client secret.

Declare the MCP server first

Add the server in tools/mcp.ts and reference the connection slug.
tools/mcp.ts
For more information, see Connect to MCP servers.

Create from the project declaration

When the slug matches exactly one user-owned MCP connection in the project, create with the slug alone. The CLI reads the server URL from the MCP declaration:

Create from an explicit MCP URL

Pass --mcp when you want to name the server URL explicitly, or when the slug is not yet declared in the project:
A scheme-less value such as mcp.notion.com/mcp is stored as https://mcp.notion.com/mcp. If the server cannot register a client automatically, the CLI says so and points you at general OAuth (--oauth or manual endpoints) instead. mda deploy applies the same inference to missing user-owned MCP connections. It leaves existing connections unchanged, creates each unique missing MCP connection through OAuth discovery, and fails before deployment when discovery or registration is unavailable.

Handle the authorization interrupt

Managed Deep Agents runs the OAuth round-trip for you. A project needs no callback route, no token store, no refresh logic, and no consent screen. The run pauses, the caller grants access, and the run resumes with that person’s credential. Before the first model turn, Managed Deep Agents checks every user-owned connection the run needs. If the caller is missing one or more grants, the credential gate raises a single LangGraph interrupt. Slack and LangSmith Studio handle that interrupt for the caller. A custom frontend reads the same payload from the LangChain frontend SDK and resumes after the caller connects. User-owned connections require an authenticated caller. Anonymous or agent-only runs cannot complete the credential gate. See Identify the caller for where that identity comes from.

Interrupt payload

With useStream (@langchain/react, @langchain/vue, @langchain/svelte) or injectStream (@langchain/angular), the pending interrupt is on stream.interrupt. The credential gate payload is stream.interrupt.value. For a missing OAuth grant, each entry in credentials carries the URL where the caller completes consent:
One interrupt lists every missing grant. Handle each entry before resuming. An entry with "kind": "secret" represents a user-owned API key rather than an OAuth grant. Slack and Studio do not collect those. For more information, see Review current limitations.

Read the interrupt in your UI

The frontend that renders this interrupt is a web application, so these examples are TypeScript whether the agent is written in Python or TypeScript. Detect the credential gate payload on stream.interrupt, render a connect card, then resume with stream.respond after every grant is stored:
For the general interrupt lifecycle (stream.interrupt, resume, checkpoints), see Human-in-the-loop.

Handle OAuth grants (kind: "oauth2")

For each OAuth entry:
  1. Show the slug and a Connect control that opens connect_url (HTTPS only; reject URLs with embedded credentials).
  2. Long-poll Agent Auth until the session completes:
The response status is pending, completed, failed, or expired. Keep polling while the status is pending. On completed, mark that slug connected. On failed or expired, ask the caller to start a new run for a fresh connect link. Do not put the access token in your UI. Agent Auth stores the grant for the caller; the agent reads it on resume through connections.get(...).

Resume the run

After every entry in credentials is connected, resume with:
Pass that object to stream.respond(resume, { interruptId: stream.interrupt?.id }) as shown above. If you resume while a grant is still missing, the gate interrupts again with a fresh payload.

Built-in Slack handling

When the agent runs through the Slack channel, Slack renders OAuth entries that include an HTTPS connect_url. The caller opens the link, completes consent, and Slack resumes the run, so nobody has to open LangSmith to connect a service.
Screenshot placeholder: Add the Slack OAuth authorization prompt screenshot here.

Slack OAuth authorization prompt

Inspect and delete connections

Use list or get to inspect connection metadata. list shows every connection in the workspace, not only the ones this project uses:
Pass --json to list or get for machine-readable output. Pass --yes to delete to skip the confirmation prompt.

Develop locally

For mda dev, an agent-owned opaque connection reads MDA_DEV_<SLUG>. The CLI converts the slug to uppercase and replaces hyphens with underscores. For example, organization-tavily reads MDA_DEV_ORGANIZATION_TAVILY. User-owned connections require an authenticated caller and Agent Auth. Deploy the agent to exercise the authorization interrupt end to end.

Review current limitations

Connections are part of the Managed Deep Agents public beta. The following gaps apply to the current release:
  • User-owned API keys: A user-owned connection holds an OAuth grant. Slack and Studio do not collect a per-caller API key, and the CLI does not create an empty slot for one. Use an agent-owned secret instead, or collect the key in a custom frontend as described in the following section.
  • Custom channels: Slack and Studio resolve caller identity and complete authorization for the caller. A custom frontend handles the authorization interrupt itself.
  • Workspace UI: LangSmith does not list connections in the UI. Use mda connections list and mda connections get for connection metadata.
  • Grant visibility: mda connections list is workspace-scoped and does not report which deployments hold a credential under a slug. A run that fails with no agent connection is set for slug '<slug>' means this deployment owns no credential for it, even when list shows the slug. Run mda connections create <slug> from the project root to mint one.
An interrupt entry with "kind": "secret" has no connect_url. To collect one in a custom frontend, prompt for the value with a hidden input, then create the credential against the existing connection slug:
Agent Auth reuses the existing connection for that slug and attaches the caller’s secret. Secret material is write-only. After a successful create, mark that slug connected and resume the run. For more information, see Set up Agent Auth.

See also