Metadata-Version: 2.4
Name: subway-mcp-open-api-adapter
Version: 1.1.0
Summary: MCP Adapter for Subway Open Platform - Exposes open platform APIs as MCP tools
Author-email: Subway Team <vesalius.li@subway.com.cn>
License: MIT
Project-URL: Homepage, https://www.subway.com.cn
Keywords: mcp,open-platform,subway,ai,adapter
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: mcp>=1.0.0
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: cryptography>=41.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: black>=23.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"

# Subway Open Platform MCP Adapter

将 Subway 开放平台 API 通过 MCP (Model Context Protocol) 协议暴露为 AI 可调用的工具。

## 概述

这个 MCP Adapter 服务将 Java 开放平台客户端封装为 Python MCP 工具，使得 AI 助手可以直接调用开放平台接口。它自动处理：

- ✅ RSA 签名生成（完全兼容 Java 实现）
- ✅ 时间戳和随机数生成
- ✅ 请求头自动注入
- ✅ Token 鉴权支持
- ✅ 异步 HTTP 调用

## 快速开始

### 1. 安装 uv

```bash
# macOS
brew install uv

# Linux/Windows
curl -LsSf https://astral.sh/uv/install.sh | sh
```

### 2. 配置 AI IDE

在 Cursor/Claude Desktop 的 MCP 配置中添加：

```json
{
  "mcpServers": {
    "subway-open-platform": {
      "command": "uvx",
      "args": ["subway-mcp-open-api-adapter"],
      "env": {
        "OPEN_PLATFORM_GATEWAY_URL": "https://your-gateway.com",
        "OPEN_PLATFORM_APP_INSTANCE_ID": "your-instance-id",
        "OPEN_PLATFORM_PARTNER_ID": "your-partner-id",
        "OPEN_PLATFORM_APP_INSTANCE_VERSION": "1.0.0",
        "OPEN_PLATFORM_PRIVATE_KEY": "-----BEGIN PRIVATE KEY-----\nYOUR_KEY\n-----END PRIVATE KEY-----",
        "OPEN_PLATFORM_ACCESS_TOKEN": "token-abc-123"
      }
    }
  }
}
```

### 3. 开始使用

重启 AI IDE 后，可以直接在对话中使用：

```
查询会员 3742473176800792202 的信息
```

## 配置说明

### 环境变量清单

| 环境变量 | 必填 | 说明 | 示例 |
|---------|------|------|------|
| `OPEN_PLATFORM_GATEWAY_URL` | ✅ | 开放平台网关地址 | `https://api.example.com` |
| `OPEN_PLATFORM_APP_INSTANCE_ID` | ✅ | 应用实例 ID | `instance-001` |
| `OPEN_PLATFORM_PARTNER_ID` | ✅ | **商户号** | `P123456` |
| `OPEN_PLATFORM_APP_INSTANCE_VERSION` | ❌ | 应用版本（默认 `1.0.0`） | `1.0.0` |
| `OPEN_PLATFORM_PRIVATE_KEY` | ✅ | RSA 私钥（PEM 格式） | `-----BEGIN PRIVATE KEY-----...` |
| `OPEN_PLATFORM_ACCESS_TOKEN` | ❌ | 访问令牌 | `token-abc-123` |

### 重要说明

**appInstanceId vs partnerId**：
- `OPEN_PLATFORM_APP_INSTANCE_ID` → 用于 `appInstanceId` 请求头（网关签名）
- `OPEN_PLATFORM_PARTNER_ID` → 用于 `auth_partnerId` 请求头（业务鉴权）和请求体中的 `partnerId` 字段
- 这两个值**可能相同**，但它们是**不同的配置项**

## 可用的 MCP 工具

### 1. get_member_info - 查询会员信息

**对应Java接口**: `SaasMemberClient.getMember()`  
**API路径**: `POST /opencenter/customer/member/getMember`

支持通过会员ID、手机号或动态码查询：

```python
# 通过会员ID查询
get_member_info(ident_type="memberId", ident_id="3742473176800792202")

# 通过手机号查询
get_member_info(ident_type="mobile", ident_id="13800138000")

# 通过动态码查询
get_member_info(ident_type="dynamicCode", ident_id="56#123456#")
```

### 2. svc_refund - 会员储值卡退款

**对应Java接口**: `SaasMemberSvcClient.svcRefund()`  
**API路径**: `POST /opencenter/mam/member/svc/refund`

```python
svc_refund(
    fpid="FP001",
    out_order_no="OUT123456",
    refund_trade_no="REFUND789",
    refund_amount=10000,  # 单位：分（10000分=100元）
    refund_desc="客户申请退款"
)
```

## 签名机制

### 自动处理的请求头

每次请求都会自动生成以下请求头：

#### 签名相关（SaaSFeignConfig）

```http
apiVersion: v2
appInstanceId: {OPEN_PLATFORM_APP_INSTANCE_ID}
appVersion: {OPEN_PLATFORM_APP_INSTANCE_VERSION}
nonce: {自动生成10位随机字符串}
timestamp: {当前时间戳(毫秒)}
sign: {RSA签名}
```

**签名算法**：
- 签名字符串格式：`{timestamp};{nonce};{request_body};`
- 签名算法：SHA256withRSA
- 使用紧凑JSON格式（无空格），与Java Feign/Jackson一致

#### 业务鉴权（GlobalFeignConfig）

```http
access_token: {OPEN_PLATFORM_ACCESS_TOKEN}  # 如果配置了
auth_partnerId: {OPEN_PLATFORM_PARTNER_ID}
auth_appId: {OPEN_PLATFORM_APP_ID}
```

## 项目结构

```
mcp-python/
├── src/subway_mcp_adapter/          # 源代码
│   ├── __init__.py                  # 包初始化
│   ├── config.py                    # 配置管理
│   ├── client.py                    # HTTP客户端（含签名逻辑）
│   ├── server.py                    # MCP Server（工具定义）
│   └── utils/
│       ├── rsa.py                   # RSA签名工具
│       └── nonce.py                 # 随机数生成
├── README.md                        # 项目文档
├── HEADERS_MAPPING.md               # 请求头详细说明
├── INTERFACE_REVISION.md            # 接口修订说明
├── pyproject.toml                   # 项目配置
├── requirements.txt                 # Python依赖
└── Makefile                         # 构建脚本
```

## 技术栈

- **Python**: 3.10+
- **MCP Framework**: FastMCP
- **HTTP Client**: httpx (异步)
- **加密库**: cryptography
- **配置管理**: pydantic + pyyaml

## 常见问题

### Q: 签名验证失败怎么办？

1. 检查私钥格式是否正确（PEM格式）
2. 确认所有必填环境变量已配置
3. 设置 DEBUG 日志查看详细信息：
   ```bash
   export MCP_LOG_LEVEL=DEBUG
   ```

### Q: 如何添加新的 API 接口？

编辑 `src/subway_mcp_adapter/server.py`，在 `_register_tools()` 方法中添加：

```python
@self.mcp.tool(name="new_tool", description="描述这个工具的功能")
async def new_tool(param1: str) -> str:
    response = await self.client.post(
        "/your-api-path",
        body={"param1": param1}
    )
    return json.dumps(response, ensure_ascii=False, indent=2)
```

## 相关文档

- [请求头详细说明](HEADERS_MAPPING.md) - 完整的请求头映射和签名算法说明

## 许可证

Internal Use Only
