实现一个免费可用的文生图的MCP Server

news2025/6/5 6:03:53

概述

  • 文生图模型为使用 Cloudflare Worker AI 部署 Flux 模型,是参照视频https://www.bilibili.com/video/BV1UbkcYcE24/?spm_id_from=333.337.search-card.all.click&vd_source=9ca2da6b1848bc903db417c336f9cb6b的复现
  • Cursor MCP Server实现是参照文章https://juejin.cn/post/7485267450880229402#heading-9实现

Cloudflare部署 Flux 模型

获取Cloudflare账号和token

  • 注册、登录等步骤省略

管理账号——账户API令牌——Workers AI——使用模版
在这里插入图片描述
继续以显示摘要
在这里插入图片描述
创建令牌
在这里插入图片描述

找到文生图模型github地址

Workers AI——模型——flux-1-schnell——了解更多

在这里插入图片描述
Guides——Tutorials——How to Build an Image Generator using Workers AI
在这里插入图片描述

https://developers.cloudflare.com/workers-ai/guides/tutorials/image-generation-playground/image-generator-flux/
在这里插入图片描述

在这里插入图片描述

部署文生图模型

github地址

https://github.com/kristianfreeman/workers-ai-image-playground?tab=readme-ov-file#readme

执行顺序:

  1. git clone到本地
  2. 修改配置文件
  • 将.dev.vars.example改为.dev.vars
  • 替换CLOUDFLARE_ACCOUNT_ID(账号)和CLOUDFLARE_API_TOKEN(令牌)


3. 执行npm install
4. 执行npm run preview(生产为preview)
在这里插入图片描述
在这里插入图片描述
5. 打开网页(http://localhost:8788),选择flux-1-schnell

在这里插入图片描述

输入prompt进行测试
在这里插入图片描述

Cursor调用MCP Server

实现一个调用Cloudflare Workers AI模型的MCP Server

参照文章(https://juejin.cn/post/7485267450880229402#heading-9)进行项目设置

项目设置

让我们从创建项目和安装依赖开始:

mkdir mcp-image-generator
cd mcp-image-generator
npm init -y
npm install @modelcontextprotocol/sdk zod dotenv
npm install --save-dev typescript @types/node

接下来,创建一个基本的TypeScript配置文件。在项目根目录创建tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "outDir": "./dist",
    "strict": true
  },
  "include": ["src/**/*"]
}

然后,创建一个.env文件来存储你的Cloudflare凭证:
ini 体验AI代码助手 代码解读复制代码CLOUDFLARE_ACCOUNT_ID=你的账户ID
CLOUDFLARE_API_TOKEN=你的API令牌

别忘了将这个文件添加到.gitignore,保护你的API密钥不被意外公开。

构建MCP服务器

直接替换src/index.ts文件

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import fs from 'fs';
import path from 'path';
import os from 'os';
import * as dotenv from 'dotenv';

// 加载环境变量
dotenv.config();

// 创建MCP服务器
const server = new McpServer({
    name: "AI图片生成助手",
    version: "1.0.0"
});

