touchstone-mcp-tools 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -43,6 +43,14 @@ export declare class WolvesHandler {
43
43
  progression_parameters?: any[];
44
44
  }>;
45
45
  }): Promise<ToolResult>;
46
+ updateSubscribers(params: {
47
+ experiment_id: string;
48
+ subscribers: Array<{
49
+ id: string;
50
+ type: string;
51
+ tenantId: string;
52
+ }>;
53
+ }): Promise<ToolResult>;
46
54
  getExperiment(params: {
47
55
  experiment_id: string;
48
56
  }): Promise<ToolResult>;
@@ -1,4 +1,18 @@
1
1
  import { WolvesApiClient } from "../utils/wolves-api.js";
2
+ // Generate 8-character variant ID: 4 lowercase letters + 4 digits
3
+ // Matches ExP-Hub UI convention (e.g., "kifj6658", "tvan3734")
4
+ function generateVariantId() {
5
+ const letters = "abcdefghijklmnopqrstuvwxyz";
6
+ const digits = "0123456789";
7
+ let result = "";
8
+ for (let i = 0; i < 4; i++) {
9
+ result += letters.charAt(Math.floor(Math.random() * letters.length));
10
+ }
11
+ for (let i = 0; i < 4; i++) {
12
+ result += digits.charAt(Math.floor(Math.random() * digits.length));
13
+ }
14
+ return result;
15
+ }
2
16
  export class WolvesHandler {
3
17
  api;
4
18
  constructor(api) {
@@ -39,13 +53,18 @@ export class WolvesHandler {
39
53
  }
40
54
  // Tool 5: create_experiment
41
55
  async createExperiment(params) {
56
+ // Auto-generate 8-char variant IDs for variants that don't have one
57
+ const variants = params.variants.map((v) => ({
58
+ ...v,
59
+ id: v.id || generateVariantId(),
60
+ }));
42
61
  const result = await this.api.createExperiment({
43
62
  name: params.name,
44
63
  description: params.description,
45
64
  experimentation_group: params.experimentation_group,
46
65
  assignment_unit_id: params.assignment_unit_id,
47
66
  subscribers: params.subscribers,
48
- variants: params.variants,
67
+ variants,
49
68
  metrics: params.metrics,
50
69
  progressions: params.progressions,
51
70
  });
@@ -54,7 +73,17 @@ export class WolvesHandler {
54
73
  message: `Experiment "${result.name}" created (ID: ${result.id})`,
55
74
  };
56
75
  }
57
- // Tool 6: get_experiment
76
+ // Tool 6: update_subscribers
77
+ async updateSubscribers(params) {
78
+ await this.api.updateSubscribers(params.experiment_id, {
79
+ subscribers: params.subscribers,
80
+ });
81
+ return {
82
+ data: { experiment_id: params.experiment_id, subscriber_count: params.subscribers.length },
83
+ message: `Updated ${params.subscribers.length} subscriber(s) for experiment "${params.experiment_id}"`,
84
+ };
85
+ }
86
+ // Tool 8: get_experiment
58
87
  async getExperiment(params) {
59
88
  const result = await this.api.getExperiment(params.experiment_id);
60
89
  return {
@@ -62,7 +91,7 @@ export class WolvesHandler {
62
91
  message: `Retrieved experiment "${result.name}" (status: ${result.status})`,
63
92
  };
64
93
  }
65
- // Tool 7: list_experiments
94
+ // Tool 8: list_experiments
66
95
  async listExperiments(params) {
67
96
  const result = await this.api.listExperiments({
68
97
  page: params.page,
@@ -92,7 +92,7 @@
92
92
  "type": "object",
93
93
  "required": ["type"],
94
94
  "properties": {
95
- "id": { "type": "string", "description": "Variant ID (auto-generated if omitted)" },
95
+ "id": { "type": "string", "description": "Variant ID. 8-character alphanumeric (4 letters + 4 digits, e.g., 'kifj6658'). Auto-generated if omitted." },
96
96
  "type": { "type": "string", "enum": ["control", "treatment"], "description": "Variant type" },
97
97
  "description": { "type": "string", "description": "Variant description" }
98
98
  }
@@ -130,6 +130,33 @@
130
130
  }
131
131
  }
132
132
  },
133
+ "update_subscribers": {
134
+ "name": "update_subscribers",
135
+ "description": "Update subscribers for an experiment. Subscribers receive notifications about experiment changes. Requires subscriber objects with id, type, and tenantId (obtained from search_subscribers).",
136
+ "inputSchema": {
137
+ "type": "object",
138
+ "required": ["experiment_id", "subscribers"],
139
+ "properties": {
140
+ "experiment_id": {
141
+ "type": "string",
142
+ "description": "UUID of the experiment to update subscribers for"
143
+ },
144
+ "subscribers": {
145
+ "type": "array",
146
+ "description": "List of subscriber objects. Each subscriber must include id, type, and tenantId from search_subscribers results.",
147
+ "items": {
148
+ "type": "object",
149
+ "required": ["id", "type", "tenantId"],
150
+ "properties": {
151
+ "id": { "type": "string", "description": "Subscriber's user ID (from search_subscribers)" },
152
+ "type": { "type": "string", "description": "Subscriber type (e.g., 'UserAccount')" },
153
+ "tenantId": { "type": "string", "description": "Subscriber's tenant ID (from search_subscribers)" }
154
+ }
155
+ }
156
+ }
157
+ }
158
+ }
159
+ },
133
160
  "get_experiment": {
134
161
  "name": "get_experiment",
135
162
  "description": "Get detailed information about a specific experiment by its ID.",
@@ -42,6 +42,9 @@ export class WolvesServer {
42
42
  case "create_experiment":
43
43
  result = await this.handler.createExperiment(args);
44
44
  break;
45
+ case "update_subscribers":
46
+ result = await this.handler.updateSubscribers(args);
47
+ break;
45
48
  case "get_experiment":
46
49
  result = await this.handler.getExperiment(args);
47
50
  break;
@@ -44,6 +44,14 @@ export interface SubscriberSearchResult {
44
44
  type: string;
45
45
  tenantId: string;
46
46
  }
47
+ export interface SubscriberInput {
48
+ id: string;
49
+ type: string;
50
+ tenantId: string;
51
+ }
52
+ export interface UpdateSubscribersRequest {
53
+ subscribers: SubscriberInput[];
54
+ }
47
55
  export interface VariantInput {
48
56
  id?: string;
49
57
  type: "control" | "treatment";
@@ -124,6 +132,7 @@ export declare class WolvesApiClient {
124
132
  listAssignmentUnits(filter?: string): Promise<AssignmentUnitsListResponse>;
125
133
  searchSubscribers(search: string, count?: number, fetchUserPhoto?: boolean): Promise<SubscriberSearchResult[]>;
126
134
  createExperiment(data: CreateExperimentRequest): Promise<ExperimentDetail>;
135
+ updateSubscribers(experimentId: string, data: UpdateSubscribersRequest): Promise<void>;
127
136
  getExperiment(experimentId: string): Promise<ExperimentDetail>;
128
137
  listExperiments(params?: {
129
138
  page?: number;
@@ -69,6 +69,9 @@ export class WolvesApiClient {
69
69
  const response = await this.client.post("/api/experiments/experiments", data);
70
70
  return response.data;
71
71
  }
72
+ async updateSubscribers(experimentId, data) {
73
+ await this.client.put(`/api/experiments/experiments/${encodeURIComponent(experimentId)}/subscribers`, data);
74
+ }
72
75
  async getExperiment(experimentId) {
73
76
  const response = await this.client.get(`/api/experiments/experiments/${experimentId}`);
74
77
  return response.data;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "touchstone-mcp-tools",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "MCP tools for TouchStone Experimentation platform",
5
5
  "type": "module",
6
6
  "main": "build/index.js",