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

# Connect Third-Party Integrations to Your Agents

> Add Slack, Notion, Twilio, Google Drive, and custom MCP servers to Feather. Give your agents real-world tools backed by your existing services.

Integrations extend your agents beyond conversation — they let your AI act on the world by calling real APIs, sending messages, querying documents, and triggering workflows inside the tools your team already uses. Feather's integration layer handles OAuth flows, credential storage, and tool schema sync so you can focus on building agent logic rather than plumbing.

## Browse available integrations

Before connecting, discover what's available. The `/v1/integrations` endpoint returns a catalog of supported services, each described by an `IntegrationSummary` object.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET https://api-sandbox.featherhq.com/v1/integrations \
    -H "x-api-key: <your_api_key>"
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api-sandbox.featherhq.com/v1/integrations",
      headers={"x-api-key": "<your_api_key>"}
  )
  print(response.json())
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch(
    "https://api-sandbox.featherhq.com/v1/integrations",
    { headers: { "x-api-key": "<your_api_key>" } }
  );
  const data = await response.json();
  ```
</CodeGroup>

**Example response:**

```json theme={null}
[
  {
    "key": "slack",
    "display_name": "Slack",
    "description": "Send messages, read channels, react to events.",
    "category": "communication",
    "logo_url": "https://cdn.feather.io/integrations/slack.svg"
  },
  {
    "key": "notion",
    "display_name": "Notion",
    "description": "Search and edit pages, databases, and blocks; read comments and users.",
    "category": "productivity",
    "logo_url": "https://cdn.feather.io/integrations/notion.svg"
  },
  {
    "key": "google_drive",
    "display_name": "Google Drive",
    "description": "Ingest Google Docs, Sheets, Slides, and files into a knowledge base.",
    "category": "productivity",
    "logo_url": "https://cdn.feather.io/integrations/google-drive.svg"
  },
  {
    "key": "twilio",
    "display_name": "Twilio",
    "description": "Bring your own Twilio account for SMS and voice.",
    "category": "communication",
    "logo_url": "https://cdn.feather.io/integrations/twilio.svg"
  },
  {
    "key": "calcom",
    "display_name": "Cal.com",
    "description": "Check availability and book, cancel, or reschedule meetings.",
    "category": "scheduling",
    "logo_url": "https://cdn.feather.io/integrations/calcom.svg"
  },
  {
    "key": "email",
    "display_name": "Email",
    "description": "Send email to the customer from your connected mailbox.",
    "category": "communication",
    "logo_url": "https://cdn.feather.io/integrations/email.svg"
  },
  {
    "key": "custom_mcp",
    "display_name": "Custom MCP",
    "description": "Connect any MCP server with customer-supplied auth.",
    "category": "custom",
    "logo_url": "https://cdn.feather.io/integrations/mcp.svg"
  }
]
```

***

## Connect an integration (OAuth)

Most first-party integrations use OAuth. Feather delegates the OAuth handshake to [Nango](https://nango.dev), an open-source auth platform — you never handle raw credentials.

<Steps>
  <Step title="Initiate the connection">
    Create a connection record and receive a short-lived `session_token`.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api-sandbox.featherhq.com/v1/integrations/connections \
        -H "x-api-key: <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
          "integration_key": "slack",
          "nickname": "My Slack Workspace"
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api-sandbox.featherhq.com/v1/integrations/connections",
          headers={"x-api-key": "<your_api_key>"},
          json={"integration_key": "slack", "nickname": "My Slack Workspace"}
      )
      print(response.json())
      ```

      ```typescript TypeScript theme={null}
      const response = await fetch(
        "https://api-sandbox.featherhq.com/v1/integrations/connections",
        {
          method: "POST",
          headers: {
            "x-api-key": "<your_api_key>",
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            integration_key: "slack",
            nickname: "My Slack Workspace",
          }),
        }
      );
      const data = await response.json();
      ```
    </CodeGroup>

    **Response:**

    ```json theme={null}
    {
      "connection_id": "conn_01hx9z3p4qr7mn2k8wdt",
      "session_token": "nango_sess_eyJhbGciOiJIUzI1NiJ9...",
      "expires_at": "2024-09-01T14:32:00Z",
      "vendor": "nango"
    }
    ```
  </Step>

  <Step title="Open the OAuth popup">
    Use the `session_token` with the Nango frontend SDK to launch the OAuth consent screen in your UI.

    ```typescript theme={null}
    import Nango from "@nangohq/frontend";

    const nango = new Nango();
    await nango.auth("slack", "<connection_id>", {
      sessionToken: "<session_token>",
    });
    ```

    The popup guides your user through Slack's standard OAuth flow. No credentials touch your server.
  </Step>

  <Step title="Finalize the connection">
    Once the user completes OAuth, activate the connection so Feather can begin syncing tools.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api-sandbox.featherhq.com/v1/integrations/connections/conn_01hx9z3p4qr7mn2k8wdt/finalize \
        -H "x-api-key: <your_api_key>"
      ```

      ```python Python theme={null}
      requests.post(
          "https://api-sandbox.featherhq.com/v1/integrations/connections/conn_01hx9z3p4qr7mn2k8wdt/finalize",
          headers={"x-api-key": "<your_api_key>"}
      )
      ```
    </CodeGroup>

    Feather will immediately sync the tool schema for your new connection. Tools are ready to attach to agents within seconds.
  </Step>
</Steps>

***

## Connect a custom MCP server

Any server that implements the [Model Context Protocol](https://modelcontextprotocol.io) can be connected to Feather — whether it's an internal microservice or a third-party MCP host.

### Bearer token authentication

For MCP servers protected by a static secret:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api-sandbox.featherhq.com/v1/integrations/connections/custom-mcp \
    -H "x-api-key: <your_api_key>" \
    -H "Content-Type: application/json" \
    -d '{
      "nickname": "My MCP",
      "server_url": "https://mcp.example.com",
      "transport": "sse",
      "auth_type": "bearer",
      "token": "<secret>"
    }'
  ```

  ```python Python theme={null}
  requests.post(
      "https://api-sandbox.featherhq.com/v1/integrations/connections/custom-mcp",
      headers={"x-api-key": "<your_api_key>"},
      json={
          "nickname": "My MCP",
          "server_url": "https://mcp.example.com",
          "transport": "sse",
          "auth_type": "bearer",
          "token": "<secret>"
      }
  )
  ```

  ```typescript TypeScript theme={null}
  await fetch(
    "https://api-sandbox.featherhq.com/v1/integrations/connections/custom-mcp",
    {
      method: "POST",
      headers: {
        "x-api-key": "<your_api_key>",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        nickname: "My MCP",
        server_url: "https://mcp.example.com",
        transport: "sse",
        auth_type: "bearer",
        token: "<secret>",
      }),
    }
  );
  ```
