返回笔记首页

基于Swagger的MCP实战操作手册

主题配置

一、准备工作

你需要有的东西

  1. 一个Swagger API文档
  2. Claude Desktop 或者 能用MCP的AI工具
  3. Node.js环境(用来运行MCP Server)

二、获取Swagger文档

方式1:使用公开的PetStore API(练习用)

直接访问:https://petstore.swagger.io/v2/swagger.json

你会看到一个JSON文件,内容大概是这样:

json
{
  "swagger": "2.0",
  "info": {
    "title": "Swagger Petstore",
    "version": "1.0.0"
  },
  "paths": {
    "/pet": {
      "post": {
        "summary": "Add a new pet to the store",
        "parameters": [...],
        "responses": {...}
      }
    },
    "/pet/{petId}": {
      "get": {
        "summary": "Find pet by ID",
        "parameters": [...],
        "responses": {...}
      }
    }
  },
  "definitions": {
    "Pet": {
      "type": "object",
      "properties": {
        "id": { "type": "integer" },
        "name": { "type": "string" },
        "status": { "type": "string" }
      }
    }
  }
}

方式2:从你的项目获取

如果后端用Spring Boot

访问:http://localhost:8080/v2/api-docs

如果后端用NestJS

访问:http://localhost:3000/api-json

如果后端用FastAPI

访问:http://localhost:8000/openapi.json

把JSON保存成文件,比如 swagger.json


三、方案1:不用MCP,直接让AI读Swagger

这是最简单的方式,适合快速上手。

Step 1: 准备Swagger JSON

把Swagger文档内容复制一份(如果太大,只复制你需要的部分)

Step 2: 给AI看

打开Claude,输入:

plain
我有一个Swagger API文档,帮我根据接口定义生成前端代码。

【Swagger内容】
{
  "paths": {
    "/api/users": {
      "get": {
        "summary": "获取用户列表",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "type": "integer",
            "description": "页码"
          },
          {
            "name": "pageSize",
            "in": "query",
            "type": "integer",
            "description": "每页数量"
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "schema": {
              "type": "object",
              "properties": {
                "list": {
                  "type": "array",
                  "items": { "$ref": "#/definitions/User" }
                },
                "total": { "type": "integer" }
              }
            }
          }
        }
      }
    }
  },
  "definitions": {
    "User": {
      "type": "object",
      "properties": {
        "id": { "type": "string" },
        "username": { "type": "string" },
        "email": { "type": "string" },
        "role": {
          "type": "string",
          "enum": ["admin", "user"]
        }
      },
      "required": ["id", "username", "email"]
    }
  }
}

【要求】
生成:
1. TypeScript类型定义
2. API请求函数
3. 使用示例

Step 3: AI生成代码

AI会输出:

types.ts

typescript
// 根据Swagger definitions生成
export interface User {
  id: string;
  username: string;
  email: string;
  role?: 'admin' | 'user';
}

// 根据接口响应生成
export interface UserListResponse {
  list: User[];
  total: number;
}

// 根据请求参数生成
export interface UserListParams {
  page: number;
  pageSize: number;
}
api.ts
typescript
import request from '@/utils/request';
import type { User, UserListResponse, UserListParams } from './types';

/**
 * 获取用户列表
 * @param params - 查询参数
 * @returns 用户列表和总数
 */
export async function getUserList(params: UserListParams): Promise<UserListResponse> {
  return request.get('/api/users', { params });
}
使用示例
typescript
import { getUserList } from '@/services/user/api';

// 在组件中使用
const fetchData = async () => {
  const result = await getUserList({
    page: 1,
    pageSize: 20,
  });

  console.log('用户列表:', result.list);
  console.log('总数:', result.total);
};

四、方案2:用MCP自动读取Swagger(进阶)

这个方式可以让AI直接访问Swagger URL,不用手动复制粘贴。

Step 1: 安装MCP Server

创建一个简单的MCP Server来读取Swagger:

创建目录

bash
mkdir swagger-mcp
cd swagger-mcp
npm init -y
安装依赖
bash
npm install @modelcontextprotocol/sdk axios
创建 server.js
javascript
#!/usr/bin/env node

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import axios from 'axios';

const server = new Server(
  {
    name: 'swagger-mcp-server',
    version: '1.0.0',
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// 定义工具:读取Swagger
server.setRequestHandler('tools/list', async () => {
  return {
    tools: [
      {
        name: 'read_swagger',
        description: '读取Swagger/OpenAPI文档',
        inputSchema: {
          type: 'object',
          properties: {
            url: {
              type: 'string',
              description: 'Swagger JSON的URL',
            },
          },
          required: ['url'],
        },
      },
    ],
  };
});

// 执行工具
server.setRequestHandler('tools/call', async (request) => {
  if (request.params.name === 'read_swagger') {
    const { url } = request.params.arguments;

    try {
      const response = await axios.get(url);
      const swagger = response.data;

      // 返回格式化的Swagger内容
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify(swagger, null, 2),
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: 'text',
            text: `读取失败: ${error.message}`,
          },
        ],
        isError: true,
      };
    }
  }
});

