> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended** (the `-y` flags skip prompts, so the command runs without an interactive terminal):
> ```bash
> npx -y @scalekit-inc/cli setup -y
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup -y
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for other Agent Skills-compatible agents in `~/.agents/skills`.
> Skills: integrate-agentkit, implement-saaskit, add-mcp-oauth, implement-sso, implement-scim.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Connect AI agents to the ListenLabs MCP server

The ListenLabs MCP connector routes your AI agent's tool calls to ListenLabs's own MCP server through Scalekit. Each user signs in to ListenLabs once, and Scalekit stores and refreshes their tokens, so your agent never handles credentials. It comes with 13 tools.

**Authentication:** OAuth 2.1/DCR
**Categories:** Analytics, AI
**Tools:** 13: 7 read, 4 write, 2 destructive
**Users sign in with:** OAuth
**OAuth app:** Scalekit's or your own
**Built by:** Vendor MCP
**Try it:** [Playground in the Scalekit dashboard](https://app.scalekit.com/ws/signup?sk_intent=playground&provider=LISTENLABSMCP)

## Setup

1. ### Install the SDK

   **Node.js**

   ```bash
   npm install @scalekit-sdk/node dotenv
   ```

   **Python**

   ```bash
   pip install scalekit-sdk-python python-dotenv
   ```

2. ### Set your credentials

   Add your Scalekit credentials to your `.env` file. Find values in **[app.scalekit.com](https://app.scalekit.com)** > **Developers** > **API Credentials**.

   ```sh title=".env"
   SCALEKIT_ENVIRONMENT_URL=<your-environment-url>
   SCALEKIT_CLIENT_ID=<your-client-id>
   SCALEKIT_CLIENT_SECRET=<your-client-secret>
   ```

3. ### Create the ListenLabs MCP connection

   In **AgentKit > Connections**, create a ListenLabs MCP connection. The name you give it is the `connection_name` your code passes. See [Configure connections](/agentkit/connections/).

   Scalekit credentials are available for ListenLabs MCP server, so you don't need to register an OAuth app.

4. ### Authorize a user and make your first call

   **Node.js** (`quickstart.mts`)

   ```typescript
   import { ScalekitClient } from '@scalekit-sdk/node'
   import 'dotenv/config'
   import { createInterface } from 'node:readline/promises'

   const scalekit = new ScalekitClient(
     process.env.SCALEKIT_ENVIRONMENT_URL,
     process.env.SCALEKIT_CLIENT_ID,
     process.env.SCALEKIT_CLIENT_SECRET,
   )
   const actions = scalekit.actions

   const connector = 'listenlabsmcp'
   const identifier = 'user_123'

   // Generate an authorization link for the user
   const { link } = await actions.getAuthorizationLink({ connectionName: connector, identifier })
   console.log('Authorize ListenLabs MCP:', link)
   const rl = createInterface({ input: process.stdin, output: process.stdout })
   await rl.question('Press Enter after authorizing...')
   rl.close()

   // Make your first call
   const result = await actions.executeTool({
     connector,
     identifier,
     toolName: 'listenlabsmcp_list_creatable_orgs',
     toolInput: {},
   })
   console.log(result)
   ```

   ```bash
   npx tsx quickstart.mts
   ```

   **Python** (`quickstart.py`)

   ```python
   import os
   from scalekit import ScalekitClient
   from dotenv import load_dotenv
   load_dotenv()

   scalekit_client = ScalekitClient(
       env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
       client_id=os.getenv("SCALEKIT_CLIENT_ID"),
       client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
   )
   actions = scalekit_client.actions

   connection_name = "listenlabsmcp"
   identifier = "user_123"

   # Generate an authorization link for the user
   link_response = actions.get_authorization_link(
       connection_name=connection_name,
       identifier=identifier,
   )
   print("Authorize ListenLabs MCP:", link_response.link)
   input("Press Enter after authorizing...")

   # Make your first call
   result = actions.execute_tool(
       tool_input={},
       tool_name="listenlabsmcp_list_creatable_orgs",
       connection_name=connection_name,
       identifier=identifier,
   )
   print(result)
   ```

   ```bash
   python quickstart.py
   ```

   Each user signs in once. See [Authorize a user](/agentkit/tools/authorize/) for the full flow and statuses.

## Tools

Pass the exact name to `execute_tool`, with an input like each tool's example. To ask for a tool that's missing, use the [request form](https://scalekitsupport.portal.usepylon.com/forms/request-a-connector-tool).

**Node.js**

```typescript
const result = await actions.executeTool({
  toolName: 'listenlabsmcp_get_response',
  toolInput: {
    readable_id: 1,
    study_id: '<study_id>',
  },
  connector: 'listenlabsmcp',
  identifier: 'user_123',
})
```

**Python**

```python
result = actions.execute_tool(
    tool_name="listenlabsmcp_get_response",
    tool_input={
        "readable_id": 1,
        "study_id": "<study_id>",
    },
    connection_name="listenlabsmcp",
    identifier="user_123",
)
```

`result.data` is the app's response as JSON, and `result.execution_id` (`executionId` in Node.js) is the ID of the call.

### `listenlabsmcp_get_response`

Get Response · Read-only

Deep-dive into a single respondent's interview. Returns a structured transcript with question tracking, input types, multiple choice data, and source URLs for each message. Paginated for large interviews.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `readable_id` (`number`, required): Respondent number from get_study_responses
- `study_id` (`string`, required): Study ID (UUID) from list_studies
- `cursor` (`string`, optional): Pagination cursor for long transcripts

Example input: `{"readable_id":1,"study_id":"<study_id>"}`

### `listenlabsmcp_get_study_analysis`

Get Study Analysis · Read-only

Get the AI-generated analysis report for a study, rendered as markdown. Use list_studies first to find studies where has_analysis is true. The report includes sourced respondent quotes with deep-links to the original transcript messages.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `study_id` (`string`, required): Study ID (UUID) from list_studies

Example input: `{"study_id":"<study_id>"}`

### `listenlabsmcp_get_study_responses`

Get Study Responses · Read-only

Get response transcripts for a study. Returns formatted interview transcripts with pagination. Each respondent answer includes a source link to that exact message in the transcript.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `study_id` (`string`, required): Study ID (UUID) from list_studies
- `cursor` (`string`, optional): Pagination cursor from previous response
- `max_responses` (`number`, optional): Maximum number of responses to return (default 10, max 50). Default: `10`.
- `question_numbers` (`array`, optional): Only include these question numbers in the transcript (1-indexed)
- `readable_ids` (`array`, optional): Filter to specific respondents by their readable ID numbers

Example input: `{"study_id":"<study_id>"}`

### `listenlabsmcp_get_study_state`

Get Study State · Read-only

Return the current state of a study — title, audience, study guide, questions, screener, and recruitment details. Also includes launch eligibility, credit balance, and per-recruitment cost. Call before edit_study or launch_study to inspect the current study configuration.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `studyId` (`string`, required): UUID of the study to inspect

Example input: `{"studyId":"<studyId>"}`

### `listenlabsmcp_list_creatable_orgs`

List Creatable Orgs · Read-only

List organizations the user belongs to where they can create studies. Returns org ID, name, and role. Supports pagination and case-insensitive name search. Call before create_study when the user has not specified an organization.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `cursor` (`string`, optional): Pagination cursor from a previous call's nextCursor
- `limit` (`integer`, optional): Page size (default 10, max 25)
- `textHint` (`string`, optional): Case-insensitive substring to filter org names by

Example input: `{}`

### `listenlabsmcp_list_studies`

List Studies · Read-only

List studies accessible to the authenticated user. Returns study ID, name, status, creation date, response count, and whether analysis is available. Paginated (50 per page). Use textHint to filter by study title; use cursor for pagination.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `cursor` (`string`, optional): Pagination cursor from previous response
- `status` (`string`, optional): Filter by study status. One of: `open`, `closed`.
- `textHint` (`string`, optional): Case-insensitive substring to filter study titles by

Example input: `{}`

### `listenlabsmcp_search_across_studies`

Search Across Studies · Read-only

Search across study metadata using a text query. Returns matching studies with relevant context.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `query` (`string`, required): Search term to find across studies
- `max_results` (`number`, optional): Maximum number of results to return (default 10). Default: `10`.

Example input: `{"query":"<query>"}`

### `listenlabsmcp_create_study`

Create Study · Write

Start a new guided user-interview study. Provide a plain-language description of the study goals and target audience. The platform's creation agent walks through onboarding stages; subsequent turns must use edit_study with the returned studyId and chatId.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `prompt` (`string`, required): Plain-language description of the study to create (goals, who to interview, what to learn)
- `orgId` (`string`, optional): Organization UUID when known (e.g. from list_creatable_orgs)
- `orgName` (`string`, optional): Organization name to create the study in. Required when the user belongs to multiple organizations.

Example input: `{"prompt":"<prompt>"}`

### `listenlabsmcp_edit_study`

Edit Study · Write

Send a natural-language edit instruction or structured button event to the study creation agent. Use after create_study (pass the chatId) for guided onboarding, or with a fresh chatId for direct edits to an existing study. Supply either prompt or buttonClick, not both.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `studyId` (`string`, required): UUID of the study to edit
- `buttonClick` (`object`, optional): Structured button event from the guided onboarding flow
- `chatId` (`string`, optional): Chat session ID from create_study or a previous edit_study call. Omit on the first turn.
- `prompt` (`string`, optional): Free-form instruction or user input for the study agent

Example input: `{"studyId":"<studyId>"}`

### `listenlabsmcp_move_study`

Move Study · Write

Move a study into a folder, or back out to the dashboard root. Pass folderName to move it into an existing folder; omit both folderName and folderId to move the study out of its folder and back to the dashboard root. The folder must already exist.

Read only: no. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `studyId` (`string`, required): Study identifier: the UUID from list_studies, the short link id from a Listen Labs study URL (e.g. zy4GuhxP), or the full pasted URL (e.g. https://listenlabs.ai/p/zy4GuhxP/).
- `folderId` (`string`, optional): Destination folder UUID from a previous move_study error. Use instead of folderName when selecting by ID.
- `folderName` (`string`, optional): Existing destination folder name, or a "/"-separated path to pick between folders sharing a name (e.g. "Research / Q3 2026"). Rejected if no such folder exists. Omit to move the study to the dashboard root.

Example input: `{"studyId":"<studyId>"}`

### `listenlabsmcp_publish_study`

Publish Study · Write

Publish the study's current draft revision so respondents see the latest version. No-op when the draft is identical to prod. Does not start recruitments — use launch_study to begin sourcing respondents.

Read only: no. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `studyId` (`string`, required): UUID of the study to publish

Example input: `{"studyId":"<studyId>"}`

### `listenlabsmcp_launch_study`

Launch Study · Destructive

Publish the study's draft revision (if needed) and start all unlaunched recruitments that fit the organization's credit balance. Recruitments are launched greedily in dashboard order. Returns launched and skipped recruitments with balance before/after. Safe to re-call — already-launched recruitments are skipped.

Read only: no. Destructive: yes. Idempotent (safe to retry): no.

Inputs:

- `studyId` (`string`, required): UUID of the study to launch

Example input: `{"studyId":"<studyId>"}`

### `listenlabsmcp_manage_folder`

Manage Folder · Destructive

Create, rename, re-nest, or delete a dashboard folder. Folders only: it never creates, moves, or deletes a study. Use move_study to file a study in a folder. Delete only removes an EMPTY folder, and only when the user explicitly asked to delete it.

Read only: no. Destructive: yes. Idempotent (safe to retry): yes.

Inputs:

- `action` (`string`, required): create makes a new folder, rename changes a folder's name, move re-nests it under another folder, delete permanently removes an empty one. One of: `create`, `rename`, `move`, `delete`.
- `folderName` (`string`, required): The folder to act on, or a "/"-separated path for nested folders (e.g. "Research / Q3 2026"). For create, this is the folder to make.
- `folderId` (`string`, optional): Folder UUID from list_studies folders[] or a previous error. Takes precedence over folderName; use it when a name was reported as ambiguous.
- `newName` (`string`, optional): New folder name. Required for action="rename", ignored otherwise.
- `orgId` (`string`, optional): Organization UUID when known (e.g. from list_creatable_orgs). Prefer orgName when the user gave a name.
- `orgName` (`string`, optional): Organization name. Required when the user belongs to multiple organizations and did not specify one.
- `parentFolderId` (`string`, optional): Destination folder UUID for action="move". Takes precedence over parentFolderName; use it when the parent name was reported as ambiguous.
- `parentFolderName` (`string`, optional): Folder to nest under, matched like folderName. Used by action="move"; omit it to move the folder to the dashboard root.

Example input: `{"action":"create","folderName":"Research / Q3 2026"}`

## Related

Other Analytics connectors ([all 95](/agentkit/connectors/?category=analytics)):

- [Microsoft 365](/agentkit/connectors/microsoft365/): Scalekit connector, OAuth, 317 tools
- [HubSpot](/agentkit/connectors/hubspot/): Scalekit connector, OAuth, 457 tools
- [Snowflake](/agentkit/connectors/snowflake/): Scalekit connector, OAuth, 42 tools


---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
