UNPKG

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.

94 lines (93 loc) 3.75 kB
import { ResourceClient } from "./resourceClient.js"; import * as fs from "fs"; import * as os from "os"; import * as path from "path"; export class GcsResourceClient extends ResourceClient { gcsClient; tempDir; ipAddress; constructor(gcsClient) { super(); this.gcsClient = gcsClient; this.tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "stability-ai-mcp-server-gcs-resource-")); } getPrefix(context) { return context?.requestorIpAddress + "/"; } filenameToUri(filename, context) { return `https://storage.googleapis.com/${this.gcsClient.bucketName}/${this.getPrefix(context)}${filename}`; } uriToFilename(uri, context) { return uri.replace(`https://storage.googleapis.com/${this.gcsClient.bucketName}/${this.getPrefix(context)}`, ""); } async listResources(context) { const files = await this.gcsClient.listFiles(this.getPrefix(context)); return files.map((file) => { const uri = this.filenameToUri(file.name, context); const nameWithoutPrefix = file.name.replace(this.getPrefix(context), ""); return { uri, name: nameWithoutPrefix, mimeType: this.getMimeType(nameWithoutPrefix), }; }); } async readResource(uri, context) { try { const filename = this.uriToFilename(uri, context); const tempFilePath = path.join(this.tempDir, filename); await this.gcsClient.downloadFile(this.getPrefix(context) + filename, tempFilePath); const content = await fs.promises.readFile(tempFilePath); const base64Content = content.toString("base64"); // Clean up temp file fs.unlinkSync(tempFilePath); return { uri, name: filename, blob: base64Content, mimeType: this.getMimeType(filename), }; } catch (error) { if (error instanceof Error) { throw new Error(`Failed to read resource: ${error.message}`); } throw new Error("Failed to read resource: Unknown error"); } } async createResource(uri, base64image, context) { const filename = this.uriToFilename(uri, context); if (!filename) { throw new Error("Invalid file path"); } const [name, ext] = filename.split("."); const randomString = Math.random().toString(36).substring(2, 7); const finalFilename = `${name}-${randomString}.${ext}`; // Write to temp file first const tempFilePath = path.join(this.tempDir, finalFilename); fs.writeFileSync(tempFilePath, base64image, "base64"); // Upload to GCS await this.gcsClient.uploadFile(tempFilePath, { destination: this.getPrefix(context) + finalFilename, contentType: this.getMimeType(finalFilename), }); // Clean up temp file fs.unlinkSync(tempFilePath); const fullUri = this.filenameToUri(finalFilename, context); return { uri: fullUri, name: finalFilename, mimeType: this.getMimeType(finalFilename), text: `Image ${finalFilename} successfully created at URI ${fullUri}.`, }; } async resourceToFile(uri, context) { const filename = this.uriToFilename(uri, context); if (!filename) { throw new Error("Invalid file path"); } const tempFilePath = path.join(this.tempDir, filename); await this.gcsClient.downloadFile(this.getPrefix(context) + filename, tempFilePath); return tempFilePath; } }