server.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. from __future__ import annotations
  2. import os
  3. from typing import Any
  4. from fastmcp import FastMCP
  5. from .auth import load_projects_config
  6. from .config_api import (
  7. get_command_log as api_get_command_log,
  8. get_ai_online_v2 as api_get_ai_online_v2,
  9. search_ai_rcmd_operations as api_search_ai_rcmd_operations,
  10. search_ai_systems as api_search_ai_systems,
  11. )
  12. mcp = FastMCP("m2")
  13. @mcp.tool(
  14. name="project.list",
  15. title="项目列表",
  16. description="列出目前用户可查询的项目列表。执行其他工具前,如前置未提到要查询项目的project_key,应先让用户选择要查询的项目,再使用对应的 project_key 调用后续工具。",
  17. tags={"project", "list"},
  18. )
  19. def project_list() -> dict[str, Any]:
  20. projects = load_projects_config()
  21. result: list[dict[str, Any]] = []
  22. for item in projects:
  23. if not item["enabled"]:
  24. continue
  25. result.append(
  26. {
  27. "project_key": item["project_key"],
  28. "project_name": item["project_name"],
  29. }
  30. )
  31. result.sort(key=lambda item: item["project_key"])
  32. return {
  33. "projects": result,
  34. "total": len(result),
  35. }
  36. def _append_next_page_hint(payload: Any, page_num: int) -> Any:
  37. if not isinstance(payload, dict):
  38. return payload
  39. total_page = None
  40. data = payload.get("data")
  41. if isinstance(data, dict):
  42. total_page = data.get("total_page")
  43. if total_page is None:
  44. total_page = payload.get("total_pages")
  45. if total_page is None:
  46. total_page = payload.get("total_page")
  47. if isinstance(total_page, int) and total_page > page_num:
  48. payload.setdefault(
  49. "mcp_note",
  50. f"Current result is page {page_num}. If the target was not found, continue with page_num={page_num + 1}.",
  51. )
  52. return payload
  53. @mcp.tool()
  54. def search_ai_systems(
  55. project_key: str,
  56. keyword: str = "",
  57. page_size: int = 20,
  58. page_num: int = 1,
  59. order_by: list[str] | None = None,
  60. ) -> Any:
  61. """搜索AI控制系统并返回系统code。默认 page_size 为 20,除非显式传入其他值。"""
  62. payload = api_search_ai_systems(
  63. project_key,
  64. keyword=keyword,
  65. page_size=page_size,
  66. page_num=page_num,
  67. order_by=order_by,
  68. )
  69. return _append_next_page_hint(payload, page_num)
  70. @mcp.tool()
  71. def search_ai_rcmd_operations(
  72. project_key: str,
  73. codes: list[str],
  74. end: str,
  75. page_size: int = 10,
  76. page_num: int = 1,
  77. order: str = "-create_time",
  78. ) -> Any:
  79. """按AI控制系统的code查询策略记录。默认 page_size 为 10,除非显式传入其他值。auto_exec=true 表示自动控制,否则表示推荐参考。"""
  80. payload = api_search_ai_rcmd_operations(
  81. project_key,
  82. codes=codes,
  83. end=end,
  84. page_size=page_size,
  85. page_num=page_num,
  86. order=order,
  87. )
  88. return _append_next_page_hint(payload, page_num)
  89. @mcp.tool()
  90. def get_ai_online_v2(project_key: str, codes: list[str]) -> Any:
  91. """按AI控制系统的code查询控制模式和运行状态。control_mode=1 表示自动控制;status=0 表示正常,1 表示异常。"""
  92. return api_get_ai_online_v2(project_key, codes=codes)
  93. @mcp.tool()
  94. def get_command_log(
  95. project_key: str,
  96. point_id: str,
  97. begin: int,
  98. end: int,
  99. page_size: int = 20,
  100. page_num: int = 1,
  101. export: bool = False,
  102. ) -> Any:
  103. """按 point_id 和时间范围查询指令下发日志。返回结果中 status=1 表示该点位下发成功。"""
  104. payload = api_get_command_log(
  105. project_key,
  106. point_id=point_id,
  107. begin=begin,
  108. end=end,
  109. page_size=page_size,
  110. page_num=page_num,
  111. export=export,
  112. )
  113. return _append_next_page_hint(payload, page_num)
  114. def main() -> None:
  115. host = os.getenv("MCP_HOST", "0.0.0.0").strip() or "0.0.0.0"
  116. port = int(os.getenv("MCP_PORT", "8500"))
  117. path = os.getenv("MCP_PATH", "/mcp").strip() or "/mcp"
  118. mcp.run(transport="http", host=host, port=port, path=path)
  119. if __name__ == "__main__":
  120. main()