Skip to main content
Glama
growthbook

GrowthBook MCP Server

Official
by growthbook

get_experiments

Retrieve experiments from the GrowthBook API with customizable parameters like limit, offset, and project for targeted data access.

Instructions

Fetches all experiments from the GrowthBook API

Input Schema

NameRequiredDescriptionDefault
limitNo
offsetNo
projectNo

Input Schema (JSON Schema)

{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "limit": { "default": 100, "type": "number" }, "offset": { "default": 0, "type": "number" }, "project": { "type": "string" } }, "type": "object" }

Implementation Reference

  • The handler function fetches experiments from GrowthBook API. Supports pagination (limit/offset), project filter, 'mostRecent' sorting, and 'analyze' mode to include results. Returns JSON stringified response.
    async ({ limit, offset, mostRecent, project, mode }) => { try { // Default behavior if (!mostRecent || offset > 0) { const defaultQueryParams = new URLSearchParams({ limit: limit.toString(), offset: offset.toString(), }); if (project) { defaultQueryParams.append("projectId", project); } const defaultRes = await fetch( `${baseApiUrl}/api/v1/experiments?${defaultQueryParams.toString()}`, { headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, } ); await handleResNotOk(defaultRes); const data = await defaultRes.json(); const experiments = data.experiments as Experiment[]; if (mode === "analyze") { for (const [index, experiment] of experiments.entries()) { try { const resultsRes = await fetch( `${baseApiUrl}/api/v1/experiments/${experiment.id}/results`, { headers: { Authorization: `Bearer ${apiKey}`, }, } ); await handleResNotOk(resultsRes); const resultsData = await resultsRes.json(); experiments[index].result = resultsData.result; } catch (error) { console.error( `Error fetching results for experiment ${experiment.id} (${experiment.name})`, error ); } } } return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], }; } // Most recent behavior const countRes = await fetch( `${baseApiUrl}/api/v1/experiments?limit=1`, { headers: { Authorization: `Bearer ${apiKey}`, }, } ); await handleResNotOk(countRes); const countData = await countRes.json(); const total = countData.total; const calculatedOffset = Math.max(0, total - limit); const mostRecentQueryParams = new URLSearchParams({ limit: limit.toString(), offset: calculatedOffset.toString(), }); if (project) { mostRecentQueryParams.append("projectId", project); } const mostRecentRes = await fetch( `${baseApiUrl}/api/v1/experiments?${mostRecentQueryParams.toString()}`, { headers: { Authorization: `Bearer ${apiKey}`, }, } ); await handleResNotOk(mostRecentRes); const mostRecentData = await mostRecentRes.json(); if ( mostRecentData.experiments && Array.isArray(mostRecentData.experiments) ) { mostRecentData.experiments = mostRecentData.experiments.reverse(); if (mode === "analyze") { for (const [ index, experiment, ] of mostRecentData.experiments.entries()) { try { const resultsRes = await fetch( `${baseApiUrl}/api/v1/experiments/${experiment.id}/results`, { headers: { Authorization: `Bearer ${apiKey}`, }, } ); await handleResNotOk(resultsRes); const resultsData = await resultsRes.json(); mostRecentData.experiments[index].result = resultsData.result; } catch (error) { console.error( `Error fetching results for experiment ${experiment.id} (${experiment.name})`, error ); } } } } return { content: [ { type: "text", text: JSON.stringify(mostRecentData, null, 2) }, ], }; } catch (error) { throw new Error(`Error fetching experiments: ${error}`); } }
  • Zod input schema defining parameters: optional project ID, mode (default/analyze), and pagination options from paginationSchema.
    { project: z .string() .describe("The ID of the project to filter experiments by") .optional(), mode: z .enum(["default", "analyze"]) .default("default") .describe( "The mode to use to fetch experiments. Default mode returns summary info about experiments. Analyze mode will also fetch experiment results, allowing for better analysis, interpretation, and reporting." ), ...paginationSchema, },
  • Registers the get_experiments tool on the MCP server with name, description, input schema, readOnlyHint, and handler function.
    server.tool( "get_experiments", "Fetches experiments from the GrowthBook API", { project: z .string() .describe("The ID of the project to filter experiments by") .optional(), mode: z .enum(["default", "analyze"]) .default("default") .describe( "The mode to use to fetch experiments. Default mode returns summary info about experiments. Analyze mode will also fetch experiment results, allowing for better analysis, interpretation, and reporting." ), ...paginationSchema, }, { readOnlyHint: true, }, async ({ limit, offset, mostRecent, project, mode }) => { try { // Default behavior if (!mostRecent || offset > 0) { const defaultQueryParams = new URLSearchParams({ limit: limit.toString(), offset: offset.toString(), }); if (project) { defaultQueryParams.append("projectId", project); } const defaultRes = await fetch( `${baseApiUrl}/api/v1/experiments?${defaultQueryParams.toString()}`, { headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, } ); await handleResNotOk(defaultRes); const data = await defaultRes.json(); const experiments = data.experiments as Experiment[]; if (mode === "analyze") { for (const [index, experiment] of experiments.entries()) { try { const resultsRes = await fetch( `${baseApiUrl}/api/v1/experiments/${experiment.id}/results`, { headers: { Authorization: `Bearer ${apiKey}`, }, } ); await handleResNotOk(resultsRes); const resultsData = await resultsRes.json(); experiments[index].result = resultsData.result; } catch (error) { console.error( `Error fetching results for experiment ${experiment.id} (${experiment.name})`, error ); } } } return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }], }; } // Most recent behavior const countRes = await fetch( `${baseApiUrl}/api/v1/experiments?limit=1`, { headers: { Authorization: `Bearer ${apiKey}`, }, } ); await handleResNotOk(countRes); const countData = await countRes.json(); const total = countData.total; const calculatedOffset = Math.max(0, total - limit); const mostRecentQueryParams = new URLSearchParams({ limit: limit.toString(), offset: calculatedOffset.toString(), }); if (project) { mostRecentQueryParams.append("projectId", project); } const mostRecentRes = await fetch( `${baseApiUrl}/api/v1/experiments?${mostRecentQueryParams.toString()}`, { headers: { Authorization: `Bearer ${apiKey}`, }, } ); await handleResNotOk(mostRecentRes); const mostRecentData = await mostRecentRes.json(); if ( mostRecentData.experiments && Array.isArray(mostRecentData.experiments) ) { mostRecentData.experiments = mostRecentData.experiments.reverse(); if (mode === "analyze") { for (const [ index, experiment, ] of mostRecentData.experiments.entries()) { try { const resultsRes = await fetch( `${baseApiUrl}/api/v1/experiments/${experiment.id}/results`, { headers: { Authorization: `Bearer ${apiKey}`, }, } ); await handleResNotOk(resultsRes); const resultsData = await resultsRes.json(); mostRecentData.experiments[index].result = resultsData.result; } catch (error) { console.error( `Error fetching results for experiment ${experiment.id} (${experiment.name})`, error ); } } } } return { content: [ { type: "text", text: JSON.stringify(mostRecentData, null, 2) }, ], }; } catch (error) { throw new Error(`Error fetching experiments: ${error}`); } } );
  • src/index.ts:89-95 (registration)
    Top-level call to registerExperimentTools in the main MCP server setup, which includes registering get_experiments.
    registerExperimentTools({ server, baseApiUrl, apiKey, appOrigin, user, });
  • TypeScript type definition for Experiment used in the handler to type API response.
    type Experiment = { id: string; trackingKey: string; dateCreated: string; dateUpdated: string; name: string; type: "standard"; project: string; resultSummary: { status: string; winner: string; conclusions: string; releasedVariationId: string; excludeFromPayload: true; }; result?: { [key: string]: any; }; };

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/growthbook/growthbook-mcp'

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