今天我想分享一个基于Gradio和MCP构建的模块化图像处理服务器方案。这个项目的核心目标是创建一个既能通过Web界面交互使用,又能以编程方式调用的图像处理工具集。在实际工作中,我们经常遇到这样的需求:开发了一个好用的图像处理函数,既想快速做个demo展示给同事看,又希望它能被集成到自动化流程中。传统做法往往需要分别开发API和UI,而这个方案通过Gradio的MCP模式完美解决了这个问题。
这个服务器提供了三种基础图像处理功能:
特别之处在于,这些功能不仅可以通过网页界面交互使用,还能通过MCP协议以编程方式调用。这意味着你可以:
系统采用客户端-服务器模式,核心组件包括:
服务器端:
客户端:
关键设计选择:使用Gradio的MCP模式而非传统REST API,因为MCP提供了更灵活的工具发现机制和事件驱动的通信方式,特别适合AI工具链的集成。
这个技术组合有几个显著优势:
服务器核心是三个图像处理函数,每个都设计为接收Pillow的Image对象并返回处理后的Image对象:
python复制from PIL import Image, ImageEnhance
def to_grayscale(img: Image.Image) -> Image.Image:
"""转换为灰度图像,保留RGB三通道"""
return img.convert("L").convert("RGB")
def rotate_image(img: Image.Image, angle: float) -> Image.Image:
"""旋转图像,自动调整画布大小"""
return img.rotate(angle, expand=True)
def adjust_contrast(img: Image.Image, factor: float) -> Image.Image:
"""调整对比度,因子1.0为原始图像"""
enhancer = ImageEnhance.Contrast(img)
return enhancer.enhance(factor)
注意事项:所有函数最终都返回RGB模式的图像,确保与Gradio的Image组件兼容。灰度转换后特意转回RGB,因为某些显示组件对单通道图像支持不佳。
使用Gradio Blocks创建带标签页的界面:
python复制import gradio as gr
with gr.Blocks() as demo:
gr.Markdown("# Image Editing MCP Server")
with gr.Tab("Grayscale"):
inp_g = gr.Image(type="pil", label="Input Image")
out_g = gr.Image(type="pil", label="Grayscale Output")
gr.Button("Convert").click(to_grayscale, inp_g, out_g)
with gr.Tab("Rotate"):
inp_r = gr.Image(type="pil", label="Input Image")
angle = gr.Slider(0, 360, value=90, label="Angle")
out_r = gr.Image(type="pil", label="Rotated Output")
gr.Button("Rotate").click(rotate_image, [inp_r, angle], out_r)
with gr.Tab("Contrast"):
inp_c = gr.Image(type="pil", label="Input Image")
factor = gr.Slider(0.1, 3.0, value=1.5, label="Contrast Factor")
out_c = gr.Image(type="pil", label="Adjusted Output")
gr.Button("Adjust").click(adjust_contrast, [inp_c, factor], out_c)
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
mcp_server=True, # 启用MCP端点
debug=True
)
关键配置说明:
type="pil":直接传递Pillow对象,避免不必要的编解码mcp_server=True:启用MCP协议支持,这是整个方案的核心客户端需要完成以下几个关键步骤:
python复制import asyncio, base64
from mcp import ClientSession
from mcp.client.sse import sse_client
async def main():
server_url = "http://localhost:7860/gradio_api/mcp/sse"
# 将图像编码为Data URI
with open("input.png", "rb") as f:
raw = f.read()
b64 = base64.b64encode(raw).decode("ascii")
data_uri = f"data:image/png;base64,{b64}"
async with sse_client(server_url) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
tools = await session.list_tools()
print("Available tools:", [t.name for t in tools])
async def call_and_save(tool_name, args, out_path):
res = await session.call_tool(tool_name, args)
# 解码并保存结果
if res and "img" in res:
header, encoded = res["img"].split(",", 1)
with open(out_path, "wb") as f:
f.write(base64.b64decode(encoded))
await call_and_save("to_grayscale", {"img": data_uri}, "output_grayscale.png")
await call_and_save("rotate_image", {"img": data_uri, "angle": 90}, "output_rotated.png")
await call_and_save("adjust_contrast", {"img": data_uri, "factor": 1.5}, "output_contrast.png")
if __name__ == "__main__":
asyncio.run(main())
实操技巧:使用Data URI编码图像可以避免处理临时文件,特别适合在内存中完成的流水线操作。但要注意大图像可能会使URI过长,此时可以考虑分块传输。
MCP协议的一个强大特性是客户端可以动态发现服务器提供的工具:
python复制tools = await session.list_tools()
for tool in tools:
print(f"Tool: {tool.name}")
print(f"Description: {tool.description}")
print(f"Parameters: {tool.parameters}")
这使得系统具有很好的扩展性 - 服务器新增工具后,客户端无需修改代码就能发现和使用新功能。
这种架构特别适合与大型语言模型配合使用:
示例伪代码:
python复制async def ai_agent_workflow(session, user_request):
tools = await session.list_tools()
# 使用LLM分析请求并生成调用计划
plan = llm_analyze(user_request, tools)
for step in plan:
await session.call_tool(step.tool_name, step.args)
在实际部署时需要考虑:
demo.launch(max_file_size=20)调整(单位MB)对于生产环境:
bash复制gunicorn -w 4 -k uvicorn.workers.UvicornWorker server:demo
问题:客户端无法连接到MCP端点
排查步骤:
http://{host}:{port}/gradio_api/mcp/sse问题:处理后的图像出现颜色异常或失真
解决方案:
问题:处理大图像时响应缓慢
优化建议:
这个基础架构可以扩展到更多场景:
我在实际使用中发现,这种架构特别适合快速原型开发。你可以先用简单的Python函数实现核心逻辑,通过Gradio立即获得可视化界面,同时自动获得可通过编程方式调用的API。当需求变得更加复杂时,这套架构也能平滑演进。