server.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. from __future__ import annotations
  2. import json
  3. import os
  4. from typing import Any
  5. from fastmcp import FastMCP
  6. from .auth import load_projects_config
  7. from .config_api import (
  8. SetPointValueItem,
  9. get_ai_online_v2 as api_get_ai_online_v2,
  10. search_ai_rcmd_operations as api_search_ai_rcmd_operations,
  11. search_ai_systems as api_search_ai_systems,
  12. set_multi_values as api_set_multi_values,
  13. )
  14. mcp = FastMCP("m2")
  15. @mcp.tool(
  16. name="project.list",
  17. title="Project List",
  18. description="List enabled projects configured in sys_config for m2 tools. 在执行其他工具前,询问用户要查询哪一个项目,根据用户的选择查询对应项目。",
  19. tags={"project", "list"},
  20. )
  21. def project_list() -> dict[str, Any]:
  22. projects = load_projects_config()
  23. result: list[dict[str, Any]] = []
  24. for item in projects:
  25. if not item["enabled"]:
  26. continue
  27. result.append(
  28. {
  29. "project_key": item["project_key"],
  30. "project_name": item["project_name"],
  31. }
  32. )
  33. result.sort(key=lambda item: item["project_key"])
  34. return {
  35. "projects": result,
  36. "total": len(result),
  37. }
  38. def _append_next_page_hint(payload: Any, page_num: int) -> Any:
  39. if not isinstance(payload, dict):
  40. return payload
  41. total_page = None
  42. data = payload.get("data")
  43. if isinstance(data, dict):
  44. total_page = data.get("total_page")
  45. if total_page is None:
  46. total_page = payload.get("total_pages")
  47. if total_page is None:
  48. total_page = payload.get("total_page")
  49. if isinstance(total_page, int) and total_page > page_num:
  50. payload.setdefault(
  51. "mcp_note",
  52. f"Current result is page {page_num}. If the target was not found, continue with page_num={page_num + 1}.",
  53. )
  54. return payload
  55. def _print_set_multi_values_request(project_key: str, points: list[SetPointValueItem], from_: str) -> None:
  56. print(
  57. json.dumps(
  58. {
  59. "event": "set_multi_values",
  60. "project_key": project_key,
  61. "from": from_,
  62. "points": points,
  63. },
  64. ensure_ascii=False,
  65. )
  66. )
  67. @mcp.tool()
  68. def search_ai_systems(
  69. project_key: str,
  70. keyword: str = "",
  71. page_size: int = 20,
  72. page_num: int = 1,
  73. order_by: list[str] | None = None,
  74. ) -> Any:
  75. """Search AI systems and return system codes. Default page_size is 20 unless explicitly overridden."""
  76. payload = api_search_ai_systems(
  77. project_key,
  78. keyword=keyword,
  79. page_size=page_size,
  80. page_num=page_num,
  81. order_by=order_by,
  82. )
  83. return _append_next_page_hint(payload, page_num)
  84. @mcp.tool()
  85. def search_ai_rcmd_operations(
  86. project_key: str,
  87. codes: list[str],
  88. end: str,
  89. page_size: int = 20,
  90. page_num: int = 1,
  91. order: str = "-create_time",
  92. ) -> Any:
  93. """Search AI strategy records by AI system code. Default page_size is 20 unless explicitly overridden. auto_exec=true means auto control, otherwise recommendation only."""
  94. payload = api_search_ai_rcmd_operations(
  95. project_key,
  96. codes=codes,
  97. end=end,
  98. page_size=page_size,
  99. page_num=page_num,
  100. order=order,
  101. )
  102. return _append_next_page_hint(payload, page_num)
  103. @mcp.tool()
  104. def get_ai_online_v2(project_key: str, codes: list[str]) -> Any:
  105. """Get AI control mode and status by AI system code. control_mode=1 means auto control; status=0 means normal and 1 means abnormal."""
  106. return api_get_ai_online_v2(project_key, codes=codes)
  107. @mcp.tool()
  108. def set_multi_values(project_key: str, points: list[SetPointValueItem], from_: str = "M2_BACKEND") -> Any:
  109. """Write multiple point values to upstream basedataportal."""
  110. _print_set_multi_values_request(project_key, points, from_)
  111. return api_set_multi_values(project_key, points=points, from_=from_)
  112. def main() -> None:
  113. host = os.getenv("MCP_HOST", "0.0.0.0").strip() or "0.0.0.0"
  114. port = int(os.getenv("MCP_PORT", "8500"))
  115. path = os.getenv("MCP_PATH", "/mcp").strip() or "/mcp"
  116. mcp.run(transport="http", host=host, port=port, path=path)
  117. if __name__ == "__main__":
  118. main()