Skip to main content
Glama
app.py8.82 kB
from fastmcp import FastMCP from typing import List, Optional, Union from .plan_manager import PlanManager from .models import TaskInput, DependencyEdit, TaskOutput, ToolResponse, PlanStatusData import os mcp = FastMCP("MCPlanManager") plan_manager = PlanManager() @mcp.tool() def initializePlan(goal: str, tasks: List[TaskInput]) -> ToolResponse[dict]: """ 初始化或完全替换一个新的任务计划。 Args: goal (str): 描述计划总体目标的字符串。 tasks (List[TaskInput]): 任务对象的列表。每个任务的结构如下: - name (str): 任务的名称,在一个计划中应唯一。 - dependencies (List[Union[str, int]]): 依赖的任务名称或ID列表。 - reasoning (str): 阐述为何需要此任务。 """ task_dicts = [task.model_dump() for task in tasks] return plan_manager.initializePlan(goal, task_dicts) @mcp.tool() def loadPlan(plan_data: dict) -> ToolResponse: """ 通过一个完整的计划对象加载或替换当前计划。 这个工具会直接覆盖内存中的整个计划,请谨慎使用。 Args: plan_data (dict): 一个包含完整计划数据的字典对象,通常由 dumpPlan 工具导出。 它应包含 'meta', 'state', 和 'tasks' 三个顶级键。 """ return plan_manager.loadPlan(plan_data) @mcp.tool() def dumpPlan() -> ToolResponse[dict]: """ 导出当前完整的计划数据为一个字典对象。 这个导出的对象可以被 loadPlan 工具用来恢复状态。 Returns: ToolResponse[dict]: 包含当前完整计划数据的响应对象。 """ return plan_manager.dumpPlan() @mcp.tool() def visualizeDependencies(format: str = "ascii") -> str: """ 生成当前任务依赖关系的可视化图。 Args: format (str, optional): 输出的格式。可接受的值为 'mermaid' (生成流程图代码), 'tree' (生成树状图), 或 'ascii' (生成纯文本格式的列表)。 默认为 'ascii'。 Returns: str: 包含所选格式可视化内容的字符串。 """ from .dependency_tools import DependencyVisualizer visualizer = DependencyVisualizer(plan_manager) if format == "ascii": visualization = visualizer.generate_ascii_graph() elif format == "tree": visualization = visualizer.generate_tree_view() elif format == "mermaid": visualization = visualizer.generate_mermaid_graph() else: visualization = visualizer.generate_ascii_graph() return visualization @mcp.tool() def getCurrentTask() -> ToolResponse[TaskOutput]: """ 获取当前标记为 'in_progress' (正在进行中) 的任务详情。 Returns: ToolResponse[TaskOutput]: 包含当前任务详情的响应对象。 """ return plan_manager.getCurrentTask() @mcp.tool() def startNextTask() -> ToolResponse[TaskOutput]: """ 自动查找下一个可执行的任务(所有依赖均已完成)并开始执行。 这会将任务状态更新为 'in_progress'。这是推进计划的核心方法。 Returns: ToolResponse[TaskOutput]: 包含已启动任务的响应对象。 """ return plan_manager.startNextTask() @mcp.tool() def completeTask(task_id: int, result: str) -> ToolResponse[TaskOutput]: """ 将指定ID的任务标记为 'completed' (已完成)。 这是解锁后续依赖任务的关键步骤。 Args: task_id (int): 需要标记为完成的任务的ID (从0开始)。 result (str): 描述任务完成结果或产出的字符串。 """ return plan_manager.completeTask(task_id, result) @mcp.tool() def failTask(task_id: int, error_message: str, should_retry: bool = True) -> ToolResponse[TaskOutput]: """ 将指定ID的任务标记为 'failed' (失败)。 Args: task_id (int): 需要标记为失败的任务的ID (从0开始)。 error_message (str): 描述任务失败原因的字符串。 should_retry (bool, optional): 是否应该重试该任务的标志。默认为 True。 """ return plan_manager.failTask(task_id, error_message, should_retry) @mcp.tool() def addTask(name: str, dependencies: List[int], reasoning: str, after_task_id: Optional[int] = None) -> ToolResponse[TaskOutput]: """ 向当前计划中动态添加一个新任务。 Args: name (str): 新任务的名称,应确保唯一性。 dependencies (List[int]): 新任务所依赖的任务ID的整数列表 (从0开始)。 reasoning (str): 解释为何要添加此任务的字符串。 after_task_id (int, optional): 一个任务ID,新任务将被插入到该任务之后。如果省略,则添加到列表末尾。 Returns: ToolResponse[TaskOutput]: 包含新创建任务的响应对象。 """ return plan_manager.addTask(name, dependencies, reasoning, after_task_id) @mcp.tool() def skipTask(task_id: int, reason: str) -> ToolResponse[TaskOutput]: """ 将指定ID的任务标记为 'skipped' (已跳过)。 被跳过的任务在依赖解析中被视为“已完成”,允许后续任务继续。 Args: task_id (int): 需要跳过的任务的ID (从0开始)。 reason (str): 解释为何跳过此任务的字符串。 """ return plan_manager.skipTask(task_id, reason) @mcp.tool() def editDependencies(edits: List[DependencyEdit]) -> ToolResponse[dict]: """ 以批量、事务性的方式编辑一个或多个任务的依赖关系。 此工具允许 'set' 或 'update' 操作,所有编辑将在应用前进行全面验证。 如果任何指令失败,整个操作将回滚。 Args: edits (List[DependencyEdit]): 一个包含编辑指令对象的列表,每个对象的结构如下: - task_id (int): 要修改的任务ID。 - action (Literal["set", "update"]): 要执行的操作。 - dependencies (Optional[List[int]]): 当 action 为 'set' 时,提供新的完整依赖ID列表。 - add (Optional[List[int]]): 当 action 为 'update' 时,提供要添加的依赖ID列表。 - remove (Optional[List[int]]): 当 action 为 'update' 时,提供要移除的依赖ID列表。 """ edit_dicts = [edit.model_dump(exclude_none=True) for edit in edits] return plan_manager.edit_dependencies_in_batch(edit_dicts) @mcp.tool() def getPlanStatus() -> ToolResponse[PlanStatusData]: """获取整个计划的全面概览,包括元数据、进度、任务状态统计等。""" return plan_manager.getPlanStatus() @mcp.tool() def getTaskList(status_filter: Optional[str] = None) -> ToolResponse[List[TaskOutput]]: """ 获取计划中所有任务的列表,可按状态进行过滤。 Args: status_filter (str, optional): 用于过滤任务的状态字符串。 可接受的值: 'pending', 'in_progress', 'completed', 'failed', 'skipped'。 Returns: ToolResponse[List[TaskOutput]]: 包含任务列表的响应对象。 """ return plan_manager.getTaskList(status_filter) @mcp.tool() def getExecutableTaskList() -> ToolResponse[List[TaskOutput]]: """ 获取当前所有依赖已满足且状态为 'pending' 的可执行任务列表。 Returns: ToolResponse[List[TaskOutput]]: 包含可执行任务列表的响应对象。 """ return plan_manager.getExecutableTaskList() @mcp.tool() def generateContextPrompt() -> str: """ 生成一个详细的文本提示,总结计划的当前状态。 这个提示可以作为上下文提供给AI模型,以帮助其决定下一步行动。 内容包括:总体目标、当前任务、可执行任务列表等。 """ from .dependency_tools import DependencyPromptGenerator generator = DependencyPromptGenerator(plan_manager) prompt = generator.generate_context_prompt() return prompt def main(): """ The main entry point for running the server via the 'mcplanmanager' script. """ # 检查环境变量来决定运行模式 transport = os.getenv("MCP_TRANSPORT", "stdio") host = os.getenv("MCP_HOST", "0.0.0.0") port = int(os.getenv("MCP_PORT", "8080")) if transport == "sse": print(f"Starting MCP server in SSE mode on {host}:{port}") mcp.run(transport="sse", host=host, port=port) elif transport == "http": print(f"Starting MCP server in HTTP mode on {host}:{port}") mcp.run(transport="http", host=host, port=port) else: print("Starting MCP server in STDIO mode") mcp.run() if __name__ == "__main__": main()

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/donway19/MCPlanManager'

If you have feedback or need assistance with the MCP directory API, please join our Discord server