vmoo-mcp-database-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # vmoo-mcp-database-server
2
+
3
+ VMOO数据库MCP服务器 - 支持开发和生产环境的安全数据库访问
4
+
5
+ [![npm version](https://badge.fury.io/js/vmoo-mcp-database-server.svg)](https://badge.fury.io/js/vmoo-mcp-database-server)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## 🚀 快速开始
9
+
10
+ ### 使用npx直接运行(推荐)
11
+
12
+ ```bash
13
+ # 开发环境
14
+ npx vmoo-mcp-database-server@latest --env=dev
15
+
16
+ # 生产环境
17
+ npx vmoo-mcp-database-server@latest --env=prod
18
+ ```
19
+
20
+ ### 在Augment中配置
21
+
22
+ ```json
23
+ {
24
+ "mcpServers": {
25
+ "vmoo-database-dev": {
26
+ "command": "npx",
27
+ "args": ["vmoo-mcp-database-server@latest", "--env=dev"]
28
+ },
29
+ "vmoo-database-prod": {
30
+ "command": "npx",
31
+ "args": ["vmoo-mcp-database-server@latest", "--env=prod"]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### 1. 安装依赖
38
+
39
+ ```bash
40
+ npm install
41
+ ```
42
+
43
+ ### 2. 测试数据库连接
44
+
45
+ ```bash
46
+ npm test
47
+ ```
48
+
49
+ 如果看到 ✅ 连接成功,说明配置正确。
50
+
51
+ ### 3. 启动MCP服务器
52
+
53
+ ```bash
54
+ npm start
55
+ ```
56
+
57
+ ## 🔧 在Augment中配置
58
+
59
+ ### 找到Augment配置文件
60
+
61
+ - **Windows**: `%APPDATA%\Augment\config.json`
62
+ - **macOS**: `~/Library/Application Support/Augment/config.json`
63
+ - **Linux**: `~/.config/Augment/config.json`
64
+
65
+ ### 添加MCP服务器配置
66
+
67
+ 在配置文件中添加:
68
+
69
+ ```json
70
+ {
71
+ "mcpServers": {
72
+ "vmoo-database": {
73
+ "command": "node",
74
+ "args": ["D:\\代码库\\vmoo-mcp-server\\mcp-vmoo-database-server.js"],
75
+ "env": {}
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ **注意**: 请将路径替换为你的实际路径。
82
+
83
+ ### 重启Augment
84
+
85
+ 保存配置文件后,重启Augment应用。
86
+
87
+ ## 🛠️ 可用工具
88
+
89
+ 配置成功后,你可以在Augment中直接询问:
90
+
91
+ ### 1. 查询数据库
92
+ - "列出所有fanwe_开头的表"
93
+ - "查询最近注册的10个用户"
94
+ - "显示fanwe_menu表中价格最高的商品"
95
+
96
+ ### 2. 查看表结构
97
+ - "fanwe_user表的结构是什么?"
98
+ - "描述fanwe_order表的字段"
99
+
100
+ ### 3. 获取示例数据
101
+ - "显示fanwe_menu表的前5条记录"
102
+ - "fanwe_user表的示例数据"
103
+
104
+ ### 4. 统计信息
105
+ - "fanwe_user表有多少条记录?"
106
+ - "数据库中有多少个表?"
107
+
108
+ ## 📊 数据库信息
109
+
110
+ - **主机**: 118.25.190.11:3306
111
+ - **数据库**: ceshi_v_moo_com
112
+ - **表前缀**: fanwe_
113
+ - **字符集**: utf8mb4
114
+
115
+ ## 🔒 安全特性
116
+
117
+ ### 允许的操作
118
+ - **查询操作**: SELECT、SHOW、DESCRIBE、EXPLAIN
119
+ - **数据修改**: INSERT、UPDATE(仅限新增和修改)
120
+ - **表结构**: CREATE TABLE、ALTER TABLE
121
+
122
+ ### 安全防护
123
+ - **禁止所有删除操作**: 完全阻止DELETE、DROP TABLE、DROP DATABASE等删除操作
124
+ - **测试环境专用**: 专为测试环境设计,确保数据安全
125
+ - **查询限制**: 自动添加LIMIT防止大量数据返回
126
+ - **SQL注入防护**: 使用参数化查询
127
+ - **连接池管理**: 自动管理数据库连接
128
+ - **错误处理**: 完善的错误捕获和提示
129
+
130
+ ## 📝 使用示例
131
+
132
+ ```
133
+ 用户: "VMOO数据库中有哪些用户相关的表?"
134
+ AI: 调用list_tables工具,返回包含user的表列表
135
+
136
+ 用户: "fanwe_user表的字段都有什么含义?"
137
+ AI: 调用describe_table工具,返回表结构详情
138
+
139
+ 用户: "最近一周注册的用户有多少?"
140
+ AI: 调用query_database工具,执行相应SQL查询
141
+ ```
142
+
143
+ ## 🛠️ 开发调试
144
+
145
+ ### 启用调试模式
146
+
147
+ ```bash
148
+ npm run dev
149
+ ```
150
+
151
+ 这将启用Node.js调试器,可以在Chrome DevTools中调试。
152
+
153
+ ### 查看日志
154
+
155
+ MCP服务器的日志会输出到stderr,可以通过以下方式查看:
156
+
157
+ ```bash
158
+ node mcp-vmoo-database-server.js 2> debug.log
159
+ ```
160
+
161
+ ## 🔧 故障排除
162
+
163
+ ### 连接问题
164
+ - 检查网络连接
165
+ - 确认数据库服务器可访问
166
+ - 验证防火墙设置
167
+
168
+ ### 权限问题
169
+ - 确保数据库用户有查询权限
170
+ - 检查表访问权限
171
+
172
+ ### 配置问题
173
+ - 验证Augment配置文件路径正确
174
+ - 确保Node.js版本 >= 18.0.0
175
+
176
+ ## 📄 许可证
177
+
178
+ MIT License
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ // VMOO开发环境MCP服务器启动器
4
+
5
+ import { spawn } from 'child_process';
6
+ import { fileURLToPath } from 'url';
7
+ import path from 'path';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+ // 解析命令行参数
13
+ const args = process.argv.slice(2);
14
+ const configPath = args.find(arg => arg.startsWith('--config='))?.split('=')[1];
15
+
16
+ console.log('🟡 启动VMOO开发环境MCP服务器...');
17
+
18
+ // 服务器文件路径
19
+ const serverPath = path.join(__dirname, '../vmoo-database-dev/server.js');
20
+
21
+ // 启动服务器
22
+ const serverProcess = spawn('node', [serverPath], {
23
+ stdio: 'inherit',
24
+ env: {
25
+ ...process.env,
26
+ ...(configPath && { CONFIG_PATH: configPath })
27
+ }
28
+ });
29
+
30
+ // 处理进程退出
31
+ serverProcess.on('close', (code) => {
32
+ console.log(`🟡 开发环境MCP服务器已退出,退出码: ${code}`);
33
+ process.exit(code);
34
+ });
35
+
36
+ // 处理中断信号
37
+ process.on('SIGINT', () => {
38
+ console.log('\n🛑 正在关闭开发环境MCP服务器...');
39
+ serverProcess.kill('SIGINT');
40
+ });
41
+
42
+ process.on('SIGTERM', () => {
43
+ console.log('\n🛑 正在关闭开发环境MCP服务器...');
44
+ serverProcess.kill('SIGTERM');
45
+ });
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ // VMOO生产环境MCP服务器启动器
4
+
5
+ import { spawn } from 'child_process';
6
+ import { fileURLToPath } from 'url';
7
+ import path from 'path';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+ // 解析命令行参数
13
+ const args = process.argv.slice(2);
14
+ const configPath = args.find(arg => arg.startsWith('--config='))?.split('=')[1];
15
+
16
+ console.log('🔴 启动VMOO生产环境MCP服务器...');
17
+
18
+ // 服务器文件路径
19
+ const serverPath = path.join(__dirname, '../vmoo-database-prod/server.js');
20
+
21
+ // 启动服务器
22
+ const serverProcess = spawn('node', [serverPath], {
23
+ stdio: 'inherit',
24
+ env: {
25
+ ...process.env,
26
+ ...(configPath && { CONFIG_PATH: configPath })
27
+ }
28
+ });
29
+
30
+ // 处理进程退出
31
+ serverProcess.on('close', (code) => {
32
+ console.log(`🔴 生产环境MCP服务器已退出,退出码: ${code}`);
33
+ process.exit(code);
34
+ });
35
+
36
+ // 处理中断信号
37
+ process.on('SIGINT', () => {
38
+ console.log('\n🛑 正在关闭生产环境MCP服务器...');
39
+ serverProcess.kill('SIGINT');
40
+ });
41
+
42
+ process.on('SIGTERM', () => {
43
+ console.log('\n🛑 正在关闭生产环境MCP服务器...');
44
+ serverProcess.kill('SIGTERM');
45
+ });
package/index.js ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+
3
+ // VMOO MCP数据库服务器包主入口
4
+
5
+ export { createConnectionPool, executeQuery } from './shared/database-utils.js';
6
+ export { SECURITY_LEVELS, performSecurityCheck } from './shared/security-utils.js';
7
+ export { processTimeFields } from './shared/time-utils.js';
8
+ export { anonymizeQueryResults } from './shared/privacy-utils.js';
9
+
10
+ // 默认导出服务器启动函数
11
+ export default function startServer(environment = 'dev') {
12
+ const { spawn } = require('child_process');
13
+ const path = require('path');
14
+
15
+ const serverPath = environment === 'prod'
16
+ ? path.join(__dirname, 'vmoo-database-prod/server.js')
17
+ : path.join(__dirname, 'vmoo-database-dev/server.js');
18
+
19
+ return spawn('node', [serverPath], { stdio: 'inherit' });
20
+ }
21
+
22
+ // 如果直接运行此文件,显示帮助信息
23
+ if (import.meta.url === `file://${process.argv[1]}`) {
24
+ console.log(`
25
+ 🟡 VMOO MCP数据库服务器
26
+
27
+ 使用方法:
28
+ npx @vmoo/mcp-database-server@latest --env=dev # 开发环境
29
+ npx @vmoo/mcp-database-server@latest --env=prod # 生产环境
30
+
31
+ 或者直接使用:
32
+ npx vmoo-mcp-dev # 开发环境
33
+ npx vmoo-mcp-prod # 生产环境
34
+
35
+ 配置文件:
36
+ --config=path/to/config.json # 自定义配置文件路径
37
+ `);
38
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "vmoo-mcp-database-server",
3
+ "version": "1.0.0",
4
+ "description": "VMOO数据库MCP服务器集合 - 支持开发和生产环境的安全数据库访问",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "vmoo-mcp-dev": "./bin/vmoo-mcp-dev.js",
9
+ "vmoo-mcp-prod": "./bin/vmoo-mcp-prod.js"
10
+ },
11
+ "scripts": {
12
+ "start:prod": "cd vmoo-database-prod && npm start",
13
+ "start:dev": "cd vmoo-database-dev && npm start",
14
+ "install:all": "npm install && cd vmoo-database-prod && npm install && cd ../vmoo-database-dev && npm install",
15
+ "test:all": "cd vmoo-database-prod && npm test && cd ../vmoo-database-dev && npm test",
16
+ "build": "echo '构建完成'",
17
+ "deploy": "./scripts/deploy.sh"
18
+ },
19
+ "dependencies": {
20
+ "@modelcontextprotocol/sdk": "^1.17.2",
21
+ "mysql2": "^3.6.5"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.0.0"
25
+ },
26
+ "keywords": [
27
+ "mcp",
28
+ "database",
29
+ "mysql",
30
+ "vmoo",
31
+ "model-context-protocol",
32
+ "production",
33
+ "development",
34
+ "privacy",
35
+ "security"
36
+ ],
37
+ "author": "VMOO Team",
38
+ "license": "MIT",
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ },
42
+ "files": [
43
+ "bin/",
44
+ "shared/",
45
+ "vmoo-database-dev/",
46
+ "vmoo-database-prod/",
47
+ "index.js",
48
+ "README.md"
49
+ ],
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/jinzong8/vmoo-mcp-server.git"
53
+ },
54
+ "bugs": {
55
+ "url": "https://github.com/jinzong8/vmoo-mcp-server/issues"
56
+ },
57
+ "homepage": "https://github.com/jinzong8/vmoo-mcp-server#readme"
58
+ }
@@ -0,0 +1,102 @@
1
+ // VMOO数据库工具函数
2
+ import mysql from 'mysql2/promise';
3
+
4
+ /**
5
+ * 创建数据库连接池
6
+ * @param {Object} config 数据库配置
7
+ * @returns {Object} 连接池
8
+ */
9
+ function createConnectionPool(config) {
10
+ return mysql.createPool({
11
+ ...config,
12
+ waitForConnections: true,
13
+ connectionLimit: 10,
14
+ queueLimit: 0
15
+ });
16
+ }
17
+
18
+ /**
19
+ * 标准化表名(添加fanwe_前缀)
20
+ * @param {string} tableName 表名
21
+ * @returns {string} 标准化后的表名
22
+ */
23
+ function normalizeTableName(tableName) {
24
+ if (!tableName.startsWith('fanwe_')) {
25
+ return `fanwe_${tableName}`;
26
+ }
27
+ return tableName;
28
+ }
29
+
30
+ /**
31
+ * 执行查询并处理错误
32
+ * @param {Object} pool 连接池
33
+ * @param {string} query 查询语句
34
+ * @returns {Array} 查询结果
35
+ */
36
+ async function executeQuery(pool, query) {
37
+ try {
38
+ const [rows] = await pool.execute(query);
39
+ return rows;
40
+ } catch (error) {
41
+ throw new Error(`数据库查询失败: ${error.message}`);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * 获取表结构
47
+ * @param {Object} pool 连接池
48
+ * @param {string} tableName 表名
49
+ * @returns {Array} 表结构
50
+ */
51
+ async function getTableStructure(pool, tableName) {
52
+ const normalizedName = normalizeTableName(tableName);
53
+ return await executeQuery(pool, `DESCRIBE ${normalizedName}`);
54
+ }
55
+
56
+ /**
57
+ * 获取表记录数
58
+ * @param {Object} pool 连接池
59
+ * @param {string} tableName 表名
60
+ * @returns {number} 记录数
61
+ */
62
+ async function getTableCount(pool, tableName) {
63
+ const normalizedName = normalizeTableName(tableName);
64
+ const rows = await executeQuery(pool, `SELECT COUNT(*) as count FROM ${normalizedName}`);
65
+ return rows[0].count;
66
+ }
67
+
68
+ /**
69
+ * 获取表示例数据
70
+ * @param {Object} pool 连接池
71
+ * @param {string} tableName 表名
72
+ * @param {number} limit 限制数量
73
+ * @returns {Array} 示例数据
74
+ */
75
+ async function getTableSampleData(pool, tableName, limit = 10) {
76
+ const normalizedName = normalizeTableName(tableName);
77
+ return await executeQuery(pool, `SELECT * FROM ${normalizedName} LIMIT ${limit}`);
78
+ }
79
+
80
+ /**
81
+ * 列出所有表
82
+ * @param {Object} pool 连接池
83
+ * @param {string} pattern 匹配模式
84
+ * @returns {Array} 表列表
85
+ */
86
+ async function listTables(pool, pattern = null) {
87
+ let query = "SHOW TABLES";
88
+ if (pattern) {
89
+ query += ` LIKE '%${pattern}%'`;
90
+ }
91
+ return await executeQuery(pool, query);
92
+ }
93
+
94
+ export {
95
+ createConnectionPool,
96
+ normalizeTableName,
97
+ executeQuery,
98
+ getTableStructure,
99
+ getTableCount,
100
+ getTableSampleData,
101
+ listTables
102
+ };
@@ -0,0 +1,207 @@
1
+ // 个人信息匿名化工具
2
+
3
+ /**
4
+ * 手机号码匿名化
5
+ * @param {string} phone 手机号码
6
+ * @returns {string} 匿名化后的手机号
7
+ */
8
+ function anonymizePhone(phone) {
9
+ if (!phone || typeof phone !== 'string') return phone;
10
+
11
+ // 移除所有非数字字符
12
+ const cleanPhone = phone.replace(/\D/g, '');
13
+
14
+ if (cleanPhone.length === 11) {
15
+ // 中国手机号:138****1234
16
+ return `${cleanPhone.substring(0, 3)}****${cleanPhone.substring(7)}`;
17
+ } else if (cleanPhone.length >= 7) {
18
+ // 其他格式:保留前3位和后4位
19
+ const start = cleanPhone.substring(0, 3);
20
+ const end = cleanPhone.substring(cleanPhone.length - 4);
21
+ const stars = '*'.repeat(Math.max(4, cleanPhone.length - 7));
22
+ return `${start}${stars}${end}`;
23
+ }
24
+
25
+ return phone; // 格式不符合,返回原值
26
+ }
27
+
28
+ /**
29
+ * 身份证号匿名化
30
+ * @param {string} idCard 身份证号
31
+ * @returns {string} 匿名化后的身份证号
32
+ */
33
+ function anonymizeIdCard(idCard) {
34
+ if (!idCard || typeof idCard !== 'string') return idCard;
35
+
36
+ const cleanId = idCard.replace(/\s/g, '');
37
+
38
+ if (cleanId.length === 18) {
39
+ // 18位身份证:320***********1234
40
+ return `${cleanId.substring(0, 3)}${'*'.repeat(11)}${cleanId.substring(14)}`;
41
+ } else if (cleanId.length === 15) {
42
+ // 15位身份证:320*********34
43
+ return `${cleanId.substring(0, 3)}${'*'.repeat(9)}${cleanId.substring(13)}`;
44
+ }
45
+
46
+ return idCard; // 格式不符合,返回原值
47
+ }
48
+
49
+ /**
50
+ * 邮箱地址匿名化
51
+ * @param {string} email 邮箱地址
52
+ * @returns {string} 匿名化后的邮箱
53
+ */
54
+ function anonymizeEmail(email) {
55
+ if (!email || typeof email !== 'string') return email;
56
+
57
+ const emailRegex = /^([^@]+)@(.+)$/;
58
+ const match = email.match(emailRegex);
59
+
60
+ if (match) {
61
+ const [, username, domain] = match;
62
+
63
+ if (username.length <= 3) {
64
+ // 短用户名:u**@example.com
65
+ return `${username.charAt(0)}${'*'.repeat(Math.max(2, username.length - 1))}@${domain}`;
66
+ } else {
67
+ // 长用户名:user***@example.com
68
+ return `${username.substring(0, 4)}${'*'.repeat(Math.max(3, username.length - 4))}@${domain}`;
69
+ }
70
+ }
71
+
72
+ return email; // 格式不符合,返回原值
73
+ }
74
+
75
+ /**
76
+ * 真实姓名匿名化
77
+ * @param {string} name 真实姓名
78
+ * @returns {string} 匿名化后的姓名
79
+ */
80
+ function anonymizeName(name) {
81
+ if (!name || typeof name !== 'string') return name;
82
+
83
+ const trimmedName = name.trim();
84
+
85
+ if (trimmedName.length === 1) {
86
+ return trimmedName; // 单字名不处理
87
+ } else if (trimmedName.length === 2) {
88
+ // 两字名:张*
89
+ return `${trimmedName.charAt(0)}*`;
90
+ } else if (trimmedName.length === 3) {
91
+ // 三字名:张**
92
+ return `${trimmedName.charAt(0)}**`;
93
+ } else {
94
+ // 长姓名:保留第一个字,其余用*
95
+ return `${trimmedName.charAt(0)}${'*'.repeat(Math.min(2, trimmedName.length - 1))}`;
96
+ }
97
+ }
98
+
99
+ /**
100
+ * 地址匿名化
101
+ * @param {string} address 地址
102
+ * @returns {string} 匿名化后的地址
103
+ */
104
+ function anonymizeAddress(address) {
105
+ if (!address || typeof address !== 'string') return address;
106
+
107
+ // 保留省市,隐藏详细地址
108
+ const addressRegex = /(.*?[省市区县])(.*)/;
109
+ const match = address.match(addressRegex);
110
+
111
+ if (match && match[2].length > 6) {
112
+ const [, region, detail] = match;
113
+ return `${region}***${detail.substring(detail.length - 3)}`;
114
+ }
115
+
116
+ return address;
117
+ }
118
+
119
+ /**
120
+ * 银行卡号匿名化
121
+ * @param {string} bankCard 银行卡号
122
+ * @returns {string} 匿名化后的银行卡号
123
+ */
124
+ function anonymizeBankCard(bankCard) {
125
+ if (!bankCard || typeof bankCard !== 'string') return bankCard;
126
+
127
+ const cleanCard = bankCard.replace(/\s/g, '');
128
+
129
+ if (cleanCard.length >= 12) {
130
+ // 保留前4位和后4位
131
+ const start = cleanCard.substring(0, 4);
132
+ const end = cleanCard.substring(cleanCard.length - 4);
133
+ const stars = '*'.repeat(Math.max(4, cleanCard.length - 8));
134
+ return `${start} ${stars} ${end}`;
135
+ }
136
+
137
+ return bankCard;
138
+ }
139
+
140
+ /**
141
+ * 对查询结果进行数据匿名化处理
142
+ * @param {Array} rows 查询结果
143
+ * @returns {Array} 匿名化后的结果
144
+ */
145
+ function anonymizeQueryResults(rows) {
146
+ if (!Array.isArray(rows)) return rows;
147
+
148
+ // 需要匿名化的字段映射
149
+ const fieldMappings = {
150
+ // 手机号字段
151
+ mobile: anonymizePhone,
152
+ phone: anonymizePhone,
153
+ tel: anonymizePhone,
154
+ telephone: anonymizePhone,
155
+
156
+ // 身份证字段
157
+ id_card: anonymizeIdCard,
158
+ identity_card: anonymizeIdCard,
159
+ id_number: anonymizeIdCard,
160
+
161
+ // 邮箱字段
162
+ email: anonymizeEmail,
163
+ mail: anonymizeEmail,
164
+
165
+ // 姓名字段
166
+ name: anonymizeName,
167
+ real_name: anonymizeName,
168
+ user_name: anonymizeName,
169
+ consignee: anonymizeName,
170
+
171
+ // 地址字段
172
+ address: anonymizeAddress,
173
+ delivery_address: anonymizeAddress,
174
+
175
+ // 银行卡字段
176
+ bank_card: anonymizeBankCard,
177
+ card_number: anonymizeBankCard
178
+ };
179
+
180
+ return rows.map(row => {
181
+ const anonymizedRow = { ...row };
182
+
183
+ Object.keys(anonymizedRow).forEach(key => {
184
+ const lowerKey = key.toLowerCase();
185
+
186
+ // 检查是否需要匿名化
187
+ Object.keys(fieldMappings).forEach(fieldPattern => {
188
+ if (lowerKey.includes(fieldPattern)) {
189
+ const anonymizeFunc = fieldMappings[fieldPattern];
190
+ anonymizedRow[key] = anonymizeFunc(anonymizedRow[key]);
191
+ }
192
+ });
193
+ });
194
+
195
+ return anonymizedRow;
196
+ });
197
+ }
198
+
199
+ export {
200
+ anonymizePhone,
201
+ anonymizeIdCard,
202
+ anonymizeEmail,
203
+ anonymizeName,
204
+ anonymizeAddress,
205
+ anonymizeBankCard,
206
+ anonymizeQueryResults
207
+ };