mcp-server-stability-ai
Version:
MCP [Model Context Protocol](https://modelcontextprotocol.io/) Server integrating MCP Clients with [Stability AI](https://stability.ai/) image manipulation functionalities: generate, edit, upscale, and more.
108 lines (107 loc) • 4.21 kB
JavaScript
import axios from "axios";
import FormData from "form-data";
import fs from "fs";
export class SD35Client {
apiKey;
baseUrl = "https://api.stability.ai";
axiosClient;
constructor(apiKey) {
this.apiKey = apiKey;
this.axiosClient = axios.create({
baseURL: this.baseUrl,
timeout: 60000,
maxBodyLength: Infinity,
maxContentLength: Infinity,
headers: {
Authorization: `Bearer ${this.apiKey}`,
Accept: "image/*",
},
});
}
async generateImage(options) {
const formData = new FormData();
// Required parameter
if (!options.prompt || options.prompt.length === 0) {
throw new Error("Prompt is required and cannot be empty");
}
if (options.prompt.length > 10000) {
throw new Error("Prompt cannot exceed 10000 characters");
}
formData.append("prompt", options.prompt);
// Set the mode (default to text-to-image)
const mode = options.mode || "text-to-image";
formData.append("mode", mode);
// Add specific parameters based on mode
if (mode === "image-to-image") {
if (!options.image) {
throw new Error("Image path is required for image-to-image mode");
}
formData.append("image", fs.createReadStream(options.image));
// Strength is required for image-to-image
if (options.strength === undefined) {
throw new Error("Strength parameter is required for image-to-image mode");
}
if (options.strength < 0 || options.strength > 1) {
throw new Error("Strength must be between 0 and 1");
}
formData.append("strength", options.strength.toString());
}
else {
// aspect_ratio is only valid for text-to-image
if (options.aspect_ratio) {
formData.append("aspect_ratio", options.aspect_ratio);
}
}
// Optional parameters
if (options.model) {
formData.append("model", options.model);
}
if (options.seed !== undefined) {
if (options.seed < 0 || options.seed > 4294967294) {
throw new Error("Seed must be between 0 and 4294967294");
}
formData.append("seed", options.seed.toString());
}
if (options.output_format) {
formData.append("output_format", options.output_format);
}
if (options.style_preset) {
formData.append("style_preset", options.style_preset);
}
if (options.negative_prompt) {
if (options.negative_prompt.length > 10000) {
throw new Error("Negative prompt cannot exceed 10000 characters");
}
formData.append("negative_prompt", options.negative_prompt);
}
if (options.cfg_scale !== undefined) {
if (options.cfg_scale < 1 || options.cfg_scale > 10) {
throw new Error("CFG scale must be between 1 and 10");
}
formData.append("cfg_scale", options.cfg_scale.toString());
}
try {
const response = await this.axiosClient.post("/v2beta/stable-image/generate/sd3", formData, {
headers: {
...formData.getHeaders(),
},
responseType: "arraybuffer",
});
return response.data;
}
catch (error) {
if (axios.isAxiosError(error) && error.response) {
const data = error.response.data;
if (error.response.status === 400) {
let errorMessage = "Invalid parameters";
if (data.errors && Array.isArray(data.errors)) {
errorMessage += `: ${data.errors.join(", ")}`;
}
throw new Error(errorMessage);
}
throw new Error(`API error (${error.response.status}): ${JSON.stringify(data)}`);
}
throw error;
}
}
}