Groot 5 months ago
commit
740d2aa5a1
7 changed files with 20427 additions and 0 deletions
  1. BIN
      .DS_Store
  2. 97 0
      README.md
  3. 156 0
      install.sh
  4. 19609 0
      mcp_introduce
  5. 492 0
      rap2-mcp/rap2_mcp_server.py
  6. 2 0
      requirements.txt
  7. 71 0
      start.sh

BIN
.DS_Store


+ 97 - 0
README.md

@@ -0,0 +1,97 @@
+# RAP2 MCP工具
+
+这个工具提供了RAP2 API的MCP接口,使你可以通过AI助手查询和使用RAP2 API文档。
+
+## 安装
+
+```bash
+# 克隆仓库
+git clone https://github.com/yourusername/rap-mcp.git
+cd rap-mcp
+
+# 运行安装脚本
+chmod +x install.sh
+./install.sh
+```
+
+## 配置
+
+安装完成后,您需要在Cursor的MCP配置文件中添加RAP2 MCP服务器配置。建议使用以下格式:
+
+```json
+{
+  "mcpServers": {
+    "RAP2 MCP": {
+      "command": "/path/to/venv/bin/python",
+      "args": [
+        "/path/to/rap2-mcp/rap2_mcp_server.py",
+        "--rap2-url=http://rap2api.taobao.org",
+        "--rap2-sid=您的koa.sid值",
+        "--rap2-sid-sig=您的koa.sid.sig值"
+      ]
+    }
+  }
+}
+```
+
+### 参数获取方式
+
+RAP2 MCP工具支持以下几种参数获取方式(按优先级从高到低):
+
+1. **请求头传递**:通过HTTP请求头传递参数
+   - `X-RAP2-BASE-URL`: RAP2服务器地址
+   - `X-RAP2-SID`: koa.sid Cookie值
+   - `X-RAP2-SID-SIG`: koa.sid.sig Cookie值
+
+2. **命令行参数**:通过命令行参数传递
+   ```
+   --rap2-url=http://rap2api.taobao.org --rap2-sid=您的koa.sid值 --rap2-sid-sig=您的koa.sid.sig值
+   ```
+
+### MCP配置文件位置
+
+- macOS/Linux: `~/.cursor/mcp.json`
+- Windows: `%USERPROFILE%\.cursor\mcp.json`
+
+### 获取RAP2 Cookie值
+
+1. 使用浏览器登录RAP2
+2. 打开开发者工具(F12)
+3. 切换到Network(网络)标签页
+4. 刷新页面,选择任意请求
+5. 在Headers中找到Cookie字段
+6. 从Cookie中提取以下两个值:
+   - `koa.sid=xxxxxx` 中的 xxxxxx 部分
+   - `koa.sid.sig=yyyyyy` 中的 yyyyyy 部分
+
+## 使用
+
+### 快速启动
+
+安装完成后,可以使用以下命令快速启动服务器:
+
+```bash
+./start.sh --url=http://rap2api.taobao.org --sid=您的koa.sid值 --sid-sig=您的koa.sid.sig值
+```
+
+查看帮助信息:
+
+```bash
+./start.sh --help
+```
+
+### 通过Cursor插件使用
+
+配置完成后,在Cursor IDE中启用RAP2 MCP插件即可使用。
+
+## 主要功能
+
+- **查询接口详情**:获取指定ID的接口信息
+- **获取仓库接口**:获取指定仓库中的所有接口
+- **搜索接口**:通过关键词搜索接口
+- **生成API代码**:根据接口生成前端调用代码(支持fetch、axios、react-query)
+- **测试连接**:测试与RAP2服务器的连接状态
+
+## 开发者信息
+
+如需贡献代码或报告问题,请访问我们的GitHub仓库:[rap-mcp](https://github.com/yourusername/rap-mcp) 

+ 156 - 0
install.sh

@@ -0,0 +1,156 @@
+#!/bin/bash
+
+# 颜色定义
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+RED='\033[0;31m'
+BLUE='\033[0;34m'
+NC='\033[0m' # 无颜色
+
+# 获取脚本所在目录的绝对路径
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# 显示标题
+echo -e "${BLUE}=========================================${NC}"
+echo -e "${BLUE}      RAP2 MCP 工具安装程序           ${NC}"
+echo -e "${BLUE}=========================================${NC}"
+echo ""
+
+# 检查Python环境
+echo -e "${YELLOW}[1/6] 检查Python环境...${NC}"
+if ! command -v python3 &> /dev/null; then
+    echo -e "${RED}错误: 未找到Python3,请先安装Python3${NC}"
+    exit 1
+fi
+
+PYTHON_VERSION=$(python3 --version | awk '{print $2}')
+echo -e "${GREEN}✓ 已找到Python $PYTHON_VERSION${NC}"
+
+# 检查和创建目录结构
+echo -e "${YELLOW}[2/6] 设置目录结构...${NC}"
+if [ ! -d "${SCRIPT_DIR}/rap2-mcp" ]; then
+    echo -e "创建rap2-mcp目录..."
+    mkdir -p "${SCRIPT_DIR}/rap2-mcp"
+fi
+
+# 确保服务器脚本在正确位置
+if [ -f "${SCRIPT_DIR}/rap2_mcp_server.py" ] && [ ! -f "${SCRIPT_DIR}/rap2-mcp/rap2_mcp_server.py" ]; then
+    echo -e "移动服务器脚本到正确位置..."
+    cp "${SCRIPT_DIR}/rap2_mcp_server.py" "${SCRIPT_DIR}/rap2-mcp/rap2_mcp_server.py"
+fi
+
+echo -e "${GREEN}✓ 目录结构已准备就绪${NC}"
+
+# 创建虚拟环境
+echo -e "${YELLOW}[3/6] 创建Python虚拟环境...${NC}"
+if [ -d "${SCRIPT_DIR}/venv" ]; then
+    echo -e "检测到已有虚拟环境,是否重新创建? [y/N] "
+    read -r response
+    if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
+        echo -e "删除旧的虚拟环境..."
+        rm -rf "${SCRIPT_DIR}/venv"
+        python3 -m venv "${SCRIPT_DIR}/venv"
+    fi
+else
+    python3 -m venv "${SCRIPT_DIR}/venv"
+fi
+
+# 激活虚拟环境
+if [ -f "${SCRIPT_DIR}/venv/bin/activate" ]; then
+    source "${SCRIPT_DIR}/venv/bin/activate"
+    echo -e "${GREEN}✓ 虚拟环境已激活${NC}"
+else
+    echo -e "${RED}错误: 无法创建或激活虚拟环境${NC}"
+    exit 1
+fi
+
+# 更新pip
+echo -e "${YELLOW}[4/6] 更新pip...${NC}"
+pip install --upgrade pip > /dev/null 2>&1
+echo -e "${GREEN}✓ pip已更新至最新版本${NC}"
+
+# 安装依赖
+echo -e "${YELLOW}[5/6] 安装依赖...${NC}"
+
+# 创建requirements.txt如果不存在
+if [ ! -f "${SCRIPT_DIR}/requirements.txt" ]; then
+    echo -e "创建requirements.txt文件..."
+    cat > "${SCRIPT_DIR}/requirements.txt" << EOF
+httpx>=0.24.0
+fastmcp>=0.1.0
+mcp-server>=0.1.0
+fastapi>=0.100.0
+EOF
+fi
+
+# 安装依赖
+echo -e "从requirements.txt安装依赖..."
+pip install -r "${SCRIPT_DIR}/requirements.txt"
+
+# 验证依赖安装
+DEPS_OK=true
+
+for pkg in httpx mcp.server fastmcp; do
+    echo -n "检查 $pkg... "
+    if ! python -c "import $pkg" &> /dev/null; then
+        echo -e "${RED}失败${NC}"
+        echo -e "${RED}尝试单独安装 $pkg...${NC}"
+        pip install $pkg
+        if ! python -c "import $pkg" &> /dev/null; then
+            echo -e "${RED}无法安装 $pkg${NC}"
+            DEPS_OK=false
+        else
+            echo -e "${GREEN}成功${NC}"
+        fi
+    else
+        echo -e "${GREEN}成功${NC}"
+    fi
+done
+
+if [ "$DEPS_OK" = false ]; then
+    echo -e "${RED}警告: 部分依赖安装失败,程序可能无法正常工作${NC}"
+else
+    echo -e "${GREEN}✓ 所有依赖已成功安装${NC}"
+fi
+
+# 设置启动脚本权限
+echo -e "${YELLOW}[6/6] 设置启动脚本权限...${NC}"
+chmod +x "${SCRIPT_DIR}/start.sh"
+echo -e "${GREEN}✓ 启动脚本权限已设置${NC}"
+
+echo -e "${GREEN}安装完成!${NC}"
+echo ""
+
+# 显示MCP配置说明
+echo -e "${YELLOW}=== RAP2 MCP 配置指南 ===${NC}"
+echo -e "请在Cursor的MCP配置文件中添加以下配置:"
+echo -e ""
+echo -e "${GREEN}文件路径: ${HOME}/.cursor/mcp.json${NC}"
+echo -e ""
+echo -e "配置格式:"
+echo -e "${YELLOW}{
+  \"mcpServers\": {
+    \"RAP2 MCP\": {
+      \"command\": \"${SCRIPT_DIR}/venv/bin/python\",
+      \"args\": [
+        \"${SCRIPT_DIR}/rap2-mcp/rap2_mcp_server.py\",
+        \"--rap2-url=http://rap2api.taobao.org\",
+        \"--rap2-sid=您的koa.sid值\",
+        \"--rap2-sid-sig=您的koa.sid.sig值\"
+      ]
+    }
+  }
+}${NC}"
+echo -e ""
+echo -e "${YELLOW}如何获取Cookie值:${NC}"
+echo -e "1. 使用浏览器登录RAP2系统"
+echo -e "2. 打开开发者工具(F12),切换到网络(Network)标签"
+echo -e "3. 选择任意请求,在Headers中找到Cookie"
+echo -e "4. 从Cookie中提取koa.sid和koa.sid.sig的值"
+echo -e ""
+echo -e "${YELLOW}快速启动:${NC}"
+echo -e "可以使用以下命令快速启动服务器:"
+echo -e "${GREEN}./start.sh --url=http://rap2api.taobao.org --sid=您的koa.sid值 --sid-sig=您的koa.sid.sig值${NC}"
+echo -e ""
+echo -e "${GREEN}祝你使用愉快!${NC}" 
+echo -e "${BLUE}=========================================${NC}" 