</CodeGroup>

### OAuth-protected MCP servers

For MCP servers that use OAuth, first run discovery to retrieve the authorization metadata:

<Steps>
  <Step title="Discover OAuth config">
    ```bash theme={null}
    curl -X POST https://api-sandbox.featherhq.com/v1/integrations/connections/custom-mcp/discover \
      -H "x-api-key: <your_api_key>" \
      -H "Content-Type: application/json" \
      -d '{"server_url": "https://mcp.example.com"}'
    ```

    The response includes the OAuth authorization endpoints and scopes required by the server.
  </Step>

  <Step title="Connect with OAuth">
    Use the discovered metadata to connect with `auth_type: "oauth"`, then follow the same finalize flow as standard OAuth integrations.

    ```bash theme={null}
    curl -X POST https://api-sandbox.featherhq.com/v1/integrations/connections/custom-mcp \
      -H "x-api-key: <your_api_key>" \
      -H "Content-Type: application/json" \
      -d '{
        "nickname": "My MCP",
        "server_url": "https://mcp.example.com",
        "transport": "sse",
        "auth_type": "oauth"
      }'
    ```
  </Step>
</Steps>

***

## View and manage tools

After a connection is finalized, Feather automatically syncs the available tools from the integration. Each tool has a unique `slug`, a human-readable name, and a JSON Schema describing its inputs.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api-sandbox.featherhq.com/v1/integrations/connections/conn_01hx9z3p4qr7mn2k8wdt \
    -H "x-api-key: <your_api_key>"
  ```

  ```python Python theme={null}
  requests.get(
      "https://api-sandbox.featherhq.com/v1/integrations/connections/conn_01hx9z3p4qr7mn2k8wdt",
      headers={"x-api-key": "<your_api_key>"}
  )
  ```
</CodeGroup>

**Response (tools array excerpt):**

```json theme={null}
{
  "id": "conn_01hx9z3p4qr7mn2k8wdt",
  "integration_key": "slack",
  "nickname": "My Slack Workspace",
  "status": "active",
  "tools": [
    {
      "slug": "send_message",
      "display_name": "Send Message",
      "is_enabled": true,
      "input_schema": {
        "type": "object",
        "properties": {
          "channel": { "type": "string", "description": "Channel name or ID" },
          "text": { "type": "string", "description": "Message content" }
        },
        "required": ["channel", "text"]
      }
    },
    {
      "slug": "list_channels",
      "display_name": "List Channels",
      "is_enabled": true,
      "input_schema": {
        "type": "object",
        "properties": {
          "limit": { "type": "integer", "default": 20 }
        }
      }
    }
  ]
}
```

### Disable or enable individual tools

Prevent an agent from calling specific tools without disconnecting the entire integration. The path takes the tool's `id` (the UUID from the connection's `tools` array), not its slug:

```bash theme={null}
curl -X PATCH \
  "https://api-sandbox.featherhq.com/v1/integrations/connections/conn_01hx9z3p4qr7mn2k8wdt/tools/9f8b2c14-7d3e-4a91-b6f0-2e5c1a8d4f37" \
  -H "x-api-key: <your_api_key>" \
  -H "Content-Type: application/json" \
  -d '{"is_enabled": false}'
