server.py•4.28 kB
from __future__ import annotations
from pathlib import Path
from typing import List
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.prompts import base # 用于更复杂的 prompt 返回结构(可选)
mcp = FastMCP("CJ-MCP")
BASE_DIR = Path(__file__).resolve().parent
RES_DIR = BASE_DIR / "resources"
GLOBAL_DIR = RES_DIR / "global"
MODULES_DIR = RES_DIR / "modules"
# ========== 全局资源 ==========
@mcp.resource("cj://syntax")
def cj_syntax() -> str:
"""仓颉语法/规范汇总。"""
parts: List[str] = []
if GLOBAL_DIR.exists():
for p in GLOBAL_DIR.rglob("*.md"):
text = p.read_text(encoding="utf-8", errors="ignore")
parts.append(f"# {p.name}\n\n{text}\n")
if not parts:
return "暂无全局语法文档,请在 resources/global 下添加 md 文件。"
return "\n\n".join(parts)
@mcp.resource("cj://global")
def cj_global() -> str:
"""所有 global 文档(语法 + 风格 + 公共设计)。"""
parts: List[str] = []
if GLOBAL_DIR.exists():
for p in GLOBAL_DIR.rglob("*"):
if p.is_file():
text = p.read_text(encoding="utf-8", errors="ignore")
rel = p.relative_to(GLOBAL_DIR).as_posix()
parts.append(f"===== GLOBAL: {rel} =====\n{text}\n")
if not parts:
return "resources/global 目录为空。"
return "\n\n".join(parts)
# ========== 按模块的资源(带参数) ==========
@mcp.resource("proj://modules/{module}")
def module_docs(module: str) -> str:
"""
指定模块的全部文档。
module 比如: 'ui', 'engine', 'data', 'ffi'
"""
mod_dir = MODULES_DIR / module
if not mod_dir.exists():
return f"模块 '{module}' 没有任何文档。"
parts: List[str] = []
for p in mod_dir.rglob("*.md"):
text = p.read_text(encoding="utf-8", errors="ignore")
rel = p.relative_to(mod_dir).as_posix()
parts.append(f"===== MODULE {module}: {rel} =====\n{text}\n")
if not parts:
return f"模块 '{module}' 目录存在,但没有 md 文件。"
return "\n\n".join(parts)
# ========== Tools(可以按需扩展) ==========
@mcp.tool()
def summarize_module(module: str, max_chars: int = 12000) -> str:
"""
粗粒度摘要:按文件顺序截取前若干字符 + 以 '==== FILE' 分隔。
后续可以替换为更聪明的规则(按标题提取、段落权重等)。
"""
mod = MODULES_DIR / module
if not mod.exists():
return f"[summarize_module] module '{module}' not found."
parts: List[str] = []
total = 0
for p in sorted(mod.rglob("*.md")):
try:
text = p.read_text(encoding="utf-8")
except UnicodeDecodeError:
continue
chunk = f"==== FILE: {p.relative_to(mod).as_posix()} ====\n{text}\n"
if total + len(chunk) > max_chars:
break
parts.append(chunk)
total += len(chunk)
if not parts:
return f"[summarize_module] module '{module}' has no readable md."
return "\n".join(parts)
# ========== Prompts(复用模板) ==========
@mcp.prompt()
def cj_module_dev(module: str, task: str) -> str:
"""
针对某个模块的开发任务。
"""
return f"""
你是资深 Cangjie/ArkTS 工程师。
[模块] {module}
[任务] {task}
[上下文获取指令 — 按顺序执行]
1. 从 **Context7** 获取与任务相关的仓颉语法/标准库要点。
2. 从 **CJ-MCP** 读取:
- 项目全局约定:cj://global
- 指定模块资料:proj://modules/{module}
[生成要求]
- 代码严格符合仓颉语法;语法/范式以 Context7 为准。
- 架构/接口/命名以项目文档为准(CJ-MCP)。
- 输出:仅给出最终完整代码;如需解释,置于代码块后,简洁列点。
"""
@mcp.prompt()
def cj_module_summary(module: str) -> str:
"""
总结模块设计。
"""
return f"""
请阅读 MCP 资源 proj://modules/{module} 和 cj://global,
用中文总结该模块的设计思路,包括:
- 模块目标与边界
- 关键类型/类/组件
- 状态与事件流转
- 与其他模块的依赖关系
- 已知坑点与注意事项
"""
if __name__ == "__main__":
mcp.run(transport="stdio")