Skip to main content
Glama

Magic-API MCP Server

by Dwsy
search_manager.py8.89 kB
#!/usr/bin/env python3 """Magic-API 搜索客户端 CLI。""" from __future__ import annotations import argparse import json import os import sys from dataclasses import dataclass from typing import Any, Dict, List, Mapping, MutableMapping, Optional import requests def _get_env(env: Mapping[str, str], key: str, default: str) -> str: return env.get(key, default) def _str_to_bool(value: Optional[str]) -> bool: if value is None: return False return value.strip().lower() in {"1", "true", "yes", "on"} DEFAULT_BASE_URL = "http://127.0.0.1:10712" DEFAULT_WS_URL = "ws://127.0.0.1:10712/magic/web/console" DEFAULT_TIMEOUT = 30.0 @dataclass(slots=True) class MagicAPISettings: """封装 Magic-API 服务相关的环境配置。""" base_url: str = DEFAULT_BASE_URL ws_url: str = DEFAULT_WS_URL username: str | None = None password: str | None = None token: str | None = None auth_enabled: bool = False timeout_seconds: float = DEFAULT_TIMEOUT @classmethod def from_env(cls, env: Mapping[str, str] | None = None) -> "MagicAPISettings": """从环境变量加载配置。""" env = env or os.environ base_url = _get_env(env, "MAGIC_API_BASE_URL", DEFAULT_BASE_URL).rstrip("/") ws_url = _get_env(env, "MAGIC_API_WS_URL", DEFAULT_WS_URL) username = env.get("MAGIC_API_USERNAME") or None password = env.get("MAGIC_API_PASSWORD") or None token = env.get("MAGIC_API_TOKEN") or None auth_enabled = _str_to_bool(env.get("MAGIC_API_AUTH_ENABLED")) timeout_raw = env.get("MAGIC_API_TIMEOUT_SECONDS") try: timeout_seconds = float(timeout_raw) if timeout_raw else DEFAULT_TIMEOUT except (TypeError, ValueError): timeout_seconds = DEFAULT_TIMEOUT return cls( base_url=base_url, ws_url=ws_url, username=username, password=password, token=token, auth_enabled=auth_enabled, timeout_seconds=timeout_seconds, ) def inject_auth(self, headers: MutableMapping[str, str]) -> MutableMapping[str, str]: """根据配置向请求头注入认证信息。""" if not self.auth_enabled: return headers if self.token: headers.setdefault("Authorization", f"Bearer {self.token}") headers.setdefault("Magic-Token", self.token) if self.username and self.password: headers.setdefault("Magic-Username", self.username) headers.setdefault("Magic-Password", self.password) return headers class MagicAPISearchClient: """Magic-API 搜索客户端。""" def __init__(self, settings: MagicAPISettings) -> None: self.settings = settings self.session = requests.Session() self.session.headers.update({ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", "User-Agent": "magicapi-search-manager/1.0", }) self.settings.inject_auth(self.session.headers) if self.settings.auth_enabled and self.settings.username and self.settings.password: self._login() def _login(self) -> bool: """登录获取认证。""" payload = { "username": self.settings.username, "password": self.settings.password, } try: response = self.session.post( f"{self.settings.base_url}/magic/web/login", data=payload, timeout=self.settings.timeout_seconds, ) if response.status_code == 200: try: data = response.json() return data.get("code") == 1 except json.JSONDecodeError: pass except requests.RequestException: pass return False def search(self, keyword: str, limit: int = 5) -> List[Dict[str, Any]]: """在所有 API 脚本中搜索关键词。 Args: keyword: 搜索关键词 Returns: 搜索结果列表,每个结果包含 id、text、line 字段 """ if not keyword.strip(): print("❌ 搜索关键词不能为空") return [] url = f"{self.settings.base_url}/magic/web/search" data = {'keyword': keyword} try: response = self.session.post(url, data=data, timeout=self.settings.timeout_seconds) response.raise_for_status() result = response.json() if result.get("code") == 1: results = result.get("data", []) # 应用 limit 限制 if limit > 0: results = results[:limit] return results else: print(f"❌ API 返回错误: {result.get('message', '未知错误')}") return [] except requests.RequestException as exc: print(f"❌ 请求异常: {exc}") return [] def search_todo(self, limit: int = 5) -> List[Dict[str, Any]]: """搜索所有 TODO 注释。 Returns: TODO 注释列表,每个结果包含 id、text、line 字段 """ url = f"{self.settings.base_url}/magic/web/todo" try: response = self.session.get(url, timeout=self.settings.timeout_seconds) response.raise_for_status() result = response.json() if result.get("code") == 1: results = result.get("data", []) # 应用 limit 限制 if limit > 0: results = results[:limit] return results else: print(f"❌ API 返回错误: {result.get('message', '未知错误')}") return [] except requests.RequestException as exc: print(f"❌ 请求异常: {exc}") return [] def parse_args() -> argparse.Namespace: """解析命令行参数。""" parser = argparse.ArgumentParser(description="Magic-API 搜索客户端") parser.add_argument("--search", help="在所有API脚本中搜索关键词") parser.add_argument("--todo", action="store_true", help="搜索所有TODO注释") parser.add_argument("--limit", type=int, default=5, help="返回结果的最大数量(默认5条)") parser.add_argument("--json", action="store_true", help="以JSON格式输出结果") return parser.parse_args() def build_client(settings: MagicAPISettings) -> MagicAPISearchClient: """构建搜索客户端。""" return MagicAPISearchClient(settings) def perform_search(client: MagicAPISearchClient, keyword: str, limit: int, json_output: bool) -> None: """执行关键词搜索。""" print(f"🔍 搜索关键词: '{keyword}' (限制 {limit} 条)") results = client.search(keyword, limit) if json_output: print(json.dumps(results, ensure_ascii=False, indent=2)) else: if not results: print("📭 没有找到匹配的结果") return print(f"📋 找到 {len(results)} 个匹配结果:") for i, result in enumerate(results, 1): print(f"{i}. 文件ID: {result.get('id', 'N/A')}") print(f" 行号: {result.get('line', 'N/A')}") print(f" 内容: {result.get('text', 'N/A')}") print() def perform_todo_search(client: MagicAPISearchClient, limit: int, json_output: bool) -> None: """执行TODO搜索。""" print(f"📝 搜索TODO注释... (限制 {limit} 条)") results = client.search_todo(limit) if json_output: print(json.dumps(results, ensure_ascii=False, indent=2)) else: if not results: print("📭 没有找到TODO注释") return print(f"📋 找到 {len(results)} 个TODO注释:") for i, result in enumerate(results, 1): print(f"{i}. 文件ID: {result.get('id', 'N/A')}") print(f" 行号: {result.get('line', 'N/A')}") print(f" 内容: {result.get('text', 'N/A')}") print() def main() -> None: """主函数。""" args = parse_args() # 验证参数组合 operations = [bool(args.search), args.todo] if sum(operations) != 1: print("❌ 必须且只能指定一个操作: --search 或 --todo") sys.exit(1) settings = MagicAPISettings.from_env() client = build_client(settings) try: if args.search: perform_search(client, args.search, args.limit, args.json) elif args.todo: perform_todo_search(client, args.limit, args.json) except KeyboardInterrupt: print("\n⏹️ 操作已取消") sys.exit(1) 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/Dwsy/magic-api-mcp-server'

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