// 启动服务
const transport = new StdioServerTransport();
await server.connect(transport);
修改 package.json
json
{
  "name": "swagger-mcp-server",
  "version": "1.0.0",
  "type": "module",
  "bin": {
    "swagger-mcp": "./server.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.5.0",
    "axios": "^1.6.0"
  }
}
安装到全局
bash
npm link

Step 2: 配置Claude Desktop

编辑配置文件:

Mac

bash
nano ~/Library/Application\ Support/Claude/claude_desktop_config.json
Windows
bash
notepad %APPDATA%\Claude\claude_desktop_config.json
添加配置
json
{
  "mcpServers": {
    "swagger": {
      "command": "swagger-mcp"
    }
  }
}

保存并重启Claude Desktop。

Step 3: 使用

在Claude中输入:

plain
使用read_swagger工具读取这个Swagger文档:
https://petstore.swagger.io/v2/swagger.json

读取后,帮我生成Pet相关的API代码

AI会自动调用MCP工具,读取Swagger,然后生成代码。


五、实战案例:生成完整的User模块API

假设你有这样的Swagger

json
{
  "paths": {
    "/api/users": {
      "get": {
        "summary": "获取用户列表",
        "parameters": [
          { "name": "page", "in": "query", "type": "integer" },
          { "name": "pageSize", "in": "query", "type": "integer" },
          { "name": "keyword", "in": "query", "type": "string" },
          { "name": "role", "in": "query", "type": "string" }
        ],
        "responses": {
          "200": {
            "schema": {
              "properties": {
                "list": { "type": "array", "items": { "$ref": "#/definitions/User" } },
                "total": { "type": "integer" }
              }
            }
          }
        }
      },
      "post": {
        "summary": "创建用户",
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "schema": { "$ref": "#/definitions/CreateUserDto" }
          }
        ],
        "responses": {
          "200": { "schema": { "$ref": "#/definitions/User" } }
        }
      }
    },
    "/api/users/{id}": {
      "get": {
        "summary": "获取用户详情",
        "parameters": [
          { "name": "id", "in": "path", "type": "string", "required": true }
        ],
        "responses": {
          "200": { "schema": { "$ref": "#/definitions/User" } }
        }
      },
      "put": {
        "summary": "更新用户",
        "parameters": [
          { "name": "id", "in": "path", "type": "string", "required": true },
          { "name": "body", "in": "body", "schema": { "$ref": "#/definitions/UpdateUserDto" } }
        ],
        "responses": {
          "200": { "schema": { "$ref": "#/definitions/User" } }
        }
      },
      "delete": {
        "summary": "删除用户",
        "parameters": [
          { "name": "id", "in": "path", "type": "string", "required": true }
        ],
        "responses": {
          "200": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" } } } }
        }
      }
    }
  },
  "definitions": {
    "User": {
      "type": "object",
      "properties": {
        "id": { "type": "string" },
        "username": { "type": "string" },
        "email": { "type": "string" },
        "realName": { "type": "string" },
        "role": { "type": "string", "enum": ["admin", "user", "guest"] },
        "status": { "type": "string", "enum": ["active", "inactive"] },
        "createdAt": { "type": "string", "format": "date-time" },
        "updatedAt": { "type": "string", "format": "date-time" }
      }
    },
    "CreateUserDto": {
      "type": "object",
      "required": ["username", "email", "password", "role"],
      "properties": {
        "username": { "type": "string" },
        "email": { "type": "string" },
        "password": { "type": "string" },
        "realName": { "type": "string" },
        "role": { "type": "string", "enum": ["admin", "user", "guest"] }
      }
    },
    "UpdateUserDto": {
      "type": "object",
      "properties": {
        "email": { "type": "string" },
        "realName": { "type": "string" },
        "role": { "type": "string", "enum": ["admin", "user", "guest"] },
        "status": { "type": "string", "enum": ["active", "inactive"] }
      }
    }
  }
}

给AI的Prompt

plain
根据上面的Swagger定义,生成完整的User模块代码。

【要求】
1. 生成完整的TypeScript类型定义
2. 生成所有API请求函数
3. 请求函数要有完整的JSDoc注释
4. 使用我们项目的request工具(import from '@/utils/request')
5. 错误处理要完善
6. 生成使用示例

【项目规范】
- 所有类型定义放在 types.ts
- API函数放在 api.ts
- 参数类型用 Params 后缀
- 响应类型用 Response 后缀
- DTO类型直接用接口名

