# Soda MCP

`soda-mcp` is a Model Context Protocol (MCP) server for Soda Cloud. It lets MCP-capable AI clients use Soda Cloud's public API to inspect and manage data quality resources such as datasets, checks, contracts, scans, monitors, incidents, attributes, datasources, users, and user groups.

The server runs as a local stdio MCP process. Your AI client starts `soda-mcp`, passes Soda Cloud credentials through environment variables, and then calls Soda tools through the MCP protocol. On startup, `soda-mcp` authenticates with Soda Cloud and loads organization context so the client can use the exposed tools against the correct tenant.

Use `soda-mcp` when you want an AI agent to help with Soda Cloud workflows, for example:

* List datasets and inspect their health status.
* Retrieve checks, contracts, scans, and incidents.
* Create or update contracts and monitors.
* Trigger discovery, contract verification, historical metric collection, or other supported Soda Cloud actions.
* Manage Soda Cloud resources such as attributes, roles, users, and user groups.

> Soda MCP is available for Soda Cloud customers. [Request a free account](https://soda.io/pricing) or [book a call](https://soda.io/pricing) to learn more.

{% if visitor.claims.plan === 'enterprise' || visitor.claims.plan === 'enterpriseUserBased' || visitor.claims.plan === 'datasetStandard' %}

### Installation Instructions

Follow the instructions in this section to install the Soda MCP server for your host client.

#### Requirements

* Python 3.10+
* [`uv`](https://docs.astral.sh/uv/) python package on `PATH`
* A Soda Cloud API key ID and secret
* A Soda Cloud host URL

If you don't have API keys already you can create them following the instructions [here](broken://pages/H6Piqnv5lUFCAv1Cvm75#generate-api-keys-for-use-with-soda-core-or-a-soda-cloud-api).

Set the runtime environment variables before starting the server:

```bash
export SODA_CLOUD_HOST="cloud.soda.io"
export SODA_API_KEY_ID="your-key-id"
export SODA_API_KEY_SECRET="your-key-secret"
```

<i class="fa-exclamation" style="color:$warning;">:exclamation:</i> **Note:** If you are using Windows without WSL you will need to modify the commands to work with either the Windows command prompt:

```shellscript
set SODA_CLOUD_HOST=cloud.soda.io
set SODA_API_KEY_ID=your-key-id
set SODA_API_KEY_SECRET=your-key-secret
```

or Windows Powershell:

```powershell
$env:SODA_CLOUD_HOST = "cloud.soda.io"
$env:SODA_API_KEY_ID = "your-key-id"
$env:SODA_API_KEY_SECRET = "your-key-secret"
```

You will also need to modify the commands of the following sections as is appropriate.

#### Install From Soda's Private PyPI

Stable releases are published to Soda's private PyPI indexes for Team and Enterprise customers. Choose the private index that matches your license and region, then set `UV_INDEX` using the same Soda API key credentials:

<table><thead><tr><th width="138.66665649414062">License</th><th width="122.16668701171875">Region</th><th>Index URL</th></tr></thead><tbody><tr><td>Team</td><td>EU</td><td><code>https://team.pypi.cloud.soda.io</code></td></tr><tr><td>Team</td><td>US</td><td><code>https://team.pypi.us.soda.io</code></td></tr><tr><td>Enterprise</td><td>EU</td><td><code>https://enterprise.pypi.cloud.soda.io</code></td></tr><tr><td>Enterprise</td><td>US</td><td><code>https://enterprise.pypi.us.soda.io</code></td></tr></tbody></table>

Pick the appropriate command below according to your plan and region. Note that this command depends on the Soda API key environment variables mentioned above in order to execute successfully.

Pick the proper one according to your plan and region:

{% tabs %}
{% tab title="Team EU" %}
{% code overflow="wrap" %}

```bash
export UV_INDEX="https://${SODA_API_KEY_ID}:${SODA_API_KEY_SECRET}@team.pypi.cloud.soda.io"
```

{% endcode %}
{% endtab %}

{% tab title="Team US" %}
{% code overflow="wrap" %}

```bash
export UV_INDEX="https://${SODA_API_KEY_ID}:${SODA_API_KEY_SECRET}@team.pypi.us.soda.io"
```

{% endcode %}
{% endtab %}

{% tab title="Enterprise EU" %}
{% code overflow="wrap" %}

```bash
export UV_INDEX="https://${SODA_API_KEY_ID}:${SODA_API_KEY_SECRET}@enterprise.pypi.cloud.soda.io"
```

{% endcode %}
{% endtab %}

{% tab title="Enterprise US" %}
{% code overflow="wrap" %}

```bash
export UV_INDEX="https://${SODA_API_KEY_ID}:${SODA_API_KEY_SECRET}@enterprise.pypi.us.soda.io"
```

{% endcode %}
{% endtab %}
{% endtabs %}

Smoke-test that `uvx` can resolve and start the package:

<pre class="language-bash"><code class="lang-bash"><strong>timeout 10s uvx -qq --no-progress soda-mcp@latest
</strong></code></pre>

If everything is set up correctly you will see the following output:

```
Authenticated as FirstName LastName (userEmail@soda.io) in org Soda TestOrg
Starting soda-mcp server (base_url=https://cloud.soda.io)
```

#### Configure an MCP Client

Configure your MCP client to start `soda-mcp` over stdio and pass the required environment variables to the child process.

For **Claude Code:**

```bash
claude mcp add soda-mcp \
  --transport stdio \
  --scope user \
  -e SODA_CLOUD_HOST="$SODA_CLOUD_HOST" \
  -e SODA_API_KEY_ID="$SODA_API_KEY_ID" \
  -e SODA_API_KEY_SECRET="$SODA_API_KEY_SECRET" \
  -e UV_INDEX="$UV_INDEX" \
  -- uvx -qq --no-progress soda-mcp@latest
```

For **OpenCode**, add a local MCP server entry to your user-scope `opencode.jsonc`:

```jsonc
{
  "mcp": {
    "soda-mcp": {
      "type": "local",
      "command": [
        "env",
        "SODA_CLOUD_HOST=<host>",
        "SODA_API_KEY_ID=<key-id>",
        "SODA_API_KEY_SECRET=<key-secret>",
        "UV_INDEX=<private-index-url-with-auth>",
        "uvx",
        "-qq",
        "--no-progress",
        "soda-mcp@latest"
      ]
    }
  }
}
```

For a generic stdio MCP client:

```json
{
  "mcpServers": {
    "soda-mcp": {
      "command": "uvx",
      "args": ["-qq", "--no-progress", "soda-mcp@latest"],
      "env": {
        "SODA_CLOUD_HOST": "<host>",
        "SODA_API_KEY_ID": "<key-id>",
        "SODA_API_KEY_SECRET": "<key-secret>",
        "UV_INDEX": "<private-index-url-with-auth>"
      }
    }
  }
}
```

If you installed from a local wheel, replace the `uvx -qq --no-progress soda-mcp@latest` command with `soda-mcp` in your client configuration.

#### Verify the Server

After configuring the client, confirm that `soda-mcp` appears in the client's MCP server list and is connected. Then invoke a low-cost read tool such as `list_attributes`.

A successful response confirms that:

* The MCP client can start the server.
* Soda Cloud credentials are reaching the server.
* Authentication succeeds against the configured Soda Cloud tenant.
* The client can see and call the registered Soda tools.
  {% endif %}

{% if visitor.claims.plan === 'enterprise' || visitor.claims.plan === 'enterpriseUserBased' || visitor.claims.plan === 'datasetStandard' %}

### Usage Instructions

#### Use the Tools

Once connected, ask your AI client to perform Soda Cloud tasks naturally. Examples:

```
List the datasets in my Soda Cloud organization and summarize unhealthy datasets.
```

```
Can you show me the latest failing checks?
```

```
Verify the contract for the dataset datasource/database/schema/table
```

```
Use Contract Autopoilot to craete a contract for the dataset datasource/database/schema/table
```

Some tools modify Soda Cloud resources or trigger scans. Review the client's proposed tool call before approving write, delete, or trigger actions.

#### Usage Notes

While you can create and update secrets through the MCP client it is not recommended to do so. For long lived secrets prefer to create them from the Web User Interface.

MCP servers expose tools and instructions on how to user them. Some MCP clients, like Codex and OpenCode, do not load the instructions, only the tools. This may affect performance. Claude Code loads both tools and instructions.

#### Troubleshooting

* If `uvx` cannot resolve `soda-mcp`, confirm `UV_INDEX` is set in the MCP client's environment and points at the correct private index.
* If private PyPI returns `401` or `403`, confirm the API key ID and secret are valid for the selected Team or Enterprise index.
* If startup fails with missing credential errors, confirm the MCP client passes `SODA_API_KEY_ID`, `SODA_API_KEY_SECRET`, and `SODA_CLOUD_HOST` .
* If Soda Cloud authentication fails, confirm the API key belongs to the same tenant as the configured host or URL.
* If the client does not show any tools, refresh or restart the MCP client so it reconnects and reloads tool descriptions.
  {% endif %}

<br>

***

{% if (visitor.claims.plan === 'datasetStandard')%}
{% hint style="success" %}
You are **logged in to Soda** and seeing the **Dataset Standard license** documentation. Learn more about [Documentation access & licensing](/reference/documentation-access-and-licensing.md).
{% endhint %}
{% endif %}

{% if (visitor.claims.plan === 'enterprise')%}
{% hint style="success" %}
You are **logged in to Soda** and seeing the **Team license** documentation. Learn more about [Documentation access & licensing](/reference/documentation-access-and-licensing.md).
{% endhint %}
{% endif %}

{% if (visitor.claims.plan === 'enterpriseUserBased')%}
{% hint style="success" %}
You are **logged in to Soda** and seeing the **Enterprise license** documentation. Learn more about [Documentation access & licensing](/reference/documentation-access-and-licensing.md).
{% endhint %}
{% endif %}

{% if !(visitor.claims.plan === 'enterprise' || visitor.claims.plan === 'enterpriseUserBased' || visitor.claims.plan === 'datasetStandard')%}
{% hint style="info" %}
You are **not logged in to Soda** and are viewing the default public documentation. Learn more about [Documentation access & licensing](/reference/documentation-access-and-licensing.md).
{% endhint %}
{% endif %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.soda.io/reference/soda-mcp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
