Skip to main content
Glama
Noveum

API-Market MCP Server

by Noveum

Get_Unblurred_Image_URL

Retrieve the URL of an unblurred image by providing the unique request ID. This tool simplifies accessing clear visuals from the API-Market MCP Server.

Instructions

This endpoint retrieves the URL of the Unblurred image for a given request ID.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
request_idYesUnique identifier for the request.

Implementation Reference

  • Generic execution handler for all dynamically generated tools. It constructs the HTTP request from the tool ID (method-path), uses input arguments as query params for GET or body for others, calls the API via axios, and returns the JSON response.
    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 specs from files listed in config.openApiSpec (default: modified_files.txt), iterates over paths and operations, generates toolId from method-cleanPath, tool name from operationId/summary/path with spaces replaced by _, generates inputSchema from parameters and requestBody, and registers the Tool in the internal tools Map.
    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 ListToolsRequestSchema handler that returns all registered tools.
    this.server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: Array.from(this.tools.values()),
      };
    });
  • The start method which calls parseOpenAPISpec() to register tools before connecting the server.
    async start(): Promise<void> {
      await this.parseOpenAPISpec();
      const transport = new StdioServerTransport();
      await this.server.connect(transport);
      console.error("OpenAPI MCP Server running on stdio");
    }
  • Code block where inputSchema for each tool is constructed from OpenAPI operation parameters and requestBody content.
      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);
          }
        }
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool retrieves a URL but does not describe key behaviors: whether this is a read-only operation, if it requires authentication, rate limits, error handling, or what happens if the request ID is invalid. For a tool with zero annotation coverage, this leaves significant gaps in understanding its operational traits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded in a single sentence that directly states the tool's purpose. There is no wasted text or redundancy. However, it could be slightly more structured by including usage hints or behavioral notes, but it efficiently conveys the core function without unnecessary elaboration.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (a retrieval operation with no output schema and no annotations), the description is incomplete. It lacks details on return values (e.g., URL format, expiration), error conditions, or dependencies on other tools. Without annotations or output schema, the description should compensate more to provide a complete understanding, but it does not.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage, with the 'request_id' parameter documented as a 'Unique identifier for the request.' The description adds no additional semantic meaning beyond this, such as format examples or constraints. With high schema coverage, the baseline score is 3, as the schema adequately handles parameter documentation without needing extra details from the description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'retrieves the URL of the Unblurred image for a given request ID.' It specifies the verb ('retrieves'), resource ('URL of the Unblurred image'), and key input ('request ID'). However, it does not explicitly differentiate from sibling tools like 'Get_ageing_gif_URL' or 'Get_audio_analysis_URL', which have similar naming patterns but different purposes, so it lacks sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It does not mention prerequisites (e.g., needing a prior request ID from another tool), exclusions, or comparisons to siblings like 'Deblurer' (which might handle image deblurring differently). Usage is implied only by the tool name and description, with no explicit context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

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

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