Skip to main content
Glama
Noveum
by Noveum

getWhoisInfo

Retrieve WHOIS information for any domain by making a GET request, providing detailed domain registration and ownership data for analysis or verification.

Instructions

Make a GET request to magicapi/whois/whois/{domain}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
domainYesDomain to query WHOIS information for

Implementation Reference

  • This is the execution handler for all MCP tools, including "getWhoisInfo". It finds the tool by name or ID, reconstructs the HTTP method and path from the tool ID, builds the request using axios, handles GET params and POST body, and returns the API response as text content.
    // Handle tool execution this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { id, name, arguments: params } = request.params; console.error("Received request:", request.params); console.error("Using parameters from arguments:", params); // Find tool by ID or name let tool: Tool | undefined; let toolId: string | undefined; if (id) { toolId = id.trim(); tool = this.tools.get(toolId); } else if (name) { // Search for tool by name for (const [tid, t] of this.tools.entries()) { if (t.name === name) { tool = t; toolId = tid; break; } } } if (!tool || !toolId) { console.error( `Available tools: ${Array.from(this.tools.entries()) .map(([id, t]) => `${id} (${t.name})`) .join(", ")}`, ); throw new Error(`Tool not found: ${id || name}`); } console.error(`Executing tool: ${toolId} (${tool.name})`); try { // Extract method and path from tool ID const [method, ...pathParts] = toolId.split("-"); let path = "/" + pathParts.join("/") .replace(/-/g, "/") .replaceAll('!', "-"); // Ensure base URL ends with slash for proper joining const baseUrl = this.config.apiBaseUrl.endsWith("/") ? this.config.apiBaseUrl : `${this.config.apiBaseUrl}/`; // Remove leading slash from path to avoid double slashes const cleanPath = path.startsWith("/") ? path.slice(1) : path; let url; try { // Validate that the path results in a valid URL // Construct the full URL url = new URL(cleanPath, baseUrl).toString(); } catch (error) { throw new Error(`Invalid path generated from tool ID ${toolId}: ${error.message}`); } // Prepare request configuration this.config.headers = this.config.headers || {}; const contentType = this.headers.get(toolId); if (contentType) { this.config.headers['Content-Type'] = contentType; } const config: any = { method: method.toLowerCase(), url: url, headers: this.config.headers, }; // Handle different parameter types based on HTTP method if (method.toLowerCase() === "get") { // For GET requests, ensure parameters are properly structured if (params && typeof params === "object") { // Handle array parameters properly const queryParams: Record<string, string> = {}; for (const [key, value] of Object.entries(params)) { if (Array.isArray(value)) { // Join array values with commas for query params queryParams[key] = value.join(","); } else if (value !== undefined && value !== null) { // Convert other values to strings queryParams[key] = String(value); } } config.params = queryParams; } } else { // For POST, PUT, PATCH - send as body config.data = params; } console.error("Final request config:", config); try { const response = await axios(config); return { content: [{ type: "text", text: JSON.stringify(response.data, null, 2) }] }; } catch (error) { if (axios.isAxiosError(error)) { console.error("Request failed:", { status: error.response?.status, statusText: error.response?.statusText, data: error.response?.data, headers: error.response?.headers, }); throw new Error( `API request failed: ${error.message} - ${JSON.stringify(error.response?.data)}`, ); } throw error; } } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`API request failed: ${error.message}`); } throw error; } });
  • Parses OpenAPI specifications from files listed in config.openApiSpec (modified_files.txt), generates MCP Tool objects (including schema from params/body) for each HTTP operation, computes tool name from operationId/summary, toolId from method-path, and registers them in the internal tools Map used by the handler.
    private async parseOpenAPISpec(): Promise<void> { const paths = await this.listOfFilePaths() for (const cur_path of paths) { if (!cur_path || cur_path.trim() === '') { console.error('Skipping empty path'); continue; } try { const spec = await this.loadOpenAPISpec(path.resolve(__dirname, cur_path)); // Convert each OpenAPI path to an MCP tool for (const [path, pathItem] of Object.entries(spec.paths)) { if (!pathItem) continue; for (const [method, operation] of Object.entries(pathItem)) { if (method === "parameters" || !operation) continue; const op = operation as OpenAPIV3.OperationObject; // Create a clean tool ID by removing the leading slash and replacing special chars const cleanPath = path.replace(/^\//, ""); const toolId = `${method.toUpperCase()}-${cleanPath}`.replace( /[^a-zA-Z0-9-_]/g, "-", ); const tool: Tool = { name: (op.operationId || op.summary || `${method.toUpperCase()} ${path}`).replace(/\s+/g, "_"), description: op.description || `Make a ${method.toUpperCase()} request to ${path}`, inputSchema: { type: "object", properties: {}, // Add any additional properties from OpenAPI spec }, }; // Add parameters from operation if (op.parameters) { for (const param of op.parameters) { if ("name" in param && "in" in param) { const paramSchema = param.schema as OpenAPIV3.SchemaObject; tool.inputSchema.properties[param.name] = { type: paramSchema.type || "string", description: param.description || `${param.name} parameter`, }; if (param.required) { tool.inputSchema.required = tool.inputSchema.required || []; tool.inputSchema.required.push(param.name); } } } } // Add request body if present (for POST, PUT, etc.) if (op.requestBody) { const requestBody = op.requestBody as OpenAPIV3.RequestBodyObject; const content = requestBody.content; // Usually we'd look for application/json content type if (content?.['application/json']) { this.headers.set(toolId, 'application/json'); const jsonSchema = content['application/json'].schema as OpenAPIV3.SchemaObject; // If it's a reference, we'd need to resolve it // For simplicity, assuming it's an inline schema if (jsonSchema.properties) { // Add all properties from the request body schema for (const [propName, propSchema] of Object.entries(jsonSchema.properties)) { tool.inputSchema.properties[propName] = propSchema; } // Add required properties if defined if (jsonSchema.required) { tool.inputSchema.required = tool.inputSchema.required || []; tool.inputSchema.required.push(...jsonSchema.required); } } } else if (content?.['application/x-www-form-urlencoded']) { this.headers.set(toolId, 'application/x-www-form-urlencoded'); const urlencodedSchema = content['application/x-www-form-urlencoded'].schema as OpenAPIV3.SchemaObject; if (urlencodedSchema.properties) { for (const [propName, propSchema] of Object.entries(urlencodedSchema.properties)) { tool.inputSchema.properties[propName] = propSchema; } if (urlencodedSchema.required) { tool.inputSchema.required = tool.inputSchema.required || []; tool.inputSchema.required.push(...urlencodedSchema.required); } } } } this.tools.set(toolId, tool); } } } catch (error) { console.error(`Error parsing OpenAPI spec from ${cur_path}:`, error); } } }
  • Registers the listTools request handler that returns all registered tools, including getWhoisInfo.
    // Handle tool listing this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: Array.from(this.tools.values()), }; });
  • Internal storage for Tool objects which include inputSchema for validation.
    private tools: Map<string, Tool> = new Map(); private headers: Map<string, string> = new Map(); constructor(config: APIMarketMCPServerConfig) { this.config = config; this.server = new Server({ name: config.name, version: config.version, }); this.initializeHandlers(); } private async loadOpenAPISpec(file_path: string): Promise<OpenAPIV3.Document> { if (typeof file_path === "string") { if (file_path.startsWith("http")) { // Load from URL const response = await axios.get(file_path); return response.data as OpenAPIV3.Document; } else { // Load from local file const content = await readFile(file_path, "utf-8"); return JSON.parse(content) as OpenAPIV3.Document; } } if (typeof file_path === "object" && file_path !== null) { return file_path as OpenAPIV3.Document; } throw new Error("Invalid OpenAPI specification format"); } private async listOfFilePaths(): Promise<string[]> { const lines = []; try { const fileStream = fs.createReadStream(this.config.openApiSpec); const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity }); for await (const line of rl) { lines.push(line); } return lines; // Return the array of lines } catch (error) { console.error(`Error reading file paths from ${this.config.openApiSpec}:`, error); throw new Error(`Failed to read API specifications list: ${error.message}`); } } private async parseOpenAPISpec(): Promise<void> { const paths = await this.listOfFilePaths() for (const cur_path of paths) { if (!cur_path || cur_path.trim() === '') { console.error('Skipping empty path'); continue; } try { const spec = await this.loadOpenAPISpec(path.resolve(__dirname, cur_path)); // Convert each OpenAPI path to an MCP tool for (const [path, pathItem] of Object.entries(spec.paths)) { if (!pathItem) continue; for (const [method, operation] of Object.entries(pathItem)) { if (method === "parameters" || !operation) continue; const op = operation as OpenAPIV3.OperationObject; // Create a clean tool ID by removing the leading slash and replacing special chars const cleanPath = path.replace(/^\//, ""); const toolId = `${method.toUpperCase()}-${cleanPath}`.replace( /[^a-zA-Z0-9-_]/g, "-", ); const tool: Tool = { name: (op.operationId || op.summary || `${method.toUpperCase()} ${path}`).replace(/\s+/g, "_"), description: op.description || `Make a ${method.toUpperCase()} request to ${path}`, inputSchema: { type: "object", properties: {}, // Add any additional properties from OpenAPI spec }, }; // Add parameters from operation if (op.parameters) { for (const param of op.parameters) { if ("name" in param && "in" in param) { const paramSchema = param.schema as OpenAPIV3.SchemaObject; tool.inputSchema.properties[param.name] = { type: paramSchema.type || "string", description: param.description || `${param.name} parameter`, }; if (param.required) { tool.inputSchema.required = tool.inputSchema.required || []; tool.inputSchema.required.push(param.name); } } } } // Add request body if present (for POST, PUT, etc.) if (op.requestBody) { const requestBody = op.requestBody as OpenAPIV3.RequestBodyObject; const content = requestBody.content; // Usually we'd look for application/json content type if (content?.['application/json']) { this.headers.set(toolId, 'application/json'); const jsonSchema = content['application/json'].schema as OpenAPIV3.SchemaObject; // If it's a reference, we'd need to resolve it // For simplicity, assuming it's an inline schema if (jsonSchema.properties) { // Add all properties from the request body schema for (const [propName, propSchema] of Object.entries(jsonSchema.properties)) { tool.inputSchema.properties[propName] = propSchema; } // Add required properties if defined if (jsonSchema.required) { tool.inputSchema.required = tool.inputSchema.required || []; tool.inputSchema.required.push(...jsonSchema.required); } } } else if (content?.['application/x-www-form-urlencoded']) { this.headers.set(toolId, 'application/x-www-form-urlencoded'); const urlencodedSchema = content['application/x-www-form-urlencoded'].schema as OpenAPIV3.SchemaObject; if (urlencodedSchema.properties) { for (const [propName, propSchema] of Object.entries(urlencodedSchema.properties)) { tool.inputSchema.properties[propName] = propSchema; } if (urlencodedSchema.required) { tool.inputSchema.required = tool.inputSchema.required || []; tool.inputSchema.required.push(...urlencodedSchema.required); } } } } this.tools.set(toolId, tool); } } } catch (error) { console.error(`Error parsing OpenAPI spec from ${cur_path}:`, error); } } } private initializeHandlers(): void { // Handle tool listing this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: Array.from(this.tools.values()), }; });

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/Noveum/api-market-mcp-server'

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