// 添加一个文生图工具
server.tool(
  "generate-image-from-text",
  "使用Cloudflare的Flux模型生成图像",
  {
      prompt: z.string()
          .min(1, "提示文本不能为空")
          .max(2048, "提示文本不能超过2048个字符")
          .describe("用于生成图像的文本描述"),
      steps: z.number()
          .int("步数必须是整数")
          .max(8, "步数最大为8")
          .default(4)
          .describe("扩散步数,值越高质量越好但耗时更长"),
      outputPath: z.string()
          .min(1, "输出路径不能为空")
          .describe("生成图片的保存目录路径"),
      filename: z.string()
          .min(1, "文件名不能为空")
          .describe("保存的图片文件名,不需要包含扩展名")
  },
  async ({ prompt, steps = 4, outputPath, filename }) => {
    const CLOUDFLARE_ACCOUNT_ID = process.env.CLOUDFLARE_ACCOUNT_ID;
    const CLOUDFLARE_API_TOKEN = process.env.CLOUDFLARE_API_TOKEN;

    const url = `https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/run/@cf/black-forest-labs/flux-1-schnell`;

    console.log(url);
    try {
        // 调用Cloudflare API
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${CLOUDFLARE_API_TOKEN}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                prompt: prompt
            })
        });

        // 解析响应
        const responseData = await response.json() as { image?: string;[key: string]: unknown };

        if (!response.ok) {
            return {
                content: [{ type: "text", text: `调用API失败: ${response.status} ${response.statusText}` }]
            };
        }

        // 提取图像数据
        let imageBase64 = null;

        if (responseData.image) {
            imageBase64 = responseData.image as string;
        } else if (responseData.result && typeof responseData.result === 'object') {
            const resultObj = responseData.result as Record<string, unknown>;
            if (resultObj.image) {
                imageBase64 = resultObj.image as string;
            } else if (resultObj.data) {
                imageBase64 = resultObj.data as string;
            }
        }

        if (!imageBase64) {
            return {
                content: [{ type: "text", text: "API返回的数据中没有图像" }]
            };
        }

        // 图像处理逻辑将在下一步添加
        // 保存图像文件
        let targetFilePath = path.join(outputPath, `${filename}.jpg`);
        let actualSavePath = targetFilePath;
        let message = '';

        try {
            // 确保输出目录存在
            if (!fs.existsSync(outputPath)) {
                fs.mkdirSync(outputPath, { recursive: true });
            }

            // 测试目录是否可写
            const testFileName = path.join(outputPath, '.write-test');
            fs.writeFileSync(testFileName, '');
            fs.unlinkSync(testFileName);

            // 将Base64图像保存为文件
            const imageBuffer = Buffer.from(imageBase64, 'base64');
            fs.writeFileSync(targetFilePath, imageBuffer);
            message = `图像已成功生成并保存到: ${targetFilePath}`;
        } catch (fileError) {
            // 备用方案:保存到临时目录
            const tempDir = path.join(os.tmpdir(), 'mcp_generated_images');
            if (!fs.existsSync(tempDir)) {
                fs.mkdirSync(tempDir, { recursive: true });
            }

            actualSavePath = path.join(tempDir, `${filename}.jpg`);
            const imageBuffer = Buffer.from(imageBase64, 'base64');
            fs.writeFileSync(actualSavePath, imageBuffer);

            message = `由于权限问题无法保存到 ${targetFilePath},已保存到临时位置: ${actualSavePath}`;
        }

        return {
            content: [{ type: "text", text: message }]
        };

    } catch (error: unknown) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
            content: [{ type: "text", text: `发生错误: ${errorMessage}` }]
        };
    }
}
);


// 启动服务器
const transport = new StdioServerTransport();
await server.connect(transport);

编译和运行

在package.json中添加以下脚本:

"scripts": {
  "build": "tsc",
  "start": "node dist/index.js"
}

然后编译并运行你的服务器:

npm run build
在Cursor中配置MCP服务

在这里插入图片描述
在这里插入图片描述

{
  "mcpServers": {
    "imageGenerator": {
      "command": "node",
      "args": [
        "/Users/admin/Desktop/work/study/mcp-image-generator/dist/index.js" # 替换为你的路径
      ]
    }
  }
}

重启Cursor使配置生效

测试效果

输入

Please generate a picture of an animal fox and save it to the directory /Users/admin/Desktop/work/study/mcp-image-generator/pictures with the filename fox.

在这里插入图片描述
Run tool,查看图片
在这里插入图片描述

参考

https://juejin.cn/post/7485267450880229402
https://www.cnblogs.com/foxhank/p/18378208
https://github.com/fengin/image-gen-server?tab=readme-ov-file
https://cursor.directory/mcp
https://zhuanlan.zhihu.com/p/27327515233
https://blog.csdn.net/m0_65096391/article/details/147570383

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2397814.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【手搓一个原生全局loading组件解决页面闪烁问题】

