@growthbook/mcp 0.1.0 → 0.1.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.
- package/README.md +12 -12
- package/build/docs.js +508 -0
- package/build/index.js +37 -3
- package/build/tools/defaults.js +169 -0
- package/build/tools/environments.js +0 -1
- package/build/tools/experiments.js +148 -40
- package/build/tools/features.js +51 -85
- package/build/tools/projects.js +1 -2
- package/build/tools/sdk-connections.js +4 -17
- package/build/tools/search.js +1 -2
- package/build/utils.js +38 -29
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
With the GrowthBook MCP server, you can interact with GrowthBook right from your LLM client. See experiment details, add a feature flag, and more.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<a href="https://glama.ai/mcp/servers/@growthbook/growthbook-mcp">
|
|
6
|
+
<img width="380" height="200" src="https://glama.ai/mcp/servers/@growthbook/growthbook-mcp/badge" alt="GrowthBook Server MCP server" />
|
|
7
|
+
</a>
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
1. Clone the repo
|
|
10
|
-
2. Run `npx tsc` to generate a build
|
|
9
|
+
## Setup
|
|
11
10
|
|
|
12
11
|
**Environment Variables**
|
|
13
12
|
Use the following env variables to configure the MCP server.
|
|
@@ -31,8 +30,8 @@ Find instructions below to add the MCP server to a client. Any client that suppo
|
|
|
31
30
|
{
|
|
32
31
|
"mcpServers": {
|
|
33
32
|
"growthbook": {
|
|
34
|
-
"command": "
|
|
35
|
-
"args": ["
|
|
33
|
+
"command": "npx",
|
|
34
|
+
"args": ["-y", "@growthbook/mcp"],
|
|
36
35
|
"env": {
|
|
37
36
|
"GB_API_KEY": "YOUR_API_KEY",
|
|
38
37
|
"GB_API_URL": "YOUR_API_URL",
|
|
@@ -57,9 +56,9 @@ You should now see a green active status after the server successfully connects!
|
|
|
57
56
|
"mcp": {
|
|
58
57
|
"servers": {
|
|
59
58
|
"growthbook": {
|
|
60
|
-
"command": "
|
|
59
|
+
"command": "npx",
|
|
61
60
|
"args": [
|
|
62
|
-
"
|
|
61
|
+
"-y", "@growthbook/mcp"
|
|
63
62
|
],
|
|
64
63
|
"env": {
|
|
65
64
|
"GB_API_KEY": "YOUR_API_KEY",
|
|
@@ -87,8 +86,8 @@ GrowthBook MCP is now ready to use in VS Code.
|
|
|
87
86
|
{
|
|
88
87
|
"mcpServers": {
|
|
89
88
|
"growthbook": {
|
|
90
|
-
"command": "
|
|
91
|
-
"args": ["
|
|
89
|
+
"command": "npx",
|
|
90
|
+
"args": ["-y", "@growthbook/mcp"],
|
|
92
91
|
"env": {
|
|
93
92
|
"GB_API_KEY": "YOUR_API_KEY",
|
|
94
93
|
"GB_API_URL": "YOUR_API_URL",
|
|
@@ -122,6 +121,7 @@ A hammer icon should appear in the chat window, indicating that your GrowthBook
|
|
|
122
121
|
- `get_experiments`: List all experiments in GrowthBook.
|
|
123
122
|
- `get_experiment`: Fetch details for a specific experiment by ID.
|
|
124
123
|
- `get_attributes`: List all user attributes tracked in GrowthBook (useful for targeting).
|
|
124
|
+
- `create_experiment`: Creates a feature-flag based experiment.
|
|
125
125
|
|
|
126
126
|
- **Environments**
|
|
127
127
|
|
|
@@ -137,4 +137,4 @@ A hammer icon should appear in the chat window, indicating that your GrowthBook
|
|
|
137
137
|
- `create_sdk_connection`: Create a new SDK connection for your app, specifying language and environment.
|
|
138
138
|
|
|
139
139
|
- **Documentation Search**
|
|
140
|
-
- `search_growthbook_docs`: Search the GrowthBook documentation for information on how to use a feature, by keyword or question.
|
|
140
|
+
- `search_growthbook_docs`: Search the GrowthBook documentation for information on how to use a feature, by keyword or question.
|
package/build/docs.js
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
export const FEATURE_FLAG_DOCS = {
|
|
2
|
+
react: `## React Feature Flag Implementation
|
|
3
|
+
|
|
4
|
+
### Boolean Feature Flags
|
|
5
|
+
Use \`useFeatureIsOn\` for simple on/off features. \`useFeatureIsOn\` should appear in the component body, not in the return statement/template:
|
|
6
|
+
\`\`\`tsx
|
|
7
|
+
import { useFeatureIsOn } from "@growthbook/growthbook-react";
|
|
8
|
+
|
|
9
|
+
function LoginPage() {
|
|
10
|
+
const showNewDesign = useFeatureIsOn("new-login-design");
|
|
11
|
+
|
|
12
|
+
return showNewDesign ? <NewLoginForm /> : <OldLoginForm />;
|
|
13
|
+
}
|
|
14
|
+
\`\`\`
|
|
15
|
+
|
|
16
|
+
### Feature Values with Defaults
|
|
17
|
+
Use \`useFeatureValue\` when you need specific values. \`useFeatureValue\` should appear in the component body, not in the return statement/template:
|
|
18
|
+
\`\`\`tsx
|
|
19
|
+
import { useFeatureValue } from "@growthbook/growthbook-react";
|
|
20
|
+
|
|
21
|
+
function Button() {
|
|
22
|
+
const buttonColor = useFeatureValue("button-color", "blue");
|
|
23
|
+
const buttonSize = useFeatureValue("button-size", "medium");
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<button
|
|
27
|
+
className={\`btn btn-\${buttonColor} btn-\${buttonSize}\`}
|
|
28
|
+
>
|
|
29
|
+
Click me
|
|
30
|
+
</button>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
\`\`\`
|
|
34
|
+
|
|
35
|
+
### Declarative Components
|
|
36
|
+
Use feature components for conditional rendering:
|
|
37
|
+
\`\`\`tsx
|
|
38
|
+
import { IfFeatureEnabled, FeatureString } from "@growthbook/growthbook-react";
|
|
39
|
+
|
|
40
|
+
function HomePage() {
|
|
41
|
+
return (
|
|
42
|
+
<div>
|
|
43
|
+
<h1>
|
|
44
|
+
<FeatureString feature="site-title" default="Welcome" />
|
|
45
|
+
</h1>
|
|
46
|
+
|
|
47
|
+
<IfFeatureEnabled feature="promo-banner">
|
|
48
|
+
<PromoBanner />
|
|
49
|
+
</IfFeatureEnabled>
|
|
50
|
+
|
|
51
|
+
<IfFeatureEnabled feature="new-checkout" fallback={<OldCheckout />}>
|
|
52
|
+
<NewCheckout />
|
|
53
|
+
</IfFeatureEnabled>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
\`\`\``,
|
|
58
|
+
javascript: `## JavaScript Feature Flag Implementation
|
|
59
|
+
|
|
60
|
+
### Simple Feature Checks
|
|
61
|
+
Use \`isOn()\` for boolean features:
|
|
62
|
+
\`\`\`javascript
|
|
63
|
+
function renderDashboard() {
|
|
64
|
+
if (gb.isOn("new-dashboard")) {
|
|
65
|
+
return renderNewDashboard();
|
|
66
|
+
}
|
|
67
|
+
return renderOldDashboard();
|
|
68
|
+
}
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
71
|
+
### Feature Values with Fallbacks
|
|
72
|
+
Use \`getFeatureValue()\` for configuration values:
|
|
73
|
+
\`\`\`javascript
|
|
74
|
+
function configureAPI() {
|
|
75
|
+
const apiTimeout = gb.getFeatureValue("api-timeout", 5000);
|
|
76
|
+
const retryCount = gb.getFeatureValue("retry-count", 3);
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
timeout: apiTimeout,
|
|
80
|
+
retries: retryCount
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
### Detailed Feature Evaluation
|
|
86
|
+
Use \`evalFeature()\` when you need metadata:
|
|
87
|
+
\`\`\`javascript
|
|
88
|
+
function trackFeatureUsage(featureKey) {
|
|
89
|
+
const result = gb.evalFeature(featureKey);
|
|
90
|
+
|
|
91
|
+
// Track feature usage for analytics
|
|
92
|
+
analytics.track('feature_evaluated', {
|
|
93
|
+
feature: featureKey,
|
|
94
|
+
value: result.value,
|
|
95
|
+
source: result.source,
|
|
96
|
+
ruleId: result.ruleId
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return result.value;
|
|
100
|
+
}
|
|
101
|
+
\`\`\``,
|
|
102
|
+
vue: `## Vue Feature Flag Implementation
|
|
103
|
+
|
|
104
|
+
### Composition API
|
|
105
|
+
\`\`\`typescript
|
|
106
|
+
import { ref, watch, inject } from 'vue'
|
|
107
|
+
|
|
108
|
+
const showBanner = ref(growthbook?.isOn('show-banner'))
|
|
109
|
+
|
|
110
|
+
// Optional real-time watching
|
|
111
|
+
watch(growthbook, () => {
|
|
112
|
+
showBanner.value = growthbook?.isOn('show-banner')
|
|
113
|
+
})
|
|
114
|
+
\`\`\`
|
|
115
|
+
|
|
116
|
+
### Options API
|
|
117
|
+
\`\`\`typescript
|
|
118
|
+
export default {
|
|
119
|
+
data() {
|
|
120
|
+
return {
|
|
121
|
+
showBanner: false
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
mounted() {
|
|
125
|
+
const gb = inject(gbKey)
|
|
126
|
+
if (gb) {
|
|
127
|
+
this.showBanner = gb.isOn('show-banner')
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
\`\`\`
|
|
132
|
+
|
|
133
|
+
### Template Usage
|
|
134
|
+
\`\`\`html
|
|
135
|
+
<template>
|
|
136
|
+
<div>
|
|
137
|
+
<h1 v-if="showBanner">Now you see me!</h1>
|
|
138
|
+
</div>
|
|
139
|
+
</template>
|
|
140
|
+
\`\`\``,
|
|
141
|
+
python: `## Python Feature Flag Implementation
|
|
142
|
+
|
|
143
|
+
### Boolean Feature Checks
|
|
144
|
+
Use \`is_on()\` and \`is_off()\` for feature toggles:
|
|
145
|
+
\`\`\`python
|
|
146
|
+
def process_payment(gb, payment_data):
|
|
147
|
+
if gb.is_on("new-payment-processor"):
|
|
148
|
+
return new_payment_service.process(payment_data)
|
|
149
|
+
else:
|
|
150
|
+
return legacy_payment_service.process(payment_data)
|
|
151
|
+
\`\`\`
|
|
152
|
+
|
|
153
|
+
### Feature Values with Defaults
|
|
154
|
+
Use \`get_feature_value()\` for configuration:
|
|
155
|
+
\`\`\`python
|
|
156
|
+
def get_api_config(gb):
|
|
157
|
+
return {
|
|
158
|
+
'timeout': gb.get_feature_value("api-timeout", 30),
|
|
159
|
+
'max_retries': gb.get_feature_value("max-retries", 3),
|
|
160
|
+
'batch_size': gb.get_feature_value("batch-size", 100)
|
|
161
|
+
}
|
|
162
|
+
\`\`\`
|
|
163
|
+
|
|
164
|
+
### Detailed Feature Evaluation
|
|
165
|
+
Use \`evalFeature()\` for comprehensive feature info:
|
|
166
|
+
\`\`\`python
|
|
167
|
+
def evaluate_feature_with_tracking(gb, feature_key):
|
|
168
|
+
result = gb.evalFeature(feature_key)
|
|
169
|
+
|
|
170
|
+
# Log feature evaluation for debugging
|
|
171
|
+
logger.info(f"Feature {feature_key}: value={result.value}, source={result.source}")
|
|
172
|
+
|
|
173
|
+
return result.value
|
|
174
|
+
\`\`\`
|
|
175
|
+
|
|
176
|
+
### Web Framework Integration (Django Example)
|
|
177
|
+
\`\`\`python
|
|
178
|
+
def growthbook_middleware(get_response):
|
|
179
|
+
def middleware(request):
|
|
180
|
+
# Initialize GrowthBook for each request
|
|
181
|
+
request.gb = create_growthbook_instance(
|
|
182
|
+
user_id=getattr(request.user, 'id', None),
|
|
183
|
+
is_authenticated=request.user.is_authenticated,
|
|
184
|
+
user_type=getattr(request.user, 'user_type', 'anonymous')
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
response = get_response(request)
|
|
188
|
+
return response
|
|
189
|
+
return middleware
|
|
190
|
+
\`\`\``,
|
|
191
|
+
go: `## Go Feature Flag Implementation
|
|
192
|
+
|
|
193
|
+
### Basic Feature Evaluation
|
|
194
|
+
\`\`\`go
|
|
195
|
+
// Evaluate a text feature
|
|
196
|
+
buttonColor := client.EvalFeature(context.Background(), "buy-button-color")
|
|
197
|
+
if buttonColor.Value == "blue" {
|
|
198
|
+
// Perform actions for blue button
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Evaluate a boolean feature
|
|
202
|
+
darkMode := client.EvalFeature(context.Background(), "dark-mode")
|
|
203
|
+
if darkMode.On {
|
|
204
|
+
// Enable dark mode
|
|
205
|
+
}
|
|
206
|
+
\`\`\`
|
|
207
|
+
|
|
208
|
+
### Detailed Feature Inspection
|
|
209
|
+
\`\`\`go
|
|
210
|
+
result, err := client.EvalFeature(context.TODO(), "my-feature")
|
|
211
|
+
if err != nil {
|
|
212
|
+
// Handle error
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Check feature value and source
|
|
216
|
+
if result.On {
|
|
217
|
+
// Feature is enabled
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Inspect how the feature value was determined
|
|
221
|
+
switch result.Source {
|
|
222
|
+
case gb.DefaultValueResultSource:
|
|
223
|
+
// Used default value
|
|
224
|
+
case gb.ExperimentResultSource:
|
|
225
|
+
// Value determined by an experiment
|
|
226
|
+
case gb.ForceResultSource:
|
|
227
|
+
// Manually forced value
|
|
228
|
+
}
|
|
229
|
+
\`\`\``,
|
|
230
|
+
php: `## PHP Feature Flag Implementation
|
|
231
|
+
|
|
232
|
+
### Basic Feature Checks
|
|
233
|
+
\`\`\`php
|
|
234
|
+
// Check if a feature is on
|
|
235
|
+
if ($growthbook->isOn("my-feature")) {
|
|
236
|
+
echo "It's on!";
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Check if a feature is off
|
|
240
|
+
if ($growthbook->isOff("my-feature")) {
|
|
241
|
+
echo "It's off :(";
|
|
242
|
+
}
|
|
243
|
+
\`\`\`
|
|
244
|
+
|
|
245
|
+
### Feature Values with Fallback
|
|
246
|
+
\`\`\`php
|
|
247
|
+
// Get feature value with default fallback
|
|
248
|
+
$color = $growthbook->getValue("button-color", "blue");
|
|
249
|
+
echo "<button style='color:\${color}'>Click Me!</button>";
|
|
250
|
+
\`\`\`
|
|
251
|
+
|
|
252
|
+
### Detailed Feature Result
|
|
253
|
+
\`\`\`php
|
|
254
|
+
$featureResult = $growthbook->getFeature("my-feature");
|
|
255
|
+
|
|
256
|
+
// Access feature result properties
|
|
257
|
+
$value = $featureResult->value;
|
|
258
|
+
$isOn = $featureResult->on;
|
|
259
|
+
$source = $featureResult->source; // e.g. 'defaultValue', 'experiment'
|
|
260
|
+
\`\`\`
|
|
261
|
+
|
|
262
|
+
### Inline Experiments
|
|
263
|
+
\`\`\`php
|
|
264
|
+
$exp = Growthbook\\InlineExperiment::create(
|
|
265
|
+
"my-experiment",
|
|
266
|
+
["red", "blue", "green"]
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
// Run experiment and get result
|
|
270
|
+
$result = $growthbook->runInlineExperiment($exp);
|
|
271
|
+
echo $result->value; // Will be "red", "blue", or "green"
|
|
272
|
+
\`\`\``,
|
|
273
|
+
ruby: `## Ruby Feature Flag Implementation
|
|
274
|
+
|
|
275
|
+
### Basic Feature Evaluation
|
|
276
|
+
\`\`\`ruby
|
|
277
|
+
# Check if feature is enabled
|
|
278
|
+
if gb.feature_on?("my-feature")
|
|
279
|
+
puts "Feature is on!"
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Get feature value with default
|
|
283
|
+
color = gb.get_feature_value("button-color", "blue")
|
|
284
|
+
\`\`\`
|
|
285
|
+
|
|
286
|
+
### Detailed Feature Results
|
|
287
|
+
\`\`\`ruby
|
|
288
|
+
result = gb.eval_feature("my-feature")
|
|
289
|
+
puts result.value
|
|
290
|
+
puts result.on?
|
|
291
|
+
puts result.source
|
|
292
|
+
\`\`\``,
|
|
293
|
+
java: `## Java Feature Flag Implementation
|
|
294
|
+
|
|
295
|
+
### Feature State Checks
|
|
296
|
+
\`\`\`java
|
|
297
|
+
// Check if a feature is on/off
|
|
298
|
+
boolean isDarkModeEnabled = growthBook.isOn("dark_mode");
|
|
299
|
+
boolean isFeatureDisabled = growthBook.isOff("feature_key");
|
|
300
|
+
\`\`\`
|
|
301
|
+
|
|
302
|
+
### Feature Values with Defaults
|
|
303
|
+
\`\`\`java
|
|
304
|
+
// Get feature value with a default
|
|
305
|
+
String welcomeMessage = growthBook.getFeatureValue("welcome_message", "Default Welcome");
|
|
306
|
+
Float pricing = growthBook.getFeatureValue("product_price", 9.99f);
|
|
307
|
+
\`\`\`
|
|
308
|
+
|
|
309
|
+
### Complex Type Evaluation
|
|
310
|
+
\`\`\`java
|
|
311
|
+
// For complex objects, specify the class for deserialization
|
|
312
|
+
MyConfig config = growthBook.getFeatureValue(
|
|
313
|
+
"app_config",
|
|
314
|
+
defaultConfig,
|
|
315
|
+
MyConfig.class
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
// Detailed feature evaluation
|
|
319
|
+
FeatureResult<Float> result = growthBook.evalFeature("pricing");
|
|
320
|
+
Float value = result.getValue();
|
|
321
|
+
FeatureResultSource source = result.getSource();
|
|
322
|
+
\`\`\``,
|
|
323
|
+
csharp: `## C# Feature Flag Implementation
|
|
324
|
+
|
|
325
|
+
### Basic Feature Evaluation
|
|
326
|
+
\`\`\`csharp
|
|
327
|
+
// Check if feature is enabled
|
|
328
|
+
if (gb.IsOn("my-feature"))
|
|
329
|
+
{
|
|
330
|
+
Console.WriteLine("Feature is enabled!");
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Get feature value with default
|
|
334
|
+
var buttonColor = gb.GetFeatureValue("button-color", "blue");
|
|
335
|
+
\`\`\`
|
|
336
|
+
|
|
337
|
+
### Typed Feature Values
|
|
338
|
+
\`\`\`csharp
|
|
339
|
+
// Get strongly typed feature values
|
|
340
|
+
var maxRetries = gb.GetFeatureValue<int>("max-retries", 3);
|
|
341
|
+
var timeout = gb.GetFeatureValue<double>("timeout-seconds", 30.0);
|
|
342
|
+
\`\`\`
|
|
343
|
+
|
|
344
|
+
### Feature Result Details
|
|
345
|
+
\`\`\`csharp
|
|
346
|
+
var result = gb.EvalFeature("my-feature");
|
|
347
|
+
Console.WriteLine($"Value: {result.Value}");
|
|
348
|
+
Console.WriteLine($"Source: {result.Source}");
|
|
349
|
+
Console.WriteLine($"On: {result.On}");
|
|
350
|
+
\`\`\``,
|
|
351
|
+
swift: `## Swift Feature Flag Implementation
|
|
352
|
+
|
|
353
|
+
### Basic Feature Checks
|
|
354
|
+
\`\`\`swift
|
|
355
|
+
// Check if feature is enabled
|
|
356
|
+
if gb.isOn(feature: "dark-mode") {
|
|
357
|
+
// Enable dark mode
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Get feature value with default
|
|
361
|
+
let buttonColor = gb.getFeatureValue(feature: "button-color", defaultValue: "blue")
|
|
362
|
+
\`\`\`
|
|
363
|
+
|
|
364
|
+
### Feature Evaluation
|
|
365
|
+
\`\`\`swift
|
|
366
|
+
let result = gb.evalFeature("my-feature")
|
|
367
|
+
print("Value: \\(result.value)")
|
|
368
|
+
print("On: \\(result.on)")
|
|
369
|
+
print("Source: \\(result.source)")
|
|
370
|
+
\`\`\``,
|
|
371
|
+
elixir: `## Elixir Feature Flag Implementation
|
|
372
|
+
|
|
373
|
+
### Basic Feature Evaluation
|
|
374
|
+
\`\`\`elixir
|
|
375
|
+
# Check if feature is enabled
|
|
376
|
+
case GrowthBook.feature_on?(gb, "my-feature") do
|
|
377
|
+
true -> IO.puts("Feature is on!")
|
|
378
|
+
false -> IO.puts("Feature is off")
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Get feature value with default
|
|
382
|
+
button_color = GrowthBook.get_feature_value(gb, "button-color", "blue")
|
|
383
|
+
\`\`\`
|
|
384
|
+
|
|
385
|
+
### Feature Result Evaluation
|
|
386
|
+
\`\`\`elixir
|
|
387
|
+
result = GrowthBook.eval_feature(gb, "my-feature")
|
|
388
|
+
IO.inspect(result.value)
|
|
389
|
+
IO.inspect(result.on)
|
|
390
|
+
IO.inspect(result.source)
|
|
391
|
+
\`\`\``,
|
|
392
|
+
kotlin: `## Kotlin Feature Flag Implementation
|
|
393
|
+
|
|
394
|
+
### Basic Feature Checks
|
|
395
|
+
\`\`\`kotlin
|
|
396
|
+
// Get feature and check if enabled
|
|
397
|
+
val feature = gb.feature("dark-mode")
|
|
398
|
+
if (feature.on) {
|
|
399
|
+
// Enable dark mode
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Check if feature is off
|
|
403
|
+
if (feature.off) {
|
|
404
|
+
// Feature is disabled
|
|
405
|
+
}
|
|
406
|
+
\`\`\`
|
|
407
|
+
|
|
408
|
+
### Feature Values
|
|
409
|
+
\`\`\`kotlin
|
|
410
|
+
// Get feature value
|
|
411
|
+
val buttonColor = gb.feature("button-color")
|
|
412
|
+
val colorValue = buttonColor.value
|
|
413
|
+
|
|
414
|
+
// Direct value access with fallback logic
|
|
415
|
+
val actualColor = if (buttonColor.on) buttonColor.value else "blue"
|
|
416
|
+
\`\`\`
|
|
417
|
+
|
|
418
|
+
### Feature Result Details
|
|
419
|
+
\`\`\`kotlin
|
|
420
|
+
val feature = gb.feature("my-feature")
|
|
421
|
+
println("Value: \${feature.value}")
|
|
422
|
+
println("On: \${feature.on}")
|
|
423
|
+
println("Off: \${feature.off}")
|
|
424
|
+
println("Source: \${feature.source}")
|
|
425
|
+
\`\`\``,
|
|
426
|
+
flutter: `## Flutter Feature Flag Implementation
|
|
427
|
+
|
|
428
|
+
### Basic Feature Usage
|
|
429
|
+
\`\`\`dart
|
|
430
|
+
// Check if feature is enabled
|
|
431
|
+
if (gb.isOn('dark-mode')) {
|
|
432
|
+
// Enable dark mode
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Get feature value with default
|
|
436
|
+
String buttonColor = gb.getFeatureValue('button-color', 'blue');
|
|
437
|
+
\`\`\`
|
|
438
|
+
|
|
439
|
+
### Widget Integration
|
|
440
|
+
\`\`\`dart
|
|
441
|
+
class MyWidget extends StatelessWidget {
|
|
442
|
+
@override
|
|
443
|
+
Widget build(BuildContext context) {
|
|
444
|
+
final showBanner = gb.isOn('show-banner');
|
|
445
|
+
|
|
446
|
+
return Column(
|
|
447
|
+
children: [
|
|
448
|
+
if (showBanner) BannerWidget(),
|
|
449
|
+
MainContent(),
|
|
450
|
+
],
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
\`\`\`
|
|
455
|
+
|
|
456
|
+
### Feature Result Evaluation
|
|
457
|
+
\`\`\`dart
|
|
458
|
+
GBFeatureResult result = gb.evalFeature('my-feature');
|
|
459
|
+
print('Value: \${result.value}');
|
|
460
|
+
print('On: \${result.on}');
|
|
461
|
+
print('Source: \${result.source}');
|
|
462
|
+
\`\`\``,
|
|
463
|
+
};
|
|
464
|
+
export function getFeatureFlagDocs(language) {
|
|
465
|
+
switch (language.toLowerCase()) {
|
|
466
|
+
case "react":
|
|
467
|
+
case "tsx":
|
|
468
|
+
case "jsx":
|
|
469
|
+
return FEATURE_FLAG_DOCS.react;
|
|
470
|
+
case "javascript":
|
|
471
|
+
case "js":
|
|
472
|
+
case "node":
|
|
473
|
+
return FEATURE_FLAG_DOCS.javascript;
|
|
474
|
+
case "vue":
|
|
475
|
+
return FEATURE_FLAG_DOCS.vue;
|
|
476
|
+
case "python":
|
|
477
|
+
case "py":
|
|
478
|
+
return FEATURE_FLAG_DOCS.python;
|
|
479
|
+
case "go":
|
|
480
|
+
return FEATURE_FLAG_DOCS.go;
|
|
481
|
+
case "php":
|
|
482
|
+
return FEATURE_FLAG_DOCS.php;
|
|
483
|
+
case "ruby":
|
|
484
|
+
case "rb":
|
|
485
|
+
return FEATURE_FLAG_DOCS.ruby;
|
|
486
|
+
case "java":
|
|
487
|
+
return FEATURE_FLAG_DOCS.java;
|
|
488
|
+
case "csharp":
|
|
489
|
+
case "cs":
|
|
490
|
+
return FEATURE_FLAG_DOCS.csharp;
|
|
491
|
+
case "swift":
|
|
492
|
+
return FEATURE_FLAG_DOCS.swift;
|
|
493
|
+
case "elixir":
|
|
494
|
+
case "ex":
|
|
495
|
+
case "exs":
|
|
496
|
+
return FEATURE_FLAG_DOCS.elixir;
|
|
497
|
+
case "kotlin":
|
|
498
|
+
case "kt":
|
|
499
|
+
case "kts":
|
|
500
|
+
case "ktm":
|
|
501
|
+
return FEATURE_FLAG_DOCS.kotlin;
|
|
502
|
+
case "flutter":
|
|
503
|
+
case "dart":
|
|
504
|
+
return FEATURE_FLAG_DOCS.flutter;
|
|
505
|
+
default:
|
|
506
|
+
return "Feature flag documentation not available for this language. Check GrowthBook docs for implementation details.";
|
|
507
|
+
}
|
|
508
|
+
}
|
package/build/index.js
CHANGED
|
@@ -7,7 +7,8 @@ import { registerFeatureTools } from "./tools/features.js";
|
|
|
7
7
|
import { registerProjectTools } from "./tools/projects.js";
|
|
8
8
|
import { registerSdkConnectionTools } from "./tools/sdk-connections.js";
|
|
9
9
|
import { getApiKey, getApiUrl, getAppOrigin, getUser } from "./utils.js";
|
|
10
|
-
import {
|
|
10
|
+
import { registerSearchTools } from "./tools/search.js";
|
|
11
|
+
import { registerDefaultsTools } from "./tools/defaults.js";
|
|
11
12
|
export const baseApiUrl = getApiUrl();
|
|
12
13
|
export const apiKey = getApiKey();
|
|
13
14
|
export const appOrigin = getAppOrigin();
|
|
@@ -17,7 +18,34 @@ const server = new McpServer({
|
|
|
17
18
|
name: "GrowthBook MCP",
|
|
18
19
|
version: "1.0.0",
|
|
19
20
|
}, {
|
|
20
|
-
instructions:
|
|
21
|
+
instructions: `You are a helpful assistant that interacts with GrowthBook, an open source feature flagging and experimentation platform. You can create and manage feature flags, experiments (A/B tests), and other resources associated with GrowthBook.
|
|
22
|
+
|
|
23
|
+
**Key Workflows:**
|
|
24
|
+
|
|
25
|
+
1. **Creating Feature Flags:**
|
|
26
|
+
- Use create_feature_flag for simple boolean/string/number/json flags
|
|
27
|
+
- Use create_force_rule to add conditional rules to existing flags
|
|
28
|
+
- Always specify the correct fileExtension for code integration
|
|
29
|
+
|
|
30
|
+
2. **Creating Experiments (A/B Tests):**
|
|
31
|
+
- CRITICAL: Always call get_defaults FIRST to see naming conventions and examples
|
|
32
|
+
- Use create_experiment to create experiments
|
|
33
|
+
- Experiments automatically create linked feature flags
|
|
34
|
+
|
|
35
|
+
3. **Exploring Existing Resources:**
|
|
36
|
+
- Use get_projects, get_environments, get_feature_flags, get_experiments, or get_attributes to understand current setup
|
|
37
|
+
- Use get_single_feature_flag for detailed flag information
|
|
38
|
+
- Use get_stale_safe_rollouts to find completed rollouts that can be cleaned up
|
|
39
|
+
|
|
40
|
+
4. **SDK Integration:**
|
|
41
|
+
- Use get_sdk_connections to see existing integrations
|
|
42
|
+
- Use create_sdk_connection for new app integrations
|
|
43
|
+
- Use generate_flag_types to create TypeScript definitions
|
|
44
|
+
|
|
45
|
+
**Important Notes:**
|
|
46
|
+
- Feature flags and experiments require a fileExtension parameter for proper code integration
|
|
47
|
+
- Always review generated GrowthBook links with users so they can launch experiments
|
|
48
|
+
- When experiments are "draft", users must visit GrowthBook to review and launch them`,
|
|
21
49
|
});
|
|
22
50
|
registerEnvironmentTools({
|
|
23
51
|
server,
|
|
@@ -46,9 +74,15 @@ registerExperimentTools({
|
|
|
46
74
|
baseApiUrl,
|
|
47
75
|
apiKey,
|
|
48
76
|
appOrigin,
|
|
77
|
+
user,
|
|
78
|
+
});
|
|
79
|
+
registerSearchTools({
|
|
80
|
+
server,
|
|
49
81
|
});
|
|
50
|
-
|
|
82
|
+
registerDefaultsTools({
|
|
51
83
|
server,
|
|
84
|
+
baseApiUrl,
|
|
85
|
+
apiKey,
|
|
52
86
|
});
|
|
53
87
|
// Start receiving messages on stdin and sending messages on stdout
|
|
54
88
|
const transport = new StdioServerTransport();
|