AI生成的代码

user/types.ts

typescript
/**
 * 用户实体
 */
export interface User {
  id: string;
  username: string;
  email: string;
  realName?: string;
  role: 'admin' | 'user' | 'guest';
  status: 'active' | 'inactive';
  createdAt: string;
  updatedAt: string;
}

/**
 * 用户列表查询参数
 */
export interface UserListParams {
  page: number;
  pageSize: number;
  keyword?: string;
  role?: string;
}

/**
 * 用户列表响应
 */
export interface UserListResponse {
  list: User[];
  total: number;
}

/**
 * 创建用户DTO
 */
export interface CreateUserDto {
  username: string;
  email: string;
  password: string;
  realName?: string;
  role: 'admin' | 'user' | 'guest';
}

/**
 * 更新用户DTO
 */
export interface UpdateUserDto {
  email?: string;
  realName?: string;
  role?: 'admin' | 'user' | 'guest';
  status?: 'active' | 'inactive';
}

/**
 * 删除用户响应
 */
export interface DeleteUserResponse {
  success: boolean;
}
user/api.ts
typescript
import request from '@/utils/request';
import type {
  User,
  UserListParams,
  UserListResponse,
  CreateUserDto,
  UpdateUserDto,
  DeleteUserResponse,
} from './types';

/**
 * 获取用户列表
 * @param params - 查询参数
 * @param params.page - 页码,从1开始
 * @param params.pageSize - 每页数量
 * @param params.keyword - 搜索关键词(用户名或邮箱)
 * @param params.role - 角色筛选
 * @returns 用户列表和总数
 * @example
 * const result = await getUserList({ page: 1, pageSize: 20 });
 * console.log(result.list); // User[]
 * console.log(result.total); // number
 */
export async function getUserList(params: UserListParams): Promise<UserListResponse> {
  return request.get('/api/users', { params });
}

/**
 * 获取用户详情
 * @param id - 用户ID
 * @returns 用户信息
 * @throws {Error} 用户不存在时抛出404错误
 * @example
 * const user = await getUserDetail('user-123');
 * console.log(user.username);
 */
export async function getUserDetail(id: string): Promise<User> {
  return request.get(`/api/users/${id}`);
}

/**
 * 创建用户
 * @param data - 用户数据
 * @returns 创建的用户信息
 * @throws {Error} 用户名或邮箱已存在时抛出400错误
 * @example
 * const newUser = await createUser({
 *   username: 'john',
 *   email: 'john@example.com',
 *   password: 'Pass1234',
 *   role: 'user',
 * });
 */
export async function createUser(data: CreateUserDto): Promise<User> {
  return request.post('/api/users', data);
}

/**
 * 更新用户信息
 * @param id - 用户ID
 * @param data - 要更新的字段
 * @returns 更新后的用户信息
 * @example
 * const updated = await updateUser('user-123', {
 *   realName: 'John Doe',
 *   status: 'inactive',
 * });
 */
export async function updateUser(id: string, data: UpdateUserDto): Promise<User> {
  return request.put(`/api/users/${id}`, data);
}

/**
 * 删除用户
 * @param id - 用户ID
 * @returns 删除结果
 * @throws {Error} 不能删除当前登录用户
 * @example
 * const result = await deleteUser('user-123');
 * if (result.success) {
 *   console.log('删除成功');
 * }
 */
export async function deleteUser(id: string): Promise<DeleteUserResponse> {
  return request.delete(`/api/users/${id}`);
}
使用示例
typescript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { message } from 'antd';
import { getUserList, getUserDetail, createUser, updateUser, deleteUser } from './api';

// 1. 获取列表
export function useUserList(params: UserListParams) {
  return useQuery({
    queryKey: ['users', params],
    queryFn: () => getUserList(params),
  });
}

// 2. 获取详情
export function useUserDetail(id: string) {
  return useQuery({
    queryKey: ['user', id],
    queryFn: () => getUserDetail(id),
    enabled: !!id,
  });
}

// 3. 创建用户
export function useCreateUser() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: createUser,
    onSuccess: () => {
      message.success('创建成功');
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
    onError: (error: any) => {
      if (error.response?.data?.code === 'USER_EXISTS') {
        message.error('用户名或邮箱已存在');
      } else {
        message.error('创建失败');
      }
    },
  });
}

// 4. 更新用户
export function useUpdateUser() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: ({ id, data }: { id: string; data: UpdateUserDto }) => updateUser(id, data),
    onSuccess: (_, { id }) => {
      message.success('保存成功');
      queryClient.invalidateQueries({ queryKey: ['users'] });
      queryClient.invalidateQueries({ queryKey: ['user', id] });
    },
    onError: () => {
      message.error('保存失败');
    },
  });
}

