Skip to main content
Glama

OpenAI Web Search MCP Server

by tiovikram
index.ts21.8 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, Tool, } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; import { v4 as uuidv4 } from "uuid"; // Define the version const VERSION = "1.0.0"; // Validation schemas for the API endpoints // Start Automation const StartAutomationSchema = z.object({ user_id: z.string().describe("The ID for the user initiating the flow"), saved_item_id: z.string().describe("The ID for the saved flow"), project_id: z .string() .optional() .describe("The ID of the project within which the flow is executed"), pipeline_inputs: z .array( z.object({ input_name: z .string() .describe("The 'input_name' parameter from your Input node"), value: z .string() .describe("The value to be passed in to the Input node"), }), ) .optional() .describe("A list of inputs for the flow, containing key-value pairs"), }); // Retrieve Run Details const RetrieveRunDetailsSchema = z .object({ run_id: z.string().describe("ID of the flow run to retrieve"), user_id: z .string() .optional() .describe( "The ID for the user initiating the flow. Required if project_id is not provided", ), project_id: z .string() .optional() .describe( "The ID of the project within which the flow is executed. Required if user_id is not provided", ), }) .refine((data) => data.user_id || data.project_id, { message: "Either user_id or project_id is required", }); // List Saved Flows const ListSavedFlowsSchema = z .object({ user_id: z .string() .optional() .describe( "The user ID for which to list items. Required if project_id is not provided", ), project_id: z .string() .optional() .describe( "The project ID for which to list items. Required if user_id is not provided", ), }) .refine((data) => data.user_id || data.project_id, { message: "Either user_id or project_id is required", }); // List Workbooks and Their Saved Flows const ListWorkbooksSchema = z .object({ user_id: z .string() .optional() .describe( "The user ID for which to list workbooks. Required if project_id is not provided", ), project_id: z .string() .optional() .describe( "The project ID for which to list workbooks. Required if user_id is not provided", ), }) .refine((data) => data.user_id || data.project_id, { message: "Either user_id or project_id is required", }); // Retrieve Input Schema const RetrieveInputSchemaSchema = z .object({ saved_item_id: z .string() .describe("The ID of the saved item for which to retrieve input schemas"), user_id: z .string() .optional() .describe( "User ID that created the flow. Required if project_id is not provided", ), project_id: z .string() .optional() .describe( "Project ID that the flow is under. Required if user_id is not provided", ), }) .refine((data) => data.user_id || data.project_id, { message: "Either user_id or project_id is required", }); // Upload File const UploadFileSchema = z .object({ file_name: z.string().describe("The name of the file to be uploaded"), file_content: z.string().describe("Base64 encoded content of the file"), user_id: z .string() .optional() .describe( "The user ID associated with the file. Required if project_id is not provided", ), project_id: z .string() .optional() .describe( "The project ID associated with the file. Required if user_id is not provided", ), }) .refine((data) => data.user_id || data.project_id, { message: "Either user_id or project_id is required", }); // Upload Multiple Files const UploadMultipleFilesSchema = z .object({ files: z .array( z.object({ file_name: z.string().describe("The name of the file to be uploaded"), file_content: z .string() .describe("Base64 encoded content of the file"), }), ) .describe("Array of file objects to upload"), user_id: z .string() .optional() .describe( "The user ID associated with the files. Required if project_id is not provided", ), project_id: z .string() .optional() .describe( "The project ID associated with the files. Required if user_id is not provided", ), }) .refine((data) => data.user_id || data.project_id, { message: "Either user_id or project_id is required", }); // Download File const DownloadFileSchema = z.object({ file_name: z.string().describe("The name of the file to download"), run_id: z .string() .describe("The ID of the flow run associated with the file"), saved_item_id: z .string() .describe("The saved item ID associated with the file"), user_id: z .string() .optional() .describe("The user ID associated with the flow run"), project_id: z .string() .optional() .describe("The project ID associated with the flow run"), }); // Download Multiple Files const DownloadMultipleFilesSchema = z .object({ file_names: z .array(z.string()) .describe("An array of file names to download"), run_id: z .string() .describe("The ID of the flow run associated with the files"), user_id: z .string() .optional() .describe( "The user ID associated with the files. Required if project_id is not provided", ), project_id: z .string() .optional() .describe( "The project ID associated with the files. Required if user_id is not provided", ), saved_item_id: z .string() .optional() .describe("The saved item ID associated with the files"), }) .refine((data) => data.user_id || data.project_id, { message: "Either user_id or project_id is required", }); // API client class to handle requests class GumloopAPI { private baseUrl = "https://api.gumloop.com/api/v1"; private apiKey: string; constructor() { const apiKey = process.env.GUMLOOP_API_KEY; if (!apiKey) { throw new Error("GUMLOOP_API_KEY environment variable is required"); } this.apiKey = apiKey; } private async makeRequest( endpoint: string, method: "GET" | "POST", data?: unknown, ) { const headers = { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json", }; const options: RequestInit = { method, headers, }; let url = this.baseUrl + endpoint; if (method === "GET" && data) { // For GET requests, append query parameters const queryParams = new URLSearchParams(); for (const [key, value] of Object.entries(data as Record<string, any>)) { if (value !== undefined && value !== null) { queryParams.append(key, String(value)); } } const queryString = queryParams.toString(); if (queryString) { url += "?" + queryString; } } else if (data) { options.body = JSON.stringify(data); } const response = await fetch(url, options); if (!response.ok) { throw new Error( `Gumloop API request failed: ${response.status} - ${response.statusText}`, ); } const contentType = response.headers.get("content-type"); if (contentType && contentType.includes("application/json")) { return response.json(); } else { return response.arrayBuffer(); // For file downloads } } // Start Automation async startAutomation(params: z.infer<typeof StartAutomationSchema>) { return this.makeRequest("/start_pipeline", "POST", params); } // Retrieve Run Details async retrieveRunDetails(params: z.infer<typeof RetrieveRunDetailsSchema>) { return this.makeRequest("/get_pl_run", "GET", params); } // List Saved Flows async listSavedFlows(params: z.infer<typeof ListSavedFlowsSchema>) { return this.makeRequest("/list_saved_items", "GET", params); } // List Workbooks and Their Saved Flows async listWorkbooks(params: z.infer<typeof ListWorkbooksSchema>) { return this.makeRequest("/list_workbooks", "GET", params); } // Retrieve Input Schema async retrieveInputSchema(params: z.infer<typeof RetrieveInputSchemaSchema>) { return this.makeRequest("/get_inputs", "GET", params); } // Upload File async uploadFile(params: z.infer<typeof UploadFileSchema>) { return this.makeRequest("/upload_file", "POST", params); } // Upload Multiple Files async uploadMultipleFiles(params: z.infer<typeof UploadMultipleFilesSchema>) { return this.makeRequest("/upload_files", "POST", params); } // Download File async downloadFile(params: z.infer<typeof DownloadFileSchema>) { return this.makeRequest("/download_file", "POST", params); } // Download Multiple Files async downloadMultipleFiles( params: z.infer<typeof DownloadMultipleFilesSchema>, ) { return this.makeRequest("/download_files", "POST", params); } } // Define tools const TOOLS: Record<string, Tool> = { startAutomation: { name: "startAutomation", description: "Initiates a new flow run for a specific saved automation", inputSchema: { type: "object", properties: { user_id: { type: "string", description: "The ID for the user initiating the flow", }, saved_item_id: { type: "string", description: "The ID for the saved flow", }, project_id: { type: "string", description: "The ID of the project within which the flow is executed", }, pipeline_inputs: { type: "array", items: { type: "object", properties: { input_name: { type: "string", description: "The 'input_name' parameter from your Input node", }, value: { type: "string", description: "The value to be passed in to the Input node", }, }, required: ["input_name", "value"], }, description: "A list of inputs for the flow, containing key-value pairs", }, }, required: ["user_id", "saved_item_id"], }, }, retrieveRunDetails: { name: "retrieveRunDetails", description: "Retrieves details about a specific flow run", inputSchema: { type: "object", properties: { run_id: { type: "string", description: "ID of the flow run to retrieve", }, user_id: { type: "string", description: "The ID for the user initiating the flow", }, project_id: { type: "string", description: "The ID of the project within which the flow is executed", }, }, required: ["run_id"], }, }, listSavedFlows: { name: "listSavedFlows", description: "Retrieves a list of all saved flows for a user or project", inputSchema: { type: "object", properties: { user_id: { type: "string", description: "The user ID to for which to list items", }, project_id: { type: "string", description: "The project ID for which to list items", }, }, }, }, listWorkbooks: { name: "listWorkbooks", description: "Retrieves a list of all workbooks and their associated saved flows for a user or project", inputSchema: { type: "object", properties: { user_id: { type: "string", description: "The user ID for which to list workbooks", }, project_id: { type: "string", description: "The project ID for which to list workbooks", }, }, }, }, retrieveInputSchema: { name: "retrieveInputSchema", description: "Retrieves the input schema for a specific saved flow", inputSchema: { type: "object", properties: { saved_item_id: { type: "string", description: "The ID of the saved item for which to retrieve input schemas", }, user_id: { type: "string", description: "User ID that created the flow", }, project_id: { type: "string", description: "Project ID that the flow is under", }, }, required: ["saved_item_id"], }, }, uploadFile: { name: "uploadFile", description: "Uploads a single file to the Gumloop platform", inputSchema: { type: "object", properties: { file_name: { type: "string", description: "The name of the file to be uploaded", }, file_content: { type: "string", description: "Base64 encoded content of the file", }, user_id: { type: "string", description: "The user ID associated with the file", }, project_id: { type: "string", description: "The project ID associated with the file", }, }, required: ["file_name", "file_content"], }, }, uploadMultipleFiles: { name: "uploadMultipleFiles", description: "Uploads multiple files to the Gumloop platform in a single request", inputSchema: { type: "object", properties: { files: { type: "array", items: { type: "object", properties: { file_name: { type: "string", description: "The name of the file to be uploaded", }, file_content: { type: "string", description: "Base64 encoded content of the file", }, }, required: ["file_name", "file_content"], }, description: "Array of file objects to upload", }, user_id: { type: "string", description: "The user ID associated with the files", }, project_id: { type: "string", description: "The project ID associated with the files", }, }, required: ["files"], }, }, downloadFile: { name: "downloadFile", description: "Downloads a specific file from the Gumloop platform", inputSchema: { type: "object", properties: { file_name: { type: "string", description: "The name of the file to download", }, run_id: { type: "string", description: "The ID of the flow run associated with the file", }, saved_item_id: { type: "string", description: "The saved item ID associated with the file", }, user_id: { type: "string", description: "The user ID associated with the flow run", }, project_id: { type: "string", description: "The project ID associated with the flow run", }, }, required: ["file_name", "run_id", "saved_item_id"], }, }, downloadMultipleFiles: { name: "downloadMultipleFiles", description: "Downloads multiple files from the Gumloop platform as a zip archive", inputSchema: { type: "object", properties: { file_names: { type: "array", items: { type: "string" }, description: "An array of file names to download", }, run_id: { type: "string", description: "The ID of the flow run associated with the files", }, user_id: { type: "string", description: "The user ID associated with the files", }, project_id: { type: "string", description: "The project ID associated with the files", }, saved_item_id: { type: "string", description: "The saved item ID associated with the files", }, }, required: ["file_names", "run_id"], }, }, }; // Create and configure the MCP server async function main() { const api = new GumloopAPI(); const server = new Server( { name: "gumloop-mcp-server", version: VERSION, }, { capabilities: { tools: {}, }, }, ); // Register tool list handler server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: Object.values(TOOLS), })); // Register tool call handler server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const args = request.params.arguments as Record<string, unknown>; switch (request.params.name) { case "startAutomation": { const validatedArgs = StartAutomationSchema.parse(args); const result = await api.startAutomation(validatedArgs); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "retrieveRunDetails": { const validatedArgs = RetrieveRunDetailsSchema.parse(args); const result = await api.retrieveRunDetails(validatedArgs); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "listSavedFlows": { const validatedArgs = ListSavedFlowsSchema.parse(args); const result = await api.listSavedFlows(validatedArgs); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "listWorkbooks": { const validatedArgs = ListWorkbooksSchema.parse(args); const result = await api.listWorkbooks(validatedArgs); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "retrieveInputSchema": { const validatedArgs = RetrieveInputSchemaSchema.parse(args); const result = await api.retrieveInputSchema(validatedArgs); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "uploadFile": { const validatedArgs = UploadFileSchema.parse(args); const result = await api.uploadFile(validatedArgs); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "uploadMultipleFiles": { const validatedArgs = UploadMultipleFilesSchema.parse(args); const result = await api.uploadMultipleFiles(validatedArgs); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "downloadFile": { const validatedArgs = DownloadFileSchema.parse(args); const result = await api.downloadFile(validatedArgs); // For file downloads, we need to handle binary data differently // In a real implementation, you might want to encode this as base64 or handle it another way return { content: [ { type: "text", text: "File downloaded successfully. Binary data is available but not displayed here.", }, ], }; } case "downloadMultipleFiles": { const validatedArgs = DownloadMultipleFilesSchema.parse(args); const result = await api.downloadMultipleFiles(validatedArgs); // For file downloads, we need to handle binary data differently return { content: [ { type: "text", text: "Files downloaded successfully as a zip archive. Binary data is available but not displayed here.", }, ], }; } default: return { content: [ { type: "text", text: `Unknown tool: ${request.params.name}`, }, ], isError: true, }; } } catch (error) { return { content: [ { type: "text", text: `API error: ${error instanceof Error ? error.message : "Unknown error"}`, }, ], isError: true, }; } }); // Start the server const transport = new StdioServerTransport(); try { await server.connect(transport); } catch (error) { if (error instanceof Error) { console.error("Failed to start server:", error.message); } else { console.error("Failed to start server with unknown error"); } process.exit(1); } } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

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/tiovikram/gumloop-mcp'

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