Skip to main content
Glama

Bucketeer MCP Server

Official
by bucketeer-io
client.ts4.71 kB
import axios, { type AxiosInstance, type AxiosError } from "axios"; import type { ListFeaturesRequest, ListFeaturesResponse, CreateFeatureRequest, CreateFeatureResponse, GetFeatureRequest, GetFeatureResponse, UpdateFeatureRequest, UpdateFeatureResponse, BucketeerError, } from "../types/bucketeer.js"; export class BucketeerClient { private client: AxiosInstance; constructor(host: string, apiKey: string) { this.client = axios.create({ baseURL: `https://${host}`, headers: { Authorization: apiKey, "Content-Type": "application/json", }, timeout: 30000, }); // Add response interceptor for error handling this.client.interceptors.response.use( (response) => response, (error: AxiosError) => { throw this.handleError(error); }, ); } private handleError(error: AxiosError): Error { if (error.response) { const data = error.response.data as any; const bucketeerError: BucketeerError = { code: data.code || error.response.status, message: data.message || error.message, details: data.details, }; // Map error codes to user-friendly messages switch (bucketeerError.code) { case 3: throw new Error(`Invalid arguments: ${bucketeerError.message}`); case 5: throw new Error(`Not found: ${bucketeerError.message}`); case 7: throw new Error(`Not authorized: ${bucketeerError.message}`); case 16: throw new Error(`Not authenticated: ${bucketeerError.message}`); default: throw new Error(bucketeerError.message || "Unknown error occurred"); } } else if (error.request) { throw new Error("No response from server. Please check your connection."); } else { throw new Error(`Request error: ${error.message}`); } } async listFeatures( params: ListFeaturesRequest, ): Promise<ListFeaturesResponse> { const response = await this.client.get<ListFeaturesResponse>( "/v1/features", { params: { environmentId: params.environmentId, pageSize: params.pageSize, cursor: params.cursor, tags: params.tags, orderBy: params.orderBy, orderDirection: params.orderDirection, searchKeyword: params.searchKeyword, maintainer: params.maintainer, hasExperiment: params.hasExperiment, archived: params.archived, }, }, ); return response.data; } async createFeature( data: CreateFeatureRequest, ): Promise<CreateFeatureResponse> { // Prepare variations - let the server generate IDs const variationsForRequest = data.variations.map((v) => ({ value: v.value, name: v.name, description: v.description || "", })); // Format the request body according to Bucketeer Gateway API spec // Note: environmentId is NOT included in the request body for Gateway API // The Gateway API automatically gets the environmentId from the API key const requestBody: any = { id: data.id, name: data.name, variations: variationsForRequest, onVariationIndex: data.defaultOnVariationIndex, offVariationIndex: data.defaultOffVariationIndex, variationType: data.variationType || "STRING", }; // Only include optional fields if they are provided if (data.description !== undefined && data.description !== "") { requestBody.description = data.description; } if (data.tags && data.tags.length > 0) { requestBody.tags = data.tags; } const response = await this.client.post<CreateFeatureResponse>( "/v1/feature", requestBody, ); return response.data; } async getFeature(params: GetFeatureRequest): Promise<GetFeatureResponse> { const response = await this.client.get<GetFeatureResponse>("/v1/feature", { params: { id: params.id, environmentId: params.environmentId, featureVersion: params.featureVersion, }, }); return response.data; } async updateFeature( data: UpdateFeatureRequest, ): Promise<UpdateFeatureResponse> { // For PATCH request, include all required fields const patchData: any = { id: data.id, environmentId: data.environmentId, comment: data.comment, // Required for all updates }; // Gateway API expects plain values, not protobuf wrapper format if (data.name !== undefined) { patchData.name = data.name; } if (data.description !== undefined) { patchData.description = data.description; } if (data.enabled !== undefined) { patchData.enabled = data.enabled; } if (data.archived !== undefined) { patchData.archived = data.archived; } if (data.tags !== undefined) { patchData.tags = data.tags; // StringListValue format: { values: [...] } } const response = await this.client.patch<UpdateFeatureResponse>( "/v1/feature", patchData, ); return response.data; } }

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/bucketeer-io/bucketeer-mcp'

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