Content
# Dameng MCP Server
## Project Introduction
Based on the [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) protocol, a multi-data source query service. Supports relational databases **Dameng (DM)**, **Oracle**, **MySQL**, as well as **Elasticsearch** and **Redis**, for LLM clients like Claude Desktop, Cursor, Cherry Studio, Qoder, providing natural language-driven data query, statistics, analysis, and data operation capabilities.
Through the standard MCP protocol, AI assistants can directly connect and operate on your data sources, achieving intelligent data exploration and management. Supports two operating modes: **Stdio mode** (local MCP client) and **HTTP mode** (Streamable HTTP transmission exposes MCP service + built-in Web data source management page).
## Features
- **Dual operating modes**: `stdio` (default, local process communication) and `http` (Streamable HTTP transmission + Web management page), switchable with Spring Profile
- **Web dynamic data source management**: provides built-in Web page + REST API in http mode, can add/**edit**/delete/test data sources at runtime, configuration persisted to embedded **H2 database**, automatically restored on restart
- **Multi-data source support**: supports configuring multiple data sources simultaneously, each with an independent name and usage description, routed by name at runtime
- **Multi-data source types**: built-in Dameng, Oracle, MySQL relational adapters, as well as Elasticsearch, Redis adapters, unified registration/management/persistence logic
- **Relational database tools (11)**: data source list, schema list, table list, table structure, SQL query, sample data, table statistics, column statistics, and INSERT / UPDATE / DELETE
- **Elasticsearch tools (6)**: column index, mapping query, document count statistics, DSL query, and document write/delete
- **Redis tools (6)**: key scan, key metadata view, value read, and SET / DEL / EXPIRE
- **Write operation security**: relies on MCP client confirmation mechanism + read-only data source interception; relational SQL additionally undergoes whitelist + blacklist + comment stripping + multi-statement injection detection + identifier verification multi-layer protection
- **Access token protection**: optional `X-Access-Token`, protects MCP transmission endpoint and data source management API
- **Extensible adapter architecture**: `DatabaseAdapter` + `DatabaseDialect` dual-interface design, adding new relational database types only requires implementing two interfaces
## Technical Stack
| Component | Technology | Version |
| ---- | ---- | ---- |
| Framework | Spring Boot | 3.5.8 |
| MCP Protocol | Spring AI MCP Server (Stdio + WebMVC / Streamable HTTP) | 1.1.0 |
| Connection Pool | Alibaba Druid | 1.2.23 |
| Dameng Driver | DmJdbcDriver18 | 8.1.3.140 |
| Oracle Driver | ojdbc11 | 23.3.0.23.09 |
| MySQL Driver | mysql-connector-j | managed by Spring Boot |
| Elasticsearch | elasticsearch-rest-client (compatible with 7.x/8.x) | 8.13.4 |
| Redis | Jedis | 5.1.5 |
| Dynamic Source Persistence | H2 Database (embedded file mode) | 2.2.224 |
| Build Tool | Maven | 3.x |
| JDK | Java | 17+ |
## Quick Start
### Prerequisites
- JDK 17 or higher
- Maven 3.6+
- At least one available database instance (Dameng / Oracle / MySQL)
- Corresponding database JDBC driver (project already built-in)
### Build
```bash
# Clone project
git clone <repository-url>
cd dameng-mcp-server
# Compile and package
mvn clean package -DskipTests
```
After building, the JAR file is located at `target/dameng-mcp-server-2.0.0.jar`.
### Run
This service supports two operating modes, switchable via Spring Profile (not interfering with each other).
#### Mode 1: Stdio Mode (default)
For local MCP clients like Claude Desktop / Cursor, communicate through standard input and output, without listening to network ports.
```bash
# Directly run (default is stdio mode)
java -jar target/dameng-mcp-server-2.0.0.jar
# Or run through Maven
mvn spring-boot:run
```
#### Mode 2: HTTP Mode (Streamable HTTP)
Exposes MCP service through Streamable HTTP transmission (Spring AI WebMVC) and provides a built-in Web management page for dynamic data source management at runtime.
```bash
# Enable http mode (default port 8080)
java -jar target/dameng-mcp-server-2.0.0.jar --spring.profiles.active=http
# Or use environment variable
SPRING_PROFILES_ACTIVE=http java -jar target/dameng-mcp-server-2.0.0.jar
# Custom port
java -jar target/dameng-mcp-server-2.0.0.jar --spring.profiles.active=http --server.port=9090
```
After startup:
- **MCP access address**: `http://<host>:8080/mcp` (Streamable HTTP single endpoint, GET to build stream + POST to send message). Configure to support Streamable HTTP MCP client to call data tools.
> Client address must point to `/mcp`, cannot just fill root address (otherwise hit static welcome page returns 406).
- **Web data source management page**: open browser to `http://<host>:8080/`, can view/add/edit/delete/test data sources.
## HTTP Mode and Dynamic Data Source Management
### Web Management Page
In http mode, access `http://<host>:8080/`, the page provides:
- Registered data source list (distinguish between "built-in" = application.yml configuration, "dynamic" = runtime through Web addition)
- Add/edit data source form: type dropdown (dameng/oracle/mysql/elasticsearch/redis), connection information, read-only switch, description, support "test connection" and "save and register"
- Only "dynamic" data sources can be edited and deleted through the page; "built-in" data sources cannot be modified/deleted
- Name cannot be changed during editing; password/apiKey not echoed, leave blank to keep original value unchanged
### REST API
All interface base paths `/api/datasources`, only take effect in http mode:
| Method | Path | Description |
| ---- | ---- | ---- |
| GET | `/api/datasources` | List all data sources (without password) |
| GET | `/api/datasources/{name}` | Get single data source configuration (for edit echo, password/apiKey already desensitized to empty) |
| POST | `/api/datasources` | Add data source |
| PUT | `/api/datasources/{name}` | Modify dynamic data source (name cannot be changed, take path name as standard; password/apiKey leave blank to use original value) |
| DELETE | `/api/datasources/{name}` | Delete dynamic data source |
| POST | `/api/datasources/test` | Test connection (not saved) |
Request body contains fields: `name`/`type`/`url`/`username`/`password`/`readonly`/`description` (Redis additionally supports `host`/`port`/`database`, Elasticsearch additionally supports `apiKey`).
Request/response example:
```bash
# Test connection
curl -X POST http://localhost:8080/api/datasources/test \
-H 'Content-Type: application/json' \
-H 'X-Access-Token: your token' \
-d '{"name":"pg-test","type":"mysql","url":"jdbc:mysql://host:3306/db","username":"root","password":"pwd"}'
# Add data source
curl -X POST http://localhost:8080/api/datasources \
-H 'Content-Type: application/json' \
-H 'X-Access-Token: your token' \
-d '{"name":"finance-oracle","type":"oracle","url":"jdbc:oracle:thin:@host:1521:ORCL","username":"u","password":"p","readonly":true,"description":"Financial library"}'
# Modify data source (password left blank to keep unchanged)
curl -X PUT http://localhost:8080/api/datasources/finance-oracle \
-H 'Content-Type: application/json' \
-H 'X-Access-Token: your token' \
-d '{"type":"oracle","url":"jdbc:oracle:thin:@newhost:1521:ORCL","username":"u","password":"","readonly":true,"description":"Financial library (new address)"}'
```
Unified response structure: `{"success": true|false, "message": "...", "data": ...}`.
### Persistence
- Dynamically added data sources through Web will be written to the embedded H2 database, automatically restored when the application restarts.
- H2 database file base path is configured by `mcp.dynamic-datasource-h2`, default `${user.home}/.dameng-mcp/datasources` (actually generates `datasources.mv.db`).
- **Password stored in plaintext**, please be sure to: limit database file permissions (like `chmod 600`), deploy service in a trusted intranet, use read-only database account.
### Access Token (protect MCP endpoint + management API)
Configure `mcp.web.access-token` to a non-empty value, [AccessTokenFilter](src/main/java/com/dameng/mcp/web/AccessTokenFilter.java) will force verification of the request header `X-Access-Token` (default off) for the following sensitive endpoints:
- `/mcp`, `/mcp/**`: MCP transmission endpoint (actually execute tool call entry in Streamable HTTP mode);
- `/api/**`: data source management interface.
Static management page (`/`) is allowed, page top provides token input box, token saved in browser local. Token comparison uses `MessageDigest.isEqual` constant time comparison, avoiding timing side-channel.
```yaml
mcp:
web:
access-token: "use a long enough random string, like openssl rand -hex 32 to generate"
```
MCP client connecting to `/mcp` also needs to carry this token. Take Cursor as an example:
```json
{
"mcpServers": {
"dameng-mcp": {
"url": "https://your-host:8080/mcp",
"headers": { "X-Access-Token": "your token" }
}
}
}
```
> Streamable HTTP is a single-endpoint protocol, client requests will carry this request header every time, no problem like handshake timeout caused by subsequent message requests without header in old SSE dual-endpoint mode. Token only read from request header, does not support query parameters (avoid appearing in access logs).
### Security Hardening List when No Intranet Isolation
If network isolation cannot be achieved (service needs to be exposed on the public internet or untrusted network), be sure to stack the following measures:
1. **Enable HTTPS**: token walking clear text HTTP will be eavesdropped by the man-in-the-middle. Open `server.ssl` (`application.yml` http segment already attached certificate generation example), or use Nginx/Caddy reverse proxy to terminate TLS.
2. **Set strong random access token** and rotate regularly, do not use default empty value or weak password.
3. **Minimum permission**: database account try to use read-only account, data source configuration `readonly: true`, from the source limit "write tool" damage surface.
4. **Tighten file permissions**: dynamic data source H2 library file contains plaintext password, `chmod 600 <data source H2 base path>.mv.db`, and limit running account.
5. **Binding and rate limiting**: available `server.address` binding specified network card; do IP whitelist, rate limit and fail2ban in reverse proxy layer to prevent token from being brutally enumerated.
6. **Audit**: filter will record rejected unauthorized access with `WARN`, convenient for monitoring abnormal source.
> **Security tip**: access token + HTTPS is the minimum requirement in the "no intranet isolation" scenario; only relying on clear text HTTP token is not enough to defend against network sniffing.
## Multi-Data Source Configuration
Configure multiple data sources in `src/main/resources/application.yml` through `mcp.datasources`:
```yaml
spring:
main:
web-application-type: none
banner-mode: off
ai:
mcp:
server:
name: dameng-mcp-server
version: 2.0.0
stdio: true
mcp:
datasources:
# Dameng database example
- name: dm-prod
description: "Production environment - Dameng database"
type: dameng
url: jdbc:dm://192.168.1.100:5236
username: SYSDBA
password: your_password
readonly: true
# Oracle database example
- name: finance-oracle
description: "Financial system - Oracle database"
type: oracle
url: jdbc:oracle:thin:@192.168.1.101:1521:ORCL
username: finance_user
password: your_password
# MySQL database example
- name: log-mysql
description: "Log system - MySQL database"
type: mysql
url: jdbc:mysql://192.168.1.102:3306/logs?useSSL=false&serverTimezone=UTC
username: root
password: your_password
# Elasticsearch example (compatible with 7.x/8.x, based on low-level REST client)
# - url: ES base address, multiple nodes separated by English commas, like http://a:9200,https://b:9200
# - authentication choose one: username/password (basic) or apiKey (ES API Key)
- name: es-log
description: "Log retrieval cluster"
type: elasticsearch
url: http://127.0.0.1:9200
username: elastic
password: changeme
# apiKey: "base64EncodedApiKey" # choose one with username/password
readonly: true
# Redis example (standalone, host/port/database; also available url: redis://host:port/db)
- name: redis-cache
description: "Business cache"
type: redis
host: 127.0.0.1
port: 6379
database: 0
# username: default # Redis 6+ ACL optional
password: ""
readonly: true
logging:
level:
root: OFF
```
### Configuration Item Description
| Property | Required | Default | Description |
| ---- | ---- | ------ | ---- |
| name | yes | - | data source name, globally unique, MCP call positioning |
| description | no | - | data source purpose description, for LLM to understand and choose |
| type | yes | - | type: `dameng` / `oracle` / `mysql` / `elasticsearch` / `redis` |
| url | conditional | - | relational is JDBC URL; ES is HTTP address (multiple nodes comma separated); Redis can use `redis://host:port/db` instead of host/port/database |
| username | conditional | - | relational/ES username; Redis 6+ ACL optional |
| password | conditional | - | connection password |
| readonly | no | false | read-only data source, reject all write operations when true (SQL write / ES write/delete / Redis SET·DEL·EXPIRE) |
| host | conditional | - | **Redis specific**: host address (when not using url) |
| port | no | 6379 | **Redis specific**: port |
| database | no | 0 | **Redis specific**: database index |
| apiKey | no | - | **Elasticsearch specific**: ES API Key (choose one with username/password) |
| initialSize | no | 5 | Druid initial connection number (only relational) |
| minIdle | no | 5 | Druid minimum idle connection number (only relational) |
| maxActive | no | 20 | Druid maximum active connection number (only relational) |
| maxWait | no | 60000 | maximum wait time for getting connection (milliseconds, only relational) |
> **Note**: the first configured relational data source is the default relational data source; ES/Redis tools respectively take the first ES/Redis data source when datasource is empty.
### http Mode Exclusive Configuration (Dynamic Source Persistence and Token)
| Property | Default Value | Description |
| ---- | ------ | ---- |
| `mcp.dynamic-datasource-h2` | `${user.home}/.dameng-mcp/datasources` | Dynamic data source H2 database file base path (without extension, actual generation `datasources.mv.db`) |
| `mcp.dynamic-datasource-h2-username` | `sa` | H2 username |
| `mcp.dynamic-datasource-h2-password` | (empty) | H2 password. Note: file database creates a solid password for the first time, and the same password is required after the database is created |
| `mcp.web.access-token` | (empty) | Enable access token verification when not empty (see above) |
## Environment Variables
Support covering data source connection information through environment variables (suitable for containerized deployment):
| Environment Variable | Description | Default Value |
| -------- | ---- | ------ |
| DM_HOST | Dameng database host address | localhost |
| DM_PORT | Dameng database port | 5236 |
| DM_USERNAME | Dameng database username | SYSDBA |
| DM_PASSWORD | Dameng database password | SYSDBA |
Configuration example (used in `application.yml`):
```yaml
mcp:
datasources:
- name: default
description: "Default Dameng database"
type: dameng
url: jdbc:dm://${DM_HOST:localhost}:${DM_PORT:5236}
username: ${DM_USERNAME:SYSDBA}
password: ${DM_PASSWORD:SYSDBA}
```
## MCP Client Configuration
In multi-data source scenarios, **it is recommended to use an external `application.yml` configuration file** to manage all data sources, and specify it when starting the MCP client jar using the `--spring.config.location` parameter.
### Configuration Method Description
- **Recommended approach (multi-data source)**: Place the `application.yml` configuration file in an independent directory (e.g., `~/.dameng-mcp/application.yml`), configure all data sources (Dameng / Oracle / MySQL arbitrary combination) in it, and specify it when starting with `--spring.config.location=file:/path/to/application.yml`.
- **Quick way (single data source)**: If there is only one Dameng data source, you can use environment variables (`DM_HOST`, `DM_PORT`, `DM_USERNAME`, `DM_PASSWORD`) to start without specifying an external configuration file.
### External application.yml Complete Example (Multi-data Source)
The following example shows a complete configuration of a Dameng + an Oracle + a MySQL, which can be saved as `~/.dameng-mcp/application.yml`:
```yaml
spring:
main:
web-application-type: none
banner-mode: off
ai:
mcp:
server:
name: dameng-mcp-server
version: 2.0.0
stdio: true
mcp:
datasources:
# Dameng database
- name: dm-prod
description: "Production environment - Dameng database"
type: dameng
url: jdbc:dm://192.168.1.100:5236
username: SYSDBA
password: your_password
# Oracle database
- name: finance-oracle
description: "Financial system - Oracle database"
type: oracle
url: jdbc:oracle:thin:@192.168.1.101:1521:ORCL
username: finance_user
password: your_password
# MySQL database
- name: log-mysql
description: "Log system - MySQL database"
type: mysql
url: jdbc:mysql://192.168.1.102:3306/logs?useSSL=false&serverTimezone=UTC
username: root
password: your_password
logging:
level:
root: OFF
```
### Claude Desktop
Edit `claude_desktop_config.json` and specify an external configuration file using `--spring.config.location`:
```json
{
"mcpServers": {
"dameng-mcp-server": {
"command": "java",
"args": [
"-jar",
"/path/to/dameng-mcp-server-2.0.0.jar",
"--spring.config.location=file:/path/to/your-config/application.yml"
]
}
}
}
```
### Cherry Studio
Add the following in Cherry Studio's MCP server settings:
```json
{
"mcpServers": {
"dameng-mcp-server": {
"command": "java",
"args": [
"-jar",
"/path/to/dameng-mcp-server-2.0.0.jar",
"--spring.config.location=file:/path/to/your-config/application.yml"
]
}
}
}
```
### Cursor
Add the following in Cursor's MCP configuration file `.cursor/mcp.json`:
```json
{
"mcpServers": {
"dameng-mcp-server": {
"command": "java",
"args": [
"-jar",
"/path/to/dameng-mcp-server-2.0.0.jar",
"--spring.config.location=file:/path/to/your-config/application.yml"
]
}
}
}
```
> **Hint**:
> - Please replace `/path/to/dameng-mcp-server-2.0.0.jar` with the actual JAR file absolute path.
> - Please replace `/path/to/your-config/application.yml` with the actual absolute path of the external configuration file.
> - **Single data source quick way**: If only one Dameng data source is used, the `--spring.config.location` parameter can be omitted, and the `DM_HOST` / `DM_PORT` / `DM_USERNAME` / `DM_PASSWORD` environment variables can be passed through the `env` field.
## Available Tool List
> A total of 23 MCP tools: 11 relational databases + 6 Elasticsearch + 6 Redis. The `datasource` parameter of all tools is optional. If left blank, the default (first) data source of the corresponding type will be used.
### Metadata Tools (Relational)
| Tool Name | Description | Parameters |
| ------ | ---- | ---- |
| `list_datasources` | List all available data source connections, including name, type, and purpose description | None |
| `list_schemas` | List all available schema names in the specified data source | `datasource` (optional): data source name |
| `list_tables` | List all tables under the specified schema, including table name and comment | `datasource` (optional): data source name<br>`schema` (required): schema name |
| `describe_table` | Get the detailed structure information of the table (column name, type, nullable, default value, comment) | `datasource` (optional): data source name<br>`schema` (required): schema name<br>`table` (required): table name |
### Query Tools
| Tool Name | Description | Parameters |
| ------ | ---- | ---- |
| `execute_query` | Execute read-only SQL query, only supports SELECT statements | `datasource` (optional): data source name<br>`sql` (required): SQL query statement<br>`maxRows` (optional): maximum returned rows, default 100, upper limit 500 |
| `get_sample_data` | Get sample data of the specified table, quickly preview table content | `datasource` (optional): data source name<br>`schema` (required): schema name<br>`table` (required): table name<br>`limit` (optional): sample rows, default 10, upper limit 50 |
### Statistics Tools
| Tool Name | Description | Parameters |
| ------ | ---- | ---- |
| `get_table_statistics` | Get table statistics overview (row count, table size, etc.) | `datasource` (optional): data source name<br>`schema` (required): schema name<br>`table` (required): table name |
| `get_column_statistics` | Get column statistics information (去重数, 空值数, 最值) | `datasource` (optional): data source name<br>`schema` (required): schema name<br>`table` (required): table name<br>`column` (required): column name |
### Write Operation Tools (Relational)
| Tool Name | Description | Parameters |
| ------ | ---- | ---- |
| `execute_insert` | Execute INSERT insertion operation ⚠️ | `datasource` (optional): data source name<br>`sql` (required): INSERT SQL statement |
| `execute_update` | Execute UPDATE update operation ⚠️ | `datasource` (optional): data source name<br>`sql` (required): UPDATE SQL statement |
| `execute_delete` | Execute DELETE deletion operation ⚠️ | `datasource` (optional): data source name<br>`sql` (required): DELETE SQL statement |
> **⚠️ Write operation tools** will pop up a confirmation dialog box in the MCP client, and the user will confirm before execution; read-only data sources will directly reject.
### Elasticsearch Tools
| Tool Name | Description | Parameters |
| ------ | ---- | ---- |
| `esListIndices` | List all indices (name, health status, document count, storage size) | `datasource` (optional) |
| `esGetMapping` | Get index mapping (field definition) | `datasource` (optional)<br>`index` (required): index name |
| `esCount` | Count index documents, optional Query DSL for conditional statistics | `datasource` (optional)<br>`index` (required)<br>`query` (optional): Query DSL JSON |
| `esSearch` | Execute Query DSL query on index | `datasource` (optional)<br>`index` (required)<br>`dsl` (optional): Query DSL JSON<br>`size` (optional): return count, default 10, upper limit 100 |
| `esIndexDocument` | Write or update document ⚠️ | `datasource` (optional)<br>`index` (required)<br>`id` (optional): automatically generated if empty<br>`document` (required): document JSON |
| `esDeleteDocument` | Delete document ⚠️ | `datasource` (optional)<br>`index` (required)<br>`id` (required): document ID |
### Redis Tools
| Tool Name | Description | Parameters |
| ------ | ---- | ---- |
| `redisScanKeys` | Scan keys matching the pattern based on SCAN (avoid KEYS blocking) | `datasource` (optional)<br>`pattern` (optional): e.g., user:*, empty matches all<br>`count` (optional): default 50, upper limit 500 |
| `redisKeyInfo` | View key type and TTL | `datasource` (optional)<br>`key` (required) |
| `redisGetKey` | Read key value type-aware (string/list/set/hash/zset) | `datasource` (optional)<br>`key` (required) |
| `redisSet` | Set string key (SET) ⚠️ | `datasource` (optional)<br>`key` (required)<br>`value` (required) |
| `redisDelete` | Delete key (DEL) ⚠️ | `datasource` (optional)<br>`key` (required) |
| `redisExpire` | Set expiration time for key (EXPIRE, seconds) ⚠️ | `datasource` (optional)<br>`key` (required)<br>`seconds` (required): positive integer |
> **⚠️ ES/Redis write operations** (write/delete documents, SET/DEL/EXPIRE) are also intercepted by read-only data sources, and execution on read-only sources will be rejected.
## Security Mechanism
### Read-only Query Security
Adopt **whitelist + blacklist** dual verification strategy:
**Whitelist (allowed starting keywords)**:
- `SELECT`
- `WITH`
- `EXPLAIN`
- `SHOW`
**Blacklist (prohibited keywords)**:
- DDL: `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `RENAME`
- DML write: `INSERT`, `UPDATE`, `DELETE`, `MERGE`, `UPSERT`
- DCL: `GRANT`, `REVOKE`
- Dangerous operations: `EXEC`, `EXECUTE`, `CALL`, `INTO OUTFILE`, `LOAD DATA`
### Write Operation Security
Write operations use independent security verification process:
**Whitelist (allowed starting keywords)**:
- `INSERT`
- `UPDATE`
- `DELETE`
**Blacklist (prohibited keywords)**:
- DDL: `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `RENAME`
- DCL: `GRANT`, `REVOKE`
- Dangerous operations: `EXEC`, `EXECUTE`, `CALL`, `INTO OUTFILE`, `LOAD DATA`
### Multi-layer Protection Matrix
| Protection Layer | Mechanism | Description |
| ------ | ---- | ---- |
| Comment stripping | Remove `--` and `/* */` comments | Prevent bypassing keyword detection through comments |
| Whitelist check | SQL starting keyword matching | Ensure SQL type meets expectations |
| Blacklist check | Full-text forbidden keyword scanning | Intercept dangerous operation keywords |
| Multi-statement injection detection | Strip string and detect semicolon | Prevent SQL injection attacks |
| Identifier verification | Only allow letters/numbers/underscores/dot | Prevent splicing injection |
| Operation type matching | Tool and SQL type strong binding | `executeInsert` only allows INSERT |
| WHERE condition detection | UPDATE/DELETE missing WHERE warning | Prevent full table operation |
| Row limit | Automatically wrap LIMIT/ROWNUM | Prevent large result set |
### MCP Client Confirmation Mechanism
Write operation tools (`execute_insert`, `execute_update`, `execute_delete`) contain explicit **warning descriptions** in their `@Tool` annotations. MCP protocol specifications require clients to display a confirmation dialog box to users before executing operations with side effects.
Workflow:
1. LLM generates write SQL and calls write operation tools
2. MCP client intercepts requests and displays SQL content and warning information to users
3. User confirms, and the request is sent to the server for execution
4. Server performs security verification again before execution
## Extension Guide
### Add New Database Type (PostgreSQL Example)
#### 1. Add JDBC Driver Dependency
Add the following in `pom.xml`:
```xml
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
```
#### 2. Implement DatabaseDialect Interface
Create `src/main/java/com/dameng/mcp/adapter/postgresql/PostgresqlDialect.java`:
```java
package com.dameng.mcp.adapter.postgresql;
import com.dameng.mcp.adapter.DatabaseDialect;
public class PostgresqlDialect implements DatabaseDialect {
@Override
public String wrapLimitQuery(String sql, int maxRows) {
return sql + " LIMIT " + maxRows;
}
@Override
public String buildSampleQuery(String schema, String table, int limit) {
return "SELECT * FROM \"" + schema + "\".\"" + table + "\" LIMIT " + limit;
}
@Override
public String buildCountQuery(String schema, String table) {
return "SELECT COUNT(*) FROM \"" + schema + "\".\"" + table + "\"";
}
}
```
#### 3. Implement DatabaseAdapter Interface
Create `src/main/java/com/dameng/mcp/adapter/postgresql/PostgresqlDatabaseAdapter.java`, refer to existing `DamengDatabaseAdapter` or `MysqlDatabaseAdapter` to implement metadata query, data query, etc.
#### 4. Register to Factory
Add a branch to the `create` method in `DatabaseAdapterFactory.java`:
```java
case "postgresql":
return new PostgresqlDatabaseAdapter(jdbcTemplate, new PostgresqlDialect(), securityValidator);
```
Also, add corresponding configurations to the `getDriverClassName` and `getValidationQuery` methods:
```java
// getDriverClassName
case "postgresql":
return "org.postgresql.Driver";
// getValidationQuery
case "postgresql":
return "SELECT 1";
```
#### 5. Configure Data Source
Add the following configuration to `application.yml`:
```yaml
mcp:
datasources:
- name: pg-analytics
description: "Analytics System - PostgreSQL"
type: postgresql
url: jdbc:postgresql://localhost:5432/analytics
username: postgres
password: your_password
```
## Project Structure
```
dameng-mcp-server/
├── pom.xml # Maven build configuration
├── README.md # Project documentation
├── src/main/
│ ├── java/com/dameng/mcp/
│ │ ├── DamengMcpServerApplication.java # Spring Boot startup class
│ │ ├── adapter/ # Data source adapter layer
│ │ │ ├── DatabaseAdapter.java # Relational adapter interface
│ │ │ ├── DatabaseDialect.java # Dialect interface
│ │ │ ├── DatabaseAdapterFactory.java # Relational adapter factory
│ │ │ ├── DataSourceRegistry.java # Multi-data source registry (relational/ES/Redis)
│ │ │ ├── dameng/ # Dameng adapter
│ │ │ │ ├── DamengDatabaseAdapter.java
│ │ │ │ └── DamengDialect.java
│ │ │ ├── oracle/ # Oracle adapter
│ │ │ │ ├── OracleDatabaseAdapter.java
│ │ │ │ └── OracleDialect.java
│ │ │ ├── mysql/ # MySQL adapter
│ │ │ │ ├── MysqlDatabaseAdapter.java
│ │ │ │ └── MysqlDialect.java
│ │ │ ├── elasticsearch/ # Elasticsearch adapter
│ │ │ │ ├── ElasticsearchClientFactory.java
│ │ │ │ └── ElasticsearchRestClient.java
│ │ │ └── redis/ # Redis adapter
│ │ │ ├── RedisClientFactory.java
│ │ │ └── RedisConnection.java
│ │ ├── config/ # Configuration classes
│ │ │ ├── DataSourceConfig.java # Multi-data source initialization (yml + persistent dynamic source)
│ │ │ ├── DataSourceProperties.java # Data source configuration properties
│ │ │ ├── DataSourcePersistence.java # Dynamic data source H2 persistence
│ │ │ └── McpToolConfig.java # MCP tool registration
│ │ ├── model/ # Data models
│ │ │ ├── ColumnInfo.java # Column information
│ │ │ ├── ColumnStatistics.java # Column statistics
│ │ │ ├── DataSourceInfo.java # Data source information
│ │ │ ├── ExecuteResult.java # Execution result
│ │ │ ├── QueryResult.java # Query result
│ │ │ ├── TableDefinition.java # Table definition
│ │ │ ├── TableInfo.java # Table information
│ │ │ └── TableStatistics.java # Table statistics
│ │ ├── security/ # Security module
│ │ │ └── SqlSecurityValidator.java # SQL security validator
│ │ ├── service/ # MCP tool services
│ │ │ ├── DatabaseMetadataService.java # Metadata tool (relational)
│ │ │ ├── DatabaseQueryService.java # Query tool (relational)
│ │ │ ├── DatabaseStatisticsService.java # Statistics tool (relational)
│ │ │ ├── DatabaseWriteService.java # Write operation tool (relational)
│ │ │ ├── ElasticsearchToolService.java # Elasticsearch MCP tool
│ │ │ ├── RedisToolService.java # Redis MCP tool
│ │ │ └── DataSourceManager.java # Data source dynamic management (add/delete/modify/test/persistent)
│ │ └── web/ # HTTP mode web layer (only http profile)
│ │ ├── AccessTokenFilter.java # Access token filter
│ │ ├── ApiResponse.java # Unified response structure
│ │ └── DataSourceController.java # Data source management REST interface
│ └── resources/
│ ├── application.yml # Application configuration (stdio/http dual profile)
│ ├── application.yml.example # Desensitized example configuration template
│ └── static/
│ └── index.html # Built-in web data source management page
└── target/ # Build output
```
## Notes
1. **Database Driver Installation**: The Dameng JDBC driver (`DmJdbcDriver18`) must be installed in the Maven repository or manually installed in the local repository:
```bash
mvn install:install-file -DgroupId=com.dameng -DartifactId=DmJdbcDriver18 \
-Dversion=8.1.3.140 -Dpackaging=jar -Dfile=/path/to/DmJdbcDriver18.jar
```
2. **Log Closure**: In the production environment, the log level is set to `OFF` by default, as the MCP Stdio mode uses standard output communication, and any log output will interfere with the protocol communication. For debugging, you can temporarily modify it to `DEBUG` and use file logging:
```yaml
logging:
level:
root: DEBUG
file:
name: ./logs/mcp-server.log
```
3. **Read-only Account Recommendation**: For scenarios that only require query capabilities, it is strongly recommended to use a **read-only database account** to connect, eliminating the risk of mistakenly writing data from the database level.
4. **Connection Pool Configuration**: The default Druid connection pool parameters are suitable for most scenarios. In high-concurrency scenarios, you can appropriately increase `maxActive`; in resource-constrained environments, you can reduce `initialSize` and `minIdle`.
5. **Network Environment**: The MCP service runs in Stdio mode, and there is no need to expose network ports. However, ensure that the running environment can access the target database's network address and port.
6. **Character Set**: It is recommended to specify the character set in the database connection URL to avoid Chinese character garbled:
- MySQL: `jdbc:mysql://host:3306/db?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC`
- Dameng/Oracle: Default UTF-8, usually no additional configuration is required
7. **Write Operation Risk**: Write operation tools (INSERT/UPDATE/DELETE) will actually modify database data. Although there are multiple layers of security protection and client confirmation mechanisms, it is still recommended to verify the correctness of SQL in a **non-production environment** first.
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