# MCP tools for integrations, provider fields, and apps

Discover and connect integrations, inspect provider fields, test credentials, and retrieve connected Senja resources through MCP.

Available on the Grow, Scale, and Pro plans.

Use these MCP tools to connect your email platform or Senja, check a connection, and find provider fields. Connection changes and provider field creation take effect immediately in your account or the external service. They aren't unpublished website edits. Configuration undo cannot reverse them.

## MCP integration access and credentials

Every operation accepts an optional string `project_id` and follows the [shared MCP authorization and project-selection rules](https://rightmessage.com/help/mcp-authorization-reference). Invalid IDs, missing project selection, unavailable MCP access, and cross-project access return errors.

Examples are illustrative and were not executed. Requests show `tools/call` parameters; responses show decoded content. Response excerpts are labeled. Credentials in examples are deliberately fake. Never include real keys in a report or saved prompt.

OAuth email-platform connections must be established in the RightMessage dashboard using the returned `setup_url`. These tools cannot complete an OAuth authorization flow. A project can have one active email/CRM integration; credentialed apps such as Senja are separate connections.

## `list-connectable-integrations`

Discovers connection keys and credential slots before attempting a connection.

**Arguments:** optional `project_id` string.

```json
{"name":"list-connectable-integrations","arguments":{"project_id":"123456789"}}
```

Illustrative entry from `integrations`:

```json
{"key":"senja","label":"Senja","kind":"app","auth_type":"keys","connectable":true,"connected":false,"needs_reconnect":false,"fields":[{"key":"apiKey","label":"API key","help":"Find your API key in the Automate section of your Senja account at https://app.senja.io.","required":true}],"unlocked_tools":["list-apps","get-app-resources"]}
```

The envelope is `{integrations: [...], total, connected}`. Entries are sorted connected-first, then by label. Each has `key`, `label`, `kind` (`email` or `app`), `auth_type`, `connectable`, `connected`, `needs_reconnect`, and `fields`. Field entries contain `key`, `label`, `help`, and `required`. Email entries also have `integration_version`; app entries have `unlocked_tools`. OAuth entries have no credential fields, `connectable: false`, and dashboard `setup_url`/`setup_note`.

Email field slots are `api_key`, `api_secret`, and `api_secret_two`; their labels describe provider-specific meaning. The catalog marks only the first email slot required, but provider validation can still require later slots. This local catalog read neither validates saved credentials upstream nor returns their values.

## `connect-integration`

Validates and saves an API-key email connection or a credentialed app connection.

| Argument         | Type             | Required           | Meaning                                                                                  |
| ---------------- | ---------------- | ------------------ | ---------------------------------------------------------------------------------------- |
| `project_id`     | string           | No                 | Project to connect.                                                                      |
| `integration`    | string           | One key required   | Key from the connection catalog.                                                         |
| `provider`       | string           | Alternative        | Alias for `integration`; if both are present they must match after trimming/lowercasing. |
| `api_key`        | string           | Provider-dependent | Primary credential, sometimes an account API URL. Also accepted for Senja.               |
| `api_secret`     | string           | Provider-dependent | Second email-platform credential.                                                        |
| `api_secret_two` | string           | Provider-dependent | Third credential, such as a site or publication ID.                                      |
| `fields`         | array of objects | No                 | Each entry requires string `key` and string `value`.                                     |

For email platforms, `fields` recognizes the three credential-slot names above; nonempty top-level slots take precedence. For Senja, use `fields: [{"key":"apiKey","value":"..."}]` or `api_key`. Its key must be 1–4,096 printable ASCII characters without whitespace. Duplicate app field keys use the last value.

```json
{"name":"connect-integration","arguments":{"project_id":"123456789","integration":"senja","fields":[{"key":"apiKey","value":"ILLUSTRATIVE-NOT-A-REAL-KEY"}]}}
```

```json
{"connected":true,"created":true,"replaced":false,"integration":"senja","kind":"app","project_id":"123456789","connection":{"connected":true,"verifiedAt":"2026-10-13T12:00:00.000000Z"},"unlocked_tools":["list-apps","get-app-resources"],"tools_changed":true,"hint":"If new tools do not appear, start a new chat. Some clients, including ChatGPT, ignore the tools/list_changed notification."}
```

App connections are checked upstream before saving. Reconnecting replaces existing app credentials and returns `created: false`, `replaced: true`. Senja verification reads its resource catalog.

Email success returns `created`, `provider`, `integration_version`, and, for newer connections, `health`. This tool adds `integration`, `kind: "email"`, `project_id`, `unlocked_tools: []`, `tools_changed: false`, and `hint`. Healthy newer connections update the successful-connection timestamp and refresh tags. Userlist can be saved with pending health when an authorized test write is still needed. Connection creation is not proof that this later verification succeeded.

Every successful connection sends `notifications/tools/list_changed`. Restart the chat if your client does not refresh. Unknown keys, conflicting aliases, missing/malformed credentials, rejected keys, provider outages, existing email connections, and a different active email provider return errors. Email reconnect requires deleting the old connection first; app reconnect does not. OAuth connections return dashboard-only guidance.

## `create-integration`

This registered compatibility operation connects API-key email platforms through the same save path. It does not connect Senja. Prefer `connect-integration` for new clients.

**Arguments:** optional `project_id` string; required `provider` and `api_key` strings; optional `api_secret` and `api_secret_two` strings. Credential meanings come from `list-connectable-integrations`.

```json
{"name":"create-integration","arguments":{"project_id":"123456789","provider":"klaviyo","api_key":"ILLUSTRATIVE-NOT-A-REAL-KEY"}}
```

Illustrative response excerpt:

```json
{"created":true,"provider":"klaviyo","integration_version":"v2","health":{"healthy":true,"message":"Connected to Klaviyo","details":{"status_code":200}}}
```

The response does not add the newer operation's app fields, tool-refresh hint, or notification. Older connection paths return only `created`, `provider`, and `integration_version`. External validation, immediate storage, email-provider conflicts, OAuth restrictions, pending test-write handling, and failure modes are the same as `connect-integration`.

## `list-integrations`

Lists available email platforms and their capabilities, not credentialed apps.

**Arguments:** optional `project_id` string.

```json
{"name":"list-integrations","arguments":{"project_id":"123456789"}}
```

Illustrative entry from the response's `integrations` array:

```json
{"name":"klaviyo","label":"Klaviyo","auth_type":"keys","is_connected":true,"needs_reconnect":false,"integration_version":"v2","can_personalize_emails":true,"supported_features":["custom_fields"],"connected_at":"2026-10-13T12:00:00Z","updated_at":"2026-10-13T12:00:00Z"}
```

The envelope contains `integrations`, `total`, and `connected`. Every entry has the first eight fields shown, with `supported_features` drawn from `tags`, `custom_fields`, `lists`, `events`, `automations`, and `native_fields`. Connected entries add timestamps. OAuth entries add `setup_url` and `setup_note`.

Older connections can appear as `needs_reconnect: true` and `is_connected: false`. This local metadata read does not prove live provider health or enumerate contacts.

## `get-integration`

Returns detailed local metadata for one email provider.

**Arguments:** optional `project_id` string; required `provider` string, trimmed and lowercased.

```json
{"name":"get-integration","arguments":{"project_id":"123456789","provider":"klaviyo"}}
```

Illustrative response excerpt:

```json
{"provider":"klaviyo","integration_version":"v2","is_connected":true,"connected_at":"2026-10-13T12:00:00Z","updated_at":"2026-10-13T12:00:00Z","last_successful_connection":"2026-10-13T12:00:00Z","health_note":"Use test-integration for a live health check."}
```

Provider metadata adds `label`, `auth_type`, `esp_feature_support`, `can_personalize_emails`, and, where provided, `setup_instructions`. Feature-support metadata is provider-defined rather than one universal nested schema. Older connections expose `last_ping_at` and `last_ping_succeeded` instead of the newer health fields. Unconnected OAuth providers include setup guidance.

No credentials are returned. Missing provider input or an unknown provider returns an error. This operation reads saved status; it does not make a live health check. Its older-connection `is_connected` value is not the reconnect policy reported by `list-integrations`.

## `get-integration-data`

Reads the connected provider's field, tag, and list catalogs.

| Argument     | Type   | Required | Default                                    |
| ------------ | ------ | -------- | ------------------------------------------ |
| `project_id` | string | No       | Active or eligible project.                |
| `provider`   | string | Yes      | Connected email provider key.              |
| `data_types` | array  | No       | All available types when omitted or empty. |

Recognized type strings are `custom_fields`, `tags`, `lists`, and `native_fields`. The declared item schema allows strings or numbers, but numbers and unknown strings do not identify a catalog.

```json
{"name":"get-integration-data","arguments":{"project_id":"123456789","provider":"klaviyo","data_types":["custom_fields"]}}
```

```json
{"provider":"klaviyo","integration_version":"v2","custom_fields":[]}
```

The response contains `provider`, `integration_version`, and available requested catalog keys. Catalog items retain provider-specific field shapes. Newer list objects normalize to `{id, name, is_static}`; already-array list items pass through. Each failed catalog can produce `<type>_error` instead of its data, so an otherwise successful response can be partial. Unsupported newer-provider methods are omitted, not fabricated as supported empty catalogs.

The newest connection is used, preferring the newer integration system. Missing connections and provider-initialization failures are MCP errors. Reads can call the external provider but do not change a field or subscriber.

## `create-custom-field`

Creates a field in the external email platform. Check existing fields and provider support first.

**Arguments:** optional `project_id` string; required `provider` string and nonempty `label` string; optional `type` string, default `text`. Provider and type are trimmed/lowercased; label is trimmed. Types such as `number` and `date` depend on the provider.

```json
{"name":"create-custom-field","arguments":{"project_id":"123456789","provider":"bento","label":"Business type","type":"text"}}
```

```json
{"created":true,"provider":"bento","field":{"id":"business_type","label":"Business type","slug":"business_type"},"next_step":"Use update-segment-group (or update_segment_group in Righty) with sync_field set to \"business_type\" to map a dimension to this field."}
```

`field.id` is the provider ID. `label` falls back to the requested label; `slug` uses the provider's templating token, key, or ID. This does not itself map a dimension or publish configuration. Unstructured providers may accept arbitrary field keys without pre-creation.

Missing connections, changed credentials during dispatch, unsupported field creation, and provider errors return errors. A response saying the field was created but no valid response/ID was returned means the external write may already have happened. Inspect the provider dashboard before retrying to avoid duplicates.

## `test-integration`

Checks saved email-provider credentials and reachability.

**Arguments:** optional `project_id` string; required `provider` string.

```json
{"name":"test-integration","arguments":{"project_id":"123456789","provider":"klaviyo"}}
```

```json
{"provider":"klaviyo","integration_version":"v2","healthy":true,"message":"Connected to Klaviyo","details":{"status_code":200},"tested_at":"2026-10-13T12:00:00Z"}
```

The response has `provider`, `integration_version`, `healthy`, `message`, and `tested_at`; newer-provider responses normally add provider-defined `details`. A thrown newer-provider exception returns `healthy: false` with `Health check failed: ...`, not necessarily an MCP error. Missing connections are MCP errors.

This makes an external health request and can update saved health timestamps. It is not a no-side-effect local read, a synchronization test, or proof that every provider write is authorized. No website publication is needed.

## `delete-integration`

Disconnects an email provider by removing all its saved connections for this project, including older duplicates.

**Arguments:** optional `project_id` string; required `provider` string.

```json
{"name":"delete-integration","arguments":{"project_id":"123456789","provider":"klaviyo"}}
```

```json
{"deleted":true,"provider":"klaviyo"}
```

This immediately removes credentials and refreshes tags. It is not a draft edit and cannot be reversed with configuration undo. Existing collected visitor data and segment assignments remain. The operation does not disconnect apps or revoke credentials in the provider's own account. A missing connection returns `No integration found for provider: ...`.

## `get-dimension-sync-data`

Reads published dimension-to-provider mappings. Despite the tool description mentioning Liquid examples, the actual response is mapping data, not generated templates.

**Arguments:** optional `project_id` string.

```json
{"name":"get-dimension-sync-data","arguments":{"project_id":"123456789"}}
```

```json
[{"dimensionId":"dim_example","Name":"Business type","fieldName":"business_type","syncTo":"bento","questionText":"What kind of business do you run?","segments":[{"segmentId":"seg_agency","name":"Agency","fieldValue":"Agency"}],"hasOtherOption":false,"otherFieldName":null}]
```

Note the capital `Name`. Each entry includes the fields shown. Only dimensions with both a sync destination and custom field are included, and only segments with non-null sync values appear. Question text has markup removed and phrase fallbacks rendered. No published configuration or no mapped dimensions returns `[]`. This does not fetch contacts, write provider fields, or include unpublished mappings.

## `list-apps`

Lists registered non-email apps, their activation metadata, and local connection status. This tool is exposed only when Senja is connected to the selected project.

**Arguments:** optional `project_id` string.

```json
{"name":"list-apps","arguments":{"project_id":"123456789"}}
```

Illustrative Senja entry from the response's `apps` array:

```json
{"key":"senja","listing":{"name":"Senja","logo":"/img/integrations/senja.png","description":"Display testimonials and Walls of Love in your flows.","category":"app"},"activation":{"kind":"credentials","scheme":{"kind":"apiKey","fields":[{"key":"apiKey","label":"API key","help":"Find your API key in the Automate section of your Senja account at https://app.senja.io."}]}},"connection":{"connected":true,"verifiedAt":"2026-10-13T12:00:00.000000Z"}}
```

The envelope is `{apps: [...]}`. Each entry has `key`, `listing` (`name`, `logo`, `description`, `category`), `activation`, and `connection`. Credential activation contains `kind: "credentials"` and a scheme; other apps use their own activation metadata and have `connection: null`. Credential connection status contains `connected` and nullable `verifiedAt`.

This does not call providers or expose key values. Use the always-available connection catalog to discover and connect Senja before this conditional tool appears.

## `get-app-resources`

Fetches a connected app's public editor catalog using stored credentials. Like `list-apps`, it is exposed only for a Senja-connected project.

**Arguments:** optional `project_id` string and required `app` string. No credential arguments are accepted.

```json
{"name":"get-app-resources","arguments":{"project_id":"123456789","app":"senja"}}
```

```json
{"widgets":[{"id":"workforge-quotes","name":"WorkForge customer quotes","design":"carousel","floating":false}],"wallsOfLove":[{"slug":"customer-stories","permalink":"workforge","name":"WorkForge customer stories"}]}
```

Senja returns `widgets` with string `id`, `name`, `design` and boolean `floating`, plus `wallsOfLove` with string `slug`, `permalink`, and `name`. Popup, toast, and recent-sales designs are marked floating. The response contains catalog metadata, not credentials or a newly installed embed.

Missing app keys, unsupported apps, and disconnected apps return errors. Rejected credentials request reconnection; provider timeouts and failures return retry guidance. Creating an embed is a separate configuration action. Floating widgets need a page target, while nonfloating embeds can target an element; there is no RightMessage-widget target. Publishing that configuration is separate from reading this catalog.
