Content
中文 | [English](README_EN.md)
# Tool List
DW MCP AI Permission Center is an enterprise-level AI tool permission management platform specifically designed for the Model Context Protocol (MCP), based on the standard RBAC permission model.
It features built-in JDBC data source proxy and HTTP interface proxy capabilities, which can automatically convert database SQL and business HTTP interfaces into standardized MCP tools with one click.
It provides unified access authentication, tool visibility isolation, and multi-data source access permission interception for Cursor, Claude Desktop, and various self-developed AI Agent client terminals.
It solves core pain points such as permission chaos, data overrun, key management loss of control, and tool lack of hierarchical control when multiple users and AI clients share MCP tools.
## Function Overview
- **RBAC Dynamic Tool List**: Different roles are bound to different MCP tools. After users authenticate through API Key, they only see tools authorized by their role.
- **JWT + API Key Dual-Channel Authentication**: Management end JWT login + MCP end API Key Bearer Token, path completely isolated.
- **User Self-Service Management**: Any authenticated user can modify personal information and modify password (need to verify old password) without ADMIN permission.
- **Role Hierarchical View**: Administrators view all data, and ordinary users only see tools and corresponding categories they have permission to.
- **API Key Authentication**: Bearer Token mode, compatible with mainstream MCP clients such as Claude Desktop and Cursor.
- **JDBC Tool Execution**: Execute SQL template and return JSON result through Dynamic-Datasource multi-data source dynamic switching.
- **HTTP Proxy Tool**: Proxy external HTTP interface as MCP tool.
- **Feign API Declaration**: Management interface declared through OpenFeign, convenient for microservice call or Gateway proxy.
- **AI One-Click Generation**: Input SQL template, AI generates tool name, description, and JSON Schema, SSE real-time display thinking process.
- **Permission Cache**: Based on Redis user permission cache + API Key verification cache, RBAC change asynchronous batch clearing.
- **Multi-Machine Deployment**: Based on Redisson distributed lock to ensure concurrent safety of role allocation and other operations.
- **Full Logic Deletion**: All data only marked deletion, support recovery and audit (`sys_role_tool` table except, the table uses physical deletion).
## Technology Stack
| Component | Version | Description |
|------|------|------|
| Java | 21 | Running Environment |
| Spring Boot | 4.0.6 | Basic Framework |
| Spring AI | 2.0.0 | MCP Server Implementation (Streamable HTTP Transmission) |
| Spring Security | 7.x | Stateless JWT + API Key Dual-Channel Authentication |
| Spring Cloud OpenFeign | 2025.0.0 | Management Interface Feign Declaration |
| MyBatis-Plus | 3.5.16 | ORM + Pagination + Logic Deletion |
| Dynamic-Datasource | 4.5.0 | Multi-Data Source Dynamic Switching |
| FastJson2 | 2.0.58 | JSON Serialization (Controller Layer + Business Layer) |
| Redisson | 4.1.0 | Distributed Lock + Redis Client |
| JJWT | 0.12.6 | JWT Generation and Verification |
| MySQL | 8.0 | Production Database |
| PostgreSQL / Oracle / SQL Server | - | Multi-Data Source JDBC Driver |
| Hutool | 5.8.36 | Tool Class |
| Vue 3 + Element Plus | - | Management Background Front End |
| Lombok | - | Code Simplification |
## Project Structure
```
dw-mcp-ai-permission-center/ Parent POM (packaging=pom)
├── dw-mcp-permission-api/ API Declaration Module (Lightweight Jar, for Caller Dependency)
│ └── com.easyhome.api
│ ├── dto/ Request DTO (8 types: User, Role, ApiKey, Tool, Datasource, ToolCategory, UpdateProfile, ChangePassword)
│ ├── vo/ Response VO (8 types: Result, PageResult + 6 business VO)
│ └── feign/ Feign Client Interface (6 types: User, Role, ApiKey, Tool, Datasource, ToolCategory)
├── dw-mcp-permission-server/ Service Implementation Module (Spring Boot Startup Entrance)
│ └── com.easyhome
│ ├── controller/ Controller (8 types: 6 Feign Interface Implementations + AuthController + Call Log Query)
│ ├── service/ Service Interface 8 types + Impl 8 types
│ ├── mapper/ MyBatis-Plus Mapper (9 types)
│ ├── entity/ Entity Class (BaseEntity + 9 types)
│ ├── config/ Configuration Class (Security, MybatisPlus, MetaHandler, Async, Filter, Redisson)
│ ├── common/config/ Global Exception Handler (400/403/404/500 Standardized Response)
│ ├── security/ Dual-Channel Authentication (JwtAuthFilter + JwtAuthenticationToken + ApiKeyAuthFilter + ApiKeyAuthenticationToken)
│ ├── mcp/ MCP Core (McpToolRegistry + JdbcToolExecutor + Event/Filter/Synchronization)
│ │ ├── event/ Event-Driven (RbacChangeEvent + McpToolChangeEvent + Asynchronous Listener)
│ │ └── filter/ MCP Tool List RBAC Filter
│ ├── ai/ AI One-Click Generation Tool Configuration (Streamable SSE + Synchronization)
│ └── App.java Startup Class
├── dw-mcp-permission-ui/ Vue 3 + Element Plus Management Background (Independent Front End Project)
└── pom.xml
```
## Database Design
Database Name: `dw_mcp_permission`, 9 tables in total:
```
sys_user ──1:N── sys_user_role ──N:1── sys_role ──1:N── sys_role_tool ──N:1── mcp_tool ──N:1── mcp_tool_category
│ │
└──1:N── sys_api_key │
└──1:N── mcp_tool_call_log
mcp_datasource
```
| Table Name | Description | Common Fields |
|------|------|---------|
| `sys_user` | System User | All (status/is_deleted/creator/modifier/time) |
| `sys_role` | System Role | All |
| `sys_user_role` | User-Role Association | is_deleted/creator/time (Logic Deletion) |
| `sys_api_key` | User API Key | All |
| `mcp_datasource` | MCP Data Source Configuration | All |
| `mcp_tool_category` | MCP Tool Category | is_deleted/creator/modifier/time (No status) |
| `mcp_tool` | MCP Tool Definition | All |
| `sys_role_tool` | Role-Tool Association | creator/time (Physical Deletion, no is_deleted) |
| `mcp_tool_call_log` | MCP Tool Call Log | Only id + Business Fields (No BaseEntity Inheritance) |
Common Field Conventions:
- `status`: 1=Enabled, 2=Disabled
- `is_deleted`: 0=Not Deleted, 1=Deleted (Global Logic Deletion, Prohibited Physical Deletion; `sys_role_tool` table exception, using physical deletion)
- `creator_id` / `creator`: Creator (MetaHandler automatically fills from SecurityContext)
- `modifier_id` / `modifier`: Modifier (same as above)
- `created_at` / `updated_at`: Timestamp (database automatic maintenance)
## Quick Start
### Environment Requirements
- JDK 21
- MySQL 8.0+
- Redis 6.0+
- Node.js 18+ (Front End Construction)
- Maven 3.8+
### 1. Initialize Database
```sql
-- Execute DDL + Initialize Data
source dw-mcp-permission-server/src/main/resources/db/schema.sql;
```
Initialization data includes:
- 1 default tool category: `other`
- 3 preset roles: `ADMIN`, `DATA_ANALYST`, `READONLY`
- 1 administrator user: `admin`
- 1 demonstration API Key: `sk-demo-admin-key-for-testing-only`
### 2. Configure Environment Variables
Copy `.env.example` to `.env`, modify according to actual environment:
```bash
cp .env.example .env
# Edit .env to fill in database, Redis, JWT key and other configurations
```
Complete configuration items see [.env.example](.env.example), mainly including:
| Configuration Item | Description |
|---------|------|
| `MYSQL_HOST` / `MYSQL_USER` / `MYSQL_PASSWORD` | Database Connection |
| `REDIS_HOST` / `REDIS_PORT` / `REDIS_PASSWORD` | Redis Connection |
| `JWT_SECRET` | JWT Signature Key (production environment must be modified to strong random string) |
| `CORS_ALLOWED_ORIGINS` | CORS allowed front-end domain (multiple separated by commas) |
| `MAIL_*` | SMTP email configuration (forgot password verification code) |
| `OPENAI_API_KEY` / `OPENAI_BASE_URL` / `OPENAI_MODEL` | AI Model Configuration |
> Can also directly edit `application.yml` or create `application-dev.yml` to override default values.
### 3. Compile and Start
```bash
# Back End
mvn clean package -DskipTests
java -jar dw-mcp-permission-server/target/dw-mcp-permission-server-1.0.0.jar
```
Service default listening `http://localhost:8091`.
```bash
# Front End (Development Mode)
cd dw-mcp-permission-ui
npm install
npm run dev
```
Front end default listening `http://localhost:5173`, access back-end interface through Vite proxy.
## API Interface
### MCP Protocol Endpoints
| Endpoint | Description |
|------|------|
| `POST /mcp` | MCP Streamable HTTP Endpoint (Claude Desktop / Cursor Connection Address) |
MCP Client Configuration Example (Claude Desktop `claude_desktop_config.json`):
```json
{
"mcpServers": {
"mcp-permission-center": {
"url": "http://localhost:8091/mcp",
"headers": {
"Authorization": "Bearer sk-your-api-key-here"
}
}
}
}
```
### Management Interface
All management interface paths start with `/api/`, requiring JWT authentication; most interfaces require ADMIN role.
| Module | Path Prefix | Feign Client | Description |
|------|---------|-------------|------|
| Authentication | `/api/auth` | None | JWT Login/User Information |
| User Management | `/api/users` | `SysUserClient` | CRUD + Role Allocation (ADMIN) |
| User Self-Service | `/api/users/me/*` | `SysUserClient` | Modify Personal Information/Modify Password (any authenticated user) |
| Role Management | `/api/roles` | `SysRoleClient` | CRUD + Tool Authorization (ADMIN) |
| API Key Management | `/api/api-keys` | `SysApiKeyClient` | Generate/Enable/Disable/Delete |
| MCP Tool Management | `/api/mcp/tools` | `McpToolClient` | CRUD + Enable/Disable (ADMIN) |
| MCP Tool (Mine) | `/api/mcp/tools/mine` | `McpToolClient` | Enabled tools accessible to current user (any authenticated user) |
| MCP Tool Category | `/api/mcp/tool-categories` | `McpToolCategoryClient` | CRUD (ADMIN) |
| MCP Tool Category (Mine) | `/api/mcp/tool-categories/mine` | `McpToolCategoryClient` | Tool category belonging to current user (any authenticated user) |
| MCP Data Source Management | `/api/mcp/datasources` | `McpDatasourceClient` | CRUD + Connectivity Test (ADMIN) |
| AI Tool Generation | `/api/ai` | None | Streamable/Synchronous AI Generation Tool Configuration (ADMIN) |
| Call Log Query | `/api/mcp/tool-call-logs` | None | Paginated query tool call records |
### Microservice Call
Other services only need to depend on the api module to call through Feign:
```xml
<dependency>
<groupId>com.easyhome</groupId>
<artifactId>dw-mcp-permission-api</artifactId>
<version>1.0.0</version>
</dependency>
```
```java
@EnableFeignClients(basePackages = "com.easyhome.api.feign")
@SpringBootApplication
public class YourApplication { }
@RestController
@RequiredArgsConstructor
public class YourController {
private final SysUserClient sysUserClient;
public Result<SysUserVO> getUser(Long id) {
return sysUserClient.getById(id);
}
}
```
## Authentication Mechanism
### Dual-Channel Authentication
| Channel | Path | Authentication Method | Filter |
|------|------|---------|--------|
| Management End | `/api/**` | JWT (Account Password Login) | `JwtAuthFilter` |
| MCP End | `/mcp/**` | API Key (Bearer Token) | `ApiKeyAuthFilter` |
Two Filters implement path isolation through `shouldNotFilter`, without interfering with each other.
### JWT Authentication Process
```
1. User account password login → AuthController issues JWT Token
2. Front-end request Header: Authorization: Bearer <jwt-token>
3. JwtAuthFilter intercepts → Verify signature + expiration time → Construct JwtAuthenticationToken
4. SecurityContext stores authentication information (userId/username/roles)
```
### API Key Authentication Process
```
1. MCP client request Header: Authorization: Bearer sk-xxxx
2. ApiKeyAuthFilter intercepts → Verify Key from cache/database
3. Verification passed → Load user information + role list → Construct ApiKeyAuthenticationToken
4. SecurityContext stores authentication information → Subsequent RBAC query use
```
### Permission Control
- `/api/auth/login` — Public access
- `/api/**` — Requires JWT authentication, method-level role verification through `@PreAuthorize`
- `@PreAuthorize("hasRole('ADMIN')")` — Requires ADMIN role (user/role/tool management, etc.)
- `@PreAuthorize("isAuthenticated()")` — Any authenticated user (/mine endpoint, personal information/password modification)
- `/mcp/**` — Requires API Key authentication, tool list dynamically filtered according to user role
- `/actuator/health` — Public access
### Global Exception Handling
| Exception Type | HTTP Status Code | Scenario |
|---------|-----------|------|
| `IllegalArgumentException` | 400 | Business parameter verification failed |
| `MethodArgumentNotValidException` | 400 | @Validated verification failed |
| `AuthorizationDeniedException` | 403 | @PreAuthorize permission denied |
| `NoResourceFoundException` | 404 | Request path does not exist |
| Other `Exception` | 500 | Uncaught exception bottom line |
## RBAC Tool Dynamic Filtering
MCP client calls `tools/list` filtering chain:
```
User API Key → Locate user → Query user role → Query role-authorized tools → Return tool list
```
Core implementation: `McpToolsListFilter` → `McpToolPermissionService.getAccessibleToolNames()` → `McpToolMapper.selectToolsByUserId(userId)`
```sql
SELECT t.* FROM mcp_tool t
INNER JOIN sys_role_tool rt ON t.id = rt.tool_id
INNER JOIN sys_user_role ur ON rt.role_id = ur.role_id
WHERE ur.user_id = #{userId}
AND t.status = 1 AND t.is_deleted = 0
AND rt.is_deleted = 0 AND ur.is_deleted = 0
```
## JDBC Tool Execution Process
```
1. MCP client calls tools/call, passing tool name + parameters
2. RbacMcpContextExtractor extracts userId from SecurityContext and injects TransportContext
3. McpToolRegistry.executeWithRbacCheck() verifies RBAC permission
4. JdbcToolExecutor replaces parameters with SQL template #{param} placeholder
5. DatasourceRegistry.createConnection() creates native JDBC connection
6. SqlPaginationUtil automatically appends pagination + executes COUNT query
7. JdbcTemplate.execute(sql) executes query
8. FastJson2 serializes result to JSON and returns to AI
9. Asynchronously save call log to mcp_tool_call_log
```
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available