页面闪烁效果1 页面闪烁效果2 封装一个全局loading组件 class GlobalLoading extends HTMLElement {constructor() {super();this.attachShadow({ mode: open });}connectedCallback() {this.render();this.init();}render() {this.shadowRoot.innerHTML <style>.load…

CSS基础巩固-基础-选择

目录 CSS是如何工作的&#xff1f; 当浏览器遇到无法解析的CSS代码时 如何导入CSS样式&#xff1f; 改变元素的默认样式 选择 前缀符号&#xff08;后面会具体介绍&#xff09; 优先级 同时应用样式到多个类上 属性选择器 伪类 伪元素 关系选择器 后代选择器 子代…

一种在SQL Server中传递多行数据的方法

这是一种比较偷懒的方法&#xff0c;其实各种数据库对Json 支持的很好。sql server 、oracle都不错。所以可以直接传json declare 这是一个json varchar(max) set 这是一个json{"data":[{"code":"1","name":"啥1"},{"…

【Docker 从入门到实战全攻略(一):核心概念 + 命令详解 + 部署案例】

1. 是什么 Docker 是一个用于开发、部署和运行应用程序的开源平台&#xff0c;它使用 容器化技术 将应用及其依赖打包成独立的容器&#xff0c;确保应用在不同环境中一致运行。 2. Docker与虚拟机 2.1 Docker&#xff08;容器化&#xff09; 容器化是一种轻量级的虚拟化技术…

github 提交失败,连接不上

1. 第一种情况&#xff0c;开了加速器&#xff0c;导致代理错误 删除hosts文件里相关的github代理地址 2. 有些ip不支持22端口连接,改为443连接 ssh -vT gitgithub.com // 命令执行结果 OpenSSH_for_Windows_9.5p1, LibreSSL 3.8.2 debug1: C…

系统架构设计师(一):计算机系统基础知识

系统架构设计师&#xff08;一&#xff09;&#xff1a;计算机系统基础知识 引言计算机系统概述计算机硬件处理器处理器指令集常见处理器 存储器总线总线性能指标总线分类按照总线在计算机中所处的位置划分按照连接方式分类按照功能分类 接口接口分类 计算机软件文件系统文件类…

清理 pycharm 无效解释器

1. 起因&#xff0c; 目的: 经常使用 pycharm 来调试深度学习项目&#xff0c;每次新建虚拟环境&#xff0c;都是显示一堆不存在的名称&#xff0c;删也删不掉。 总觉得很烦&#xff0c;是个痛点。决定深入研究一下。 2. 先看效果 效果是能行&#xff0c;而且清爽多了。 3. …

手机如何压缩文件为 RAR 格式:详细教程与工具推荐

在如今这个数字化时代&#xff0c;手机已经成为我们生活中不可或缺的工具。随着我们使用手机的频率越来越高&#xff0c;手机中的文件也越来越多&#xff0c;照片、视频、文档等各种类型的文件不断占据着手机的存储空间。 据统计&#xff0c;普通用户的手机存储空间中&#xf…

Java 注解式限流教程(使用 Redis + AOP)

Java 注解式限流教程&#xff08;使用 Redis AOP&#xff09; 在上一节中&#xff0c;我们已经实现了基于 Redis 的请求频率控制。现在我们将进一步升级功能&#xff0c;使用 Spring AOP 自定义注解 实现一个更优雅、可复用的限流方式 —— 即通过 RateLimiter 注解&#xf…

C# XAML 基础:构建现代 Windows 应用程序的 UI 语言

在现代 Windows 应用程序开发中&#xff0c;XAML (eXtensible Application Markup Language) 扮演着至关重要的角色。作为一种基于 XML 的声明性语言&#xff0c;XAML 为 WPF (Windows Presentation Foundation)、UWP (Universal Windows Platform) 和 Xamarin.Forms 应用程序提…

【Linux】进程地址空间揭秘(初步认识)

10.进程地址空间&#xff08;初步认识&#xff09; 文章目录 10.进程地址空间&#xff08;初步认识&#xff09;一、进程地址空间的实验现象解析二、进程地址空间三、虚拟内存管理补充&#xff1a;数据的写时拷贝&#xff08;浅谈&#xff09;补充&#xff1a;页表&#xff08;…

设计模式——备忘录设计模式(行为型)

摘要 备忘录设计模式是一种行为型设计模式&#xff0c;用于在不破坏封装性的前提下&#xff0c;捕获对象的内部状态并在需要时恢复。它包含三个关键角色&#xff1a;原发器&#xff08;Originator&#xff09;、备忘录&#xff08;Memento&#xff09;和负责人&#xff08;Car…

UI自动化测试的革新,新一代AI工具MidScene.js实测!

前言 AI已经越来越深入地走入我们的实际工作,在软件测试领域,和AI相关的新测试工具、方法也层出不穷。在之前我们介绍过结合 mcp server 实现 AI 驱动测试的案例,本文我们将介绍一个近期崭露头角的国产AI测试工具 Midscene.js Midscene.js简介 MidScene.js 是由字节跳动 w…

4. Qt对话框(2)

在上节中已经学习了对话框的确认和取消&#xff0c;本节内容继续接上节完成登录对话框实例并得到登录信息。 本文部分ppt、视频截图原链接&#xff1a;[萌马工作室的个人空间-萌马工作室个人主页-哔哩哔哩视频] 1 实现登录对话框 1.1 功能需要 得到登录信息&#xff0c;需要…

Android Studio 2022.2.1.20 汉化教程

查看Android Studio 版本 Android Studio Flamingo | 2022.2.1 Patch 2 下载&#xff1a;https://plugins.jetbrains.com/plugin/13710-chinese-simplified-language-pack----/versions/stable

golang -- slice 底层逻辑

目录 一、前言二、结构三、创建3.1 根据 make创建3.2 通过数组创建 四、内置append追加元素4.1 追加元素4.2 是否扩容4.2.1 不扩容4.2.2 扩容 总结 一、前言 前段时间学了go语言基础&#xff0c;过了一遍之后还是差很多&#xff0c;所以又结合几篇不同资料重新学习了一下相关…

SOC-ESP32S3部分:26-物联网MQTT连云

飞书文档https://x509p6c8to.feishu.cn/wiki/IGCawAgqFibop7kO83KcsDFBnNb ESP-MQTT 是 MQTT 协议客户端的实现&#xff0c;MQTT 是一种基于发布/订阅模式的轻量级消息传输协议。ESP-MQTT 当前支持 MQTT v5.0。 特性 支持基于 TCP 的 MQTT、基于 Mbed TLS 的 SSL、基于 WebSo…

制造业的未来图景:超自动化与劳动力转型的双重革命

市场现状&#xff1a;传统制造业的转型阵痛 当前全球制造业正站在历史性变革的十字路口。埃森哲对552位工厂经理的全球调研显示&#xff0c;60%的受访者将劳动力转型视为首要战略任务​​&#xff0c;而63%的工厂正在加速部署自动化技术[1]。超过​75%的工厂经理​​认为&…

【Unity】相机 Cameras

1 前言 主要介绍官方文档中相机模块的内容。 关于“9动态分辨率”&#xff0c;这部分很多API文档只是提了一下&#xff0c;具体细节还需要自己深入API才行。 2 摄像机介绍 Unity 场景在三维空间中表示游戏对象。由于观察者的屏幕是二维屏幕&#xff0c;Unity 需要捕捉视图并将…

如何在 Solana 上发币,并创建初始流动性让项目真正“动”起来?

在 Solana 上发行代币如今已不再是技术门槛&#xff0c;而是市场策略和执行效率的较量。如果你只是简单发了一个代币&#xff0c;却没为它建立流动性和市场机制&#xff0c;那么它就只是一个“死币”。 本文将带你一步步理解&#xff0c;如何从发币到建立流动性池&#xff0c;…