从混乱到清晰:一次MCP服务器开发的反思与总结
一、项目背景
今天的工作始于一个简单的需求:为基于Astro的博客系统创建一个MCP(Model Context Protocol)服务器,实现博客发布的自动化。MCP是一种让AI助手能够安全地与外部系统交互的协议,通过它,我们可以让AI直接操作文件系统、执行Git命令等。
二、技术实现
1. 技术选型
选择了Python和FastMCP框架来实现MCP服务器。FastMCP的优势在于:
- 极简的API设计
- 通过装饰器即可将普通函数转换为MCP工具
- 内置的stdio通信支持
2. 核心功能实现
最终实现了一个整合的publish_blog_post
工具,它包含了完整的发布流程:
@app.tool()
async def publish_blog_post(
directory: str,
content: str,
filename: str,
commit_message: str = None,
deploy: bool = True
) -> str:
"""Save article, commit changes, and optionally deploy - all in one command."""
# 1. 保存文章(自动添加frontmatter)
# 2. Git提交
# 3. 可选的部署
关键特性:
- 智能frontmatter生成:自动为Markdown文件添加必要的元数据
- 一站式操作:整合了文件保存、Git操作和部署
- 错误处理:优雅处理”nothing to commit”等情况
三、遇到的问题与解决
问题1:初稿”乱写一通”
第一次写的博客文章被指出”乱写一通”,原因是我把FastMCP描述得过于复杂,实际上它就是一个简单的Python脚本。
反思:技术写作要准确、简洁,不要为了显得高深而把简单的事情复杂化。
解决:重新理解项目本质,强调Python脚本的简洁性,用不到100行代码就实现了完整功能。
问题2:测试的困境
尝试测试MCP工具时遇到了FastMCP装饰器导致的调用问题:
TypeError: 'FunctionTool' object is not callable
原因:@app.tool()
装饰器将函数包装成了FunctionTool
对象,不能直接调用。
解决:在MCP服务器中添加了测试模式:
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "--test":
asyncio.run(test_mode())
else:
app.run()
问题3:测试原则的违背
最初的测试直接操作文件系统,而不是通过MCP服务器,完全违背了测试原则。
解决:修改MCP服务器程序,添加内置的测试功能,确保测试通过服务器的工具函数进行。
四、项目成果
-
成功发布的博客文章:
- 《用Python脚本快速实现MCP服务器》(中英文版本)
- 准确描述了FastMCP的使用方法
-
功能完整的MCP服务器:
- 代码已推送到 GitHub
- 实现了发布、搜索、删除功能(后两者已注释,保持简洁)
-
简化的工作流程:
- 从4步手动操作简化为1个函数调用
- 实现了真正的”一键发布”
五、技术细节与最佳实践
1. 环境配置的灵活性
ASTRO_DIR = pathlib.Path(os.getenv("ASTRO_DIR", "./astro")).expanduser().resolve()
2. 命令执行的封装
def _run(cmd: List[str]) -> str:
proc = subprocess.run(cmd, cwd=ASTRO_DIR, capture_output=True, text=True)
banner = f"$ {' '.join(cmd)}\n"
return banner + proc.stdout + proc.stderr
3. 时间格式的规范化
从简单的日期格式演进到包含时分秒:
pubDate: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
六、经验教训
-
清晰沟通的重要性:技术实现再好,如果不能清晰地传达价值,就是失败的。
-
简洁即是美:不到100行Python代码就能实现强大的功能,这本身就是FastMCP的魅力。
-
测试的正确方式:测试应该通过被测试的系统进行,而不是绕过它。
-
迭代改进:从初始版本到最终版本,经历了多次重构和简化,每次都让代码更清晰。
七、未来展望
虽然当前版本已经满足了核心需求,但仍有改进空间:
- 恢复搜索和删除功能
- 添加更多的错误处理
- 支持批量操作
- 集成更多的博客平台
总结
这次开发经历虽然只有一天,但收获颇丰。从被批评”乱写一通”到最终实现清晰、实用的MCP服务器,这个过程本身就是一次宝贵的学习经历。它提醒我们:好的技术方案不仅要功能强大,更要简洁明了、易于理解和使用。
正如这个项目的标题所示,从混乱到清晰,不仅是代码的演进,更是认知的提升。
脱敏说明:本文所有出现的表名、字段名、接口地址、变量名、IP地址及示例数据等均非真实,仅用于阐述技术思路与实现步骤,示例代码亦非公司真实代码。示例方案亦非公司真实完整方案,仅为本人记忆总结,用于技术学习探讨。
• 文中所示任何标识符并不对应实际生产环境中的名称或编号。
• 示例 SQL、脚本、代码及数据等均为演示用途,不含真实业务数据,也不具备直接运行或复现的完整上下文。
• 读者若需在实际项目中参考本文方案,请结合自身业务场景及数据安全规范,使用符合内部命名和权限控制的配置。Data Desensitization Notice: All table names, field names, API endpoints, variable names, IP addresses, and sample data appearing in this article are fictitious and intended solely to illustrate technical concepts and implementation steps. The sample code is not actual company code. The proposed solutions are not complete or actual company solutions but are summarized from the author's memory for technical learning and discussion.
• Any identifiers shown in the text do not correspond to names or numbers in any actual production environment.
• Sample SQL, scripts, code, and data are for demonstration purposes only, do not contain real business data, and lack the full context required for direct execution or reproduction.
• Readers who wish to reference the solutions in this article for actual projects should adapt them to their own business scenarios and data security standards, using configurations that comply with internal naming and access control policies.版权声明:本文版权归原作者所有,未经作者事先书面许可,任何单位或个人不得以任何方式复制、转载、摘编或用于商业用途。
• 若需非商业性引用或转载本文内容,请务必注明出处并保持内容完整。
• 对因商业使用、篡改或不当引用本文内容所产生的法律纠纷,作者保留追究法律责任的权利。Copyright Notice: The copyright of this article belongs to the original author. Without prior written permission from the author, no entity or individual may copy, reproduce, excerpt, or use it for commercial purposes in any way.
• For non-commercial citation or reproduction of this content, attribution must be given, and the integrity of the content must be maintained.
• The author reserves the right to pursue legal action against any legal disputes arising from the commercial use, alteration, or improper citation of this article's content.Copyright © 1989–Present Ge Yuxu. All Rights Reserved.