// 5. 删除用户
export function useDeleteUser() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: deleteUser,
    onSuccess: () => {
      message.success('删除成功');
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
    onError: (error: any) => {
      if (error.response?.status === 403) {
        message.error('不能删除当前登录用户');
      } else {
        message.error('删除失败');
      }
    },
  });
}

六、Swagger变更后的更新流程

后端改了接口,前端怎么快速同步?

Step 1: 拿到新的Swagger

访问后端的Swagger地址,复制新的JSON。

Step 2: 对比变更

给AI这样的Prompt:

plain
对比旧Swagger和新Swagger,告诉我哪些接口变了。

【旧Swagger】
{旧的JSON}

【新Swagger】
{新的JSON}

【输出】
1. 新增的接口
2. 修改的接口(参数或响应变了)
3. 删除的接口
4. 需要更新的前端代码位置

AI会输出:

plain
变更分析:

1. 新增接口:
   - POST /api/users/batch-import - 批量导入用户

2. 修改接口:
   - GET /api/users - 新增参数 status(用户状态筛选)
   - PUT /api/users/{id} - 新增字段 department(部门)

3. 删除接口:
   无

4. 需要更新的代码:
   - types.ts: User接口新增 department 字段
   - types.ts: UserListParams新增 status 字段
   - api.ts: 新增 batchImportUsers 函数

Step 3: 让AI生成更新代码

plain
根据变更,更新我的代码。

【当前代码】
{粘贴现有的types.ts和api.ts}

【变更内容】
{上面的变更分析}

生成完整的新代码。

AI会生成更新后的完整代码,你复制替换就行。


七、Mock数据生成

开发前端时,后端接口还没好,需要Mock数据。

Prompt

plain
根据这个User类型定义,生成10条Mock数据。

【类型定义】
{粘贴User interface}

【要求】
1. 数据要真实合理
2. 包含各种角色(admin/user/guest)
3. 包含各种状态(active/inactive)
4. 用户名和邮箱要匹配
5. 时间用最近一个月内的

AI生成

typescript
// mock/users.ts
export const mockUsers = [
  {
    id: 'user-001',
    username: 'admin',
    email: 'admin@company.com',
    realName: '系统管理员',
    role: 'admin',
    status: 'active',
    createdAt: '2024-01-15T08:30:00Z',
    updatedAt: '2024-02-01T14:20:00Z',
  },
  {
    id: 'user-002',
    username: 'zhangsan',
    email: 'zhangsan@company.com',
    realName: '张三',
    role: 'user',
    status: 'active',
    createdAt: '2024-01-18T09:15:00Z',
    updatedAt: '2024-01-18T09:15:00Z',
  },
  {
    id: 'user-003',
    username: 'lisi',
    email: 'lisi@company.com',
    realName: '李四',
    role: 'user',
    status: 'inactive',
    createdAt: '2024-01-20T10:00:00Z',
    updatedAt: '2024-01-25T16:30:00Z',
  },
  // ... 更多数据
];

八、常见问题

Q1: Swagger太大,AI读不完怎么办?

方案1: 只提取需要的部分

javascript
// 从完整Swagger提取User相关接口
const filteredSwagger = {
  paths: Object.fromEntries(
    Object.entries(fullSwagger.paths).filter(([path]) => path.includes('/users'))
  ),
  definitions: {
    User: fullSwagger.definitions.User,
    CreateUserDto: fullSwagger.definitions.CreateUserDto,
    UpdateUserDto: fullSwagger.definitions.UpdateUserDto,
  }
};

方案2: 分批次处理

plain
先处理User模块的接口,处理完了再处理Product模块

Q2: Swagger定义不规范怎么办?

手动补充信息:

plain
这个Swagger的字段说明不清楚,我补充一下:

- username: 用户名,3-20个字符
- email: 邮箱,必须是公司邮箱(@company.com结尾)
- role: 角色,admin是管理员,user是普通用户

按这些规则生成代码。

Q3: 如何保证生成的代码和项目规范一致?

结合Skill.md:

plain
读取 api-standard.md 规范文件,然后根据Swagger生成代码。

【Swagger内容】
...

必须严格遵守 api-standard.md 里的规范。

九、总结

Swagger转前端代码的流程:

  1. 获取Swagger JSON(后端提供或自己导出)
  2. 给AI看Swagger(直接粘贴或用MCP)
  3. AI生成代码(类型、API函数、使用示例)
  4. 复制到项目(types.ts、api.ts)
  5. 测试验证(Mock数据或真实接口)
  6. 后续维护(Swagger变了就重新生成)

不需要复杂的工具,最简单的方式就是复制粘贴Swagger给AI看,让AI生成代码。

如果接口多,就配置MCP自动读取,更省事。