File diff suppressed because it is too large
+ 19609 - 0
mcp_introduce


+ 492 - 0
rap2-mcp/rap2_mcp_server.py

@@ -0,0 +1,492 @@
+import httpx
+import json
+import argparse
+import os
+from fastmcp import FastMCP
+from typing import Dict, List, Optional, Union, Any, Tuple
+from fastmcp.server.dependencies import get_http_headers
+from mcp.server.session import ServerSession
+
+
+old__received_request = ServerSession._received_request
+
+async def _received_request(self, *args, **kwargs):
+    try:
+        return await old__received_request(self, *args, **kwargs)
+    except RuntimeError:
+        pass
+
+# pylint: disable-next=protected-access
+ServerSession._received_request = _received_request
+
+# 初始化FastMCP服务器
+app = FastMCP('rap2-api-server')
+
+# 设置服务器配置
+HOST = '0.0.0.0'  # 绑定到所有接口,允许局域网访问
+PORT = 8903       # 使用8903端口
+TRANSPORT = 'stdio'  # 使用SSE传输
+
+# 解析命令行参数
+parser = argparse.ArgumentParser(description='RAP2 MCP服务器')
+parser.add_argument('--rap2-url', help='RAP2服务器地址')
+parser.add_argument('--rap2-sid', help='RAP2 koa.sid Cookie值')
+parser.add_argument('--rap2-sid-sig', help='RAP2 koa.sid.sig Cookie值')
+
+# 全局存储命令行参数
+args = parser.parse_args()
+
+# 错误消息常量
+RAP2_URL_MISSING_ERROR = "未提供RAP2服务器地址,请通过命令行参数--rap2-url、环境变量RAP2_URL或请求头X-RAP2-BASE-URL提供"
+EMPTY_RESPONSE_ERROR = "服务器返回了空响应"
+
+# 通用的JSON解析函数
+def parse_rap2_response(response: httpx.Response) -> Tuple[bool, Dict]:
+    """
+    解析RAP2 API响应
+    
+    Args:
+        response: HTTP响应对象
+        
+    Returns:
+        Tuple[bool, Dict]: (是否成功, 数据或错误信息)
+    """
+    # 检查响应内容是否为空
+    if not response.text.strip():
+        return False, {"error": EMPTY_RESPONSE_ERROR}
+    
+    # 尝试解析JSON响应
+    try:
+        data = response.json()
+    except json.JSONDecodeError as e:
+        return False, {
+            "error": f"无法解析返回的JSON: {str(e)}",
+            "content": response.text[:500]
+        }
+    
+    # 检查是否有错误消息
+    if data.get("errMsg"):
+        return False, {"error": data.get("errMsg")}
+    
+    return True, data
+
+# 创建带Cookie的请求头,同时支持从命令行参数和请求头获取
+def get_requestInfo():
+    """
+    获取RAP2请求信息,支持从环境变量、命令行参数和请求头获取
+    优先级: 请求头 > 命令行参数 > 环境变量
+    
+    Returns:
+        Dict: 包含url和header的字典
+    """
+    info = {
+        "url": None,
+        "header": {
+            "cookies": {}
+        }
+    }
+    
+    # 按优先级获取URL
+    info["url"] = (get_http_headers().get("X-RAP2-BASE-URL") if get_http_headers() else None) or \
+                  args.rap2_url or \
+                  os.environ.get("RAP2_URL")
+    
+    # 按优先级获取Cookie
+    headers = get_http_headers()
+    
+    # koa.sid
+    sid = (headers.get("X-RAP2-SID") if headers else None) or \
+          args.rap2_sid or \
+          os.environ.get("RAP2_SID")
+    if sid:
+        info["header"]["cookies"]["koa.sid"] = sid
+    
+    # koa.sid.sig
+    sid_sig = (headers.get("X-RAP2-SID-SIG") if headers else None) or \
+              args.rap2_sid_sig or \
+              os.environ.get("RAP2_SID_SIG")
+    if sid_sig:
+        info["header"]["cookies"]["koa.sid.sig"] = sid_sig
+    
+    return info
+
+@app.tool()
+async def get_interface_by_id(interface_id: str) -> Dict:
+    """
+    通过接口ID获取RAP2接口的详细信息
+    
+    Args:
+        interface_id: RAP2中的接口ID
+        
+    Returns:
+        接口的详细信息,包括URL、方法、参数和响应数据结构
+    """
+    try:
+        # 从请求中获取RAP2信息
+        rap2_info = get_requestInfo()
+        rap2_base_url = rap2_info["url"]
+        rap2_header = rap2_info["header"]
+        
+        if not rap2_base_url:
+            return {"error": RAP2_URL_MISSING_ERROR}
+        
+        # 处理请求头,将cookies字典转换为字符串格式
+        headers = {}
+        if "cookies" in rap2_header:
+            cookies_dict = rap2_header["cookies"]
+            cookie_str = "; ".join([f"{k}={v}" for k, v in cookies_dict.items()])
+            headers["Cookie"] = cookie_str
+        
+        # 调用RAP2 API获取接口详情
+        async with httpx.AsyncClient() as client:
+            url = f"{rap2_base_url}/interface/get?id={interface_id}"
+            
+            response = await client.get(url, headers=headers)
+            response.raise_for_status()
+            
+            # 解析响应
+            success, result = parse_rap2_response(response)
+            if not success:
+                return result
+                
+            interface = result.get("data", {})
+            return interface
+    except httpx.HTTPError as e:
+        return {"error": f"HTTP请求失败: {str(e)}"}
+    except Exception as e:
+        return {"error": f"获取接口信息失败: {str(e)}"}
+
+@app.tool()
+async def get_repository_interfaces(repository_id: str) -> List[Dict]:
+    """
+    获取指定仓库中的所有接口列表
+    
+    Args:
+        repository_id: RAP2中的仓库ID
+        
+    Returns:
+        仓库中的所有接口列表
+    """
+    try:
+        # 从请求中获取RAP2信息
+        rap2_info = get_requestInfo()
+        rap2_base_url = rap2_info["url"]
+        rap2_header = rap2_info["header"]
+        
+        if not rap2_base_url:
+            return {"error": RAP2_URL_MISSING_ERROR}
+            
+        async with httpx.AsyncClient() as client:
+            url = f"{rap2_base_url}/repository/get?id={repository_id}"
+            
+            response = await client.get(url, headers=rap2_header)
+            response.raise_for_status()
+            
+            # 解析响应
+            success, result = parse_rap2_response(response)
+            if not success:
+                return result
+            
+            # 返回仓库中的所有模块和接口
+            modules = result.get("data", {}).get("modules", [])
+            interfaces = []
+            
+            for module in modules:
+                for interface in module.get("interfaces", []):
+                    interface["moduleName"] = module.get("name", "")
+                    interfaces.append(interface)
+            
+            return interfaces
+    except httpx.HTTPError as e:
+        return {"error": f"HTTP请求失败: {str(e)}"}
+    except Exception as e:
+        return {"error": f"获取仓库接口列表失败: {str(e)}"}
+
+@app.tool()
+async def search_interfaces_by_keyword(keyword: str, repository_id: Optional[str] = None) -> List[Dict]:
+    """
+    通过关键词搜索接口
+    
+    Args:
+        keyword: 搜索关键词,可以是接口名称或URL的一部分
+        repository_id: 可选,限制在指定的仓库中搜索
+        
+    Returns:
+        匹配的接口列表
+    """
+    try:    
+        # 从请求中获取RAP2信息
+        rap2_info = get_requestInfo()
+        rap2_base_url = rap2_info["url"]
+        rap2_header = rap2_info["header"]
+        
+        if not rap2_base_url:
+            return {"error": RAP2_URL_MISSING_ERROR}
+            
+        # 如果提供了repository_id,则在指定仓库中搜索
+        if repository_id:
+            interfaces = await get_repository_interfaces(repository_id)
+            if isinstance(interfaces, dict) and interfaces.get("error"):
+                return interfaces
+        else:
+            # 否则使用RAP2的搜索API
+            async with httpx.AsyncClient() as client:
+                url = f"{rap2_base_url}/interface/list?keyword={keyword}"
+                
+                response = await client.get(url, headers=rap2_header)
+                response.raise_for_status()
+                
+                # 解析响应
+                success, result = parse_rap2_response(response)
+                if not success:
+                    return result
+                
+                interfaces = result.get("data", [])
+        
+        # 如果是在指定仓库中搜索,需要过滤结果
+        if repository_id and not isinstance(interfaces, dict):
+            filtered_interfaces = []
+            for interface in interfaces:
+                if (keyword.lower() in interface.get("name", "").lower() or 
+                    keyword.lower() in interface.get("url", "").lower()):
+                    filtered_interfaces.append(interface)
+            return filtered_interfaces
+        
+        return interfaces
+    except httpx.HTTPError as e:
+        return {"error": f"HTTP请求失败: {str(e)}"}
+    except Exception as e:
+        return {"error": f"搜索接口失败: {str(e)}"}
+
+@app.tool()
+async def generate_api_implementation(interface_id: str, framework: str = "fetch") -> Dict:
+    """
+    根据接口ID生成API调用代码
+    
+    Args:
+        interface_id: RAP2中的接口ID
+        framework: 代码框架,可选值: fetch, axios, react-query
+        
+    Returns:
+        生成的API调用代码和类型定义
+    """
+    interface = await get_interface_by_id(interface_id)
+    
+    if isinstance(interface, dict) and interface.get("error"):
+        return interface
+    
+    # 构建基本信息
+    url = interface.get("url", "")
+    method = interface.get("method", "GET")
+    name = interface.get("name", "")
+    
+    # 获取请求参数和响应数据结构
+    properties = interface.get("properties", [])
+    request_params = [p for p in properties if p.get("scope") == "request"]
+    response_params = [p for p in properties if p.get("scope") == "response"]
+    
+    # 构建TypeScript类型定义
+    req_type_def = _build_type_definition(request_params, "Request")
+    res_type_def = _build_type_definition(response_params, "Response")
+    
+    # 根据框架生成不同的实现代码
+    impl_code = _generate_implementation_code(url, method, name, framework)
+    
+    return {
+        "name": name,
+        "url": url,
+        "method": method,
+        "requestType": req_type_def,
+        "responseType": res_type_def,
+        "implementationCode": impl_code,
+        "fullImplementation": f"{req_type_def}\n\n{res_type_def}\n\n{impl_code}"
+    }
+
+def _build_type_definition(params: List[Dict], suffix: str) -> str:
+    """构建TypeScript类型定义"""
+    # TypeScript类型映射
+    ts_type_map = {
+        "String": "string",
+        "Number": "number",
+        "Boolean": "boolean",
+        "Object": "object",
+        "Array": "any[]"
+    }
+    
+    result = [f"interface {suffix} {{"]
+    
+    for param in params:
+        prop_name = param.get("name", "")
+        prop_type = param.get("type", "String")
+        required = not param.get("required", False)
+        description = param.get("description", "")
+        
+        ts_type = ts_type_map.get(prop_type, "any")
+        comment = f" // {description}" if description else ""
+        optional_mark = "?" if not required else ""
+        
+        result.append(f"  {prop_name}{optional_mark}: {ts_type};{comment}")
+    
+    result.append("}")
+    return "\n".join(result)
+
+def _generate_implementation_code(url: str, method: str, name: str, framework: str) -> str:
+    """根据不同框架生成实现代码"""
+    fn_name = "".join([word.lower() if i == 0 else word.capitalize() for i, word in enumerate(name.split())])
+    method_upper = method.upper()
+    is_body_method = method_upper in ['POST', 'PUT', 'PATCH']
+    
+    if framework == "fetch":
+        return f"""
+// 使用fetch实现{name}接口
+export async function {fn_name}(params: Request): Promise<Response> {{
+  const response = await fetch('{url}', {{
+    method: '{method}',
+    headers: {{
+      'Content-Type': 'application/json',
+    }},
+    body: {is_body_method and 'JSON.stringify(params)' or 'undefined'},
+  }});
+  
+  if (!response.ok) {{
+    throw new Error(`API请求失败: ${{response.status}}`);
+  }}
+  
+  return response.json();
+}}
+""".strip()
+    elif framework == "axios":
+        return f"""
+// 使用axios实现{name}接口
+import axios from 'axios';
+
+export async function {fn_name}(params: Request): Promise<Response> {{
+  const response = await axios({{
+    url: '{url}',
+    method: '{method}',
+    data: {is_body_method and 'params' or 'undefined'},
+    params: {method_upper == 'GET' and 'params' or 'undefined'},
+  }});
+  
+  return response.data;
+}}
+""".strip()
+    elif framework == "react-query":
+        is_get = method_upper == 'GET'
+        hook_name = f"use{name.replace(' ', '')}"
+        
+        if is_get:
+            return f"""
+// 使用react-query实现{name}接口
+import {{ useQuery }} from '@tanstack/react-query';
+import axios from 'axios';
+
+// GET请求实现
+export function {hook_name}(params: Request) {{
+  return useQuery(['{name}', params], async () => {{
+    const response = await axios.get('{url}', {{ params }});
+    return response.data;
+  }});
+}}
+""".strip()
+        else:
+            return f"""
+// 使用react-query实现{name}接口
+import {{ useMutation }} from '@tanstack/react-query';
+import axios from 'axios';
+
+// 变更请求实现
+export function {hook_name}() {{
+  return useMutation(async (params: Request) => {{
+    const response = await axios.{method.lower()}('{url}', params);
+    return response.data;
+  }});
+}}
+""".strip()
+    else:
+        return f"// 未支持的框架: {framework}"
+
+@app.tool()
+async def test_rap2_connection() -> Dict:
+    """
+    测试与RAP2服务器的连接
+    
+    Returns:
+        测试结果,包含状态和详细信息
+    """
+    try:
+        # 从请求中获取RAP2信息
+        rap2_info = get_requestInfo()
+        rap2_base_url = rap2_info["url"]
+        rap2_header = rap2_info["header"]
+        
+        if not rap2_base_url:
+            return {
+                "status": "连接失败",
+                "message": RAP2_URL_MISSING_ERROR,
+                "url": "未知"
+            }
+            
+        # 测试1: 不带Cookie的请求
+        async with httpx.AsyncClient() as client:
+            response1 = await client.get(f"{rap2_base_url}/test/test", timeout=10.0)
+        
+        # 测试2: 带Cookie的请求
+        async with httpx.AsyncClient() as client:
+            response2 = await client.get(f"{rap2_base_url}/repository/joined", headers=rap2_header, timeout=10.0)
+            
+            # 解析响应
+            success, result = parse_rap2_response(response2)
+            if not success:
+                return {
+                    "status": "解析失败",
+                    "message": result.get("error", "未知错误"),
+                    "statusCode": response2.status_code
+                }
+            
+            # 检查身份验证状态
+            if isinstance(result, dict):
+                if result.get("isOk") is False and "没有访问权限" in str(result.get("errMsg", "")):
+                    return {
+                        "status": "未授权",
+                        "message": "Cookie无效或已过期,请更新Cookie",
+                        "detail": str(result.get("errMsg", ""))
+                    }
+        
+        return {
+            "status": "连接成功",
+            "message": f"成功连接到RAP2服务器: {rap2_base_url}",
+            "statusCode1": response1.status_code,
+            "statusCode2": response2.status_code
+        }
+    except Exception as e:
+        return {
+            "status": "连接失败",
+            "message": f"无法连接到RAP2服务器: {str(e)}",
+            "url": rap2_base_url if 'rap2_base_url' in locals() else "未知"
+        }
+
+if __name__ == "__main__":
+    # 输出启动配置信息
+    print("\n=== RAP2 MCP服务器启动 ===")
+    print(f"服务器地址: {HOST}:{PORT}")
+    print(f"传输方式: {TRANSPORT}")
+    
+    # 检查RAP2配置
+    rap2_url = args.rap2_url or os.environ.get("RAP2_URL")
+    rap2_sid = args.rap2_sid or os.environ.get("RAP2_SID")
+    rap2_sid_sig = args.rap2_sid_sig or os.environ.get("RAP2_SID_SIG")
+    
+    if rap2_url:
+        print(f"RAP2服务器: {rap2_url}")
+        if rap2_sid and rap2_sid_sig:
+            print("RAP2认证: 已配置")
+        else:
+            print("RAP2认证: 未配置 (将使用请求头获取)")
+    else:
+        print("RAP2服务器: 未配置 (将使用请求头获取)")
+    
+    print("=========================\n")
+    
+    # 直接使用 SSE 传输协议运行 MCP 服务器
+    app.run(transport=TRANSPORT)

