Skip to main content
Glama

post_profile_clone_multi

Clone multiple browser profiles into a specified folder using the GoLogin MCP server. Simplify profile management by duplicating multiple IDs simultaneously.

Instructions

Clone multiple profiles

Input Schema

NameRequiredDescriptionDefault
browsersIdsYesArray of browser IDs to clone.
folderNameNoFolder name to clone profiles to.

Input Schema (JSON Schema)

{ "properties": { "browsersIds": { "description": "Array of browser IDs to clone.", "items": { "type": "string" }, "type": "array" }, "folderName": { "description": "Folder name to clone profiles to.", "type": "string" } }, "required": [ "browsersIds" ], "type": "object" }

Implementation Reference

  • Dynamic handler that implements the 'post_profile_clone_multi' tool by matching the tool name to the corresponding OpenAPI POST /profile/clone/multi (or similar) endpoint, extracting parameters, building the request URL, and executing an HTTP POST request via fetch to the GoLogin API server.
    private async callDynamicTool( toolName: string, parameters: CallParameters = {}, headers: Record<string, string> = {} ): Promise<CallToolResult> { console.log('parameters', parameters.body); if (!this.apiSpec || !this.apiSpec.paths) { throw new Error('API specification not loaded'); } let targetPath = ''; let targetMethod = ''; let operation: OpenAPIV3.OperationObject | undefined; for (const [path, pathItem] of Object.entries(this.apiSpec.paths)) { if (!pathItem) continue; for (const [method, op] of Object.entries(pathItem)) { if (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'].includes(method) && op) { const opObj = op as OpenAPIV3.OperationObject; const generatedToolName = `${method}${path.replace('browser', 'profile').replace(/[^a-zA-Z0-9]/g, '_')}`; if (generatedToolName === toolName) { targetPath = path; targetMethod = method.toUpperCase(); operation = opObj; break; } } } if (operation) break; } if (!operation) { throw new Error(`Tool "${toolName}" not found`); } let url = `${this.baseUrl}${targetPath}`; const requestHeaders: Record<string, string> = { ...headers }; let requestBody: string | undefined; requestHeaders['User-Agent'] = 'gologin-mcp'; console.error('this.token', this.token); if (this.token) { requestHeaders['Authorization'] = `Bearer ${this.token}`; } if (parameters.path) { for (const [key, value] of Object.entries(parameters.path)) { url = url.replace(`{${key}}`, encodeURIComponent(value)); } } const queryParams = new URLSearchParams(); if (parameters.query) { for (const [key, value] of Object.entries(parameters.query)) { if (value) { queryParams.append(key, value); } } } if (queryParams.toString()) { url += `?${queryParams.toString()}`; } if (parameters.body && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(targetMethod)) { requestHeaders['Content-Type'] = 'application/json'; requestBody = JSON.stringify(parameters.body); } console.log('requestBody', requestBody); try { const fetchOptions: RequestInit = { method: targetMethod, headers: requestHeaders, }; console.error('fetchOptions', fetchOptions); if (requestBody) { fetchOptions.body = requestBody; } const response = await fetch(url, fetchOptions); const responseHeaders: Record<string, string> = {}; response.headers.forEach((value, key) => { responseHeaders[key] = value; }); let responseBody: any; const contentType = response.headers.get('content-type') || ''; if (contentType.includes('application/json')) { try { responseBody = await response.json(); } catch { responseBody = await response.text(); } } else { responseBody = await response.text(); } return { content: [ { type: 'text', text: `API Call Result:\n` + `URL: ${url}\n` + `Method: ${targetMethod}\n` + `Status: ${response.status} ${response.statusText}\n\n` + `Response Headers:\n${JSON.stringify(responseHeaders, null, 2)}\n\n` + `Response Body:\n${typeof responseBody === 'object' ? JSON.stringify(responseBody, null, 2) : responseBody}`, }, ], }; } catch (error) { throw new Error(`API call failed: ${error instanceof Error ? error.message : String(error)}`); } }
  • src/index.ts:47-72 (registration)
    Registers 'post_profile_clone_multi' dynamically in the MCP tools list by generating tool names from OpenAPI spec paths (key line 56 generates the exact name for /profile/clone/multi endpoints).
    this.server.setRequestHandler(ListToolsRequestSchema, async () => { const tools: Tool[] = []; if (this.apiSpec && this.apiSpec.paths) { for (const [path, pathItem] of Object.entries(this.apiSpec.paths)) { if (!pathItem) continue; for (const [method, operation] of Object.entries(pathItem)) { if (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'].includes(method) && operation) { const op = operation as OpenAPIV3.OperationObject; const toolName = `${method}${path.replace('browser', 'profile').replace(/[^a-zA-Z0-9]/g, '_')}`; const inputSchema = this.buildInputSchema(op, path); tools.push({ name: toolName, description: op.summary || op.description || `${method.toUpperCase()} ${path}`, inputSchema, }); } } } } return { tools }; });
  • Builds the input schema (JSON Schema) for the 'post_profile_clone_multi' tool based on the OpenAPI operation's parameters, path params from path pattern, query params, and requestBody.
    private buildInputSchema(operation: OpenAPIV3.OperationObject, path: string): any { const properties: any = {}; const required: string[] = []; const pathParams = this.extractPathParameters(operation, path); const queryParams = this.extractQueryParameters(operation); const bodySchema = this.extractRequestBodySchema(operation); if (pathParams.properties && Object.keys(pathParams.properties).length > 0) { for (const [key, prop] of Object.entries(pathParams.properties)) { properties[key] = this.convertOpenAPISchemaToJsonSchema(prop as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject); if (pathParams.required.includes(key)) { required.push(key); } } } if (queryParams.properties && Object.keys(queryParams.properties).length > 0) { for (const [key, prop] of Object.entries(queryParams.properties)) { properties[key] = this.convertOpenAPISchemaToJsonSchema(prop as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject); if (queryParams.required.includes(key)) { required.push(key); } } } if (bodySchema && bodySchema.properties) { for (const [key, prop] of Object.entries(bodySchema.properties)) { properties[key] = this.convertOpenAPISchemaToJsonSchema(prop as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject); if (bodySchema.required && bodySchema.required.includes(key)) { required.push(key); } } } const schema: any = { type: 'object', properties, }; if (required.length > 0) { schema.required = required; } return schema; }
  • src/index.ts:73-93 (registration)
    Registers the general call tool handler which dispatches to specific tool execution, including for 'post_profile_clone_multi'.
    this.server.setRequestHandler(CallToolRequestSchema, async (request: any): Promise<CallToolResult> => { const { name, arguments: args } = request.params; if (!args) { throw new Error('No arguments provided'); } console.log('args', args); try { const parameters: CallParameters = this.extractParametersFromArgs(name, args); return await this.callDynamicTool(name, parameters, args.headers as Record<string, string> | undefined); } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } });
  • Helper that parses tool arguments into path/query/body params by resolving the toolName 'post_profile_clone_multi' to the matching OpenAPI operation.
    private extractParametersFromArgs(toolName: string, args: Record<string, any>): CallParameters { if (!this.apiSpec || !this.apiSpec.paths) { return { body: args }; } let operation: OpenAPIV3.OperationObject | undefined; let path = ''; for (const [apiPath, pathItem] of Object.entries(this.apiSpec.paths)) { if (!pathItem) continue; for (const [method, op] of Object.entries(pathItem)) { if (['get', 'post', 'put', 'delete', 'patch', 'head', 'options'].includes(method) && op) { const opObj = op as OpenAPIV3.OperationObject; const generatedToolName = opObj.operationId || `${method}_${apiPath.replace(/[^a-zA-Z0-9]/g, '_')}`; if (generatedToolName === toolName) { operation = opObj; path = apiPath; break; } } } if (operation) break; } if (!operation) { return { body: args }; } const pathParams: Record<string, string> = {}; const queryParams: Record<string, string> = {}; const bodyParams: any = {}; const pathParamNames = path.match(/\{([^}]+)\}/g)?.map(p => p.slice(1, -1)) || []; if (operation.parameters) { operation.parameters.forEach(param => { if ('$ref' in param) return; const parameter = param as OpenAPIV3.ParameterObject; const paramName = parameter.name; if (parameter.in === 'path' && args[paramName] !== undefined) { pathParams[paramName] = String(args[paramName]); } else if (parameter.in === 'query' && args[paramName] !== undefined) { queryParams[paramName] = String(args[paramName]); } }); } pathParamNames.forEach(paramName => { if (args[paramName] !== undefined && !pathParams[paramName]) { pathParams[paramName] = String(args[paramName]); } }); const usedParams = new Set([...Object.keys(pathParams), ...Object.keys(queryParams)]); for (const [key, value] of Object.entries(args)) { if (!usedParams.has(key)) { bodyParams[key] = value; } } const parameters: CallParameters = {}; if (Object.keys(pathParams).length > 0) { parameters.path = pathParams; } if (Object.keys(queryParams).length > 0) { parameters.query = queryParams; } if (Object.keys(bodyParams).length > 0) { parameters.body = bodyParams; } return parameters; }

Other Tools

Related Tools

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/gologinapp/gologin-mcp'

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