# folder_documentation_mcp.py
"""
MCP服务:文件夹中文说明文件生成器
功能:为项目中的每个主要文件夹添加中文说明文件和思维导图
"""
from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any
import os
import datetime
import json
# 初始化MCP服务器
mcp = FastMCP("folder_documentation_mcp")
# 定义工具输入模型
class GenerateReadmeInput(BaseModel):
"""生成README.md文件输入模型"""
root_dir: str = Field(..., description="项目根目录路径")
exclude_dirs: List[str] = Field(default_factory=list, description="排除的目录列表")
force_update: bool = Field(default=False, description="是否强制更新现有README.md文件")
class GenerateMindmapInput(BaseModel):
"""生成思维导图输入模型"""
root_dir: str = Field(..., description="项目根目录路径")
output_file: str = Field(default="folder_structure_mindmap.md", description="思维导图输出文件路径")
exclude_dirs: List[str] = Field(default_factory=list, description="排除的目录列表")
class UpdateDocumentationInput(BaseModel):
"""更新文档输入模型"""
root_dir: str = Field(..., description="项目根目录路径")
exclude_dirs: List[str] = Field(default_factory=list, description="排除的目录列表")
update_mindmap: bool = Field(default=True, description="是否更新思维导图")
# 辅助函数:获取文件夹描述
def get_folder_description(folder_path: str) -> str:
"""根据文件夹名称获取中文描述"""
# 预设常见文件夹的中文描述
folder_descriptions = {
"skills": "技能文件夹",
"skills-translated": "翻译后的技能文件夹",
"技能": "中文技能文件夹",
"算法艺术": "算法艺术相关技能",
"品牌指南": "品牌指南相关技能",
"画布设计": "画布设计相关技能",
"文档协作": "文档协作相关技能",
"Word文档": "Word文档处理技能",
"PDF文档": "PDF文档处理技能",
"PPT演示文稿": "PPT演示文稿处理技能",
"Excel表格": "Excel表格处理技能",
"Web应用测试": "Web应用测试技能",
"Web构件构建器": "Web构件构建器技能",
"前端设计": "前端设计技能",
"内部通信": "内部通信技能",
"主题工厂": "主题工厂技能",
"MCP构建器": "MCP构建器技能",
"技能创建器": "技能创建器技能",
"参考": "参考文档",
"脚本": "脚本文件",
"示例": "示例文件",
"模板": "模板文件",
"规范": "规范文件",
"Office开放XML": "Office开放XML相关文件",
"画布字体": "画布设计使用的字体文件",
"ArsenalSC": "ArsenalSC字体",
"BigShoulders": "BigShoulders字体",
"Boldonse": "Boldonse字体",
"BricolageGrotesque": "BricolageGrotesque字体",
"CrimsonPro": "CrimsonPro字体",
"DMMono": "DMMono字体",
"EricaOne": "EricaOne字体",
"GeistMono": "GeistMono字体",
"Gloock": "Gloock字体",
"IBMPlexMono": "IBMPlexMono字体",
"IBMPlexSerif": "IBMPlexSerif字体",
"InstrumentSans": "InstrumentSans字体",
"InstrumentSerif": "InstrumentSerif字体",
"Italiana": "Italiana字体",
"JetBrainsMono": "JetBrainsMono字体",
"Jura": "Jura字体",
"LibreBaskerville": "LibreBaskerville字体",
"Lora": "Lora字体",
"NationalPark": "NationalPark字体",
"NothingYouCouldDo": "NothingYouCouldDo字体",
"Outfit": "Outfit字体",
"PixelifySans": "PixelifySans字体",
"PoiretOne": "PoiretOne字体",
"RedHatMono": "RedHatMono字体",
"Silkscreen": "Silkscreen字体",
"SmoochSans": "SmoochSans字体",
"Tektur": "Tektur字体",
"WorkSans": "WorkSans字体",
"YoungSerif": "YoungSerif字体",
"Slack动图创建器": "Slack动图创建器技能",
"核心": "核心功能模块"
}
folder_name = os.path.basename(folder_path)
return folder_descriptions.get(folder_name, folder_name)
# 辅助函数:生成README.md内容
def generate_readme_content(folder_path: str) -> str:
"""生成文件夹的README.md内容"""
folder_name = os.path.basename(folder_path)
description = get_folder_description(folder_path)
# 获取文件夹中的文件列表
files = []
subfolders = []
for item in os.listdir(folder_path):
item_path = os.path.join(folder_path, item)
if os.path.isfile(item_path):
files.append(item)
elif os.path.isdir(item_path):
subfolders.append(item)
# 生成README.md内容
content = f"# {description}\n\n"
content += f"## 文件夹用途\n\n"
content += f"该文件夹包含{description.lower()}相关的文件和子文件夹。\n\n"
if subfolders:
content += "## 子文件夹\n\n"
for subfolder in subfolders:
subfolder_desc = get_folder_description(os.path.join(folder_path, subfolder))
content += f"- **{subfolder}**: {subfolder_desc}\n"
content += "\n"
if files:
content += "## 文件说明\n\n"
for file in files:
# 根据文件扩展名获取文件类型描述
file_ext = os.path.splitext(file)[1].lower()
if file_ext in ['.py']:
file_type = "Python脚本文件"
elif file_ext in ['.md']:
file_type = "Markdown文档"
elif file_ext in ['.txt']:
file_type = "文本文件"
elif file_ext in ['.json']:
file_type = "JSON配置文件"
elif file_ext in ['.xsd']:
file_type = "XML Schema文件"
elif file_ext in ['.ttf', '.otf']:
file_type = "字体文件"
elif file_ext in ['.html']:
file_type = "HTML文件"
elif file_ext in ['.js']:
file_type = "JavaScript文件"
elif file_ext in ['.pdf']:
file_type = "PDF文档"
else:
file_type = "其他文件"
content += f"- **{file}**: {file_type}\n"
content += f"\n## 更新时间\n\n"
content += f"该文件生成于:{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
return content
# 辅助函数:生成文件夹结构树
def generate_folder_tree(root_dir: str, exclude_dirs: List[str], prefix: str = "", is_last: bool = True) -> str:
"""生成文件夹结构树"""
tree = ""
items = os.listdir(root_dir)
items.sort()
# 过滤排除的目录
items = [item for item in items if item not in exclude_dirs]
for i, item in enumerate(items):
is_last_item = i == len(items) - 1
item_path = os.path.join(root_dir, item)
if os.path.isdir(item_path):
# 添加目录到树中
connector = "└── " if is_last_item else "├── "
tree += f"{prefix}{connector}{item}/\n"
# 递归处理子目录
new_prefix = prefix + (" " if is_last_item else "│ ")
tree += generate_folder_tree(item_path, exclude_dirs, new_prefix, is_last_item)
else:
# 添加文件到树中
connector = "└── " if is_last_item else "├── "
tree += f"{prefix}{connector}{item}\n"
return tree
# 辅助函数:生成思维导图
def generate_mindmap(root_dir: str, exclude_dirs: List[str]) -> str:
"""生成文件夹结构思维导图"""
mindmap = f"# 项目文件夹结构思维导图\n\n"
mindmap += f"生成时间:{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
# 生成Markdown格式的思维导图
mindmap += "```mermaid\n"
mindmap += "flowchart TD\n"
mindmap += " subgraph 项目结构\n"
# 生成节点和连接
def add_nodes(path: str, parent_node: str, level: int):
"""递归添加节点和连接"""
if level > 4: # 限制最大深度,避免思维导图过于复杂
return ""
result = ""
items = os.listdir(path)
items.sort()
items = [item for item in items if item not in exclude_dirs]
for item in items:
item_path = os.path.join(path, item)
node_id = item_path.replace("\\", "_").replace(":", "_").replace(".", "_")
node_label = item
if os.path.isdir(item_path):
node_label += "/"
# 添加节点
result += f" {node_id}[\"{node_label}\"]\n"
# 添加连接
if parent_node:
result += f" {parent_node} --> {node_id}\n"
# 递归处理子目录
if os.path.isdir(item_path):
result += add_nodes(item_path, node_id, level + 1)
return result
mindmap += add_nodes(root_dir, "", 0)
mindmap += " end\n"
mindmap += "```\n"
# 添加更新日志
mindmap += "\n## 更新日志\n\n"
mindmap += f"- **{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}**: 生成初始文件夹结构思维导图\n"
return mindmap
# 注册工具:生成README.md文件
@mcp.tool()
async def generate_readme_files(params: GenerateReadmeInput) -> str:
"""为项目中的每个主要文件夹生成中文README.md文件"""
root_dir = params.root_dir
exclude_dirs = params.exclude_dirs + [".git", ".trae", ".claude-plugin", ".claude插件"]
force_update = params.force_update
generated_count = 0
skipped_count = 0
# 遍历根目录下的所有文件夹
for root, dirs, files in os.walk(root_dir):
# 过滤排除的目录
dirs[:] = [d for d in dirs if d not in exclude_dirs]
# 为当前文件夹生成README.md文件
readme_path = os.path.join(root, "README.md")
# 检查是否已存在README.md文件
if os.path.exists(readme_path) and not force_update:
skipped_count += 1
continue
# 生成README.md内容
readme_content = generate_readme_content(root)
# 写入README.md文件
with open(readme_path, "w", encoding="utf-8") as f:
f.write(readme_content)
generated_count += 1
return f"已生成 {generated_count} 个README.md文件,跳过 {skipped_count} 个已存在的文件。"
# 注册工具:生成思维导图
@mcp.tool()
async def generate_mindmap(params: GenerateMindmapInput) -> str:
"""生成项目文件夹结构的思维导图"""
root_dir = params.root_dir
output_file = params.output_file
exclude_dirs = params.exclude_dirs + [".git", ".trae", ".claude-plugin", ".claude插件"]
# 生成思维导图内容
mindmap_content = generate_mindmap(root_dir, exclude_dirs)
# 写入输出文件
with open(output_file, "w", encoding="utf-8") as f:
f.write(mindmap_content)
return f"已生成思维导图文件:{output_file}"
# 注册工具:更新文档
@mcp.tool()
async def update_documentation(params: UpdateDocumentationInput) -> str:
"""更新项目中的README.md文件和思维导图"""
root_dir = params.root_dir
exclude_dirs = params.exclude_dirs + [".git", ".trae", ".claude-plugin", ".claude插件"]
update_mindmap_flag = params.update_mindmap
# 更新README.md文件
generated_count = 0
updated_count = 0
for root, dirs, files in os.walk(root_dir):
# 过滤排除的目录
dirs[:] = [d for d in dirs if d not in exclude_dirs]
# 更新当前文件夹的README.md文件
readme_path = os.path.join(root, "README.md")
# 生成README.md内容
readme_content = generate_readme_content(root)
if os.path.exists(readme_path):
# 更新现有文件
with open(readme_path, "w", encoding="utf-8") as f:
f.write(readme_content)
updated_count += 1
else:
# 生成新文件
with open(readme_path, "w", encoding="utf-8") as f:
f.write(readme_content)
generated_count += 1
result = f"已更新 {updated_count} 个README.md文件,生成 {generated_count} 个新的README.md文件。\n"
# 更新思维导图
if update_mindmap_flag:
mindmap_path = os.path.join(root_dir, "folder_structure_mindmap.md")
mindmap_content = generate_mindmap(root_dir, exclude_dirs)
with open(mindmap_path, "w", encoding="utf-8") as f:
f.write(mindmap_content)
result += f"已更新思维导图文件:{mindmap_path}"
return result
# 注册工具:获取文件夹结构
@mcp.tool()
async def get_folder_structure(params: GenerateReadmeInput) -> str:
"""获取项目的文件夹结构"""
root_dir = params.root_dir
exclude_dirs = params.exclude_dirs + [".git", ".trae", ".claude-plugin", ".claude插件"]
# 生成文件夹结构树
folder_tree = generate_folder_tree(root_dir, exclude_dirs)
return f"# 项目文件夹结构\n\n```\n{folder_tree}```"
# 启动服务器
if __name__ == "__main__":
mcp.run()