```

### Bulk toggle all tools

```bash theme={null}
curl -X PATCH \
  "https://api-sandbox.featherhq.com/v1/integrations/connections/conn_01hx9z3p4qr7mn2k8wdt/tools" \
  -H "x-api-key: <your_api_key>" \
  -H "Content-Type: application/json" \
  -d '{"is_enabled": true}'
```

***

## Test a tool

Before attaching a tool to an agent, verify it works end-to-end using the test invoke endpoint.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST \
    "https://api-sandbox.featherhq.com/v1/integrations/connections/conn_01hx9z3p4qr7mn2k8wdt/test-invoke" \
    -H "x-api-key: <your_api_key>" \
    -H "Content-Type: application/json" \
    -d '{
      "slug": "send_message",
      "input": {
        "channel": "#general",
        "text": "Hello from Feather!"
      }
    }'
  ```

  ```python Python theme={null}
  requests.post(
      "https://api-sandbox.featherhq.com/v1/integrations/connections/conn_01hx9z3p4qr7mn2k8wdt/test-invoke",
      headers={"x-api-key": "<your_api_key>"},
      json={
          "slug": "send_message",
          "input": {"channel": "#general", "text": "Hello from Feather!"}
      }
  )
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "result": {
    "ok": true,
    "channel": "C08ABCDEF",
    "ts": "1725200000.123456",
    "message": { "text": "Hello from Feather!", "type": "message" }
  },
  "narrowed": {
    "ok": true,
    "channel": "C08ABCDEF",
    "ts": "1725200000.123456"
  }
}
```

The `result` field is the full vendor API response. `narrowed` is the field-map filtered result that your agent actually receives — only the fields relevant to decision-making.

***

## Attach integration tools to an agent

Reference integration tools in your agent revision's `tool_refs` array using the tool's slug. Each tool slug is built as `{nickname_slug}_{tool_slug}` — the connection nickname slugified (lowercased, non-alphanumeric runs collapsed to underscores) joined to the slugified tool path with an underscore. A connection nicknamed "My Slack Workspace" therefore produces slugs like `my_slack_workspace_send_message`.

```json theme={null}
{
  "tool_refs": [
    {
      "kind": "integration",
      "slug": "my_slack_workspace_send_message"
    },
    {
      "kind": "integration",
      "slug": "my_slack_workspace_list_channels"
    },
    {
      "kind": "integration",
      "slug": "my_notion_search_pages"
    }
  ]
}
```

The agent will automatically receive the tool's input schema in its context and can invoke it during a conversation without any additional wiring.

<Tip>
  If an integration provider adds new tools or changes their schema, use `POST /v1/integrations/connections/{connection_id}/refresh-tools` to manually re-sync. This is useful when building against a frequently updated MCP server.
</Tip>
