> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useagentflow.co/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK: MCP

> Install, configure, discover, and provision tools from MCP servers

Use `client.mcp_catalog` for curated server definitions and `client.mcp_servers` for server, credential, OAuth, discovery, and tool-provisioning operations.

## Install from the curated catalog

<CodeGroup>
  ```python Python theme={null}
  items = await client.mcp_catalog.list()
  item = await client.mcp_catalog.get(items[0].catalog_id)
  installed = await client.mcp_catalog.install(
      item.catalog_id,
      default_credential_scope="tenant",
  )
  ```

  ```ts TypeScript theme={null}
  const items = await client.mcp_catalog.list();
  const item = await client.mcp_catalog.get(items[0].catalog_id);
  const installed = await client.mcp_catalog.install(item.catalog_id, {
    default_credential_scope: "tenant",
  });
  ```
</CodeGroup>

## Register a server

<CodeGroup>
  ```python Python theme={null}
  server = await client.mcp_servers.create(
      name="support_mcp",
      display_name="Support MCP",
      endpoint_url="https://mcp.example.com",
      allowed_credential_scopes=["tenant", "user"],
      default_credential_scope="user",
  )
  ```

  ```ts TypeScript theme={null}
  const server = await client.mcp_servers.create({
    name: "support_mcp",
    display_name: "Support MCP",
    endpoint_url: "https://mcp.example.com",
    allowed_credential_scopes: ["tenant", "user"],
    default_credential_scope: "user",
  });
  ```
</CodeGroup>

Server definitions can also include an icon, tenant-context header, and OAuth issuer/client configuration. OAuth client secrets and stored credentials are never returned by read methods.

## Credentials and OAuth

<CodeGroup>
  ```python Python theme={null}
  credential = await client.mcp_servers.upsert_credential(
      server.id,
      credential_scope="user",
      auth_type="static_headers",
      payload={"headers": {"Authorization": f"Bearer {access_token}"}},
      background_safe=False,
  )

  oauth = await client.mcp_servers.oauth_start(
      server.id,
      redirect_uri="https://app.example.com/mcp/callback",
      credential_scope="user",
  )
  ```

  ```ts TypeScript theme={null}
  const credential = await client.mcp_servers.upsert_credential(server.id, {
    credential_scope: "user",
    auth_type: "static_headers",
    payload: { headers: { Authorization: `Bearer ${accessToken}` } },
    background_safe: false,
  });

  const oauth = await client.mcp_servers.oauth_start(server.id, {
    redirect_uri: "https://app.example.com/mcp/callback",
    credential_scope: "user",
  });
  ```
</CodeGroup>

Open `oauth.authorization_url` in your application, then pass the returned `code`, the original single-use `state`, and the same `redirect_uri` to `oauth_exchange(...)`.

## Discover and provision

<CodeGroup>
  ```python Python theme={null}
  probe = await client.mcp_servers.test(server.id, credential_scope="user")
  discovery = await client.mcp_servers.discover(server.id, credential_scope="user")
  print([tool.remote_tool_name for tool in discovery.tools])
  ```

  ```ts TypeScript theme={null}
  const probe = await client.mcp_servers.test(server.id, "user");
  const discovery = await client.mcp_servers.discover(server.id);
  console.log(discovery.tools.map((tool) => tool.remote_tool_name));
  ```
</CodeGroup>

The TypeScript `discover(...)` method uses the server/default credential resolution path; Python additionally accepts an explicit `credential_scope`. When a credential becomes active or discovery runs manually, AgentFlow creates newly discovered tenant tools and provisionally assigns them to `MainAgent`. Existing administrator enablement and assignment decisions are preserved on later reconnects.

`import_tool(...)` is an explicit recovery path for one remote definition when automatic provisioning did not create it. That method returns an unassigned tool, so assign it through `client.agents.tools`. Calling it after successful provisioning can return a conflict because the tool already exists.

Use `list_credentials(...)`, `credentials_self(...)`, `rotate_credential(...)`, and `delete_credential(...)` to manage credential metadata and lifecycle.