+ 2 - 0
requirements.txt

@@ -0,0 +1,2 @@
+httpx>=0.24.0
+mcp-server>=0.1.0 

+ 71 - 0
start.sh

@@ -0,0 +1,71 @@
+#!/bin/bash
+
+# 获取脚本所在目录的绝对路径
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# 激活虚拟环境
+if [ -f "${SCRIPT_DIR}/venv/bin/activate" ]; then
+    source "${SCRIPT_DIR}/venv/bin/activate"
+else
+    echo "警告: 虚拟环境未找到,将使用系统Python环境"
+fi
+
+# 默认配置
+RAP2_URL=${RAP2_URL:-"http://rap2.atmob.com"}
+RAP2_SID=${RAP2_SID:-""}
+RAP2_SID_SIG=${RAP2_SID_SIG:-""}
+
+# 解析命令行参数
+while [[ $# -gt 0 ]]; do
+    case $1 in
+        --url=*)
+            RAP2_URL="${1#*=}"
+            shift
+            ;;
+        --sid=*)
+            RAP2_SID="${1#*=}"
+            shift
+            ;;
+        --sid-sig=*)
+            RAP2_SID_SIG="${1#*=}"
+            shift
+            ;;
+        --help)
+            echo "用法: ./start.sh [选项]"
+            echo "选项:"
+            echo "  --url=URL       设置RAP2服务器地址"
+            echo "  --sid=SID       设置RAP2 koa.sid Cookie值"
+            echo "  --sid-sig=SIG   设置RAP2 koa.sid.sig Cookie值"
+            echo "  --help          显示此帮助信息"
+            exit 0
+            ;;
+        *)
+            echo "未知选项: $1"
+            echo "使用 --help 查看帮助"
+            exit 1
+            ;;
+    esac
+done
+
+# 构建参数
+ARGS=""
+if [ -n "$RAP2_URL" ]; then
+    ARGS="$ARGS --rap2-url=$RAP2_URL"
+fi
+if [ -n "$RAP2_SID" ]; then
+    ARGS="$ARGS --rap2-sid=$RAP2_SID"
+fi
+if [ -n "$RAP2_SID_SIG" ]; then
+    ARGS="$ARGS --rap2-sid-sig=$RAP2_SID_SIG"
+fi
+
+echo "启动RAP2 MCP服务器..."
+echo "RAP2服务器: $RAP2_URL"
+if [ -n "$RAP2_SID" ] && [ -n "$RAP2_SID_SIG" ]; then
+    echo "RAP2认证: 已配置"
+else
+    echo "RAP2认证: 未配置"
+fi
+
+# 运行服务器,直接传递参数
+python "${SCRIPT_DIR}/rap2-mcp/rap2_mcp_server.py" $ARGS