Skip to content

feat(vwo): add VWO MCP for A/B testing and experiments#313

Open
viniciusventura29 wants to merge 3 commits intomainfrom
viniciusventura29/vwo-mcp
Open

feat(vwo): add VWO MCP for A/B testing and experiments#313
viniciusventura29 wants to merge 3 commits intomainfrom
viniciusventura29/vwo-mcp

Conversation

@viniciusventura29
Copy link
Collaborator

@viniciusventura29 viniciusventura29 commented Mar 16, 2026

Summary

Implement comprehensive VWO MCP with 22 tools for A/B testing campaign management, feature flags, and optimization experiment analysis.

Tools by Category:

  • Workspaces (3): list, get, create
  • Campaigns (4): list with filtering, get, share link, update status
  • Goals (4): list, get, create, update
  • Variations & Sections (2): list operations
  • Feature Flags (4): list, create, and rule management
  • Reports & Analytics (1): metric report retrieval
  • Admin (4): users, websites, drafts, custom widgets

Key Features:

  • Bearer token authentication via VWO API tokens
  • Account ID configuration in state with per-tool override support
  • Automatic response unwrapping from _data with error handling
  • Full query parameter support (pagination, filtering)

🤖 Generated with Claude Code


Summary by cubic

Adds a new vwo MCP that integrates with VWO for A/B testing, feature flags, and experiment reporting. Ships 22 tools and a typed VWOClient with state-based token auth (token sent via token header), default account state, and automatic _data unwrapping.

  • New Features

    • vwo MCP with 22 tools: workspaces; campaigns (list/get/share/status); goals (list/get/create/update); variations/sections; features and rules (list/create); reports; users; websites; drafts; widgets.
    • Typed VWOClient with query helpers and _data unwrapping. Default accountId in state with per-tool override.
  • Bug Fixes

    • Trim and validate apiToken and accountId; enforce .min(1) for accountId.
    • Stronger schemas: campaign status as enum; campaign ids and feature goals arrays require at least one item.
    • Feature rules accept string | number for environmentId and featureId.

Written for commit 0533a17. Summary will update on new commits.

Implement comprehensive MCP for VWO with 22 tools covering:
- Workspaces: list, get, create
- Campaigns: list (with filtering), get, share link, update status
- Goals: list, get, create, update
- Variations: list
- Sections: list
- Feature Flags: list, create
- Feature Flag Rules: list, create
- Metric Reports: get report
- Users, Websites, Drafts, Custom Widgets: list operations

Authentication uses VWO API tokens (Bearer token header) with configurable default account ID. Client automatically unwraps _data responses and handles errors. Supports account ID override per tool call for multi-workspace operations.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 issues found across 28 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="vwo/server/types/env.ts">

<violation number="1" location="vwo/server/types/env.ts:6">
P2: Tighten `accountId` validation: `z.string()` currently accepts empty or whitespace-only values, so invalid config can pass schema validation and break VWO requests later.</violation>
</file>

<file name="vwo/server/tools/features.ts">

<violation number="1" location="vwo/server/tools/features.ts:39">
P2: Enforce at least one goal in the schema; the current validator accepts `goals: []` even though the tool contract requires a metric.</violation>
</file>

<file name="vwo/server/tools/campaigns.ts">

<violation number="1" location="vwo/server/tools/campaigns.ts:112">
P2: Reject empty `ids` arrays in the update-status schema.</violation>

<violation number="2" location="vwo/server/tools/campaigns.ts:113">
P2: Constrain `status` to the documented VWO status values instead of accepting arbitrary strings.</violation>
</file>

<file name="vwo/README.md">

<violation number="1" location="vwo/README.md:10">
P2: This README step is incorrect for this repository: MCPs are deployed via automatic discovery, so telling contributors to update `deploy.json` sends them to a manual configuration path that should not exist.</violation>
</file>

<file name="vwo/server/tools/reports.ts">

<violation number="1" location="vwo/server/tools/reports.ts:17">
P2: Use a numeric schema for `reportId`; the current string schema rejects valid metric report IDs returned by VWO.</violation>
</file>

<file name="vwo/server/lib/env.ts">

<violation number="1" location="vwo/server/lib/env.ts:19">
P2: Trim and validate `accountId`; whitespace-only values currently bypass the guard and produce malformed VWO URLs.</violation>
</file>

<file name="vwo/server/tools/feature-rules.ts">

<violation number="1" location="vwo/server/tools/feature-rules.ts:16">
P2: Accept numeric environment/feature IDs here; the current schema rejects documented ID-based calls.</violation>
</file>

<file name="vwo/server/lib/vwo-client.ts">

<violation number="1" location="vwo/server/lib/vwo-client.ts:72">
P1: Wrap the update-goal payload in `goals`; the PATCH endpoint does not accept the raw object.</violation>

<violation number="2" location="vwo/server/lib/vwo-client.ts:72">
P1: Wrap the create-goal payload in the `goals` object expected by VWO.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

