Skip to main content
Glama
mercuryadvising

Adobe Launch / Tags MCP Server

Adobe Launch / Tags MCP Server

An MCP server wrapping the Adobe Experience Platform Reactor API — the API behind Adobe Launch, now called Adobe Experience Platform Tags.

It gives an assistant read access to your tag properties, rules, data elements, extensions, libraries and environments, plus the ability to author changes. It does not publish anything by default. Nothing this server does reaches a live site unless you explicitly enable dangerous mode and approve a build.


Why this exists

The Reactor API is a JSON:API surface with ~240 endpoints and a few sharp edges that make it awkward to hand to a model raw:

  • Delegate configuration is stored in a settings attribute that is a JSON-encoded string, not an object. Passing an object returns a cryptic 422.

  • Resources are fat — a rule component carries about 20 audit fields — so a list of 200 rules will swamp a context window.

  • Rules are meaningless without their rule components, which live at a separate endpoint.

  • Authoring and publishing are entirely separate concerns, and it is easy to conflate them.

This wrapper handles all four: it encodes and decodes settings, shapes responses down to what matters, joins rules to their components, and gates publishing behind an explicit opt-in.


Setup

1. Create an OAuth Server-to-Server credential

Adobe retired the Service Account (JWT) flow on 1 January 2025. You need an OAuth Server-to-Server credential.

  1. Go to the Adobe Developer Console and sign in.

  2. Create a new project (or open an existing one).

  3. Add API → select Adobe Experience Platform Launch API (listed under Experience Cloud).

  4. Choose OAuth Server-to-Server as the authentication type.

  5. Select the product profile(s) that grant access to the properties you care about. Product profiles are managed in the Adobe Admin Console; if you are not an admin, ask yours which profile covers your properties. This is the single most common cause of empty results or 403s — the credential can authenticate fine and still see nothing.

  6. From the credential's page, copy:

    • Client IDREACTOR_CLIENT_ID

    • Client SecretREACTOR_CLIENT_SECRET

    • Organization ID (ends in @AdobeOrg) → REACTOR_ORG_ID

    • Scopes (the comma-separated list shown on the credential page) → REACTOR_SCOPES

The server exchanges these for a 24-hour access token at https://ims-na1.adobelogin.com/ims/token/v3 and refreshes it automatically. You never handle a token yourself.

2. Install

A prebuilt, dependency-free bundle ships at build/adobe-launch-reactor-mcp.mjs. It is a single self-contained ESM file — no npm install required to run the server. Node 20+ is the only prerequisite.

To rebuild it from source, or to run the tests:

npm install
npm run build     # tsc -> dist/
npm run bundle    # single file -> build/adobe-launch-reactor-mcp.mjs
npm test

The server reads its credentials from environment variables supplied by your MCP client. It does not load a .env file — .env.example is a reference for which values to set.

3. Configure your MCP client

Claude Desktopclaude_desktop_config.json:

{
  "mcpServers": {
    "adobe-launch": {
      "command": "node",
      "args": ["/absolute/path/to/launch-mcp/build/adobe-launch-reactor-mcp.mjs"],
      "env": {
        "REACTOR_CLIENT_ID": "your-client-id",
        "REACTOR_CLIENT_SECRET": "your-client-secret",
        "REACTOR_ORG_ID": "XXXXXXXXXXXX@AdobeOrg",
        "REACTOR_SCOPES": "openid,AdobeID,read_organizations,additional_info.projectedProductContext,additional_info.roles,session",
        "REACTOR_WRITE_MODE": "read"
      }
    }
  }
}

Claude Codeclaude mcp add:

claude mcp add adobe-launch \
  --env REACTOR_CLIENT_ID=... \
  --env REACTOR_CLIENT_SECRET=... \
  --env REACTOR_ORG_ID=...@AdobeOrg \
  --env REACTOR_WRITE_MODE=safe \
  -- node /absolute/path/to/launch-mcp/build/adobe-launch-reactor-mcp.mjs

Then ask: "What rules are in my Acme Web property, and which ones are unpublished?"


Configuration

Variable

Required

Default

Purpose

REACTOR_CLIENT_ID

yes

Client ID from Developer Console; also sent as x-api-key.

REACTOR_CLIENT_SECRET

yes

Client secret.

REACTOR_ORG_ID

yes

IMS org ID, ends in @AdobeOrg.

REACTOR_SCOPES

no

openid,AdobeID,read_organizations,additional_info.projectedProductContext,additional_info.roles,session

Comma-separated scopes. Copy the exact list from your credential page — the default is typical but not universal.

REACTOR_WRITE_MODE

no

read

read, safe, or dangerous. See below.

REACTOR_DEFAULT_PROPERTY_ID

no

Pin a property so tools don't need property_id each call.

REACTOR_DEFAULT_COMPANY_ID

no

Pin a company, skipping a lookup call.

REACTOR_BASE_URL

no

https://reactor.adobe.io

Override for testing.

REACTOR_IMS_TOKEN_URL

no

https://ims-na1.adobelogin.com/ims/token/v3

Change for non-NA1 IMS regions.

REACTOR_MAX_RESPONSE_CHARS

no

60000

Cap on a single tool response before truncation.

REACTOR_TIMEOUT_MS

no

30000

Per-request timeout.

Write modes

Mode

Can do

Cannot do

read (default)

List and get everything, search, read audit events

Any mutation

safe

Everything in read, plus create/update rules, rule components, data elements, extensions, libraries, notes; assemble library contents

Delete, build, publish

dangerous

Everything, including deletes, reactor_create_build and reactor_transition_library (submit/approve/publish)

The mode is enforced in two places: write tools are simply not registered below their tier, and the reactor_request escape hatch whitelists HTTP methods by mode — so a model cannot route around the tier by calling the raw endpoint.

safe is the right default for most work. Authoring in Reactor is non-destructive: a new or edited rule sits in the property's authoring state and changes nothing on a live site until a library containing it is built and published. Keeping publishing in a separate, explicitly-enabled tier means a mistake is something you fix in the UI, not an incident.


Tools

Read (all modes)

Tool

What it does

reactor_whoami

Profile + visible companies. Start here to verify auth.

reactor_list_properties

Properties in a company.

reactor_get_property

One property with its platform settings.

reactor_list_rules

Rules in a property.

reactor_get_rule

A rule plus its components — use this to answer "what does this rule do?".

reactor_list_rule_components

Events, conditions and actions of a rule.

reactor_list_data_elements / reactor_get_data_element

Data elements, with settings decoded.

reactor_list_extensions / reactor_get_extension

Installed extensions and their configuration.

reactor_list_extension_packages

The catalog of installable extensions.

reactor_get_extension_package

Delegate descriptors an extension provides — how you discover valid delegate_descriptor_id values.

reactor_list_libraries

Libraries and their workflow state.

reactor_get_library

A library plus every rule, data element and extension it contains, and its last build.

reactor_list_builds

Build history for a library.

reactor_list_environments

Environments with embed codes.

reactor_list_hosts

Akamai / SFTP hosts.

reactor_list_audit_events

Who changed what, newest first.

reactor_search

Structured search across resource types when you don't know which property something lives in.

reactor_list_notes

Notes attached to a resource.

reactor_request

Raw passthrough for the ~200 endpoints without a dedicated tool. Method-gated by write mode.

Authoring (safe and dangerous)

reactor_create_rule, reactor_update_rule, reactor_create_rule_component, reactor_update_rule_component, reactor_create_data_element, reactor_update_data_element, reactor_install_extension, reactor_update_extension, reactor_create_library, reactor_update_library, reactor_library_add_resources, reactor_library_remove_resources, reactor_create_note.

Destructive (dangerous only)

reactor_create_build, reactor_transition_library, reactor_delete_resource. All three require an explicit confirm: true argument and carry the MCP destructiveHint annotation, so a well-behaved client will prompt before running them.


Notes on the API

Filtering. List tools take a filter object keyed by attribute, with values of the form "OPERATOR value". Operators: EQ, NOT, LT, GT, BETWEEN, CONTAINS.

{ "filter": { "name": "CONTAINS checkout", "enabled": "EQ true" } }

Adobe silently ignores filters on non-filterable attributes and returns the full set, so a filter that appears to do nothing is usually a typo or an unsupported attribute rather than a genuinely empty result.

Filterable attributes by resource:

  • rules, rule_components, data_elements: name, enabled, dirty, published, published_at, revision_number, origin_id, created_at, updated_at (rule components also negate)

  • properties: name, platform, enabled, token, created_at, updated_at

  • extensions: name, display_name, version, enabled, dirty, published, revision_number, created_at, updated_at

  • libraries: name, state, stale, published_at, created_at, updated_at

  • environments: name, stage, archive, token, created_at, updated_at

  • builds: status, token, created_at, updated_at

  • hosts: name, type_of, created_at, updated_at

Pagination. 25 records per page by default, 100 max. Pass fetch_all: true to walk every page (capped at 20 pages). Responses larger than REACTOR_MAX_RESPONSE_CHARS are truncated at a record boundary, so the JSON stays parseable and says how much was dropped.

Rate limits. Reactor's soft limit is roughly 120 requests per minute per integration. The client retries 429 and 5xx with exponential backoff, honouring Retry-After.

Settings. Reactor stores delegate configuration as a JSON-encoded string. The write tools accept a plain object and encode it; the read tools decode it back. If you pass a string it goes through unchanged.

Publishing model. Authoring changes are inert. To make a change live: create or edit resources → add them to a library → build the library → transition it to published. The last two steps require dangerous mode; otherwise do them in the Launch UI.


Development

npm run typecheck   # tsc --noEmit
npm test            # 35 tests against an in-memory mock of IMS + Reactor
npm run build       # compile to dist/
npm run dev         # run from source via tsx

The test suite covers auth header construction and token caching, the client_credentials grant shape, JSON:API filter/sort/page encoding, multi-page walking, response shaping and truncation, settings encode/decode round-tripping, relationship construction, write-mode gating (including that the raw passthrough cannot be used to escape it), and error message quality for 404/422/429/500.

Structure

src/
  config.ts        env parsing, write-mode tiers
  auth.ts          IMS OAuth S2S token manager with caching + refresh collapsing
  client.ts        JSON:API client: headers, query encoding, retry, pagination, error formatting
  format.ts        response shaping and size-capped serialization
  server.ts        MCP server assembly
  index.ts         stdio entrypoint
  tools/
    common.ts      shared argument schemas and helpers
    read.ts        read-only tools
    write.ts       authoring tools + dangerous tier
    raw.ts         method-gated passthrough

Licence

MIT.

-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Direct access to your Sanity projects (content, datasets, releases, schemas) and agent rules

  • An agent-friendly API for product changelogs. A unified registry via CLI, API, or MCP.

  • Build and manage Cloudgate workflow-APIs: controllers, actions, workflow graphs, and databases.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mercuryadvising/adobe-launch-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server