# MCP Swagger 后端 API 服务实施方案
## 📋 方案概述
将 OpenAPI/Swagger 解析功能从前端提取为独立的后端 API 服务,实现前后端彻底分离,提升系统架构的可维护性、可扩展性和性能。
## 🎯 核心优势
### 1. 架构优势
- **关注点分离**: 前端专注UI交互,后端专注业务逻辑
- **技术栈解耦**: 前端无需处理复杂的Node.js依赖
- **独立部署**: 前后端可以独立构建、部署和扩展
- **版本管理**: API版本化管理,支持向后兼容
### 2. 性能优势
- **服务端解析**: 避免大型解析库在浏览器中加载
- **缓存机制**: 服务端可实现智能缓存策略
- **并发处理**: 服务端可处理多个并发解析请求
- **资源优化**: 减少前端包体积
### 3. 开发优势
- **调试便利**: 后端逻辑更容易调试和监控
- **测试友好**: API接口更容易进行单元测试和集成测试
- **扩展性强**: 可轻松添加新的解析格式和功能
## 🏗️ 技术架构设计
### 整体架构图
```
┌─────────────────────────────────────────────────────────────┐
│ 前端层 (Vue 3 + Vite) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ UI组件 │ │ 状态管理 │ │ HTTP客户端│ │
│ │ Naive UI │ │ Pinia │ │ Axios │ │
│ │ 表单/展示 │ │ 响应式 │ │ 拦截器 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────┼─────────────────────────────────┘
│ HTTP REST API
▼
┌─────────────────────────────────────────────────────────────┐
│ API网关层 (Express.js) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 路由管理 │ │ 中间件 │ │ 错误处理 │ │
│ │ RESTful API │ │ CORS │ │ 统一响应 │ │
│ │ 参数验证 │ │ Body Parser│ │ 日志记录 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────┼─────────────────────────────────┘
│ 业务逻辑调用
▼
┌─────────────────────────────────────────────────────────────┐
│ 业务服务层 (Service Layer) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 解析服务 │ │ 转换服务 │ │ 验证服务 │ │
│ │ ParserService│ │ConvertService│ │ValidateService│ │
│ │ 多格式支持 │ │ MCP转换 │ │ 规范检查 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────┼─────────────────────────────────┘
│ 核心库调用
▼
┌─────────────────────────────────────────────────────────────┐
│ 核心库层 (mcp-swagger-parser) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 解析器 │ │ 验证器 │ │ 转换器 │ │
│ │ 多格式解析 │ │ Schema校验 │ │ 格式转换 │ │
│ │ 错误处理 │ │ 结构验证 │ │ 数据映射 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## 🛠️ 实施计划
### 阶段一: 后端API服务搭建 (1-2天)
#### 1.1 创建独立的API服务模块
在现有的 monorepo 结构中新增:
```
packages/
├── mcp-swagger-api/ # 🆕 新增API服务
│ ├── src/
│ │ ├── app.ts # Express应用入口
│ │ ├── server.ts # 服务器启动文件
│ │ ├── routes/ # 路由定义
│ │ │ ├── index.ts
│ │ │ ├── parse.ts # 解析相关路由
│ │ │ ├── convert.ts # 转换相关路由
│ │ │ └── validate.ts # 验证相关路由
│ │ ├── services/ # 业务服务层
│ │ │ ├── parser.service.ts
│ │ │ ├── converter.service.ts
│ │ │ └── validator.service.ts
│ │ ├── middlewares/ # 中间件
│ │ │ ├── error-handler.ts
│ │ │ ├── cors.ts
│ │ │ └── validation.ts
│ │ ├── types/ # 类型定义
│ │ │ ├── api.ts
│ │ │ └── request.ts
│ │ └── utils/ # 工具函数
│ │ ├── response.ts
│ │ └── logger.ts
│ ├── package.json
│ ├── tsconfig.json
│ └── README.md
```
#### 1.2 API接口设计
##### 核心API端点设计
```typescript
// 1. 解析接口
POST /api/v1/parse
{
"source": {
"type": "url" | "file" | "text",
"content": string,
"encoding": "utf-8" | "base64"
},
"options": {
"strictMode": boolean,
"resolveReferences": boolean,
"validateSchema": boolean
}
}
// 2. 验证接口
POST /api/v1/validate
{
"source": {
"type": "url" | "file" | "text",
"content": string
},
"validationLevel": "basic" | "strict" | "extended"
}
// 3. 转换接口
POST /api/v1/convert
{
"source": {
"type": "url" | "file" | "text",
"content": string
},
"config": {
"outputFormat": "json" | "yaml",
"includeExamples": boolean,
"groupByTags": boolean,
"customSettings": object
}
}
// 4. 健康检查
GET /api/v1/health
// 5. 服务信息
GET /api/v1/info
```
##### 统一响应格式
```typescript
interface ApiResponse<T = any> {
success: boolean;
data?: T;
error?: {
code: string;
message: string;
details?: any;
};
meta?: {
timestamp: string;
requestId: string;
duration: number;
};
}
```
### 阶段二: 服务实现 (2-3天)
#### 2.1 Express应用基础架构
```typescript
// src/app.ts
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import compression from 'compression';
import { errorHandler } from './middlewares/error-handler';
import { requestLogger } from './middlewares/logger';
import routes from './routes';
export function createApp() {
const app = express();
// 安全中间件
app.use(helmet());
app.use(cors({
origin: process.env.FRONTEND_URL || 'http://localhost:5173',
credentials: true
}));
// 基础中间件
app.use(compression());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// 日志中间件
app.use(requestLogger);
// API路由
app.use('/api/v1', routes);
// 错误处理
app.use(errorHandler);
return app;
}
```
#### 2.2 核心服务实现
```typescript
// src/services/parser.service.ts
import { parseFromUrl, parseFromFile, parseFromString } from 'mcp-swagger-parser';
import type { InputSource, ParseOptions, ParseResult } from '../types/api';
export class ParserService {
async parse(source: InputSource, options: ParseOptions): Promise<ParseResult> {
try {
let result;
switch (source.type) {
case 'url':
result = await parseFromUrl(source.content, options);
break;
case 'file':
result = await this.parseFromBase64File(source.content, options);
break;
case 'text':
result = await parseFromString(source.content, options);
break;
default:
throw new Error(`Unsupported source type: ${source.type}`);
}
return {
success: true,
spec: result.spec,
apiInfo: this.extractApiInfo(result.spec),
endpoints: this.extractEndpoints(result.spec),
statistics: this.generateStatistics(result.spec)
};
} catch (error) {
throw new ParserError(`Parse failed: ${error.message}`, 'PARSE_ERROR');
}
}
private async parseFromBase64File(base64Content: string, options: ParseOptions) {
const buffer = Buffer.from(base64Content, 'base64');
const content = buffer.toString('utf-8');
return await parseFromString(content, options);
}
private extractApiInfo(spec: any) {
return {
title: spec.info?.title || 'Untitled API',
version: spec.info?.version || '1.0.0',
description: spec.info?.description,
serverUrl: spec.servers?.[0]?.url,
totalEndpoints: Object.keys(spec.paths || {}).length
};
}
private extractEndpoints(spec: any) {
// 端点提取逻辑
}
private generateStatistics(spec: any) {
// 统计信息生成逻辑
}
}
```
#### 2.3 路由控制器实现
```typescript
// src/routes/parse.ts
import { Router } from 'express';
import { ParserService } from '../services/parser.service';
import { validateRequest } from '../middlewares/validation';
import { asyncHandler } from '../utils/async-handler';
const router = Router();
const parserService = new ParserService();
router.post('/parse',
validateRequest('parseRequest'),
asyncHandler(async (req, res) => {
const { source, options = {} } = req.body;
const result = await parserService.parse(source, options);
res.json({
success: true,
data: result,
meta: {
timestamp: new Date().toISOString(),
requestId: req.id,
duration: Date.now() - req.startTime
}
});
})
);
export default router;
```
### 阶段三: 前端适配 (1-2天)
#### 3.1 API客户端封装
```typescript
// src/api/client.ts
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import type { ApiResponse, ParseRequest, ParseResult } from '@/types/api';
class ApiClient {
private client: AxiosInstance;
constructor() {
this.client = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3001/api/v1',
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
});
this.setupInterceptors();
}
private setupInterceptors() {
// 请求拦截器
this.client.interceptors.request.use(
(config) => {
console.log(`🚀 API Request: ${config.method?.toUpperCase()} ${config.url}`);
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器
this.client.interceptors.response.use(
(response: AxiosResponse<ApiResponse>) => {
if (!response.data.success) {
throw new Error(response.data.error?.message || 'API request failed');
}
return response;
},
(error) => {
console.error('❌ API Error:', error.response?.data || error.message);
return Promise.reject(error);
}
);
}
async parse(request: ParseRequest): Promise<ParseResult> {
const response = await this.client.post<ApiResponse<ParseResult>>('/parse', request);
return response.data.data!;
}
async validate(request: ValidateRequest): Promise<ValidationResult> {
const response = await this.client.post<ApiResponse<ValidationResult>>('/validate', request);
return response.data.data!;
}
async convert(request: ConvertRequest): Promise<ConvertResult> {
const response = await this.client.post<ApiResponse<ConvertResult>>('/convert', request);
return response.data.data!;
}
async healthCheck(): Promise<{ status: 'ok' | 'error', timestamp: string }> {
const response = await this.client.get<ApiResponse>('/health');
return response.data.data!;
}
}
export const apiClient = new ApiClient();
```
#### 3.2 前端服务层改造
```typescript
// src/services/parser.service.ts (前端)
import { apiClient } from '@/api/client';
import type { InputSource, ConvertConfig, OpenApiInfo, ApiEndpoint, ConvertResult } from '@/types';
export class ParserService {
/**
* 验证 OpenAPI 规范
*/
async validateOpenAPISpec(source: InputSource): Promise<ValidationResult> {
try {
return await apiClient.validate({
source,
validationLevel: 'strict'
});
} catch (error) {
console.error('验证失败:', error);
throw new ParserError(`验证失败: ${error.message}`, 'VALIDATION_ERROR');
}
}
/**
* 解析 OpenAPI 规范获取基本信息
*/
async parseApiInfo(source: InputSource): Promise<OpenApiInfo> {
try {
const result = await apiClient.parse({
source,
options: {
strictMode: false,
resolveReferences: true,
validateSchema: true
}
});
return result.apiInfo;
} catch (error) {
console.error('解析失败:', error);
throw new ParserError(`解析失败: ${error.message}`, 'PARSE_ERROR');
}
}
/**
* 解析端点信息
*/
async parseEndpoints(source: InputSource): Promise<ApiEndpoint[]> {
try {
const result = await apiClient.parse({
source,
options: {
strictMode: false,
resolveReferences: true,
validateSchema: true
}
});
return result.endpoints;
} catch (error) {
console.error('端点解析失败:', error);
throw new ParserError(`端点解析失败: ${error.message}`, 'ENDPOINT_PARSE_ERROR');
}
}
/**
* 转换为 MCP 格式
*/
async convertToMcp(source: InputSource, config: ConvertConfig): Promise<ConvertResult> {
try {
return await apiClient.convert({
source,
config
});
} catch (error) {
console.error('转换失败:', error);
throw new ParserError(`转换失败: ${error.message}`, 'CONVERT_ERROR');
}
}
}
export const parserService = new ParserService();
```
### 阶段四: 部署配置 (1天)
#### 4.1 开发环境配置
```typescript
// packages/mcp-swagger-api/src/config/development.ts
export default {
port: 3001,
cors: {
origin: ['http://localhost:5173', 'http://localhost:3000'],
credentials: true
},
logging: {
level: 'debug',
format: 'dev'
},
cache: {
enabled: false
}
};
```
#### 4.2 生产环境配置
```typescript
// packages/mcp-swagger-api/src/config/production.ts
export default {
port: process.env.PORT || 3001,
cors: {
origin: process.env.FRONTEND_URL?.split(',') || ['https://yourdomain.com'],
credentials: true
},
logging: {
level: 'info',
format: 'combined'
},
cache: {
enabled: true,
ttl: 300 // 5分钟
}
};
```
#### 4.3 Docker配置
```dockerfile
# packages/mcp-swagger-api/Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
EXPOSE 3001
CMD ["node", "dist/server.js"]
```
### 阶段五: 测试与优化 (1-2天)
#### 5.1 API测试
```typescript
// packages/mcp-swagger-api/tests/api.test.ts
import request from 'supertest';
import { createApp } from '../src/app';
describe('Parser API', () => {
const app = createApp();
describe('POST /api/v1/parse', () => {
it('should parse OpenAPI spec from URL', async () => {
const response = await request(app)
.post('/api/v1/parse')
.send({
source: {
type: 'url',
content: 'https://petstore.swagger.io/v2/swagger.json'
},
options: {
strictMode: false,
resolveReferences: true
}
})
.expect(200);
expect(response.body.success).toBe(true);
expect(response.body.data.apiInfo).toBeDefined();
expect(response.body.data.endpoints).toBeInstanceOf(Array);
});
});
});
```
#### 5.2 性能优化
```typescript
// src/middlewares/cache.ts
import NodeCache from 'node-cache';
const cache = new NodeCache({
stdTTL: 300, // 5分钟默认缓存
checkperiod: 60 // 每分钟清理过期缓存
});
export function cacheMiddleware(ttl?: number) {
return (req: Request, res: Response, next: NextFunction) => {
const key = `${req.method}:${req.url}:${JSON.stringify(req.body)}`;
const cached = cache.get(key);
if (cached) {
console.log(`🎯 Cache hit: ${key}`);
return res.json(cached);
}
const originalSend = res.json;
res.json = function(data) {
if (res.statusCode === 200) {
cache.set(key, data, ttl);
console.log(`💾 Cache set: ${key}`);
}
return originalSend.call(this, data);
};
next();
};
}
```
## 🔧 脚本与工具
### package.json 脚本配置
```json
{
"scripts": {
"dev:api": "pnpm --filter=mcp-swagger-api run dev",
"dev:ui": "pnpm --filter=mcp-swagger-ui run dev",
"dev:full": "concurrently \"pnpm run dev:api\" \"pnpm run dev:ui\"",
"build:api": "pnpm --filter=mcp-swagger-api run build",
"build:ui": "pnpm --filter=mcp-swagger-ui run build",
"test:api": "pnpm --filter=mcp-swagger-api run test",
"test:ui": "pnpm --filter=mcp-swagger-ui run test"
}
}
```
### 开发启动脚本
```bash
#!/bin/bash
# scripts/dev-full.sh
echo "🚀 启动全栈开发环境..."
# 启动API服务
echo "📡 启动API服务..."
pnpm --filter=mcp-swagger-api run dev &
API_PID=$!
# 等待API服务启动
sleep 3
# 启动前端服务
echo "🎨 启动前端服务..."
pnpm --filter=mcp-swagger-ui run dev &
UI_PID=$!
# 等待用户输入退出
echo "✅ 开发环境已启动"
echo " - API服务: http://localhost:3001"
echo " - 前端服务: http://localhost:5173"
echo ""
echo "按 Ctrl+C 退出..."
# 捕获退出信号,清理进程
trap "kill $API_PID $UI_PID; exit" INT TERM
wait
```
## 📊 迁移对比
### 改造前 (当前架构)
```
前端 (Vue 3)
├── 直接引用 mcp-swagger-parser
├── 浏览器中执行解析逻辑 ❌
├── 大量Node.js依赖打包 ❌
└── 解析错误调试困难 ❌
```
### 改造后 (目标架构)
```
前端 (Vue 3)
├── HTTP API调用
├── 轻量级客户端 ✅
└── 清晰的错误处理 ✅
后端 API服务 (Express)
├── 专业的解析服务 ✅
├── 缓存和性能优化 ✅
├── 完整的错误处理 ✅
└── 独立测试和部署 ✅
```
## 🎯 实施建议
1. **渐进式迁移**: 可以先保留现有的mock模式,新增API模式作为选项
2. **向后兼容**: 保持现有的接口不变,内部实现切换到API调用
3. **错误处理**: 当API服务不可用时,自动降级到mock模式
4. **监控告警**: 添加API服务的健康检查和监控
## 📈 预期收益
1. **开发效率**: 前后端独立开发,提升并行开发效率
2. **维护成本**: 清晰的架构边界,降低长期维护成本
3. **扩展能力**: 后端服务可独立扩展,支持更多客户端
4. **用户体验**: 更快的加载速度和更稳定的解析性能
这个方案充分利用了现有的 monorepo 架构和 mcp-swagger-parser 核心库,是一个既务实又具有前瞻性的技术方案。