async createWorkspace(body: { name: string }): Promise<unknown> {
return this.request("/accounts", {
method: "POST",
body: JSON.stringify(body),
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Wrap the update-goal payload in goals; the PATCH endpoint does not accept the raw object.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vwo/server/lib/vwo-client.ts, line 72:

<comment>Wrap the update-goal payload in `goals`; the PATCH endpoint does not accept the raw object.</comment>

<file context>
@@ -0,0 +1,288 @@
+  async createWorkspace(body: { name: string }): Promise<unknown> {
+    return this.request("/accounts", {
+      method: "POST",
+      body: JSON.stringify(body),
+    });
+  }
</file context>
Fix with Cubic

async createWorkspace(body: { name: string }): Promise<unknown> {
return this.request("/accounts", {
method: "POST",
body: JSON.stringify(body),
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Wrap the create-goal payload in the goals object expected by VWO.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vwo/server/lib/vwo-client.ts, line 72:

<comment>Wrap the create-goal payload in the `goals` object expected by VWO.</comment>

<file context>
@@ -0,0 +1,288 @@
+  async createWorkspace(body: { name: string }): Promise<unknown> {
+    return this.request("/accounts", {
+      method: "POST",
+      body: JSON.stringify(body),
+    });
+  }
</file context>
Fix with Cubic

.string()
.optional()
.describe("Account ID override. Uses default if not provided."),
reportId: z.string().describe("Metric report ID"),
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Use a numeric schema for reportId; the current string schema rejects valid metric report IDs returned by VWO.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vwo/server/tools/reports.ts, line 17:

<comment>Use a numeric schema for `reportId`; the current string schema rejects valid metric report IDs returned by VWO.</comment>

<file context>
@@ -0,0 +1,28 @@
+        .string()
+        .optional()
+        .describe("Account ID override. Uses default if not provided."),
+      reportId: z.string().describe("Metric report ID"),
+    }),
+    execute: async ({ context }) => {
</file context>
Fix with Cubic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="vwo/server/lib/env.ts">

<violation number="1" location="vwo/server/lib/env.ts:5">
P2: Trim and validate the configured API token before returning it; the current code accepts whitespace-only or padded values and forwards them as the VWO auth header.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

- Trim and validate apiToken and accountId to reject whitespace-only values
- Add .min(1) to accountId in StateSchema
- Use z.enum for campaign status instead of z.string
- Add .min(1) to campaign ids array and feature goals array
- Accept union of string | number for environmentId and featureId
- Simplify README to remove incorrect deploy.json instruction
- Update feature-rules client to accept string | number IDs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="vwo/README.md">

<violation number="1" location="vwo/README.md:7">
P2: This instruction points users to the schema file instead of the MCP settings, so it can send them to the wrong place and encourages treating secrets as source code.</violation>
</file>

<file name="vwo/server/lib/env.ts">

<violation number="1" location="vwo/server/lib/env.ts:14">
P2: Trim the override before applying the fallback. As written, a whitespace-only `accountId` override suppresses the configured default and causes these tools to throw instead of using the default account.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


## Getting Started

1. Configure your MCP credentials in `server/types/env.ts`
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This instruction points users to the schema file instead of the MCP settings, so it can send them to the wrong place and encourages treating secrets as source code.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vwo/README.md, line 7:

<comment>This instruction points users to the schema file instead of the MCP settings, so it can send them to the wrong place and encourages treating secrets as source code.</comment>

<file context>
@@ -4,10 +4,6 @@ Connect AI agents to VWO for A/B testing, experiment management, and optimizatio
 ## Getting Started
 
-1. Configure your MCP in `server/types/env.ts`
+1. Configure your MCP credentials in `server/types/env.ts`
 2. Implement tools in `server/tools/`
-3. Rename `app.json.example` to `app.json` and customize
</file context>
Suggested change
1. Configure your MCP credentials in `server/types/env.ts`
1. Configure the VWO `StateSchema` in `server/types/env.ts`, then set `apiToken` and `accountId` in the MCP settings
Fix with Cubic

}

export function getAccountId(env: Env, override?: string): string {
const id = (override || env.MESH_REQUEST_CONTEXT?.state?.accountId)?.trim();
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Trim the override before applying the fallback. As written, a whitespace-only accountId override suppresses the configured default and causes these tools to throw instead of using the default account.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vwo/server/lib/env.ts, line 14:

<comment>Trim the override before applying the fallback. As written, a whitespace-only `accountId` override suppresses the configured default and causes these tools to throw instead of using the default account.</comment>

<file context>
@@ -11,7 +11,7 @@ export function getApiToken(env: Env): string {
 
 export function getAccountId(env: Env, override?: string): string {
-  const id = override || env.MESH_REQUEST_CONTEXT?.state?.accountId;
+  const id = (override || env.MESH_REQUEST_CONTEXT?.state?.accountId)?.trim();
   if (!id) {
     throw new Error(
</file context>
Suggested change
const id = (override || env.MESH_REQUEST_CONTEXT?.state?.accountId)?.trim();
const id = override?.trim() || env.MESH_REQUEST_CONTEXT?.state?.accountId?.trim();
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant