Browse Source

feat: 添加 Admin MCP Server 和安装配置技能

- 创建 admin-mcp-server,提供 20 个管理工具
  - 认证: login, logout, get_current_user
  - 用户管理: 列表/获取/创建/更新/删除
  - 角色管理: 列表/获取/创建/更新/删除
  - 系统配置: 列表/获取/创建/更新/删除
  - 订单管理: 列表/获取
- 使用 Streamable HTTP 传输模式
- 添加 install-admin-mcp 技能,一键安装配置

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 3 weeks ago
parent
commit
2bd3ed3c1d

BIN
.claude/skills/install-admin-mcp.skill


+ 142 - 0
.claude/skills/install-admin-mcp/SKILL.md

@@ -0,0 +1,142 @@
+---
+name: install-admin-mcp
+description: 一键安装和配置 Admin MCP 服务器。让 AI 能够通过 MCP 协议直接操作后台 API,包括用户管理、角色管理、系统配置、订单管理等功能。当用户说"安装 admin MCP"、"配置 MCP 服务器"、"启动 admin-mcp-server"时触发此技能。
+---
+
+# Admin MCP Server 安装配置
+
+## 概述
+
+Admin MCP Server 是一个基于 Model Context Protocol 的服务端点,允许 AI 通过标准化协议直接操作后台 API。安装后,AI 可以执行用户管理、角色管理、系统配置、订单管理等管理操作。
+
+## 快速安装
+
+运行安装脚本即可完成全部配置:
+
+```bash
+bash .claude/skills/install-admin-mcp/scripts/install.sh
+```
+
+脚本会自动完成:
+1. 检查项目目录
+2. 安装依赖
+3. 构建项目
+4. 停止旧进程
+5. 启动 MCP 服务器
+
+## 服务器配置
+
+| 配置项 | 值 |
+|--------|-----|
+| 端点 | http://localhost:3000/mcp |
+| 健康检查 | http://localhost:3000/health |
+| 传输方式 | Streamable HTTP |
+| 后端 API | http://localhost:8080 |
+| 项目路径 | packages/admin-mcp-server |
+
+## 可用工具
+
+### 认证工具
+- `admin_login` - 登录获取 token
+- `admin_logout` - 登出
+- `admin_get_current_user` - 获取当前用户信息
+
+### 用户管理
+- `admin_list_users` - 用户列表(支持分页、排序、筛选)
+- `admin_get_user` - 获取单个用户
+- `admin_create_user` - 创建用户
+- `admin_update_user` - 更新用户
+- `admin_delete_user` - 删除用户
+
+### 角色管理
+- `admin_list_roles` - 角色列表
+- `admin_get_role` - 获取单个角色
+- `admin_create_role` - 创建角色
+- `admin_update_role` - 更新角色
+- `admin_delete_role` - 删除角色
+
+### 系统配置
+- `admin_list_system_configs` - 系统配置列表
+- `admin_get_system_config` - 获取单个配置
+- `admin_create_system_config` - 创建配置
+- `admin_update_system_config` - 更新配置
+- `admin_delete_system_config` - 删除配置
+
+### 订单管理
+- `admin_list_orders` - 订单列表
+- `admin_get_order` - 获取单个订单
+
+## 手动操作
+
+### 启动服务器
+
+```bash
+cd packages/admin-mcp-server
+pnpm run build
+nohup node dist/index.js > /tmp/admin-mcp-server.log 2>&1 &
+```
+
+### 停止服务器
+
+```bash
+fuser -k 3000/tcp
+```
+
+### 查看日志
+
+```bash
+tail -f /tmp/admin-mcp-server.log
+```
+
+### 测试连接
+
+```bash
+curl -X POST http://localhost:3000/mcp \
+  -H "Content-Type: application/json" \
+  -H "Accept: application/json, text/event-stream" \
+  -d '{
+    "jsonrpc": "2.0",
+    "id": 1,
+    "method": "tools/list"
+  }'
+```
+
+## Claude Desktop 配置
+
+如需在 Claude Desktop 中使用,编辑 `~/.claude/claude_desktop_config.json`:
+
+```json
+{
+  "mcpServers": {
+    "admin-mcp-server": {
+      "transport": {
+        "type": "http",
+        "url": "http://localhost:3000/mcp"
+      }
+    }
+  }
+}
+```
+
+## 故障排查
+
+**端口被占用**
+```bash
+fuser -k 3000/tcp
+```
+
+**服务器未响应**
+```bash
+# 检查后端 API 是否运行
+curl http://localhost:8080/api/v1/auth/login
+
+# 查看 MCP 服务器日志
+cat /tmp/admin-mcp-server.log
+```
+
+**重新构建**
+```bash
+cd packages/admin-mcp-server
+rm -rf dist
+pnpm run build
+```

+ 97 - 0
.claude/skills/install-admin-mcp/scripts/install.sh

@@ -0,0 +1,97 @@
+#!/bin/bash
+
+set -e
+
+# Admin MCP Server 安装脚本
+# 用于一键安装和配置 Admin MCP 服务器
+
+PROJECT_ROOT="/mnt/code/188-179-template-6"
+MCP_SERVER_DIR="$PROJECT_ROOT/packages/admin-mcp-server"
+LOG_FILE="/tmp/admin-mcp-server.log"
+PID_FILE="/tmp/admin-mcp-server.pid"
+
+echo "========================================"
+echo "Admin MCP Server 安装配置"
+echo "========================================"
+
+# 1. 检查项目目录
+echo ""
+echo "[1/5] 检查项目目录..."
+if [ ! -d "$MCP_SERVER_DIR" ]; then
+    echo "错误: MCP 服务器目录不存在: $MCP_SERVER_DIR"
+    exit 1
+fi
+echo "✓ 项目目录存在: $MCP_SERVER_DIR"
+
+# 2. 安装依赖
+echo ""
+echo "[2/5] 安装依赖..."
+cd "$MCP_SERVER_DIR"
+pnpm install
+echo "✓ 依赖安装完成"
+
+# 3. 构建项目
+echo ""
+echo "[3/5] 构建项目..."
+pnpm run build
+echo "✓ 项目构建完成"
+
+# 4. 停止旧进程
+echo ""
+echo "[4/5] 停止旧进程..."
+if fuser 3000/tcp 2>/dev/null; then
+    echo "发现端口 3000 被占用,正在停止..."
+    fuser -k 3000/tcp 2>/dev/null || true
+    sleep 1
+    echo "✓ 旧进程已停止"
+else
+    echo "✓ 端口 3000 未被占用"
+fi
+
+# 5. 启动 MCP 服务器
+echo ""
+echo "[5/5] 启动 MCP 服务器..."
+cd "$MCP_SERVER_DIR"
+nohup node dist/index.js > "$LOG_FILE" 2>&1 &
+echo $! > "$PID_FILE"
+
+# 等待服务启动并验证健康检查
+echo "等待服务启动..."
+for i in {1..10}; do
+    sleep 1
+    if curl -s http://localhost:3000/health > /dev/null 2>&1; then
+        echo "✓ 服务已就绪"
+        break
+    fi
+    if [ $i -eq 10 ]; then
+        echo "✗ 服务启动超时"
+        echo "请查看日志: cat $LOG_FILE"
+        exit 1
+    fi
+    echo "  等待中... ($i/10)"
+done
+
+# 最终检查服务是否正常运行
+if fuser 3000/tcp 2>/dev/null && curl -s http://localhost:3000/health > /dev/null 2>&1; then
+    echo ""
+    echo "========================================"
+    echo "✓ Admin MCP Server 安装成功!"
+    echo "========================================"
+    echo ""
+    echo "服务信息:"
+    echo "  - MCP 端点: http://localhost:3000/mcp"
+    echo "  - 健康检查: http://localhost:3000/health"
+    echo "  - 日志文件: $LOG_FILE"
+    echo "  - PID 文件: $PID_FILE"
+    echo ""
+    echo "测试连接:"
+    echo '  curl -X POST http://localhost:3000/mcp -H "Content-Type: application/json" -d '"'"'{"jsonrpc":"2.0","id":1,"method":"tools/list"}'"'"
+    echo ""
+else
+    echo ""
+    echo "========================================"
+    echo "✗ 服务启动失败"
+    echo "========================================"
+    echo "请查看日志: cat $LOG_FILE"
+    exit 1
+fi

+ 155 - 0
packages/admin-mcp-server/README.md

@@ -0,0 +1,155 @@
+# Admin MCP Server
+
+MCP (Model Context Protocol) server for admin backend API integration. This server enables AI agents to interact with the admin system through well-defined tools.
+
+## Features
+
+- **Authentication**: Login/logout and user session management
+- **User Management**: CRUD operations for users
+- **Role Management**: CRUD operations for roles
+- **System Configuration**: CRUD operations for system configs
+- **Order Management**: List and view orders
+- **Streamable HTTP Transport**: Modern, stateless HTTP transport for remote access
+
+## Installation
+
+```bash
+cd packages/admin-mcp-server
+pnpm install
+```
+
+## Configuration
+
+Set environment variables:
+
+```bash
+# API backend URL (default: http://localhost:8080)
+export API_BASE_URL="http://localhost:8080"
+
+# MCP server port (default: 3000)
+export PORT="3000"
+```
+
+## Usage
+
+### Development
+
+```bash
+pnpm run dev
+```
+
+### Production
+
+```bash
+# Build
+pnpm run build
+
+# Start
+pnpm start
+```
+
+### Health Check
+
+```bash
+curl http://localhost:3000/health
+```
+
+## MCP Tools
+
+### Authentication
+
+- `admin_login` - Authenticate with username and password
+- `admin_logout` - Logout and clear session
+- `admin_get_current_user` - Get current authenticated user info
+
+### User Management
+
+- `admin_list_users` - List users with pagination and filtering
+- `admin_get_user` - Get user by ID
+- `admin_create_user` - Create a new user
+- `admin_update_user` - Update existing user
+- `admin_delete_user` - Delete a user
+
+### Role Management
+
+- `admin_list_roles` - List roles with pagination
+- `admin_get_role` - Get role by ID
+- `admin_create_role` - Create a new role
+- `admin_update_role` - Update existing role
+- `admin_delete_role` - Delete a role
+
+### System Configuration
+
+- `admin_list_system_configs` - List system configurations
+- `admin_get_system_config` - Get config by ID
+- `admin_create_system_config` - Create a new config
+- `admin_update_system_config` - Update existing config
+- `admin_delete_system_config` - Delete a config
+
+### Order Management
+
+- `admin_list_orders` - List orders with pagination
+- `admin_get_order` - Get order by ID
+
+## MCP Connection
+
+To connect to this MCP server, use:
+
+```
+http://localhost:3000/mcp
+```
+
+## Example Usage
+
+### Using MCP Inspector
+
+```bash
+npx @modelcontextprotocol/inspector http://localhost:3000/mcp
+```
+
+### Claude Desktop Configuration
+
+Add to your Claude Desktop config:
+
+```json
+{
+  "mcpServers": {
+    "admin": {
+      "url": "http://localhost:3000/mcp",
+      "transport": "streamable_http"
+    }
+  }
+}
+```
+
+## API Endpoints
+
+The MCP server connects to the following backend API endpoints:
+
+- `/api/auth/login` - Admin login
+- `/api/auth/me` - Get current user
+- `/api/users` - User management
+- `/api/roles` - Role management
+- `/api/system-configs` - System configuration
+- `/api/orders` - Order management
+
+## Project Structure
+
+```
+admin-mcp-server/
+├── src/
+│   ├── index.ts          # Main entry point
+│   ├── constants.ts      # Constants and enums
+│   ├── types.ts          # Type definitions
+│   ├── schemas/          # Zod validation schemas
+│   ├── services/         # API client service
+│   └── tools/            # MCP tool implementations
+├── dist/                 # Built JavaScript files
+├── package.json
+├── tsconfig.json
+└── README.md
+```
+
+## License
+
+MIT

+ 29 - 0
packages/admin-mcp-server/package.json

@@ -0,0 +1,29 @@
+{
+  "name": "admin-mcp-server",
+  "version": "1.0.0",
+  "description": "MCP server for admin backend API integration",
+  "type": "module",
+  "main": "dist/index.js",
+  "scripts": {
+    "start": "node dist/index.js",
+    "dev": "tsx watch src/index.ts",
+    "build": "tsc",
+    "clean": "rm -rf dist",
+    "inspect": "node dist/index.js"
+  },
+  "engines": {
+    "node": ">=18"
+  },
+  "dependencies": {
+    "@modelcontextprotocol/sdk": "^1.6.1",
+    "axios": "^1.7.9",
+    "express": "^4.18.2",
+    "zod": "^3.23.8"
+  },
+  "devDependencies": {
+    "@types/express": "^4.17.21",
+    "@types/node": "^22.10.0",
+    "tsx": "^4.19.2",
+    "typescript": "^5.7.2"
+  }
+}

+ 27 - 0
packages/admin-mcp-server/src/constants.ts

@@ -0,0 +1,27 @@
+/**
+ * Admin MCP Server Constants
+ */
+
+// API Configuration
+export const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:8080';
+export const API_TIMEOUT = 30000;
+
+// Response Limits
+export const CHARACTER_LIMIT = 25000;
+export const DEFAULT_PAGE_SIZE = 20;
+export const MAX_PAGE_SIZE = 100;
+
+// Response Format
+export enum ResponseFormat {
+  MARKDOWN = 'markdown',
+  JSON = 'json'
+}
+
+// Sort Order
+export enum SortOrder {
+  ASC = 'ASC',
+  DESC = 'DESC'
+}
+
+// HTTP Methods
+export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';

+ 783 - 0
packages/admin-mcp-server/src/index.ts

@@ -0,0 +1,783 @@
+#!/usr/bin/env node
+/**
+ * Admin MCP Server
+ *
+ * MCP server for admin backend API integration.
+ * Provides tools for user management, role management, system configuration,
+ * order management, and authentication.
+ *
+ * Transport: Streamable HTTP (recommended for remote servers)
+ */
+
+import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
+import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
+import express from 'express';
+import { z } from 'zod';
+import { userTools } from './tools/user-tools.js';
+import { roleTools } from './tools/role-tools.js';
+import { systemConfigTools } from './tools/system-config-tools.js';
+import { orderTools } from './tools/order-tools.js';
+import { authTools } from './tools/auth-tools.js';
+
+// ============================================================================
+// Server Configuration
+// ============================================================================
+
+const SERVER_CONFIG = {
+  name: 'admin-mcp-server',
+  version: '1.0.0',
+  port: parseInt(process.env.PORT || '3000', 10),
+  apiBaseUrl: process.env.API_BASE_URL || 'http://localhost:8080'
+};
+
+// ============================================================================
+// Create MCP Server Instance
+// ============================================================================
+
+const server = new McpServer({
+  name: SERVER_CONFIG.name,
+  version: SERVER_CONFIG.version
+});
+
+// ============================================================================
+// Helper: Register Tool with Annotations
+// ============================================================================
+
+interface ToolRegistration {
+  name: string;
+  schema?: z.ZodSchema;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  handler: (...args: any[]) => any;
+}
+
+interface ToolAnnotations {
+  readOnlyHint?: boolean;
+  destructiveHint?: boolean;
+  idempotentHint?: boolean;
+  openWorldHint?: boolean;
+}
+
+function registerToolWithAnnotations(
+  registration: ToolRegistration,
+  annotations: ToolAnnotations,
+  title: string,
+  description: string
+): void {
+  const { name, schema, handler } = registration;
+
+  // Build tool options
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  const toolOptions: any = {
+    title,
+    description
+  };
+
+  // Add input schema if provided
+  if (schema) {
+    toolOptions.inputSchema = schema;
+  }
+
+  // Add annotations
+  toolOptions.annotations = annotations;
+
+  // Register the tool
+  server.registerTool(name, toolOptions, handler);
+}
+
+// ============================================================================
+// Register Authentication Tools
+// ============================================================================
+
+// Login tool
+registerToolWithAnnotations(
+  authTools.login,
+  {
+    readOnlyHint: false,
+    destructiveHint: false,
+    idempotentHint: false,
+    openWorldHint: false
+  },
+  'Admin Login',
+  `Authenticate with the admin backend using username and password.
+
+This tool establishes an authenticated session by logging in to the admin system.
+The authentication token is automatically stored and used for subsequent tool calls.
+
+Args:
+  - username (string): Admin username
+  - password (string): Admin password
+
+Returns:
+  Authentication result with user information.
+
+Examples:
+  - Use when: "Login to admin system" -> params with username="admin", password="password"
+  - Use when: "I need to access the admin API" -> first call this tool
+
+Error Handling:
+  - Returns "Error: Authentication failed" if credentials are invalid
+  - Returns "Error: Cannot connect to API server" if backend is unreachable`
+);
+
+// Logout tool
+registerToolWithAnnotations(
+  authTools.logout,
+  {
+    readOnlyHint: false,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Admin Logout',
+  `Logout from the admin backend and clear the authentication token.
+
+This tool ends the current admin session by clearing the stored authentication token.
+Subsequent API calls will require re-authentication.
+
+Args:
+  - None
+
+Returns:
+  Logout confirmation message.
+
+Examples:
+  - Use when: "Logout from admin system" or "End admin session"
+
+Error Handling:
+  - Rarely fails, mainly for client-side issues`
+);
+
+// Get current user tool
+registerToolWithAnnotations(
+  authTools.getCurrentUser,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Get Current Admin User',
+  `Retrieve information about the currently authenticated admin user.
+
+This tool returns details about the user that is currently logged in,
+including their roles, permissions, and profile information.
+
+Args:
+  - None
+
+Returns:
+  Current user information including ID, username, roles, and permissions.
+
+Examples:
+  - Use when: "Who am I logged in as?" or "Get current user info"
+  - Use when: "Check my admin permissions"
+
+Error Handling:
+  - Returns "Error: Authentication failed" if not logged in`
+);
+
+// ============================================================================
+// Register User Management Tools
+// ============================================================================
+
+// List users
+registerToolWithAnnotations(
+  userTools.userList,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: true
+  },
+  'List Users',
+  `List and search users in the admin system with pagination and filtering.
+
+This tool retrieves a paginated list of users from the admin system.
+Supports keyword search, sorting, and advanced filtering.
+
+Args:
+  - page (number): Page number, starting from 1 (default: 1)
+  - pageSize (number): Number of items per page, 1-100 (default: 20)
+  - keyword (string): Optional search keyword for partial matching
+  - sortBy (string): Optional field to sort by (e.g., "id", "createdAt", "name")
+  - sortOrder (string): Sort direction: "ASC" or "DESC" (default: "DESC")
+  - filters (string): Optional filter conditions as JSON string
+  - response_format (string): Output format: "markdown" or "json" (default: "markdown")
+
+Returns:
+  For JSON format: Structured data with schema:
+  {
+    "total": number,           // Total number of users
+    "count": number,           // Number of results in this response
+    "current": number,         // Current page number
+    "pageSize": number,        // Page size
+    "users": [...],            // Array of user objects
+    "has_more": boolean        // Whether more results exist
+  }
+
+Examples:
+  - Use when: "List all users" -> params with page=1, pageSize=20
+  - Use when: "Search for user john" -> params with keyword="john"
+  - Use when: "List active users only" -> params with filters='{"status": 1}'
+  - Use when: "List users sorted by creation date" -> params with sortBy="createdAt", sortOrder="DESC"
+
+Error Handling:
+  - Returns "Error: Permission denied" if not authorized
+  - Returns "Error: Cannot connect to API server" if backend is unreachable`
+);
+
+// Get user
+registerToolWithAnnotations(
+  userTools.userGet,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Get User by ID',
+  `Retrieve detailed information about a specific user by their ID.
+
+This tool fetches complete user information including profile, roles, and company.
+
+Args:
+  - id (number): User ID (required)
+
+Returns:
+  Complete user information with roles and company details.
+
+Examples:
+  - Use when: "Get user with ID 123" -> params with id=123
+  - Use when: "Show user details for user 456"
+
+Error Handling:
+  - Returns "Error: Resource not found" if user ID doesn't exist
+  - Returns "Error: Permission denied" if not authorized`
+);
+
+// Create user
+registerToolWithAnnotations(
+  userTools.userCreate,
+  {
+    readOnlyHint: false,
+    destructiveHint: false,
+    idempotentHint: false,
+    openWorldHint: false
+  },
+  'Create User',
+  `Create a new user in the admin system.
+
+This tool creates a new user with the provided information.
+A password will be generated if not provided.
+
+Args:
+  - username (string): Username (required)
+  - password (string): Password, min 6 characters (optional)
+  - nickname (string): Display name (optional)
+  - phone (string): Phone number in Chinese format (optional)
+  - email (string): Email address (optional)
+  - realName (string): Real/legal name (optional)
+  - avatarFileId (number): Avatar file ID (optional)
+  - companyId (number): Company ID (optional)
+  - status (number): Status: 0 = disabled, 1 = enabled (optional)
+  - roleIds (array): Array of role IDs to assign (optional)
+
+Returns:
+  Created user information with ID.
+
+Examples:
+  - Use when: "Create a new user john_doe" -> params with username="john_doe"
+  - Use when: "Add user with phone number" -> params with username="user123", phone="13800138000"
+
+Error Handling:
+  - Returns "Error: Data already exists" if username/phone/email is duplicated
+  - Returns "Error: Permission denied" if not authorized`
+);
+
+// Update user
+registerToolWithAnnotations(
+  userTools.userUpdate,
+  {
+    readOnlyHint: false,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Update User',
+  `Update an existing user's information.
+
+This tool modifies user information for the specified user ID.
+Only the fields provided will be updated.
+
+Args:
+  - id (number): User ID to update (required)
+  - username (string): Username (optional)
+  - password (string): New password, min 6 characters (optional)
+  - nickname (string): Display name (optional)
+  - phone (string): Phone number (optional)
+  - email (string): Email address (optional)
+  - realName (string): Real/legal name (optional)
+  - avatarFileId (number): Avatar file ID (optional)
+  - companyId (number): Company ID (optional)
+  - status (number): Status: 0 = disabled, 1 = enabled (optional)
+  - roleIds (array): Array of role IDs to assign (optional)
+
+Returns:
+  Updated user information.
+
+Examples:
+  - Use when: "Update user 123 nickname to John" -> params with id=123, nickname="John"
+  - Use when: "Disable user 456" -> params with id=456, status=0
+
+Error Handling:
+  - Returns "Error: Resource not found" if user ID doesn't exist
+  - Returns "Error: Permission denied" if not authorized`
+);
+
+// Delete user
+registerToolWithAnnotations(
+  userTools.userDelete,
+  {
+    readOnlyHint: false,
+    destructiveHint: true,
+    idempotentHint: false,
+    openWorldHint: false
+  },
+  'Delete User',
+  `Delete a user from the admin system.
+
+This tool permanently deletes the specified user.
+This action cannot be undone.
+
+Args:
+  - id (number): User ID to delete (required)
+
+Returns:
+  Deletion confirmation with deleted user ID.
+
+Examples:
+  - Use when: "Delete user 123" -> params with id=123
+
+Error Handling:
+  - Returns "Error: Resource not found" if user ID doesn't exist
+  - Returns "Error: Permission denied" if not authorized
+  - May fail if user has dependent records`
+);
+
+// ============================================================================
+// Register Role Management Tools
+// ============================================================================
+
+// List roles
+registerToolWithAnnotations(
+  roleTools.roleList,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: true
+  },
+  'List Roles',
+  `List and search roles in the admin system with pagination.
+
+This tool retrieves a paginated list of roles from the admin system.
+Supports keyword search and sorting.
+
+Args:
+  - page (number): Page number, starting from 1 (default: 1)
+  - pageSize (number): Number of items per page, 1-100 (default: 20)
+  - keyword (string): Optional search keyword (optional)
+  - sortBy (string): Optional field to sort by (optional)
+  - sortOrder (string): Sort direction: "ASC" or "DESC" (default: "DESC")
+  - filters (string): Optional filter conditions as JSON string (optional)
+  - response_format (string): Output format: "markdown" or "json" (default: "markdown")
+
+Returns:
+  Paginated list of roles with total count.
+
+Examples:
+  - Use when: "List all roles" -> default parameters
+  - Use when: "Search for admin role" -> params with keyword="admin"
+
+Error Handling:
+  - Returns "Error: Permission denied" if not authorized`
+);
+
+// Get role
+registerToolWithAnnotations(
+  roleTools.roleGet,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Get Role by ID',
+  `Retrieve detailed information about a specific role by ID.
+
+Args:
+  - id (number): Role ID (required)
+
+Returns:
+  Complete role information.
+
+Examples:
+  - Use when: "Get role with ID 5" -> params with id=5
+
+Error Handling:
+  - Returns "Error: Resource not found" if role ID doesn't exist`
+);
+
+// Create role
+registerToolWithAnnotations(
+  roleTools.roleCreate,
+  {
+    readOnlyHint: false,
+    destructiveHint: false,
+    idempotentHint: false,
+    openWorldHint: false
+  },
+  'Create Role',
+  `Create a new role in the admin system.
+
+Args:
+  - name (string): Role name (required)
+  - description (string): Role description (optional)
+  - code (string): Role code for permission checks (optional)
+  - status (number): Status: 0 = disabled, 1 = enabled (optional)
+
+Returns:
+  Created role information with ID.
+
+Examples:
+  - Use when: "Create role Content Manager" -> params with name="Content Manager"
+
+Error Handling:
+  - Returns "Error: Data already exists" if role name/code is duplicated`
+);
+
+// Update role
+registerToolWithAnnotations(
+  roleTools.roleUpdate,
+  {
+    readOnlyHint: false,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Update Role',
+  `Update an existing role's information.
+
+Args:
+  - id (number): Role ID to update (required)
+  - name (string): Role name (optional)
+  - description (string): Role description (optional)
+  - code (string): Role code (optional)
+  - status (number): Status (optional)
+
+Returns:
+  Updated role information.
+
+Examples:
+  - Use when: "Update role 3 description" -> params with id=3, description="New description"
+
+Error Handling:
+  - Returns "Error: Resource not found" if role ID doesn't exist`
+);
+
+// Delete role
+registerToolWithAnnotations(
+  roleTools.roleDelete,
+  {
+    readOnlyHint: false,
+    destructiveHint: true,
+    idempotentHint: false,
+    openWorldHint: false
+  },
+  'Delete Role',
+  `Delete a role from the admin system.
+
+Args:
+  - id (number): Role ID to delete (required)
+
+Returns:
+  Deletion confirmation.
+
+Examples:
+  - Use when: "Delete role 10" -> params with id=10
+
+Error Handling:
+  - Returns "Error: Resource not found" if role ID doesn't exist
+  - May fail if role is assigned to users`
+);
+
+// ============================================================================
+// Register System Config Tools
+// ============================================================================
+
+// List system configs
+registerToolWithAnnotations(
+  systemConfigTools.systemConfigList,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: true
+  },
+  'List System Configurations',
+  `List and search system configurations with pagination.
+
+This tool retrieves a paginated list of system configuration items.
+
+Args:
+  - page (number): Page number, starting from 1 (default: 1)
+  - pageSize (number): Number of items per page, 1-100 (default: 20)
+  - keyword (string): Optional search keyword (optional)
+  - sortBy (string): Optional field to sort by (optional)
+  - sortOrder (string): Sort direction: "ASC" or "DESC" (default: "DESC")
+  - filters (string): Optional filter conditions as JSON string (optional)
+  - response_format (string): Output format: "markdown" or "json" (default: "markdown")
+
+Returns:
+  Paginated list of system configurations.
+
+Examples:
+  - Use when: "List all system configs" -> default parameters
+  - Use when: "Get configs in category 'payment'" -> params with filters='{"category": "payment"}'
+
+Error Handling:
+  - Returns "Error: Permission denied" if not authorized`
+);
+
+// Get system config
+registerToolWithAnnotations(
+  systemConfigTools.systemConfigGet,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Get System Configuration by ID',
+  `Retrieve a specific system configuration by ID.
+
+Args:
+  - id (number): Configuration ID (required)
+
+Returns:
+  System configuration details.
+
+Examples:
+  - Use when: "Get config with ID 1" -> params with id=1
+
+Error Handling:
+  - Returns "Error: Resource not found" if config ID doesn't exist`
+);
+
+// Create system config
+registerToolWithAnnotations(
+  systemConfigTools.systemConfigCreate,
+  {
+    readOnlyHint: false,
+    destructiveHint: false,
+    idempotentHint: false,
+    openWorldHint: false
+  },
+  'Create System Configuration',
+  `Create a new system configuration item.
+
+Args:
+  - configKey (string): Configuration key (required)
+  - configValue (string): Configuration value (required)
+  - description (string): Configuration description (optional)
+  - category (string): Configuration category (optional)
+
+Returns:
+  Created configuration with ID.
+
+Examples:
+  - Use when: "Create config for max upload size" -> params with configKey="maxUploadSize", configValue="10485760"
+
+Error Handling:
+  - Returns "Error: Data already exists" if config key is duplicated`
+);
+
+// Update system config
+registerToolWithAnnotations(
+  systemConfigTools.systemConfigUpdate,
+  {
+    readOnlyHint: false,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Update System Configuration',
+  `Update an existing system configuration.
+
+Args:
+  - id (number): Configuration ID to update (required)
+  - configKey (string): Configuration key (optional)
+  - configValue (string): Configuration value (optional)
+  - description (string): Configuration description (optional)
+  - category (string): Configuration category (optional)
+
+Returns:
+  Updated configuration details.
+
+Examples:
+  - Use when: "Update config 5 value to 100" -> params with id=5, configValue="100"
+
+Error Handling:
+  - Returns "Error: Resource not found" if config ID doesn't exist`
+);
+
+// Delete system config
+registerToolWithAnnotations(
+  systemConfigTools.systemConfigDelete,
+  {
+    readOnlyHint: false,
+    destructiveHint: true,
+    idempotentHint: false,
+    openWorldHint: false
+  },
+  'Delete System Configuration',
+  `Delete a system configuration item.
+
+Args:
+  - id (number): Configuration ID to delete (required)
+
+Returns:
+  Deletion confirmation.
+
+Examples:
+  - Use when: "Delete config 10" -> params with id=10
+
+Error Handling:
+  - Returns "Error: Resource not found" if config ID doesn't exist`
+);
+
+// ============================================================================
+// Register Order Management Tools
+// ============================================================================
+
+// List orders
+registerToolWithAnnotations(
+  orderTools.orderList,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: true
+  },
+  'List Orders',
+  `List and search orders in the admin system with pagination and filtering.
+
+This tool retrieves a paginated list of orders from the system.
+
+Args:
+  - page (number): Page number, starting from 1 (default: 1)
+  - pageSize (number): Number of items per page, 1-100 (default: 20)
+  - keyword (string): Optional search keyword (optional)
+  - sortBy (string): Optional field to sort by (optional)
+  - sortOrder (string): Sort direction: "ASC" or "DESC" (default: "DESC")
+  - filters (string): Optional filter conditions as JSON string (optional)
+  - response_format (string): Output format: "markdown" or "json" (default: "markdown")
+
+Returns:
+  Paginated list of orders with total count.
+
+Examples:
+  - Use when: "List all orders" -> default parameters
+  - Use when: "Get pending orders" -> params with filters='{"status": "pending"}'
+
+Error Handling:
+  - Returns "Error: Permission denied" if not authorized`
+);
+
+// Get order
+registerToolWithAnnotations(
+  orderTools.orderGet,
+  {
+    readOnlyHint: true,
+    destructiveHint: false,
+    idempotentHint: true,
+    openWorldHint: false
+  },
+  'Get Order by ID',
+  `Retrieve detailed information about a specific order by ID.
+
+Args:
+  - id (number): Order ID (required)
+
+Returns:
+  Complete order information with delivery address.
+
+Examples:
+  - Use when: "Get order with ID 12345" -> params with id=12345
+
+Error Handling:
+  - Returns "Error: Resource not found" if order ID doesn't exist`
+);
+
+// ============================================================================
+// Start HTTP Server with Streamable Transport
+// ============================================================================
+
+async function runHTTP() {
+  // Create Express app
+  const app = express();
+  app.use(express.json());
+
+  // Health check endpoint
+  app.get('/health', (_req, res) => {
+    res.json({
+      status: 'healthy',
+      server: SERVER_CONFIG.name,
+      version: SERVER_CONFIG.version,
+      apiBaseUrl: SERVER_CONFIG.apiBaseUrl
+    });
+  });
+
+  // MCP endpoint
+  app.post('/mcp', async (req, res) => {
+    // Create a new transport for each request (stateless, prevents request ID collisions)
+    const transport = new StreamableHTTPServerTransport({
+      sessionIdGenerator: undefined,
+      enableJsonResponse: true
+    });
+
+    // Clean up transport when response closes
+    res.on('close', () => transport.close());
+
+    // Connect server to transport and handle request
+    await server.connect(transport);
+    await transport.handleRequest(req, res, req.body);
+  });
+
+  // Start listening
+   
+  app.listen(SERVER_CONFIG.port, () => {
+    // eslint-disable-next-line no-console
+    console.error(`🚀 ${SERVER_CONFIG.name} v${SERVER_CONFIG.version}`);
+    // eslint-disable-next-line no-console
+    console.error(`📡 MCP endpoint: http://localhost:${SERVER_CONFIG.port}/mcp`);
+    // eslint-disable-next-line no-console
+    console.error(`🏥 Health check: http://localhost:${SERVER_CONFIG.port}/health`);
+    // eslint-disable-next-line no-console
+    console.error(`🔌 API backend: ${SERVER_CONFIG.apiBaseUrl}`);
+    // eslint-disable-next-line no-console
+    console.error('');
+    // eslint-disable-next-line no-console
+    console.error(`To connect to this MCP server, use: http://localhost:${SERVER_CONFIG.port}/mcp`);
+  });
+}
+
+// ============================================================================
+// Main Entry Point
+// ============================================================================
+
+runHTTP().catch((error) => {
+  // eslint-disable-next-line no-console
+  console.error('Failed to start server:', error);
+  process.exit(1);
+});

+ 473 - 0
packages/admin-mcp-server/src/schemas/index.ts

@@ -0,0 +1,473 @@
+/**
+ * Zod Validation Schemas
+ *
+ * Runtime validation schemas for all MCP tool inputs and outputs.
+ */
+
+import { z } from 'zod';
+import { ResponseFormat, SortOrder } from '../constants.js';
+
+// ============================================================================
+// Common Schemas
+// ============================================================================
+
+/**
+ * Response format enum schema
+ */
+export const ResponseFormatSchema = z.nativeEnum(ResponseFormat);
+
+/**
+ * Sort order enum schema
+ */
+export const SortOrderSchema = z.nativeEnum(SortOrder);
+
+/**
+ * Pagination schema
+ */
+export const PaginationSchema = z.object({
+  page: z
+    .number()
+    .int()
+    .min(1, 'Page must be at least 1')
+    .default(1)
+    .describe('Page number, starting from 1'),
+  pageSize: z
+    .number()
+    .int()
+    .min(1, 'Page size must be at least 1')
+    .max(100, 'Page size cannot exceed 100')
+    .default(20)
+    .describe('Number of items per page')
+});
+
+/**
+ * Sorting schema
+ */
+export const SortingSchema = z.object({
+  sortBy: z
+    .string()
+    .optional()
+    .describe('Field to sort by (e.g., "id", "createdAt", "name")'),
+  sortOrder: SortOrderSchema.optional().default(SortOrder.DESC).describe('Sort direction')
+});
+
+/**
+ * Filters schema (JSON string)
+ */
+export const FiltersSchema = z
+  .string()
+  .optional()
+  .describe(
+    'Filter conditions as JSON string. ' +
+    'Example: \'{"status": 1, "createdAt": {"gte": "2024-01-01"}}\''
+  );
+
+/**
+ * Search schema
+ */
+export const SearchSchema = z.object({
+  keyword: z
+    .string()
+    .optional()
+    .describe('Search keyword for partial matching')
+});
+
+/**
+ * Common list query schema
+ */
+export const ListQuerySchema = z
+  .object({
+    response_format: ResponseFormatSchema
+      .default(ResponseFormat.MARKDOWN)
+      .describe('Output format: "markdown" for human-readable or "json" for machine-readable')
+  })
+  .merge(PaginationSchema)
+  .merge(SortingSchema)
+  .merge(SearchSchema)
+  .merge(z.object({ filters: FiltersSchema }))
+  .strict();
+
+/**
+ * Resource ID schema
+ */
+export const ResourceIdSchema = z
+  .object({
+    id: z
+      .number()
+      .int()
+      .positive('ID must be a positive integer')
+      .describe('Resource ID')
+  })
+  .strict();
+
+// ============================================================================
+// Auth Schemas
+// ============================================================================
+
+/**
+ * Login input schema
+ */
+export const LoginInputSchema = z
+  .object({
+    username: z
+      .string()
+      .min(1, 'Username is required')
+      .describe('Admin username'),
+    password: z
+      .string()
+      .min(1, 'Password is required')
+      .describe('Admin password')
+  })
+  .strict();
+
+// ============================================================================
+// User Schemas
+// ============================================================================
+
+/**
+ * User list input schema
+ */
+export const UserListInputSchema = ListQuerySchema;
+
+/**
+ * User get input schema
+ */
+export const UserGetInputSchema = ResourceIdSchema;
+
+/**
+ * User create input schema
+ */
+export const UserCreateInputSchema = z
+  .object({
+    username: z
+      .string()
+      .min(1, 'Username is required')
+      .max(50, 'Username cannot exceed 50 characters')
+      .describe('Username (required)'),
+    password: z
+      .string()
+      .min(6, 'Password must be at least 6 characters')
+      .optional()
+      .describe('Password (optional, defaults to a secure password if not provided)'),
+    nickname: z
+      .string()
+      .max(100, 'Nickname cannot exceed 100 characters')
+      .optional()
+      .describe('Display name'),
+    phone: z
+      .string()
+      .regex(/^1[3-9]\d{9}$/, 'Invalid phone number format')
+      .optional()
+      .describe('Phone number (Chinese format)'),
+    email: z
+      .string()
+      .email('Invalid email format')
+      .optional()
+      .describe('Email address'),
+    realName: z
+      .string()
+      .max(50, 'Real name cannot exceed 50 characters')
+      .optional()
+      .describe('Real/legal name'),
+    avatarFileId: z
+      .number()
+      .int()
+      .positive()
+      .optional()
+      .describe('Avatar file ID'),
+    companyId: z
+      .number()
+      .int()
+      .positive()
+      .optional()
+      .describe('Company ID'),
+    status: z
+      .number()
+      .int()
+      .min(0)
+      .max(1)
+      .optional()
+      .describe('Status: 0 = disabled, 1 = enabled'),
+    roleIds: z
+      .array(z.number().int().positive())
+      .optional()
+      .describe('Array of role IDs to assign')
+  })
+  .strict();
+
+/**
+ * User update input schema
+ */
+export const UserUpdateInputSchema = z
+  .object({
+    id: z
+      .number()
+      .int()
+      .positive('ID must be a positive integer')
+      .describe('User ID to update'),
+    username: z
+      .string()
+      .min(1, 'Username is required')
+      .max(50, 'Username cannot exceed 50 characters')
+      .optional()
+      .describe('Username'),
+    password: z
+      .string()
+      .min(6, 'Password must be at least 6 characters')
+      .optional()
+      .describe('New password'),
+    nickname: z
+      .string()
+      .max(100, 'Nickname cannot exceed 100 characters')
+      .optional()
+      .describe('Display name'),
+    phone: z
+      .string()
+      .regex(/^1[3-9]\d{9}$/, 'Invalid phone number format')
+      .optional()
+      .describe('Phone number'),
+    email: z
+      .string()
+      .email('Invalid email format')
+      .optional()
+      .describe('Email address'),
+    realName: z
+      .string()
+      .max(50, 'Real name cannot exceed 50 characters')
+      .optional()
+      .describe('Real/legal name'),
+    avatarFileId: z
+      .number()
+      .int()
+      .positive()
+      .optional()
+      .describe('Avatar file ID'),
+    companyId: z
+      .number()
+      .int()
+      .positive()
+      .optional()
+      .describe('Company ID'),
+    status: z
+      .number()
+      .int()
+      .min(0)
+      .max(1)
+      .optional()
+      .describe('Status: 0 = disabled, 1 = enabled'),
+    roleIds: z
+      .array(z.number().int().positive())
+      .optional()
+      .describe('Array of role IDs to assign')
+  })
+  .strict();
+
+/**
+ * User delete input schema
+ */
+export const UserDeleteInputSchema = ResourceIdSchema;
+
+// ============================================================================
+// Role Schemas
+// ============================================================================
+
+/**
+ * Role list input schema
+ */
+export const RoleListInputSchema = ListQuerySchema;
+
+/**
+ * Role get input schema
+ */
+export const RoleGetInputSchema = ResourceIdSchema;
+
+/**
+ * Role create input schema
+ */
+export const RoleCreateInputSchema = z
+  .object({
+    name: z
+      .string()
+      .min(1, 'Role name is required')
+      .max(50, 'Role name cannot exceed 50 characters')
+      .describe('Role name (required)'),
+    description: z
+      .string()
+      .max(500, 'Description cannot exceed 500 characters')
+      .optional()
+      .describe('Role description'),
+    code: z
+      .string()
+      .max(50, 'Role code cannot exceed 50 characters')
+      .optional()
+      .describe('Role code for permission checks'),
+    status: z
+      .number()
+      .int()
+      .min(0)
+      .max(1)
+      .optional()
+      .describe('Status: 0 = disabled, 1 = enabled')
+  })
+  .strict();
+
+/**
+ * Role update input schema
+ */
+export const RoleUpdateInputSchema = z
+  .object({
+    id: z
+      .number()
+      .int()
+      .positive('ID must be a positive integer')
+      .describe('Role ID to update'),
+    name: z
+      .string()
+      .min(1, 'Role name is required')
+      .max(50, 'Role name cannot exceed 50 characters')
+      .optional()
+      .describe('Role name'),
+    description: z
+      .string()
+      .max(500, 'Description cannot exceed 500 characters')
+      .optional()
+      .describe('Role description'),
+    code: z
+      .string()
+      .max(50, 'Role code cannot exceed 50 characters')
+      .optional()
+      .describe('Role code'),
+    status: z
+      .number()
+      .int()
+      .min(0)
+      .max(1)
+      .optional()
+      .describe('Status: 0 = disabled, 1 = enabled')
+  })
+  .strict();
+
+/**
+ * Role delete input schema
+ */
+export const RoleDeleteInputSchema = ResourceIdSchema;
+
+// ============================================================================
+// System Config Schemas
+// ============================================================================
+
+/**
+ * System config list input schema
+ */
+export const SystemConfigListInputSchema = ListQuerySchema;
+
+/**
+ * System config get input schema
+ */
+export const SystemConfigGetInputSchema = ResourceIdSchema;
+
+/**
+ * System config create input schema
+ */
+export const SystemConfigCreateInputSchema = z
+  .object({
+    configKey: z
+      .string()
+      .min(1, 'Config key is required')
+      .max(100, 'Config key cannot exceed 100 characters')
+      .describe('Configuration key (required)'),
+    configValue: z
+      .string()
+      .min(1, 'Config value is required')
+      .max(2000, 'Config value cannot exceed 2000 characters')
+      .describe('Configuration value (required)'),
+    description: z
+      .string()
+      .max(500, 'Description cannot exceed 500 characters')
+      .optional()
+      .describe('Configuration description'),
+    category: z
+      .string()
+      .max(50, 'Category cannot exceed 50 characters')
+      .optional()
+      .describe('Configuration category')
+  })
+  .strict();
+
+/**
+ * System config update input schema
+ */
+export const SystemConfigUpdateInputSchema = z
+  .object({
+    id: z
+      .number()
+      .int()
+      .positive('ID must be a positive integer')
+      .describe('System config ID to update'),
+    configKey: z
+      .string()
+      .min(1, 'Config key is required')
+      .max(100, 'Config key cannot exceed 100 characters')
+      .optional()
+      .describe('Configuration key'),
+    configValue: z
+      .string()
+      .min(1, 'Config value is required')
+      .max(2000, 'Config value cannot exceed 2000 characters')
+      .optional()
+      .describe('Configuration value'),
+    description: z
+      .string()
+      .max(500, 'Description cannot exceed 500 characters')
+      .optional()
+      .describe('Configuration description'),
+    category: z
+      .string()
+      .max(50, 'Category cannot exceed 50 characters')
+      .optional()
+      .describe('Configuration category')
+  })
+  .strict();
+
+/**
+ * System config delete input schema
+ */
+export const SystemConfigDeleteInputSchema = ResourceIdSchema;
+
+// ============================================================================
+// Order Schemas
+// ============================================================================
+
+/**
+ * Order list input schema
+ */
+export const OrderListInputSchema = ListQuerySchema;
+
+/**
+ * Order get input schema
+ */
+export const OrderGetInputSchema = ResourceIdSchema;
+
+// ============================================================================
+// Export all schema types
+// ============================================================================
+
+export type ListQueryInput = z.infer<typeof ListQuerySchema>;
+export type LoginInput = z.infer<typeof LoginInputSchema>;
+export type UserListInput = z.infer<typeof UserListInputSchema>;
+export type UserGetInput = z.infer<typeof UserGetInputSchema>;
+export type UserCreateInput = z.infer<typeof UserCreateInputSchema>;
+export type UserUpdateInput = z.infer<typeof UserUpdateInputSchema>;
+export type UserDeleteInput = z.infer<typeof UserDeleteInputSchema>;
+export type RoleListInput = z.infer<typeof RoleListInputSchema>;
+export type RoleGetInput = z.infer<typeof RoleGetInputSchema>;
+export type RoleCreateInput = z.infer<typeof RoleCreateInputSchema>;
+export type RoleUpdateInput = z.infer<typeof RoleUpdateInputSchema>;
+export type RoleDeleteInput = z.infer<typeof RoleDeleteInputSchema>;
+export type SystemConfigListInput = z.infer<typeof SystemConfigListInputSchema>;
+export type SystemConfigGetInput = z.infer<typeof SystemConfigGetInputSchema>;
+export type SystemConfigCreateInput = z.infer<typeof SystemConfigCreateInputSchema>;
+export type SystemConfigUpdateInput = z.infer<typeof SystemConfigUpdateInputSchema>;
+export type SystemConfigDeleteInput = z.infer<typeof SystemConfigDeleteInputSchema>;
+export type OrderListInput = z.infer<typeof OrderListInputSchema>;
+export type OrderGetInput = z.infer<typeof OrderGetInputSchema>;

+ 201 - 0
packages/admin-mcp-server/src/services/api-client.ts

@@ -0,0 +1,201 @@
+/**
+ * API Client Service
+ *
+ * Handles all HTTP communication with the admin backend API.
+ */
+
+import axios, { AxiosError, AxiosInstance } from 'axios';
+import { API_BASE_URL, API_TIMEOUT, HttpMethod } from '../constants.js';
+import type { ApiError } from '../types.js';
+
+/**
+ * API Client class for making HTTP requests to the backend
+ */
+export class ApiClient {
+  private client: AxiosInstance;
+  private token: string | null = null;
+
+  constructor(baseURL: string = API_BASE_URL) {
+    this.client = axios.create({
+      baseURL,
+      timeout: API_TIMEOUT,
+      headers: {
+        'Content-Type': 'application/json',
+        'Accept': 'application/json'
+      }
+    });
+
+    // Request interceptor to add auth token
+    this.client.interceptors.request.use((config) => {
+      if (this.token) {
+        config.headers.Authorization = `Bearer ${this.token}`;
+      }
+      return config;
+    });
+
+    // Response interceptor for error handling
+    this.client.interceptors.response.use(
+      (response) => response,
+      (error) => {
+        throw this.handleError(error);
+      }
+    );
+  }
+
+  /**
+   * Set authentication token
+   */
+  setToken(token: string): void {
+    this.token = token;
+  }
+
+  /**
+   * Get current authentication token
+   */
+  getToken(): string | null {
+    return this.token;
+  }
+
+  /**
+   * Clear authentication token
+   */
+  clearToken(): void {
+    this.token = null;
+  }
+
+  /**
+   * Make a generic API request
+   */
+  async request<T>(
+    method: HttpMethod,
+    endpoint: string,
+    data?: unknown,
+    params?: Record<string, unknown>
+  ): Promise<T> {
+    try {
+      const response = await this.client.request<T>({
+        method,
+        url: endpoint,
+        data,
+        params
+      });
+      return response.data;
+    } catch (error) {
+      throw this.handleError(error);
+    }
+  }
+
+  /**
+   * Make a GET request
+   */
+  async get<T>(endpoint: string, params?: Record<string, unknown>): Promise<T> {
+    return this.request<T>('GET', endpoint, undefined, params);
+  }
+
+  /**
+   * Make a POST request
+   */
+  async post<T>(endpoint: string, data?: unknown): Promise<T> {
+    return this.request<T>('POST', endpoint, data);
+  }
+
+  /**
+   * Make a PUT request
+   */
+  async put<T>(endpoint: string, data?: unknown): Promise<T> {
+    return this.request<T>('PUT', endpoint, data);
+  }
+
+  /**
+   * Make a DELETE request
+   */
+  async delete<T>(endpoint: string): Promise<T> {
+    return this.request<T>('DELETE', endpoint);
+  }
+
+  /**
+   * Handle API errors and return formatted error messages
+   */
+  private handleError(error: unknown): Error {
+    if (axios.isAxiosError(error)) {
+      const axiosError = error as AxiosError<ApiError>;
+
+      if (axiosError.response) {
+        const { status, data } = axiosError.response;
+
+        switch (status) {
+          case 400:
+            return new Error(
+              `Error: ${data?.message || 'Invalid request parameters'}. ` +
+              'Please check your input and try again.'
+            );
+          case 401:
+            return new Error(
+              'Error: Authentication failed. ' +
+              'Please check your credentials or re-login.'
+            );
+          case 403:
+            return new Error(
+              'Error: Permission denied. ' +
+              'You do not have access to this resource.'
+            );
+          case 404:
+            return new Error(
+              'Error: Resource not found. ' +
+              'Please check the ID is correct.'
+            );
+          case 429:
+            return new Error(
+              'Error: Rate limit exceeded. ' +
+              'Please wait before making more requests.'
+            );
+          case 500:
+            return new Error(
+              `Error: Server error. ${data?.message || 'Please try again later.'}`
+            );
+          default:
+            return new Error(
+              `Error: API request failed with status ${status}. ` +
+              (data?.message || '')
+            );
+        }
+      } else if (axiosError.code === 'ECONNABORTED') {
+        return new Error(
+          'Error: Request timed out. ' +
+          'Please try again or check your network connection.'
+        );
+      } else if (axiosError.code === 'ECONNREFUSED') {
+        return new Error(
+          `Error: Cannot connect to API server at ${this.client.defaults.baseURL}. ` +
+          'Please ensure the server is running.'
+        );
+      }
+    }
+
+    return new Error(
+      `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`
+    );
+  }
+}
+
+/**
+ * Singleton API client instance
+ */
+let apiClientInstance: ApiClient | null = null;
+
+/**
+ * Get or create the singleton API client instance
+ */
+export function getApiClient(): ApiClient {
+  if (!apiClientInstance) {
+    apiClientInstance = new ApiClient();
+  }
+  return apiClientInstance;
+}
+
+/**
+ * Reset the singleton API client instance (useful for testing)
+ */
+export function resetApiClient(): void {
+  apiClientInstance = null;
+}

+ 172 - 0
packages/admin-mcp-server/src/tools/auth-tools.ts

@@ -0,0 +1,172 @@
+/**
+ * Authentication Tools
+ *
+ * MCP tools for admin authentication.
+ */
+
+import { getApiClient } from '../services/api-client.js';
+import { LoginInputSchema } from '../schemas/index.js';
+import type { LoginInput } from '../schemas/index.js';
+import type { TokenResponse, User } from '../types.js';
+
+/**
+ * Login tool - authenticates admin user and stores token
+ */
+export const loginTool = async (args: LoginInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { username, password } = args;
+
+    const response = await apiClient.post<TokenResponse>('/api/v1/auth/login', {
+      username,
+      password
+    });
+
+    const { token, user } = response;
+
+    // Store the token for subsequent requests
+    apiClient.setToken(token);
+
+    const structuredOutput = {
+      success: true,
+      token: token.substring(0, 20) + '...', // Partial token for security
+      userId: user?.id,
+      username: user?.username,
+      nickname: user?.nickname
+    };
+
+    const markdown = [
+      '✅ **Login Successful**',
+      '',
+      `**Welcome**, ${user?.nickname || user?.username}!`,
+      `**User ID**: ${user?.id}`,
+      `**Username**: ${user?.username}`,
+      user?.nickname ? `**Nickname**: ${user.nickname}` : null,
+      '',
+      'You are now authenticated and can use other admin tools.'
+    ].filter(Boolean).join('\n');
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Login failed'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Logout tool - clears authentication token
+ */
+export const logoutTool = async () => {
+  const apiClient = getApiClient();
+
+  try {
+    // Clear the stored token
+    apiClient.clearToken();
+
+    const markdown = '✅ **Logout Successful**\n\nYou have been logged out.';
+
+    const structuredOutput = {
+      success: true,
+      message: 'Logged out successfully'
+    };
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Logout failed'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Get current user tool - returns current authenticated user info
+ */
+export const getCurrentUserTool = async () => {
+  const apiClient = getApiClient();
+
+  try {
+    const response = await apiClient.get<User>('/api/v1/auth/me');
+
+    const user = response;
+
+    const structuredOutput = {
+      id: user.id,
+      username: user.username,
+      nickname: user.nickname,
+      phone: user.phone,
+      email: user.email,
+      realName: user.realName,
+      companyId: user.companyId,
+      companyName: user.company?.companyName,
+      status: user.status,
+      userType: user.userType,
+      roles: user.roles?.map((r: { id: number; name: string }) => ({ id: r.id, name: r.name }))
+    };
+
+    let markdown = [
+      '## Current User',
+      '',
+      `**Username**: ${user.username}`,
+      user.nickname ? `**Nickname**: ${user.nickname}` : null,
+      user.realName ? `**Real Name**: ${user.realName}` : null,
+      user.phone ? `**Phone**: ${user.phone}` : null,
+      user.email ? `**Email**: ${user.email}` : null,
+      user.company ? `**Company**: ${user.company.companyName}` : null,
+      `**Status**: ${user.status === 1 ? 'Enabled' : 'Disabled'}`,
+      user.userType ? `**User Type**: ${user.userType}` : null,
+      ''
+    ].filter(Boolean).join('\n');
+
+    if (user.roles && user.roles.length > 0) {
+      markdown += '\n**Roles**:\n';
+      for (const role of user.roles) {
+        markdown += `  - ${role.name} (ID: ${role.id})\n`;
+      }
+    }
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to get current user'}`
+      }]
+    };
+  }
+};
+
+// Export tool registration configs
+export const authTools = {
+  login: {
+    name: 'admin_login',
+    schema: LoginInputSchema,
+    handler: loginTool
+  },
+  logout: {
+    name: 'admin_logout',
+    schema: undefined, // No input schema needed
+    handler: logoutTool
+  },
+  getCurrentUser: {
+    name: 'admin_get_current_user',
+    schema: undefined, // No input schema needed
+    handler: getCurrentUserTool
+  }
+};

+ 82 - 0
packages/admin-mcp-server/src/tools/index.ts

@@ -0,0 +1,82 @@
+/**
+ * MCP Tools Registration
+ *
+ * Exports all tool configurations for registering with the MCP server.
+ */
+
+import { authTools } from './auth-tools.js';
+import { userTools } from './user-tools.js';
+import { roleTools } from './role-tools.js';
+import { systemConfigTools } from './system-config-tools.js';
+import { orderTools } from './order-tools.js';
+
+// Export all tool collections
+export const allTools = {
+  ...authTools,
+  ...userTools,
+  ...roleTools,
+  ...systemConfigTools,
+  ...orderTools
+};
+
+// Export tool names for easy reference
+export const toolNames = {
+  // Auth tools
+  login: 'admin_login',
+  logout: 'admin_logout',
+  getCurrentUser: 'admin_get_current_user',
+
+  // User tools
+  userList: 'admin_list_users',
+  userGet: 'admin_get_user',
+  userCreate: 'admin_create_user',
+  userUpdate: 'admin_update_user',
+  userDelete: 'admin_delete_user',
+
+  // Role tools
+  roleList: 'admin_list_roles',
+  roleGet: 'admin_get_role',
+  roleCreate: 'admin_create_role',
+  roleUpdate: 'admin_update_role',
+  roleDelete: 'admin_delete_role',
+
+  // System config tools
+  systemConfigList: 'admin_list_system_configs',
+  systemConfigGet: 'admin_get_system_config',
+  systemConfigCreate: 'admin_create_system_config',
+  systemConfigUpdate: 'admin_update_system_config',
+  systemConfigDelete: 'admin_delete_system_config',
+
+  // Order tools
+  orderList: 'admin_list_orders',
+  orderGet: 'admin_get_order'
+};
+
+// Export tool categories for documentation
+export const toolCategories = {
+  auth: {
+    name: 'Authentication',
+    description: 'Tools for admin authentication',
+    tools: [toolNames.login, toolNames.logout, toolNames.getCurrentUser]
+  },
+  users: {
+    name: 'User Management',
+    description: 'Tools for managing system users',
+    tools: [toolNames.userList, toolNames.userGet, toolNames.userCreate, toolNames.userUpdate, toolNames.userDelete]
+  },
+  roles: {
+    name: 'Role Management',
+    description: 'Tools for managing user roles and permissions',
+    tools: [toolNames.roleList, toolNames.roleGet, toolNames.roleCreate, toolNames.roleUpdate, toolNames.roleDelete]
+  },
+  systemConfig: {
+    name: 'System Configuration',
+    description: 'Tools for managing system configuration',
+    tools: [toolNames.systemConfigList, toolNames.systemConfigGet, toolNames.systemConfigCreate, toolNames.systemConfigUpdate, toolNames.systemConfigDelete]
+  },
+  orders: {
+    name: 'Order Management',
+    description: 'Tools for viewing orders',
+    tools: [toolNames.orderList, toolNames.orderGet]
+  }
+};

+ 182 - 0
packages/admin-mcp-server/src/tools/order-tools.ts

@@ -0,0 +1,182 @@
+/**
+ * Order Management Tools
+ *
+ * MCP tools for managing orders in the admin system.
+ */
+
+import { getApiClient } from '../services/api-client.js';
+import { OrderListInputSchema, OrderGetInputSchema } from '../schemas/index.js';
+import type { OrderListInput, OrderGetInput } from '../schemas/index.js';
+import { ResponseFormat } from '../constants.js';
+import type { Order, PaginatedResponse } from '../types.js';
+
+/**
+ * Format order data for markdown output
+ */
+function formatOrderMarkdown(order: Order): string {
+  const lines = [
+    `## Order: ${order.orderNo} (ID: ${order.id})`,
+    '',
+    `**Order No**: ${order.orderNo}`,
+    `**User ID**: ${order.userId}`,
+    order.userPhone ? `**User Phone**: ${order.userPhone}` : null,
+    order.merchantId ? `**Merchant ID**: ${order.merchantId}` : null,
+    order.supplierId ? `**Supplier ID**: ${order.supplierId}` : null,
+    order.deliveryAddressId ? `**Delivery Address ID**: ${order.deliveryAddressId}` : null,
+    order.totalAmount ? `**Total Amount**: ¥${order.totalAmount.toFixed(2)}` : null,
+    order.status ? `**Status**: ${order.status}` : null,
+    `**Created At**: ${new Date(order.createdAt).toLocaleString('zh-CN')}`,
+    ''
+  ];
+
+  // Add delivery address info if available
+  if (order.deliveryAddress) {
+    const addr = order.deliveryAddress;
+    lines.push('**Delivery Address**:');
+    lines.push(`  - Receiver: ${addr.receiverName}`);
+    lines.push(`  - Phone: ${addr.receiverPhone}`);
+    lines.push(`  - Address: ${addr.province} ${addr.city} ${addr.district || ''} ${addr.detailedAddress}`);
+    lines.push('');
+  }
+
+  return lines.filter(Boolean).join('\n');
+}
+
+/**
+ * Format order list for markdown output
+ */
+function formatOrderListMarkdown(orders: Order[], total: number, current: number, pageSize: number): string {
+  const lines = [
+    `# Order List`,
+    '',
+    `Total: ${total} orders | Page: ${current} | Page Size: ${pageSize}`,
+    ''
+  ];
+
+  for (const order of orders) {
+    lines.push(formatOrderMarkdown(order));
+  }
+
+  return lines.join('\n');
+}
+
+/**
+ * List orders tool
+ */
+export const orderListTool = async (args: OrderListInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { page, pageSize, keyword, sortBy, sortOrder, filters, response_format } = args;
+
+    const params: Record<string, unknown> = {
+      page: page || 1,
+      pageSize: pageSize || 20
+    };
+
+    if (keyword) params.keyword = keyword;
+    if (sortBy) params.sortBy = sortBy;
+    if (sortOrder) params.sortOrder = sortOrder;
+    if (filters) params.filters = filters;
+
+    const response = await apiClient.get<PaginatedResponse<Order>>('/api/v1/orders', params);
+
+    const orders = response.data || [];
+    const total = response.pagination?.total || 0;
+
+    const structuredOutput = {
+      total,
+      count: orders.length,
+      current: page || 1,
+      pageSize: pageSize || 20,
+      orders: orders.map((o: Order) => ({
+        id: o.id,
+        orderNo: o.orderNo,
+        userId: o.userId,
+        userPhone: o.userPhone,
+        merchantId: o.merchantId,
+        supplierId: o.supplierId,
+        deliveryAddressId: o.deliveryAddressId,
+        totalAmount: o.totalAmount,
+        status: o.status,
+        createdAt: o.createdAt
+      })),
+      hasMore: total > (page || 1) * (pageSize || 20)
+    };
+
+    let textContent: string;
+    if (response_format === ResponseFormat.JSON) {
+      textContent = JSON.stringify(structuredOutput, null, 2);
+    } else {
+      textContent = formatOrderListMarkdown(orders, total, page || 1, pageSize || 20);
+    }
+
+    return {
+      content: [{ type: 'text', text: textContent }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to list orders'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Get single order tool
+ */
+export const orderGetTool = async (args: OrderGetInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id } = args;
+    const response = await apiClient.get<Order>(`/api/orders/${id}`);
+
+    const order = response;
+
+    const structuredOutput = {
+      id: order.id,
+      orderNo: order.orderNo,
+      userId: order.userId,
+      userPhone: order.userPhone,
+      merchantId: order.merchantId,
+      supplierId: order.supplierId,
+      deliveryAddressId: order.deliveryAddressId,
+      totalAmount: order.totalAmount,
+      status: order.status,
+      createdAt: order.createdAt,
+      updatedAt: order.updatedAt
+    };
+
+    const markdown = formatOrderMarkdown(order);
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to get order'}`
+      }]
+    };
+  }
+};
+
+// Export tool registration configs
+export const orderTools = {
+  orderList: {
+    name: 'admin_list_orders',
+    schema: OrderListInputSchema,
+    handler: orderListTool
+  },
+  orderGet: {
+    name: 'admin_get_order',
+    schema: OrderGetInputSchema,
+    handler: orderGetTool
+  }
+};

+ 288 - 0
packages/admin-mcp-server/src/tools/role-tools.ts

@@ -0,0 +1,288 @@
+/**
+ * Role Management Tools
+ *
+ * MCP tools for managing roles in the admin system.
+ */
+
+import { getApiClient } from '../services/api-client.js';
+import {
+  RoleListInputSchema,
+  RoleGetInputSchema,
+  RoleCreateInputSchema,
+  RoleUpdateInputSchema,
+  RoleDeleteInputSchema
+} from '../schemas/index.js';
+import type {
+  RoleListInput,
+  RoleGetInput,
+  RoleCreateInput,
+  RoleUpdateInput,
+  RoleDeleteInput
+} from '../schemas/index.js';
+import { ResponseFormat } from '../constants.js';
+import type { Role, PaginatedResponse } from '../types.js';
+
+/**
+ * Format role data for markdown output
+ */
+function formatRoleMarkdown(role: Role): string {
+  return [
+    `## Role: ${role.name} (ID: ${role.id})`,
+    '',
+    role.code ? `**Code**: ${role.code}` : null,
+    role.description ? `**Description**: ${role.description}` : null,
+    `**Status**: ${role.status === 1 ? 'Enabled' : 'Disabled'}`,
+    `**Created At**: ${new Date(role.createdAt).toLocaleString('zh-CN')}`,
+    ''
+  ].filter(Boolean).join('\n');
+}
+
+/**
+ * Format role list for markdown output
+ */
+function formatRoleListMarkdown(roles: Role[], total: number, current: number, pageSize: number): string {
+  const lines = [
+    `# Role List`,
+    '',
+    `Total: ${total} roles | Page: ${current} | Page Size: ${pageSize}`,
+    ''
+  ];
+
+  for (const role of roles) {
+    lines.push(formatRoleMarkdown(role));
+  }
+
+  return lines.join('\n');
+}
+
+/**
+ * List roles tool
+ */
+export const roleListTool = async (args: RoleListInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { page, pageSize, keyword, sortBy, sortOrder, filters, response_format } = args;
+
+    const params: Record<string, unknown> = {
+      page: page || 1,
+      pageSize: pageSize || 20
+    };
+
+    if (keyword) params.keyword = keyword;
+    if (sortBy) params.sortBy = sortBy;
+    if (sortOrder) params.sortOrder = sortOrder;
+    if (filters) params.filters = filters;
+
+    const response = await apiClient.get<PaginatedResponse<Role>>('/api/v1/roles', params);
+
+    const roles = response.data || [];
+    const total = response.pagination?.total || 0;
+
+    const structuredOutput = {
+      total,
+      count: roles.length,
+      current: page || 1,
+      pageSize: pageSize || 20,
+      roles: roles.map((r: Role) => ({
+        id: r.id,
+        name: r.name,
+        code: r.code,
+        description: r.description,
+        status: r.status,
+        createdAt: r.createdAt
+      })),
+      hasMore: total > (page || 1) * (pageSize || 20)
+    };
+
+    let textContent: string;
+    if (response_format === ResponseFormat.JSON) {
+      textContent = JSON.stringify(structuredOutput, null, 2);
+    } else {
+      textContent = formatRoleListMarkdown(roles, total, page || 1, pageSize || 20);
+    }
+
+    return {
+      content: [{ type: 'text', text: textContent }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to list roles'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Get single role tool
+ */
+export const roleGetTool = async (args: RoleGetInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id } = args;
+    const response = await apiClient.get<Role>(`/api/roles/${id}`);
+
+    const role = response;
+
+    const structuredOutput = {
+      id: role.id,
+      name: role.name,
+      code: role.code,
+      description: role.description,
+      status: role.status,
+      createdAt: role.createdAt,
+      updatedAt: role.updatedAt
+    };
+
+    const markdown = formatRoleMarkdown(role);
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to get role'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Create role tool
+ */
+export const roleCreateTool = async (args: RoleCreateInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const response = await apiClient.post<Role>('/api/v1/roles', args);
+
+    const role = response;
+
+    const structuredOutput = {
+      id: role.id,
+      name: role.name,
+      code: role.code,
+      description: role.description,
+      status: role.status,
+      createdAt: role.createdAt
+    };
+
+    const markdown = `✅ **Role Created Successfully**\n\n${formatRoleMarkdown(role)}`;
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to create role'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Update role tool
+ */
+export const roleUpdateTool = async (args: RoleUpdateInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id, ...updateData } = args;
+    const response = await apiClient.put<Role>(`/api/roles/${id}`, updateData);
+
+    const role = response;
+
+    const structuredOutput = {
+      id: role.id,
+      name: role.name,
+      code: role.code,
+      description: role.description,
+      status: role.status,
+      updatedAt: role.updatedAt
+    };
+
+    const markdown = `✅ **Role Updated Successfully**\n\n${formatRoleMarkdown(role)}`;
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to update role'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Delete role tool
+ */
+export const roleDeleteTool = async (args: RoleDeleteInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id } = args;
+    await apiClient.delete<{ success: boolean }>(`/api/roles/${id}`);
+
+    const markdown = `✅ **Role Deleted Successfully**\n\nRole ID ${id} has been deleted.`;
+
+    const structuredOutput = {
+      success: true,
+      deletedRoleId: id
+    };
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to delete role'}`
+      }]
+    };
+  }
+};
+
+// Export tool registration configs
+export const roleTools = {
+  roleList: {
+    name: 'admin_list_roles',
+    schema: RoleListInputSchema,
+    handler: roleListTool
+  },
+  roleGet: {
+    name: 'admin_get_role',
+    schema: RoleGetInputSchema,
+    handler: roleGetTool
+  },
+  roleCreate: {
+    name: 'admin_create_role',
+    schema: RoleCreateInputSchema,
+    handler: roleCreateTool
+  },
+  roleUpdate: {
+    name: 'admin_update_role',
+    schema: RoleUpdateInputSchema,
+    handler: roleUpdateTool
+  },
+  roleDelete: {
+    name: 'admin_delete_role',
+    schema: RoleDeleteInputSchema,
+    handler: roleDeleteTool
+  }
+};

+ 289 - 0
packages/admin-mcp-server/src/tools/system-config-tools.ts

@@ -0,0 +1,289 @@
+/**
+ * System Config Management Tools
+ *
+ * MCP tools for managing system configurations in the admin system.
+ */
+
+import { getApiClient } from '../services/api-client.js';
+import {
+  SystemConfigListInputSchema,
+  SystemConfigGetInputSchema,
+  SystemConfigCreateInputSchema,
+  SystemConfigUpdateInputSchema,
+  SystemConfigDeleteInputSchema
+} from '../schemas/index.js';
+import type {
+  SystemConfigListInput,
+  SystemConfigGetInput,
+  SystemConfigCreateInput,
+  SystemConfigUpdateInput,
+  SystemConfigDeleteInput
+} from '../schemas/index.js';
+import { ResponseFormat } from '../constants.js';
+import type { SystemConfig, PaginatedResponse } from '../types.js';
+
+/**
+ * Format system config data for markdown output
+ */
+function formatSystemConfigMarkdown(config: SystemConfig): string {
+  return [
+    `## System Config: ${config.configKey} (ID: ${config.id})`,
+    '',
+    `**Config Key**: ${config.configKey}`,
+    `**Config Value**: ${config.configValue}`,
+    config.description ? `**Description**: ${config.description}` : null,
+    config.category ? `**Category**: ${config.category}` : null,
+    `**Created At**: ${new Date(config.createdAt).toLocaleString('zh-CN')}`,
+    ''
+  ].filter(Boolean).join('\n');
+}
+
+/**
+ * Format system config list for markdown output
+ */
+function formatSystemConfigListMarkdown(configs: SystemConfig[], total: number, current: number, pageSize: number): string {
+  const lines = [
+    `# System Config List`,
+    '',
+    `Total: ${total} configs | Page: ${current} | Page Size: ${pageSize}`,
+    ''
+  ];
+
+  for (const config of configs) {
+    lines.push(formatSystemConfigMarkdown(config));
+  }
+
+  return lines.join('\n');
+}
+
+/**
+ * List system configs tool
+ */
+export const systemConfigListTool = async (args: SystemConfigListInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { page, pageSize, keyword, sortBy, sortOrder, filters, response_format } = args;
+
+    const params: Record<string, unknown> = {
+      page: page || 1,
+      pageSize: pageSize || 20
+    };
+
+    if (keyword) params.keyword = keyword;
+    if (sortBy) params.sortBy = sortBy;
+    if (sortOrder) params.sortOrder = sortOrder;
+    if (filters) params.filters = filters;
+
+    const response = await apiClient.get<PaginatedResponse<SystemConfig>>('/api/v1/system-configs', params);
+
+    const configs = response.data || [];
+    const total = response.pagination?.total || 0;
+
+    const structuredOutput = {
+      total,
+      count: configs.length,
+      current: page || 1,
+      pageSize: pageSize || 20,
+      configs: configs.map((c: SystemConfig) => ({
+        id: c.id,
+        configKey: c.configKey,
+        configValue: c.configValue,
+        description: c.description,
+        category: c.category,
+        createdAt: c.createdAt
+      })),
+      hasMore: total > (page || 1) * (pageSize || 20)
+    };
+
+    let textContent: string;
+    if (response_format === ResponseFormat.JSON) {
+      textContent = JSON.stringify(structuredOutput, null, 2);
+    } else {
+      textContent = formatSystemConfigListMarkdown(configs, total, page || 1, pageSize || 20);
+    }
+
+    return {
+      content: [{ type: 'text', text: textContent }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to list system configs'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Get single system config tool
+ */
+export const systemConfigGetTool = async (args: SystemConfigGetInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id } = args;
+    const response = await apiClient.get<SystemConfig>(`/api/system-configs/${id}`);
+
+    const config = response;
+
+    const structuredOutput = {
+      id: config.id,
+      configKey: config.configKey,
+      configValue: config.configValue,
+      description: config.description,
+      category: config.category,
+      createdAt: config.createdAt,
+      updatedAt: config.updatedAt
+    };
+
+    const markdown = formatSystemConfigMarkdown(config);
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to get system config'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Create system config tool
+ */
+export const systemConfigCreateTool = async (args: SystemConfigCreateInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const response = await apiClient.post<SystemConfig>('/api/v1/system-configs', args);
+
+    const config = response;
+
+    const structuredOutput = {
+      id: config.id,
+      configKey: config.configKey,
+      configValue: config.configValue,
+      description: config.description,
+      category: config.category,
+      createdAt: config.createdAt
+    };
+
+    const markdown = `✅ **System Config Created Successfully**\n\n${formatSystemConfigMarkdown(config)}`;
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to create system config'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Update system config tool
+ */
+export const systemConfigUpdateTool = async (args: SystemConfigUpdateInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id, ...updateData } = args;
+    const response = await apiClient.put<SystemConfig>(`/api/system-configs/${id}`, updateData);
+
+    const config = response;
+
+    const structuredOutput = {
+      id: config.id,
+      configKey: config.configKey,
+      configValue: config.configValue,
+      description: config.description,
+      category: config.category,
+      updatedAt: config.updatedAt
+    };
+
+    const markdown = `✅ **System Config Updated Successfully**\n\n${formatSystemConfigMarkdown(config)}`;
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to update system config'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Delete system config tool
+ */
+export const systemConfigDeleteTool = async (args: SystemConfigDeleteInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id } = args;
+    await apiClient.delete<{ success: boolean }>(`/api/system-configs/${id}`);
+
+    const markdown = `✅ **System Config Deleted Successfully**\n\nConfig ID ${id} has been deleted.`;
+
+    const structuredOutput = {
+      success: true,
+      deletedConfigId: id
+    };
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to delete system config'}`
+      }]
+    };
+  }
+};
+
+// Export tool registration configs
+export const systemConfigTools = {
+  systemConfigList: {
+    name: 'admin_list_system_configs',
+    schema: SystemConfigListInputSchema,
+    handler: systemConfigListTool
+  },
+  systemConfigGet: {
+    name: 'admin_get_system_config',
+    schema: SystemConfigGetInputSchema,
+    handler: systemConfigGetTool
+  },
+  systemConfigCreate: {
+    name: 'admin_create_system_config',
+    schema: SystemConfigCreateInputSchema,
+    handler: systemConfigCreateTool
+  },
+  systemConfigUpdate: {
+    name: 'admin_update_system_config',
+    schema: SystemConfigUpdateInputSchema,
+    handler: systemConfigUpdateTool
+  },
+  systemConfigDelete: {
+    name: 'admin_delete_system_config',
+    schema: SystemConfigDeleteInputSchema,
+    handler: systemConfigDeleteTool
+  }
+};

+ 334 - 0
packages/admin-mcp-server/src/tools/user-tools.ts

@@ -0,0 +1,334 @@
+/**
+ * User Management Tools
+ *
+ * MCP tools for managing users in the admin system.
+ */
+
+import { getApiClient } from '../services/api-client.js';
+import {
+  UserListInputSchema,
+  UserGetInputSchema,
+  UserCreateInputSchema,
+  UserUpdateInputSchema,
+  UserDeleteInputSchema
+} from '../schemas/index.js';
+import type {
+  UserListInput,
+  UserGetInput,
+  UserCreateInput,
+  UserUpdateInput,
+  UserDeleteInput
+} from '../schemas/index.js';
+import { CHARACTER_LIMIT, ResponseFormat } from '../constants.js';
+import type { User, PaginatedResponse } from '../types.js';
+
+/**
+ * Format user data for markdown output
+ */
+function formatUserMarkdown(user: User): string {
+  const lines = [
+    `## User: ${user.nickname || user.username} (ID: ${user.id})`,
+    '',
+    `**Username**: ${user.username}`,
+    user.nickname ? `**Nickname**: ${user.nickname}` : null,
+    user.realName ? `**Real Name**: ${user.realName}` : null,
+    user.phone ? `**Phone**: ${user.phone}` : null,
+    user.email ? `**Email**: ${user.email}` : null,
+    user.company ? `**Company**: ${user.company.companyName} (ID: ${user.companyId})` : null,
+    `**Status**: ${user.status === 1 ? 'Enabled' : 'Disabled'}`,
+    user.userType ? `**User Type**: ${user.userType}` : null,
+    `**Created At**: ${new Date(user.createdAt).toLocaleString('zh-CN')}`,
+    ''
+  ].filter(Boolean);
+
+  if (user.roles && user.roles.length > 0) {
+    lines.push('**Roles**:');
+    for (const role of user.roles) {
+      lines.push(`  - ${role.name} (ID: ${role.id})`);
+    }
+    lines.push('');
+  }
+
+  return lines.join('\n');
+}
+
+/**
+ * Format user list for markdown output
+ */
+function formatUserListMarkdown(users: User[], total: number, current: number, pageSize: number): string {
+  const lines = [
+    `# User List`,
+    '',
+    `Total: ${total} users | Page: ${current} | Page Size: ${pageSize}`,
+    ''
+  ];
+
+  for (const user of users) {
+    lines.push(formatUserMarkdown(user));
+  }
+
+  return lines.join('\n');
+}
+
+/**
+ * List users tool
+ */
+export const userListTool = async (args: UserListInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { page, pageSize, keyword, sortBy, sortOrder, filters, response_format } = args;
+
+    const params: Record<string, unknown> = {
+      page: page || 1,
+      pageSize: pageSize || 20
+    };
+
+    if (keyword) params.keyword = keyword;
+    if (sortBy) params.sortBy = sortBy;
+    if (sortOrder) params.sortOrder = sortOrder;
+    if (filters) params.filters = filters;
+
+    const response = await apiClient.get<PaginatedResponse<User>>('/api/v1/users', params);
+
+    const users = response.data || [];
+    const total = response.pagination?.total || 0;
+
+    const structuredOutput = {
+      total,
+      count: users.length,
+      current: page || 1,
+      pageSize: pageSize || 20,
+      users: users.map((u: User) => ({
+        id: u.id,
+        username: u.username,
+        nickname: u.nickname,
+        phone: u.phone,
+        email: u.email,
+        realName: u.realName,
+        companyId: u.companyId,
+        companyName: u.company?.companyName,
+        status: u.status,
+        userType: u.userType,
+        roleIds: u.roles?.map((r: { id: number }) => r.id),
+        createdAt: u.createdAt
+      })),
+      hasMore: total > (page || 1) * (pageSize || 20)
+    };
+
+    let textContent: string;
+    if (response_format === ResponseFormat.JSON) {
+      textContent = JSON.stringify(structuredOutput, null, 2);
+    } else {
+      let markdown = formatUserListMarkdown(users, total, page || 1, pageSize || 20);
+
+      // Check character limit
+      if (markdown.length > CHARACTER_LIMIT) {
+        const halfLength = Math.floor(users.length / 2);
+        const truncatedUsers = users.slice(0, halfLength);
+        markdown = formatUserListMarkdown(truncatedUsers, total, page || 1, pageSize || 20);
+        markdown += `\n---\n⚠️ **Response truncated**: Showing ${halfLength} of ${users.length} results. Use pagination to see more.\n`;
+      }
+
+      textContent = markdown;
+    }
+
+    return {
+      content: [{ type: 'text', text: textContent }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to list users'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Get single user tool
+ */
+export const userGetTool = async (args: UserGetInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id } = args;
+    const response = await apiClient.get<User>(`/api/v1/users/${id}`);
+
+    const user = response;
+
+    const structuredOutput = {
+      id: user.id,
+      username: user.username,
+      nickname: user.nickname,
+      phone: user.phone,
+      email: user.email,
+      realName: user.realName,
+      avatarFileId: user.avatarFileId,
+      companyId: user.companyId,
+      companyName: user.company?.companyName,
+      status: user.status,
+      userType: user.userType,
+      roles: user.roles?.map((r: { id: number; name: string }) => ({ id: r.id, name: r.name })),
+      createdAt: user.createdAt,
+      updatedAt: user.updatedAt
+    };
+
+    const markdown = formatUserMarkdown(user);
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to get user'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Create user tool
+ */
+export const userCreateTool = async (args: UserCreateInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const response = await apiClient.post<User>('/api/v1/users', args);
+
+    const user = response;
+
+    const structuredOutput = {
+      id: user.id,
+      username: user.username,
+      nickname: user.nickname,
+      phone: user.phone,
+      email: user.email,
+      realName: user.realName,
+      companyId: user.companyId,
+      status: user.status,
+      userType: user.userType,
+      createdAt: user.createdAt
+    };
+
+    const markdown = `✅ **User Created Successfully**\n\n${formatUserMarkdown(user)}`;
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to create user'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Update user tool
+ */
+export const userUpdateTool = async (args: UserUpdateInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id, ...updateData } = args;
+    const response = await apiClient.put<User>(`/api/v1/users/${id}`, updateData);
+
+    const user = response;
+
+    const structuredOutput = {
+      id: user.id,
+      username: user.username,
+      nickname: user.nickname,
+      phone: user.phone,
+      email: user.email,
+      realName: user.realName,
+      companyId: user.companyId,
+      status: user.status,
+      userType: user.userType,
+      updatedAt: user.updatedAt
+    };
+
+    const markdown = `✅ **User Updated Successfully**\n\n${formatUserMarkdown(user)}`;
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to update user'}`
+      }]
+    };
+  }
+};
+
+/**
+ * Delete user tool
+ */
+export const userDeleteTool = async (args: UserDeleteInput) => {
+  const apiClient = getApiClient();
+
+  try {
+    const { id } = args;
+    await apiClient.delete<{ success: boolean }>(`/api/v1/users/${id}`);
+
+    const markdown = `✅ **User Deleted Successfully**\n\nUser ID ${id} has been deleted.`;
+
+    const structuredOutput = {
+      success: true,
+      deletedUserId: id
+    };
+
+    return {
+      content: [{ type: 'text', text: markdown }],
+      structuredContent: structuredOutput
+    };
+  } catch (error) {
+    return {
+      content: [{
+        type: 'text',
+        text: `Error: ${error instanceof Error ? error.message : 'Failed to delete user'}`
+      }]
+    };
+  }
+};
+
+// Export tool registration configs
+export const userTools = {
+  userList: {
+    name: 'admin_list_users',
+    schema: UserListInputSchema,
+    handler: userListTool
+  },
+  userGet: {
+    name: 'admin_get_user',
+    schema: UserGetInputSchema,
+    handler: userGetTool
+  },
+  userCreate: {
+    name: 'admin_create_user',
+    schema: UserCreateInputSchema,
+    handler: userCreateTool
+  },
+  userUpdate: {
+    name: 'admin_update_user',
+    schema: UserUpdateInputSchema,
+    handler: userUpdateTool
+  },
+  userDelete: {
+    name: 'admin_delete_user',
+    schema: UserDeleteInputSchema,
+    handler: userDeleteTool
+  }
+};

+ 298 - 0
packages/admin-mcp-server/src/types.ts

@@ -0,0 +1,298 @@
+/**
+ * Admin MCP Server Type Definitions
+ */
+
+import { SortOrder } from './constants.js';
+
+// ============================================================================
+// Common Types
+// ============================================================================
+
+/**
+ * Pagination response metadata
+ */
+export interface PaginationMeta {
+  total: number;
+  current: number;
+  pageSize: number;
+  totalPages?: number;
+}
+
+/**
+ * Paginated response wrapper
+ */
+export interface PaginatedResponse<T> {
+  data: T[];
+  pagination: PaginationMeta;
+}
+
+/**
+ * API error response
+ */
+export interface ApiError {
+  code: number;
+  message: string;
+  errors?: unknown;
+}
+
+/**
+ * API response wrapper
+ */
+export interface ApiResponse<T = unknown> {
+  success?: boolean;
+  data?: T;
+  message?: string;
+  error?: string;
+}
+
+// ============================================================================
+// User Types
+// ============================================================================
+
+/**
+ * User entity
+ */
+export interface User {
+  id: number;
+  username: string;
+  nickname?: string | null;
+  phone?: string | null;
+  email?: string | null;
+  realName?: string | null;
+  avatarFileId?: number | null;
+  avatarFile?: File;
+  companyId?: number | null;
+  company?: Company;
+  status?: number;
+  isDisabled?: number;
+  userType?: string;
+  roles?: Role[];
+  createdAt: Date;
+  updatedAt: Date;
+}
+
+/**
+ * Create user DTO
+ */
+export interface CreateUserDto {
+  username: string;
+  password?: string;
+  nickname?: string;
+  phone?: string;
+  email?: string;
+  realName?: string;
+  avatarFileId?: number;
+  companyId?: number;
+  status?: number;
+  roleIds?: number[];
+}
+
+/**
+ * Update user DTO
+ */
+export interface UpdateUserDto {
+  username?: string;
+  password?: string;
+  nickname?: string;
+  phone?: string;
+  email?: string;
+  realName?: string;
+  avatarFileId?: number;
+  companyId?: number;
+  status?: number;
+  roleIds?: number[];
+}
+
+// ============================================================================
+// Role Types
+// ============================================================================
+
+/**
+ * Role entity
+ */
+export interface Role {
+  id: number;
+  name: string;
+  description?: string | null;
+  code?: string;
+  status?: number;
+  createdAt: Date;
+  updatedAt: Date;
+}
+
+/**
+ * Create role DTO
+ */
+export interface CreateRoleDto {
+  name: string;
+  description?: string;
+  code?: string;
+  status?: number;
+}
+
+/**
+ * Update role DTO
+ */
+export interface UpdateRoleDto {
+  name?: string;
+  description?: string;
+  code?: string;
+  status?: number;
+}
+
+// ============================================================================
+// System Config Types
+// ============================================================================
+
+/**
+ * System config entity
+ */
+export interface SystemConfig {
+  id: number;
+  configKey: string;
+  configValue: string;
+  description?: string | null;
+  category?: string;
+  createdAt: Date;
+  updatedAt: Date;
+}
+
+/**
+ * Create system config DTO
+ */
+export interface CreateSystemConfigDto {
+  configKey: string;
+  configValue: string;
+  description?: string;
+  category?: string;
+}
+
+/**
+ * Update system config DTO
+ */
+export interface UpdateSystemConfigDto {
+  configKey?: string;
+  configValue?: string;
+  description?: string;
+  category?: string;
+}
+
+// ============================================================================
+// Company Types
+// ============================================================================
+
+/**
+ * Company entity
+ */
+export interface Company {
+  id: number;
+  companyName: string;
+  contactPerson?: string | null;
+  contactPhone?: string | null;
+  contactEmail?: string | null;
+  address?: string | null;
+  status: number;
+  createTime: Date;
+  updateTime: Date;
+}
+
+// ============================================================================
+// File Types
+// ============================================================================
+
+/**
+ * File entity
+ */
+export interface File {
+  id: number;
+  fileName: string;
+  fileSize: number;
+  mimeType: string;
+  filePath: string;
+  uploadUserId: number;
+  uploadUser?: User;
+  createdAt: Date;
+}
+
+// ============================================================================
+// Order Types
+// ============================================================================
+
+/**
+ * Order entity
+ */
+export interface Order {
+  id: number;
+  orderNo: string;
+  userId: number;
+  user?: User;
+  userPhone?: string;
+  merchantId?: number;
+  supplierId?: number;
+  deliveryAddressId?: number;
+  deliveryAddress?: DeliveryAddress;
+  totalAmount?: number;
+  status?: string;
+  createdAt: Date;
+  updatedAt: Date;
+}
+
+/**
+ * Delivery address entity
+ */
+export interface DeliveryAddress {
+  id: number;
+  userId: number;
+  receiverName: string;
+  receiverPhone: string;
+  province: string;
+  city: string;
+  district?: string;
+  detailedAddress: string;
+  isDefault: number;
+  createdAt: Date;
+  updatedAt: Date;
+}
+
+// ============================================================================
+// Auth Types
+// ============================================================================
+
+/**
+ * Login request
+ */
+export interface LoginRequest {
+  username: string;
+  password: string;
+}
+
+/**
+ * Token response
+ */
+export interface TokenResponse {
+  token: string;
+  user?: User;
+}
+
+// ============================================================================
+// Query/Filter Types
+// ============================================================================
+
+/**
+ * Base list query parameters
+ */
+export interface BaseListQuery {
+  page?: number;
+  pageSize?: number;
+  keyword?: string;
+  sortBy?: string;
+  sortOrder?: SortOrder;
+  filters?: string;
+}
+
+/**
+ * Filter conditions
+ */
+export interface FilterConditions {
+  [key: string]: unknown;
+}

+ 21 - 0
packages/admin-mcp-server/tsconfig.json

@@ -0,0 +1,21 @@
+{
+  "compilerOptions": {
+    "target": "ES2022",
+    "module": "Node16",
+    "moduleResolution": "Node16",
+    "lib": ["ES2022"],
+    "types": ["node"],
+    "outDir": "./dist",
+    "rootDir": "./src",
+    "strict": true,
+    "esModuleInterop": true,
+    "skipLibCheck": true,
+    "forceConsistentCasingInFileNames": true,
+    "declaration": true,
+    "declarationMap": true,
+    "sourceMap": true,
+    "allowSyntheticDefaultImports": true
+  },
+  "include": ["src/**/*"],
+  "exclude": ["node_modules", "dist"]
+}