Skip to main content
Glama

post_workspaces__wid__profiles_transfer

Transfer browser profiles within a workspace to another user by specifying their email and instance IDs. Use this to reallocate or share profiles efficiently.

Instructions

Transfer profile

Input Schema

NameRequiredDescriptionDefault
instanceIdsYesArray of instance ids to transfer profiles to.
toEmailYesEmail of the recipient.
widYes

Input Schema (JSON Schema)

{ "properties": { "instanceIds": { "description": "Array of instance ids to transfer profiles to.", "items": { "type": "string" }, "type": "array" }, "toEmail": { "description": "Email of the recipient.", "type": "string" }, "wid": { "type": "string" } }, "required": [ "wid", "toEmail", "instanceIds" ], "type": "object" }

Implementation Reference

  • src/index.ts:47-71 (registration)
    Dynamic tool registration in the ListToolsRequestSchema handler. Loops over OpenAPI spec paths, generates tool names using `${method}${path.replace('browser', 'profile').replace(/[^a-zA-Z0-9]/g, '_')}`, which produces 'post_workspaces__wid__profiles_transfer' for POST /workspaces/{wid}/profiles/transfer.
    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 }; });
  • callDynamicTool: Executes the tool by matching toolName to OpenAPI operation (lines 468-485 reconstruct name), builds URL by interpolating path params, adds query/body, sets auth header if token provided, and fetches the API, proxying POST /workspaces/{wid}/profiles/transfer for this tool.
    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)}`); } }
  • buildInputSchema: Dynamically generates inputSchema for the tool from OpenAPI operation parameters (path/query) and requestBody, used in tool registration.
    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; }
  • extractParametersFromArgs: Parses tool call arguments into structured CallParameters (path/query/body) by matching toolName to operation and inspecting parameters schema.
    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; }
  • loadApiSpec: Fetches and parses the OpenAPI spec from 'https://docs-download.gologin.com/openapi-test.json', which contains the definition for /workspaces/{wid}/profiles/transfer endpoint.
    private async loadApiSpec(): Promise<void> { const url = 'https://docs-download.gologin.com/openapi-test.json'; console.log('url', url); const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const contentType = response.headers.get('content-type') || ''; let spec: any; if (contentType.includes('application/json')) { spec = await response.json(); } else { const text = await response.text(); try { spec = JSON.parse(text); } catch { spec = yaml.load(text); } } // console.log('spec', spec); this.apiSpec = spec; this.baseUrl = this.getBaseUrl(spec); }

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