> **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 Expo MCP server

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

**Authentication:** OAuth2.1/DCR
**Categories:** Developer Tools
**Tools:** 24: 13 read, 8 write, 3 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=EXPOMCP)

## 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 Expo MCP connection

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

   Scalekit credentials are available for Expo 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 = 'expomcp'
   const identifier = 'user_123'

   // Generate an authorization link for the user
   const { link } = await actions.getAuthorizationLink({ connectionName: connector, identifier })
   console.log('Authorize Expo 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: 'expomcp_build_list',
     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 = "expomcp"
   identifier = "user_123"

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

   # Make your first call
   result = actions.execute_tool(
       tool_input={},
       tool_name="expomcp_build_list",
       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: 'expomcp_appstore_reviews',
  toolInput: {
    bundleId: '<bundleId>',
  },
  connector: 'expomcp',
  identifier: 'user_123',
})
```

**Python**

```python
result = actions.execute_tool(
    tool_name="expomcp_appstore_reviews",
    tool_input={
        "bundleId": "<bundleId>",
    },
    connection_name="expomcp",
    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.

### `expomcp_appstore_reviews`

Get App Store Reviews · Read-only

Fetch public App Store customer reviews for an app including rating, title, body, reviewer, and territory. For TestFlight beta feedback use testflight_feedback instead.

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

Inputs:

- `bundleId` (`string`, required): The bundle ID of the app e.g. com.example.myapp
- `cursor` (`string`, optional): Pagination cursor from a previous response
- `limit` (`integer`, optional): Maximum number of reviews to return (default: 20, max: 100)

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

### `expomcp_build_info`

Get Build Info · Read-only

Fetches detailed information about a specific EAS build by ID including status, platform, artifacts, and logs URL.

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

Inputs:

- `buildId` (`string`, required): The ID of the build to fetch details for

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

### `expomcp_build_list`

List EAS Builds · Read-only

Lists recent EAS builds for a project. Provide either appId (from app.json extra.eas.projectId) or appFullName (e.g. @owner/my-app).

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

Inputs:

- `appFullName` (`string`, optional): The full name of the app e.g. @owner/my-app. Either appId or appFullName is required.
- `appId` (`string`, optional): The Expo project/app ID (UUID). Either appId or appFullName is required.
- `limit` (`number`, optional): Maximum number of builds to return (default: 10, max: 100)
- `platform` (`string`, optional): Filter builds by platform. One of: `ANDROID`, `IOS`.
- `status` (`string`, optional): Filter builds by status. One of: `NEW`, `IN_QUEUE`, `IN_PROGRESS`, `PENDING_CANCEL`, `CANCELED`, `ERRORED`, `FINISHED`, `EXPIRED`.

Example input: `{}`

### `expomcp_build_logs`

Get Build Logs · Read-only

Fetches the build logs for a specific EAS build. Returns log output to help debug build failures.

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

Inputs:

- `buildId` (`string`, required): The ID of the build to fetch logs for

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

### `expomcp_playstore_crashes`

Get Google Play Crashes · Read-only

Fetch crash and ANR data from Google Play (Android Vitals). Without issueId, lists recent crash/ANR issues. With issueId, returns the full error report with stack trace.

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

Inputs:

- `packageName` (`string`, required): The Android package name of the app e.g. com.example.myapp
- `cursor` (`string`, optional): Pagination cursor from a previous response
- `issueId` (`string`, optional): Specific error issue ID to fetch the full report for. If omitted, lists recent issues.
- `limit` (`integer`, optional): Maximum number of issues to list (default: 20, max: 100, ignored when issueId is provided)

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

### `expomcp_playstore_reviews`

Get Google Play Reviews · Read-only

Fetch user reviews from Google Play including author, star rating, device info, and comment text. Note: Google Play only exposes production reviews with text from approximately the last week.

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

Inputs:

- `packageName` (`string`, required): The Android package name of the app e.g. com.example.myapp
- `cursor` (`string`, optional): Pagination cursor from a previous response
- `limit` (`integer`, optional): Maximum number of reviews to return (default: 20, max: 100)

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

### `expomcp_read_documentation`

Read Expo Documentation Page · Read-only

Fetch a single Expo documentation page and return its content as markdown. Returns up to ~5000 tokens per call. Use offset to paginate through long pages.

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

Inputs:

- `url` (`string`, required): URL of the Expo documentation page to fetch
- `offset` (`integer`, optional): Character offset to start reading from. Defaults to 0.

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

### `expomcp_testflight_crashes`

Get TestFlight Crashes · Read-only

Fetch TestFlight crash data. Without crashId, lists recent crashes. With crashId, returns the full crash log with stack trace.

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

Inputs:

- `bundleId` (`string`, required): The bundle ID of the app e.g. com.example.myapp
- `crashId` (`string`, optional): Specific crash ID to fetch full details for. If omitted, lists recent crashes.
- `cursor` (`string`, optional): Pagination cursor from a previous response
- `limit` (`integer`, optional): Maximum number of crashes to list (default: 20, max: 100, ignored when crashId is provided)

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

### `expomcp_testflight_feedback`

Get TestFlight Feedback · Read-only

Fetch screenshot feedback from TestFlight including device info, user comments, and screenshot URLs.

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

Inputs:

- `bundleId` (`string`, required): The bundle ID of the app e.g. com.example.myapp
- `cursor` (`string`, optional): Pagination cursor from a previous response
- `limit` (`integer`, optional): Maximum number of feedback submissions to return (default: 20, max: 100)

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

### `expomcp_workflow_info`

Get Workflow Run Info · Read-only

Fetches detailed information about a specific EAS workflow run by ID including status, job results, errors, and artifacts.

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

Inputs:

- `workflowRunId` (`string`, required): The ID of the workflow run to fetch details for

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

### `expomcp_workflow_list`

List Workflow Runs · Read-only

Lists recent EAS workflow runs for a project. Provide either appId (from app.json extra.eas.projectId) or appFullName (e.g. @owner/my-app).

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

Inputs:

- `appFullName` (`string`, optional): The full name of the app e.g. @owner/my-app. Either appId or appFullName is required.
- `appId` (`string`, optional): The Expo project/app ID (UUID). Either appId or appFullName is required.
- `limit` (`number`, optional): Maximum number of workflow runs to return (default: 10, max: 100)
- `status` (`string`, optional): Filter workflow runs by status. One of: `ACTION_REQUIRED`, `CANCELED`, `FAILURE`, `IN_PROGRESS`, `NEW`, `SUCCESS`.

Example input: `{}`

### `expomcp_workflow_logs`

Get Workflow Job Logs · Read-only

Fetches logs for a specific job in an EAS workflow run. Call without sectionIndex or phase to get a summary of log sections; then call again with sectionIndex or phase to fetch that section.

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

Inputs:

- `jobName` (`string`, required): The name of the job to fetch logs for
- `workflowRunId` (`string`, required): The ID of the workflow run
- `phase` (`string`, optional): Phase name to fetch logs for
- `sectionIndex` (`integer`, optional): Index of the log section to fetch

Example input: `{"jobName":"<jobName>","workflowRunId":"<workflowRunId>"}`

### `expomcp_workflow_validate`

Validate EAS Workflow · Read-only

Validates an EAS workflow YAML file for syntax and configuration errors. Use after workflow_create to ensure the workflow is valid before running.

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

Inputs:

- `fileName` (`string`, required): Workflow file name to validate e.g. build-and-deploy.yml
- `projectRoot` (`string`, required): Root directory of the project

Example input: `{"fileName":"<fileName>","projectRoot":"<projectRoot>"}`

### `expomcp_add_library`

Add Expo Library · Write

Add an Expo library to the project using expo install and attach usage instructions when available.

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

Inputs:

- `libraryName` (`string`, required): Name of the Expo library to install
- `projectRoot` (`string`, required): Root directory of the Expo project

Example input: `{"libraryName":"<libraryName>","projectRoot":"<projectRoot>"}`

### `expomcp_appstore_reply_review`

Reply to App Store Review · Write

Post or edit the public developer response to an App Store customer review. The response is visible to everyone on the App Store. Any existing response is replaced.

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

Inputs:

- `responseBody` (`string`, required): The response text, posted publicly as the developer response (max 5970 characters)
- `reviewId` (`string`, required): The ID of the customer review to respond to (from appstore_reviews)

Example input: `{"responseBody":"<responseBody>","reviewId":"<reviewId>"}`

### `expomcp_build_run`

Run EAS Build · Write

Triggers a new EAS build using a build profile from eas.json. Requires a GitHub repository to be connected to the project.

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

Inputs:

- `buildProfile` (`string`, required): The build profile name from eas.json e.g. development, preview, production
- `gitRef` (`string`, required): Git reference (branch name, tag, or commit SHA) to build from
- `platform` (`string`, required): The platform to build for (ANDROID or IOS). One of: `ANDROID`, `IOS`.
- `appFullName` (`string`, optional): The full name of the app e.g. @owner/my-app. Either appId or appFullName is required.
- `appId` (`string`, optional): The Expo project/app ID (UUID). Either appId or appFullName is required.
- `autoSubmit` (`boolean`, optional): Whether to automatically submit the build after completion
- `baseDirectory` (`string`, optional): Base directory for monorepos e.g. apps/mobile
- `submitProfile` (`string`, optional): Submit profile to use if autoSubmit is true

Example input: `{"buildProfile":"<buildProfile>","gitRef":"<gitRef>","platform":"ANDROID"}`

### `expomcp_build_submit`

Submit Build to Store · Write

Submits an existing EAS build to the App Store (iOS) or Google Play (Android). Provide appId or appFullName, the buildId, and platform.

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

Inputs:

- `buildId` (`string`, required): The ID of the build to submit
- `platform` (`string`, required): The platform to submit to (ANDROID or IOS). One of: `ANDROID`, `IOS`.
- `appFullName` (`string`, optional): The full name of the app e.g. @owner/my-app. Either appId or appFullName is required.
- `appId` (`string`, optional): The Expo project/app ID (UUID). Either appId or appFullName is required.
- `ascAppIdentifier` (`string`, optional): For iOS: The App Store Connect app identifier (Apple ID of the app). Required for iOS submissions.
- `track` (`string`, optional): For Android: The release track (internal, alpha, beta, production). Required for Android submissions.

Example input: `{"buildId":"<buildId>","platform":"ANDROID"}`

### `expomcp_learn`

Learn Expo Topic · Write

Learn Expo how-to for a specific topic and remember it for future conversations.

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

Inputs:

- `topic` (`string`, required): The Expo topic to learn about. One of: `expo-router`.

Example input: `{"topic":"expo-router"}`

### `expomcp_playstore_reply_review`

Reply to Google Play Review · Write

Post a public developer reply to a Google Play user review, or edit the existing reply. Each review has a single developer reply, so replying again replaces it. Reply text is limited to 350 characters.

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

Inputs:

- `packageName` (`string`, required): The Android package name of the app e.g. com.example.myapp
- `replyText` (`string`, required): The reply text, posted publicly as the developer reply (max 350 characters)
- `reviewId` (`string`, required): The ID of the review to reply to (from playstore_reviews)

Example input: `{"packageName":"<packageName>","replyText":"<replyText>","reviewId":"<reviewId>"}`

### `expomcp_workflow_create`

Create EAS Workflow · Write

Creates a new EAS workflow YAML file for Expo projects or fetches workflow syntax documentation. Use when users want to create CI/CD workflows in .eas/workflows/ or need to learn EAS workflow syntax.

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

Inputs:

- `action` (`string`, required): Action to perform: create to make a new EAS workflow YML file, learn to get syntax documentation. One of: `create`, `learn`.
- `fileName` (`string`, optional): Workflow file name e.g. build-and-deploy.yml (required for create action)
- `projectRoot` (`string`, optional): Root directory of the project (required for create action)
- `workflowYaml` (`string`, optional): Complete YAML content for the EAS workflow (required for create action)

Example input: `{"action":"create"}`

### `expomcp_workflow_run`

Run EAS Workflow · Write

Triggers an EAS workflow run for a project. Provide either appId (from app.json extra.eas.projectId) or appFullName (e.g. @owner/my-app) and the workflow file name.

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

Inputs:

- `workflowFileName` (`string`, required): The workflow file name to run e.g. build-and-deploy.yml
- `appFullName` (`string`, optional): The full name of the app e.g. @owner/my-app. Either appId or appFullName is required.
- `appId` (`string`, optional): The Expo project/app ID (UUID). Either appId or appFullName is required.
- `gitRef` (`string`, optional): Git reference (branch name, tag, or commit SHA) to run the workflow on

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

### `expomcp_appstore_delete_review_response`

Delete App Store Review Response · Destructive

Delete the public developer response on an App Store customer review. No-op-safe — if the review has no response, it reports that nothing was deleted.

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

Inputs:

- `reviewId` (`string`, required): The ID of the customer review whose response should be deleted

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

### `expomcp_build_cancel`

Cancel EAS Build · Destructive

Cancels an EAS build that is queued or in progress. Use build_info to check the current status first.

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

Inputs:

- `buildId` (`string`, required): The ID of the build to cancel

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

### `expomcp_workflow_cancel`

Cancel Workflow Run · Destructive

Cancels an EAS workflow run that is queued or in progress.

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

Inputs:

- `workflowRunId` (`string`, required): The ID of the workflow run to cancel

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

## Related

Other Developer Tools connectors ([all 94](/agentkit/connectors/?category=developer-tools)):

- [GitHub](/agentkit/connectors/github/): Scalekit connector, OAuth, 217 tools
- [Datadog](/agentkit/connectors/datadog/): Scalekit connector, API key, 105 tools
- [Linear](/agentkit/connectors/linear/): Scalekit connector, OAuth, 62 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 |
