05-mcp-server案例分享-用豆包大模型 1.6 手搓文生图视频 MCP-server发布到PyPI官网

1前言

上期给大家介绍过mcp-server案例分享-用豆包大模型 1.6 手搓文生图视频 MCP-server。当时部署的方式使用了一个私有云SSE的部署。当时缺少一个本地部署的方式,有的小伙伴给我留言能不能有一个本地话部署方式了。今天就给大家带来一个本地化部署的方案。

话不多说下面介绍一下具体如何打包和操作的。

2.打包发布Python库到PyPI

基于上期文章我们已经有了代码mcp_ai_server.py

# doubao_mcp_server.py
import time
import base64
import requests
import asyncio
from typing import Any, Dict, Optional, Union
from openai import OpenAI
from mcp.server.fastmcp import FastMCP# 创建MCP服务器实例
mcp = FastMCP("AI Generation Server")# 全局配置
API_KEY = None
BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"def initialize_client():"""初始化OpenAI客户端"""if not API_KEY:raise ValueError("API key is required")return OpenAI(api_key=API_KEY, base_url=BASE_URL)@mcp.tool()
def set_api_key(api_key: str) -> str:"""设置豆包API密钥"""global API_KEYAPI_KEY = api_keyreturn "API密钥设置成功"@mcp.tool()
def text_to_image(prompt: str, size: str = "1024x1024", model: str = "doubao-seedream-3-0-t2i-250415"
) -> Dict[str, Any]:"""文生图功能 - 根据文本描述生成图片Args:prompt: 图片描述提示词size: 图片尺寸,格式为"宽x高",如"1024x1024"model: 使用的模型名称Returns:包含图片URL或错误信息的字典"""try:client = initialize_client()params = {"model": model,"prompt": prompt,"size": size,"response_format": "url","n": 1,}response = client.images.generate(**params)if response.data and len(response.data) > 0:return {"success": True,"image_url": response.data[0].url,"message": "图片生成成功"}else:return {"success": False,"error": "未返回图片数据"}except Exception as e:return {"success": False,"error": f"生成图片时出错: {str(e)}"}@mcp.tool()
def image_to_video(prompt: str,image_base64: str,duration: str = "5",ratio: str = "16:9",model: str = "doubao-seedance-1-0-lite-i2v-250428"
) -> Dict[str, Any]:"""图生视频功能 - 根据图片和文本描述生成视频Args:prompt: 视频描述提示词image_base64: 图片的base64编码字符串duration: 视频时长(秒)ratio: 视频比例,如"16:9"model: 使用的模型名称Returns:包含视频URL或错误信息的字典"""try:# 构造图片数据URLimage_data_url = f"data:image/jpeg;base64,{image_base64}"# 自动添加参数到提示词if ratio and "--ratio" not in prompt:prompt += f" --ratio adaptive"if duration and "--duration" not in prompt and "--dur" not in prompt:prompt += f" --duration {duration}"headers = {"Content-Type": "application/json","Authorization": f"Bearer {API_KEY}"}# 构造请求内容content = [{"type": "text", "text": prompt},{"type": "image_url", "image_url": {"url": image_data_url}}]request_data = {"model": model,"content": content}# 创建视频生成任务response = requests.post(f"{BASE_URL}/contents/generations/tasks",headers=headers,json=request_data)if response.status_code != 200:return {"success": False,"error": f"创建视频生成任务失败,状态码: {response.status_code}, 信息: {response.text}"}task_id = response.json().get("id")if not task_id:return {"success": False,"error": "未获取到任务ID"}# 轮询等待任务完成max_retries = 60for retry in range(max_retries):time.sleep(5)task_resp = requests.get(f"{BASE_URL}/contents/generations/tasks/{task_id}",headers=headers)if task_resp.status_code != 200:return {"success": False,"error": f"查询任务失败,状态码: {task_resp.status_code}"}task_data = task_resp.json()status = task_data.get("status")if status == "succeeded":video_url = task_data.get("content", {}).get("video_url")return {"success": True,"video_url": video_url,"message": "视频生成成功","task_id": task_id}elif status in ("failed", "canceled"):return {"success": False,"error": f"任务{status}"}return {"success": False,"error": "视频生成超时"}except Exception as e:return {"success": False,"error": f"生成视频时出错: {str(e)}"}@mcp.tool()
def text_to_video(prompt: str,duration: str = "5",ratio: str = "16:9",model: str = "doubao-seedance-1-0-lite-t2v-250428"
) -> Dict[str, Any]:"""文生视频功能 - 根据文本描述生成视频Args:prompt: 视频描述提示词duration: 视频时长(秒)ratio: 视频比例,如"16:9"model: 使用的模型名称Returns:包含视频URL或错误信息的字典"""try:# 自动添加参数到提示词if ratio and "--ratio" not in prompt:prompt += f" --ratio {ratio}"if duration and "--duration" not in prompt and "--dur" not in prompt:prompt += f" --duration {duration}"headers = {"Content-Type": "application/json","Authorization": f"Bearer {API_KEY}"}request_data = {"model": model,"content": [{"type": "text", "text": prompt}]}# 创建视频生成任务response = requests.post(f"{BASE_URL}/contents/generations/tasks",headers=headers,json=request_data)if response.status_code != 200:return {"success": False,"error": f"创建视频生成任务失败,状态码: {response.status_code}, 信息: {response.text}"}task_id = response.json().get("id")if not task_id:return {"success": False,"error": "未获取到任务ID"}# 轮询等待任务完成max_retries = 60for retry in range(max_retries):time.sleep(5)task_resp = requests.get(f"{BASE_URL}/contents/generations/tasks/{task_id}",headers=headers)if task_resp.status_code != 200:return {"success": False,"error": f"查询任务失败,状态码: {task_resp.status_code}"}task_data = task_resp.json()status = task_data.get("status")if status == "succeeded":video_url = task_data.get("content", {}).get("video_url")return {"success": True,"video_url": video_url,"message": "视频生成成功","task_id": task_id}elif status in ("failed", "canceled"):return {"success": False,"error": f"任务{status}"}return {"success": False,"error": "视频生成超时"}except Exception as e:return {"success": False,"error": f"生成视频时出错: {str(e)}"}@mcp.tool()
def encode_image_to_base64(image_path: str) -> Dict[str, Any]:"""将本地图片文件编码为base64字符串Args:image_path: 图片文件路径Returns:包含base64编码字符串或错误信息的字典"""try:with open(image_path, 'rb') as image_file:encoded_string = base64.b64encode(image_file.read()).decode('utf-8')return {"success": True,"base64_string": encoded_string,"message": "图片编码成功"}except Exception as e:return {"success": False,"error": f"编码图片失败: {str(e)}"}@mcp.resource("config://models")
def get_available_models() -> str:"""获取可用的AI模型列表"""models = {"text_to_image": ["doubao-seedream-3-0-t2i-250415"],"image_to_video": ["doubao-seedance-1-0-lite-i2v-250428"],"text_to_video": ["doubao-seedance-1-0-lite-t2v-250428"]}return f"可用模型列表: {models}"@mcp.resource("config://settings")
def get_server_settings() -> str:"""获取服务器配置信息"""settings = {"base_url": BASE_URL,"api_key_set": bool(API_KEY),"supported_image_sizes": ["512x512", "768x768", "1024x1024", "1024x1792", "1792x1024"],"supported_video_ratios": ["16:9", "9:16", "1:1"],"max_video_duration": "10s"}return f"服务器配置: {settings}"def main():"""主函数入口点"""mcp.run(transport="stdio")if __name__ == "__main__":main()

包代码开发

将您MCP server本地脚本打包,需要在doubao_mcp_server目录新建一个文件__init__.py

init.py

from .doubao_mcp_server import main__all__ = ["main"]

本地测试

打包后测试可以将这个mcp server作为模块来运行,而不是直接通过脚本运行。

# 以模块运行
uv run -m mcp_ai_server

或者也可以在MCP 客户端比如Cherry Studio上配置config测试

{"mcpServers": {"r-FY6A48OrPGz5fknShHt": {"name": "doubao-mcp-server","type": "stdio","description": "","isActive": true,"registryUrl": "https://pypi.tuna.tsinghua.edu.cn/simple","command": "uv","args": ["--directory","F:\\work\\code\\AIcode\\doubao_mcp_server","run","doubao-mcp-server.py"]}}

Cherry Studio上 界面配置

image-20250615113705259

点击保存验证一下,查看下工具列表

image-20250615113848740

看到这个说明可以在客户端使用这个MCP-Server了。

作为一个包发布到PyPI

编写pyproject.toml

您需要确保在您的项目根目录,存在一个完整的pyproject.toml文件(在前面的步骤中应该已经自动生成)。这个文件的内容包括:

  • 包的元信息:名字、版本、描述、作者
  • 依赖项
  • 构建系统配置
  • MCP入口

pyproject.toml文件:

[project]
name = “doubao-mcp-server”
version = “0.1.0”
description = “主要实现的是火山引擎的提供的豆包文生图、文生视频、图生视频MCP-Server”
authors = [
{name = “wwzhouhui”,email = “75271002@qq.com”}
]
readme = “README.md”
requires-python = “>=3.13”
dependencies = [
“mcp[cli]>=1.9.4”, # 添加requests依赖
“requests>=2.31.0”,
“openai>=1.86.0”,
]

[project.scripts]
doubao-mcp-server = “doubao_mcp_server:main”

[build-system]
requires = [“hatchling”]
build-backend = “hatchling.build”

Python包创建一个README.md

这个地方我们省略

编译打包

构建你Python包,这个地方我稍微讲一下

cd  F:\work\code\AIcode\doubao_mcp_server
uv build

image-20250615115940544

image-20250615120014779

检查打包文件

在dist/目录下看见.whl和.tar.gz的两个文件

image-20250615120057036

准备PyPI账户

我需要登录PyPI官网:https://pypi.org/account/login/ 注册一个账号(如果之前没有的话)

关于PyPI注册比较麻烦,这里不做详细展开。主要是注册之后还需要微软的Authenticator 手机上安装,然后通过双重身份验证完成登录

image-20250615122125953

image-20250615122157980

完整双重身份验证后,我们就可以实现打包文件上传了。

image-20250615122337017

pypi api token创建

双重身份验证通过后,我们点击“add api token” 创建一个api

image-20250615122644450

image-20250615122725171

image-20250615122807168

复制上面的token用记事本保存好。

上传您的Python包

我们在命令行窗口输入如下命令

uv publish --token  pypi-xxxxxx 

image-20250615123128330

我们去pypi 查看我们上传的包

image-20250615123327343

打开view 我们就查看刚刚上传的详细的依赖包

image-20250615153449187

MCP客户端测试

一旦发布完成, 用户就可以通过uvx安装和使用您的 MCP server。uvx会创建一个临时环境,安装依赖并执行这个包,非常的简洁优雅。

接下来我们使用trae 来下载安装我们刚才上传的pypi依赖包

我们在trae 添加如下mcp-server配置

{"mcpServers": {"doubao-mcp-server": {"command": "uvx","args": ["doubao-mcp-server"],"env": {"DOUBAO_API_KEY": "your-api-key-here"}}}
}

配置完成后

image-20250615153553068

我们测试一下

image-20250615155831976

image-20250615155855206

image-20250615155932459

有点丑,不过确实已经弄个调用生产图片了。

3.部署到魔搭MCP广场

我们也可以把这个MCP部署到魔搭社区的MCP广场上给大家使用。

  • 进入魔搭MCP广场

    MCP广场地址:modelscope.cn/mcp

    img

  • 基础信息填写

    创建类型:选择“GitHub快速创建”

    英文名称:英文MCP Server名字,

    中文名称:中文MCP Server名字,

    来源地址:代码我们已经上传github地址:https://github.com/wwwzhouhui/doubao_mcp_server

    所有者:默认已填好

    托管类型:选择“可托管部署”

    image-20250615172025838

完成部署

image-20250615174149106

上面填写APIkey 就可以体验了。按照下面填写APIkey

image-20250615175744287

生成SSE URL 地址(上面地址有效期时间24个小时,也可以设置长期有效)

{"mcpServers": {"DoubaoMCPServer-MCP_Agent_Challenge": {"type": "sse","url": "https://mcp.api-inference.modelscope.net/aee3086059a34e/sse"}}
}

接下来我们也可以在魔搭的应用广场上体验了。我们点击“试用” 就可以在魔搭社区免费体验了。

image-20250615180327469

摩搭社区MCP应用广场测试

进入应用广场 输入下面的提示词

文生图

给我画一个 小白兔吃萝卜

image-20250615180612926

image-20250615180819895

这样我们在魔搭社区里面也可以使用我我们刚才部署打包的MCP-server了。

文生视频

提示词:给我生成一个小白兔吃萝卜的视频

image-20250615182331935

4.总结

今天主要带大家了解并实现了基于豆包大模型 1.6 发布的文生图、文生视频、图生视频功能的 MCP-Server 本地化部署与发布方案。通过将 MCP Server 脚本打包为 Python 库并发布至 PyPI,我们成功实现了可跨平台调用的 AI 生成服务。借助火山引擎提供的文生图、文生视频、图生视频模型 API,我们构建了一个功能完整的 MCP-Server,支持通过文本描述生成高质量图片和视频内容。

通过本文的方案,开发者可以轻松搭建自己的文生图、文生视频、图生视频服务,为应用程序添加强大的 AI 生成能力。感兴趣的小伙伴可以按照本文步骤去尝试搭建自己的 MCP-Server。今天的分享就到这里结束了,我们下一篇文章见。

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

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

相关文章

MCP Parameters 增加描述

场景:本地MCP开发完后是否发现CLINE上显示的Parameters 显示No description 方法1 :使用参数元数据 (Annotated) 可以使用 Pydantic 的with 类提供有关参数的其他元数据Annotated。这种方法更受欢迎,因为它更现代,并且将类型提示…

STM32 GPIO 寄存器开发

🔧 ​一、核心寄存器概览​ ​寄存器​​功能​​位宽​​关键位域​​GPIOx_CRL/CRH​配置引脚模式(输入/输出/复用/模拟)和输出参数32位每4位控制1个引脚:CNF[1:0](模式) MODE[1:0](速度&am…

powershell 获取 用户及进程列表

在PowerShell中获取用户的进程列表,可以通过几种方法实现。以下是一些常见的方法: 方法1:使用Get-WmiObject Get-WmiObject命令可以用来查询Windows Management Instrumentation (WMI)数据库,从而获取关于进程和用户的信息。 # …

量化面试绿皮书:15. 假币一

文中内容仅限技术学习与代码实践参考,市场存在不确定性,技术分析需谨慎验证,不构成任何投资建议。 15. 假币一 有 10个袋子,每个袋子里有 100个相同的硬币。 在除一个以外的所有袋子中,每枚硬币重10 克。 然而&#x…

Java求职者面试:Spring AI、MCP、RAG、向量数据库与Embedding模型技术解析

Java求职者面试:Spring AI、MCP、RAG、向量数据库与Embedding模型技术解析 第一轮:基础概念问题 1. 请解释Spring AI是什么?它与传统Spring框架有何不同? Spring AI是Spring生态系统的一部分,专注于人工智能和机器学…

tp框架导出excel的时候报错:unexcepted identifier “Closure“,excepting variable

记录一个简单的错误。 背景 用的是PhpOffice/PhpSpreadsheet 在本地环境下是可以正常导出excel的。但是线上就不行。 就会报错unexcepted identifier “Closure”,好像是不能用匿名函数。 首先 本地可以正常导出,然后服务器上不可以。看了各种日志。ph…

[Java恶补day24] 74. 搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。 …

解锁VSCode:从入门到精通的全攻略

目录 一、VSCode 初相识二、安装与基础设置2.1 下载安装2.2 基础设置三、核心功能深度剖析3.1 强大的代码编辑3.2 高效的版本控制集成3.3 实用的调试工具四、插件扩展,拓展无限可能4.1 插件市场探秘4.2 必备插件推荐五、个性化定制,打造专属开发环境5.1 快捷键设置5.2 用户代…

RFC4291-IPv6地址架构

RFC4291 IP Version 6 Addressing Architecture Author:Once Day Date:2025年6月15日 本文翻译自RFC 4291 - IP Version 6 Addressing Architecture 这篇文章总结了IPv6的基础概念,属于IPv6协议入门内容。 文章目录 RFC4291 IP Version 6 …

基础数据结构第03天:顺序表(实战篇)

目录 求奇数的乘积 数值统计 青年歌手大奖赛_评委会打分 猜数字 拿硬币 值相等的最小索引 最大连续1的个数 差的绝对值为K的数对数目 数组中两元素的最大乘积 数组元素和与数字和的绝对差 K个元素的最大和 等差三元组的数目 移除元素 基于排列构建数组 数组串联…

10.OpenCV—联合QT界面显示

1.显示在graphicsView控件上 .h文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>#include <QGraphicsPixmapItem> //1.声明头文件 namespace Ui { class MainWindow; }class MainWindow : public QMainWindow {Q_OBJECTpublic:explicit Ma…

ChromaDB深度技术研究报告

第一章: ChromaDB核心概念与架构 1.1 向量数据库:新一代AI应用基石 向量数据库是为存储、管理和搜索向量嵌入(Vector Embeddings)而专门设计的数据库系统。在高维空间中,向量嵌入是数据(如文本、图片、音频等)的数值表示。向量数据库的核心能力在于,它能够高效地执行相…

react 自定义状态管理库

核心实现原理 &#xff1a; 全局状态容器&#xff1a;维护单一状态源 订阅机制&#xff1a;组件订阅状态变化 状态更新调度&#xff1a;通过 Hooks 触发组件重渲染 基础版实现–核心代码 // 1. 创建全局状态存储 const createStore (initialState) > {let state initial…

解决idea无法正常加载lombok包

问题 近期发现了一个问题&#xff0c;就是很多同学在导包的&#xff0c;lombok经常会爆红&#xff0c;经过研究找到了解决方法。 解决 1、更改lombok包的版本 通过手动调整pom.xml文件的lombok&#xff0c;通常讲版本调整为1.18.20&#xff0c;或者1.18.32。 <dependenc…

0_1树和图

树的概念 树(tree)是一种能够分层存储数据的重要数据结构,树中的每个元素被称为树的节点,每个节点有若干个指针指向子节点。从节点的角度来看,树是由唯一的起始节点引出的节点集合。这个起始结点称为根(root)。树中节点的子树数目称为节点的度(degree)。在面试中,关于树的…

从0搭建出海 Demo:免费香港服务器实战指南

你有没有在通勤地铁上、午饭后摸鱼时&#xff0c;突然冒出一个想法&#xff1a;“要不我也做个应用试试&#xff1f;好像不少人靠这个补贴生活开销啊&#xff01;” 结果随手搜了几篇“海外项目经验分享”&#xff0c;瞬间被一堆术语劝退&#xff1a;CDN、备案、分发平台、服务…

《仿盒马》app开发技术分享--未完成订单列表展示逻辑优化(61)

技术栈 Appgallery connect 前言&#xff1a; 上一节我们实现订单与优惠券的联合提交时&#xff0c;我去到订单列表页面查看生成的订单信息&#xff0c;发现现在的订单从信息展示到价格计算全都是有问题的。所以紧急的把对应的问题修改一下。 问题来源&#xff1a; async …

手搓多模态-08 主模型的搭建(上)

前情回顾 在之前的章节我们已经构建好了视觉编码器&#xff0c;预处理模块&#xff0c;以及gemma模型的顶层。gemma模型的顶层&#xff0c;主要是构建图中圈出的输入&#xff0c;它把视觉编码器里每个图像patch的编码维度对齐到自然语言token的嵌入维度&#xff0c;并组装成了一…

Matlab 角点探测

文章目录 一、简介二、实现代码三、实现效果一、简介 这里实现一种角点探测功能,其思路仍然是借助图像的局部梯度信息,实现亚像素精度的角点定位。该功能核心思想是利用角点周围的局部梯度信息,通过加权最小二乘优化的方式迭代调整角点位置,使定位精度达到亚像素级别。整个…

错误监控----比如实现sentry一些思路

错误监控 ⼀、引⾔ 1.为什么需要前端错误监控 你的脚本在哪些边界条件下会报错&#xff1f; 你的脚本和样式兼容性如何&#xff1f; 有哪些地区不能正常访问你的⽹站&#xff1f; 出现问题之后&#xff0c;你如何快速定位排查&#xff0c;把损失降到最低&#xff1f; 如果你想解…