尝试开发一个MCP服务并发布到PyPI

MCP简介

模型上下文协议(Model Context Protocol)是一款由Anthropic推出的开源协议。
它改变了大语言模型(LLM)与外部世界交互的方式,扩大了LLM的能力边界

以前问AI问题,AI只能回答给出答案,并不能实际上手来解决问题。
有了MCP作为LLM和应用层面的接口,AI就可以实际与各种工具、服务或本地应用直接交互,
从而真正执行任务、完成操作,而不仅仅是“告诉你怎么做”。

比如你可以告诉你的大语言模型产品,让AI:

  • 帮我把目录中所有mov文件重命名,替换字符串aa为bb(filesystem)
  • 帮我抓取这个网站上有什么内容并总结告诉我(fetch)
  • 我的git仓库中某个文件和上个版本对比有什么差异(git)
  • 在我的github上创建一个新项目(github)
  • 帮我查看shotgrid上今天有哪些没有提交的任务(shotgrid_mcp_server)

MCP正式开源发布于2024年11月25日,直到现在,网上已经有了很多可供使用的mcp servers,
您可以在下面两个网站中找到它们直接使用。

https://modelcontextprotocol.io/examples
https://github.com/modelcontextprotocol/servers

下面将开发一个简单的MCP服务,并提供一个tool

  • 列出指定文件夹中,所有ma文件里reference的资产路径。

创建和配置项目

PyPI包的名字就叫mcp-maya-small-tools吧。

1
2
3
4
5
6
7
8
9
10
11
# 创建项目目录
mkdir mcp-maya-small-tools
cd mcp-maya-small-tools
uv init

# 创建并激活虚拟环境
uv venv
.venv\Scripts\activate

# 安装依赖
uv add mcp[cli]

新建一个server.py文件,写入代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import pathlib
from typing import Any, Dict

from mcp.server.fastmcp import FastMCP

# 定义mcp服务器
mcp = FastMCP("Maya-Small-Tools")


def get_maya_reference(file_path):
"""
以文本打开ma文件,获取所有reference文件路径列表
Args:
file_path: ma文件路径
Returns:
引用文件列表
"""
# 尝试不同的编码方式读取文件
encodings = ['utf-8', 'latin1', 'cp1252']
content = None
ref_path_list = []

for encoding in encodings:
try:
with open(file_path, 'r', encoding=encoding) as f:
content = f.readlines()
break
except UnicodeDecodeError:
continue

if content is None:
return f'[error]处理文件时出现编码错误 {file_path},请查看日志'

# 读取文件内容, 获取reference路径
for line in content:
line = line.strip()

if not line or line[-5:-2] not in ('.ma', '.mb'):
continue

if '-rfn' in line:
line = line.split()[-1]

if '"mayaAscii"' in line:
line = line.split('"mayaAscii"')[-1].strip()

if '"mayaBinary"' in line:
line = line.split('"mayaBinary"')[-1].strip()

if line.startswith('"') and line.endswith(';'):
ref_path = line.replace('"', '')
ref_path = ref_path.replace(';', '')
ref_path_list.append(ref_path)

ref_path_list = list(set(ref_path_list))

return ref_path_list


# 定义一个mcp tool
@mcp.tool()
def list_maya_references(dir_path: str) -> Dict[str, Any]:
"""
列出目录中所有maya文件(ma格式),以及其reference列表。
Args:
dir_path: 目录
Returns:
字典,key为maya文件路径,value为Reference列表
"""
dir_path = pathlib.Path(dir_path)
if not dir_path.exists():
return {}

result = {}
for maya_path in dir_path.glob('*.ma'):
ref_list = get_maya_reference(maya_path)
result[str(maya_path)] = ref_list

return result


if __name__ == "__main__":
mcp.run(transport='stdio')

先进行一下测试

1
uv run mcp dev server.py

image.png

输出结果是符合预期的。

打包上传到PyPI

获取PyPI API token的方法不赘述。
来到项目路径,需要先整理为一个标准的package结构。
然后执行打包和发布。

1
2
3
4
5
# 打包
uv build

# 发布
uv publish --token {yourToken}

使用MCP服务

这里使用Cherry Studio,首先添加MCP服务器。

image.png

来到对话页面尝试调用

总结

用大白话说,MCP服务器主要复杂业务实现,MCP宿主(Claude, Cursor, Cherry Studio等)可以连接到多个MCP服务器。
输入的自然语言,大语言模型将它转换为function的参数,传入我们定义的tool里,再对输出的结果进行解析。