Skip to main content
Glama
Noveum

API-Market MCP Server

by Noveum

text-to-image

Generate high-quality images from text prompts using customizable parameters like dimensions, scheduler, and output count via API-Market MCP Server's POST request.

Instructions

Make a POST request to bridgeml/text!to!image/text_to_image

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
guidance_scaleNoThe guidance scale
heightYesThe height of the image
negative_promptNoThe negative promptworst quality, low quality
num_inference_stepsNoThe number of inference steps
num_outputsNoThe number of outputs
promptYesThe prompt for generating the imageFuturistic space battle, hyper realistic, 4k
schedulerNoThe scheduler to useK_EULER
widthYesThe width of the image

Implementation Reference

  • The MCP tool execution handler. For 'text-to-image', it derives the HTTP endpoint from the tool ID (e.g., POST-text-to-image), constructs the request using input arguments as params or body, calls the API, and returns the JSON response as text content.
    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;
      }
    });
  • Dynamic registration of all MCP tools (including 'text-to-image') from OpenAPI specs listed in modified_files.txt. Tool names like 'text-to-image' come from operation summary after shortening by helper scripts.
    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);
        }
      }
    }
  • Dynamic input schema construction for tools from OpenAPI operation parameters and requestBody, defining the expected inputs for 'text-to-image' tool.
    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);
          }
        }
      }
    }
  • Preprocessing helper that shortens verbose OpenAPI operation summaries to concise names like 'text-to-image', ensuring MCP tool names are short and valid.
    summaries = ["A fast text-to-image model that makes high-quality images in 4 steps", "Finding the best route and get multiple stops driving directions", "Finding the best route between an origin and a destination", "Calculate distances and durations between a set of origins and destinations."]
    shortened_summaries = ["text-to-image", "best route for multiple stops", "best route bw start and stop", "distance and duration bw starts and stops"]
    if current_summary in summaries:
        index = summaries.index(current_summary)
        current_summary = shortened_summaries[index]
        print(current_summary)
        return current_summary
  • Example in LLM-based summary shortener referencing the same text-to-image model description used for tool naming.
    Bad example: 'iCanSee' for 'A fast text-to-image model that makes high-quality images in 4 steps'
Behavior1/5

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

No annotations are provided, so the description must fully disclose behavioral traits, but it only states a technical request without explaining that this is a generative AI tool, its potential costs, rate limits, or output format. It fails to describe key behaviors like image generation, making it inadequate for a tool with no annotation support.

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

Conciseness2/5

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

The description is a single, overly technical sentence that under-specifies the tool's purpose rather than being concise. It wastes space on implementation details ('POST request to bridgeml/text!to!image/text_to_image') without front-loading useful information for an AI agent.

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 (8 parameters, no output schema, no annotations), the description is incomplete. It lacks explanation of what the tool does, when to use it, behavioral traits, and output expectations, making it insufficient for effective agent use despite good schema coverage.

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?

Schema description coverage is 100%, providing detailed parameter documentation, so the baseline is 3. The description adds no additional meaning beyond the schema, as it doesn't explain parameter interactions or usage context, but the schema adequately covers semantics.

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

Purpose2/5

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

The description 'Make a POST request to bridgeml/text!to!image/text_to_image' is a tautology that restates the tool name 'text-to-image' in a technical format without explaining what the tool actually does. It doesn't specify that this generates images from text prompts or distinguish it from other image-related tools like 'Get_hairstyled_image_URL' or 'ImageFaceSwap' among the siblings.

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

Usage Guidelines1/5

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

No guidance is provided on when to use this tool versus alternatives. The description offers no context about its application, prerequisites, or comparisons to sibling tools such as 'Search_Images' or 'ImageFaceSwap', leaving the agent without usage direction.

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