Skip to main content
Glama

octomind-mcp

Official
by OctoMind-dev
api.ts12.3 kB
import axios from "axios"; import { logger } from "./logger"; import { getApiKey } from "./sessionToApiKeyResolver"; import { CreateEnvironmentOptions, CreateTestTargetBody, CreateTestTargetOptions, DeleteEnvironmentOptions, DeleteTestTargetOptions, DiscoveryOptions, DiscoveryResponse, Environment, ExecuteTestsOptions, GetTestCasesOptions, GetTestReportOptions, GetTestReportsOptions, ListEnvironmentsOptions, ListPrivateLocationsOptions, Notification, notificationSchema, PatchTestCaseOptions, PrivateLocationInfo, RegisterLocationOptions, RegisterRequest, SuccessResponse, TestCaseListItem, TestReport, TestReportResponse, TestReportsResponse, TestTarget, TestTargetExecutionRequest, UnregisterLocationOptions, UnregisterRequest, UpdateEnvironmentOptions, UpdateTestCaseElementOptions, UpdateTestTargetOptions, } from "./types"; import { version } from "./version"; const BASE_URL = process.env.OCTOMIND_API_URL || "https://app.octomind.dev/api"; // Helper function for API calls export const apiCall = async <T>( method: "get" | "post" | "put" | "delete" | "patch", endpoint: string, sessionId: string | undefined, data?: unknown, ): Promise<T> => { const apiKey = await getApiKey(sessionId); try { const response = await axios({ method, url: `${BASE_URL}${endpoint}`, data, headers: { "X-API-Key": apiKey, "Content-Type": "application/json", "User-Agent": `axios 1.8.4 (Octomind MCP Server ${version})`, }, }); return response.data as T; } catch (error) { if (axios.isAxiosError(error)) { const filteredError = { ...error, config: { ...error.config, headers: { ...error.config?.headers, "X-API-Key": "<hidden>", }, transformRequest: undefined, transformResponse: undefined, transitional: undefined, adapter: undefined, }, request: { host: error.request?.host, method: error.request?.method, path: error.request?.path, }, response: { status: error.response?.status, statusText: error.response?.statusText, headers: error.response?.headers, data: error.response?.data, }, }; logger.error( { error: filteredError }, `API Error: ${filteredError.message}`, ); throw new Error( `API request failed. ${JSON.stringify(filteredError, null, 2)}`, ); } else { logger.error("Error:", error); throw error; } } }; export type TestCaseElement = { id: string; index: number; ignoreFailure: boolean; interaction: unknown; assertion: unknown; selectors: unknown[]; }; export type TestCase = { id: string; createdAt: Date; updatedAt: Date; description: string; status: string; testTargetId: string; discovery: unknown; elements: TestCaseElement[]; }; export const getTestCase = async ({ testCaseId, testTargetId, sessionId, }: { testCaseId: string; testTargetId: string; sessionId: string | undefined; }): Promise<TestCase> => { const response = await apiCall<TestCase>( "get", `/apiKey/v3/test-targets/${testTargetId}/test-cases/${testCaseId}`, sessionId, ); return response; }; export const discovery = async ( options: DiscoveryOptions, ): Promise<DiscoveryResponse> => { const requestBody = { name: options.name, prompt: options.prompt, entryPointUrlPath: options.entryPointUrlPath, prerequisiteName: options.prerequisiteName, externalId: options.externalId, tagNames: options.tagNames, folderName: options.folderName, }; const response = await apiCall<DiscoveryResponse>( "post", `/apiKey/v3/test-targets/${options.testTargetId}/discoveries`, options.sessionId, requestBody, ); return response; }; /* example notification { "id": "ee8ffcdf-1df8-4b37-b789-9694dd37e6b3", "testTargetId": "edea1e1a-5152-4c1a-ac11-8b7d0cff9a6b", "createdAt": "2025-03-06T13:23:13.205Z", "updatedAt": "2025-03-06T13:29:14.285Z", "payload": { "testCaseId": "c1ec6d3d-36e8-40eb-b77a-5c7ca4f29605" }, "type": "VALIDATION_PASSED", "ack": "IN_WEB_APP" }, */ export const getNotifications = async ({ testTargetId, sessionId, }: { testTargetId: string; sessionId: string | undefined; }): Promise<Notification[]> => { const raw = await apiCall<Notification[]>( "get", `/apiKey/v3/test-targets/${testTargetId}/notifications`, sessionId, ); const response = raw.map((n) => notificationSchema.parse(n)); return response; }; export const executeTests = async ( options: ExecuteTestsOptions, ): Promise<TestReportResponse> => { const requestBody: TestTargetExecutionRequest = { testTargetId: options.testTargetId, url: options.url, context: { source: "manual", description: options.description || "CLI execution", triggeredBy: { type: "USER", userId: "cli-user", }, }, environmentName: options.environmentName, tags: options.tags, variablesToOverwrite: options.variablesToOverwrite, }; const response = await apiCall<TestReportResponse>( "post", "/apiKey/v3/execute", options.sessionId, requestBody, ); return response; }; export const getTestReport = async ( options: GetTestReportOptions, ): Promise<TestReport> => { const response = await apiCall<TestReport>( "get", `/apiKey/v3/test-targets/${options.testTargetId}/test-reports/${options.reportId}`, options.sessionId, ); return response; }; export const registerLocation = async ( options: RegisterLocationOptions, ): Promise<SuccessResponse> => { const requestBody: RegisterRequest = { name: options.name, registrationData: { proxypass: options.proxypass, proxyuser: options.proxyuser, address: options.address, }, }; const response = await apiCall<SuccessResponse>( "put", "/apiKey/v1/private-location/register", options.sessionId, requestBody, ); return response; }; export const unregisterLocation = async ( options: UnregisterLocationOptions, ): Promise<SuccessResponse> => { const requestBody: UnregisterRequest = { name: options.name, }; const response = await apiCall<SuccessResponse>( "put", "/apiKey/v1/private-location/unregister", options.sessionId, requestBody, ); return response; }; export const listPrivateLocations = async ( options: ListPrivateLocationsOptions, ): Promise<PrivateLocationInfo[]> => { const response = await apiCall<PrivateLocationInfo[]>( "get", "/apiKey/v1/private-location", options.sessionId, ); return response; }; export const listEnvironments = async ( options: ListEnvironmentsOptions, ): Promise<Environment[]> => { const response = await apiCall<Environment[]>( "get", `/apiKey/v3/test-targets/${options.testTargetId}/environments`, options.sessionId, ); return response; }; export const createEnvironment = async ( options: CreateEnvironmentOptions, ): Promise<Environment> => { const requestBody = { name: options.name, discoveryUrl: options.discoveryUrl, testAccount: options.testAccount, basicAuth: options.basicAuth, privateLocationName: options.privateLocationName, additionalHeaderFields: options.additionalHeaderFields, }; const response = await apiCall<Environment>( "post", `/apiKey/v3/test-targets/${options.testTargetId}/environments`, options.sessionId, requestBody, ); return response; }; export const updateEnvironment = async ( options: UpdateEnvironmentOptions, ): Promise<Environment> => { const requestBody = { name: options.name, discoveryUrl: options.discoveryUrl, testAccount: options.testAccount, basicAuth: options.basicAuth, privateLocationName: options.privateLocationName, additionalHeaderFields: options.additionalHeaderFields, }; const response = await apiCall<Environment>( "patch", `/apiKey/v3/test-targets/${options.testTargetId}/environments/${options.environmentId}`, options.sessionId, requestBody, ); return response; }; export const deleteEnvironment = async ( options: DeleteEnvironmentOptions, ): Promise<SuccessResponse> => { await apiCall( "delete", `/apiKey/v3/test-targets/${options.testTargetId}/environments/${options.environmentId}`, options.sessionId, ); return { success: true }; }; export const getTestReports = async ( options: GetTestReportsOptions, ): Promise<TestReportsResponse> => { const queryParams = new URLSearchParams(); if (options.key) { queryParams.append("key", JSON.stringify(options.key)); } if (options.filter) { queryParams.append("filter", JSON.stringify(options.filter)); } const queryString = queryParams.toString(); const endpoint = `/apiKey/v3/test-targets/${options.testTargetId}/test-reports${queryString ? `?${queryString}` : ""}`; const response = await apiCall<TestReportsResponse>( "get", endpoint, options.sessionId, ); return response; }; export const listTestTargets = async ({ sessionId, }: { sessionId: string | undefined; }): Promise<TestTarget[]> => { const response = await apiCall<TestTarget[]>( "get", "/apiKey/v3/test-targets", sessionId, ); return response; }; export const createTestTarget = async ( options: CreateTestTargetOptions, ): Promise<TestTarget> => { const requestBody: CreateTestTargetBody = { testTarget: { app: options.app, discoveryUrl: options.discoveryUrl, }, }; const response = await apiCall<TestTarget>( "post", "/apiKey/v3/test-targets", options.sessionId, requestBody, ); return response; }; export const updateTestTarget = async ( options: UpdateTestTargetOptions, ): Promise<TestTarget> => { const requestBody = { app: options.app, skipAutomaticTestCreation: options.skipAutomaticTestCreation, testIdAttribute: options.testIdAttribute, testRailIntegration: options.testRailIntegration, timeoutPerStep: options.timeoutPerStep, }; const response = await apiCall<TestTarget>( "patch", `/apiKey/v3/test-targets/${options.testTargetId}`, options.sessionId, requestBody, ); return response; }; export const deleteTestTarget = async ( options: DeleteTestTargetOptions, ): Promise<SuccessResponse> => { const res = await apiCall<SuccessResponse>( "delete", `/apiKey/v3/test-targets/${options.testTargetId}`, options.sessionId, ); return res; }; export const getTestCases = async ( options: GetTestCasesOptions, ): Promise<TestCaseListItem[]> => { const queryParams = options.filter ? `?filter=${encodeURIComponent(options.filter)}` : ""; const response = await apiCall<TestCaseListItem[]>( "get", `/apiKey/v3/test-targets/${options.testTargetId}/test-cases${queryParams}`, options.sessionId, ); return response; }; export const patchTestCase = async ( options: PatchTestCaseOptions, ): Promise<TestCase> => { const requestBody = { elements: options.elements, description: options.description, entryPointUrlPath: options.entryPointUrlPath, runStatus: options.runStatus, folderName: options.folderName, interactionStatus: options.interactionStatus, createBackendDiscoveryPrompt: options.createBackendDiscoveryPrompt, assignedTagNames: options.assignedTagNames, externalId: options.externalId, }; const response = await apiCall<TestCase>( "patch", `/apiKey/v3/test-targets/${options.testTargetId}/test-cases/${options.testCaseId}`, options.sessionId, requestBody, ); return response; }; export const updateTestCaseElement = async ( options: UpdateTestCaseElementOptions, ): Promise<TestCaseElement> => { const response = await apiCall<TestCaseElement>( "patch", `/apiKey/v3/test-targets/${options.testTargetId}/test-cases/${options.testCaseId}/elements/${options.elementId}`, options.sessionId, { locatorLine: options.locatorLine }, ); return response; };

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/OctoMind-dev/octomind-mcp'

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