SQL数据库MCP
AI编码助手(Claude、Cursor、Windsurf)的企业级数据库访问稳定,始终处于Apify Standby端点。
支持的数据库:PostgreSQL、MySQL、SQLite
特性
- 稳定的端点:始终处于待机状态的URL(没有临时运行URL)
- MCP流式HTTP:远程MCP服务器的标准传输
- 多数据库支持:连接到多个PostgreSQL、MySQL和SQLite数据库
- 安全第一:API密钥身份验证、只读强制、机密输入保护
- 审计日志:仅附加存储在Apify数据集中的查询日志
- 生产就绪:连接池、超时、行限制、错误清理
快速开始
1.部署到Apify
# Install Apify CLI
npm install -g apify-cli
# Login to Apify
apify login
# Deploy the Actor
apify push2.配置Actor输入
在Apify控制台中,配置Actor输入:
{
"apiKey": "sk_live_your_secure_random_key_here",
"postgresql": [
{
"name": "production",
"host": "your-postgres-host.com",
"port": 5432,
"database": "myapp",
"user": "readonly_user",
"password": "********",
"ssl": true
}
],
"mysql": [
{
"name": "analytics",
"host": "your-mysql-host.com",
"port": 3306,
"database": "analytics",
"user": "readonly_user",
"password": "********"
}
],
"sqlite": [
{
"name": "local",
"filepath": "/data/myapp.db",
"readonly": true
}
],
"queryTimeout": 30,
"maxRows": 1000,
"logDatasetName": "logs-sql-mcp"
}重要:所有密码和API密钥都标记为机密输入,并且永远不会出现在日志中。
3.启用待机模式
- 去你的演员那里 设置 → 待命 标签
- 启用待机
- 复制您的待机主机名(例如。,
https://sql-databases-mcp.apify.actor)
4.配置MCP客户端
添加到您的Claude桌面配置(~/Library/Application Support/Claude/claude_desktop_config.json 在macOS上):
{
"mcpServers": {
"sql-databases": {
"url": "https://your-actor-name.apify.actor/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer sk_live_your_secure_random_key_here"
}
}
}
}对于Cursor或Windsurf,请查看其各自的MCP配置文档。
可用工具
配置后,您的AI助手将可以访问这些工具:
将军
db.ping-测试与所有已配置数据库的连接
PostgreSQL
对于每个名为的PostgreSQL连接 {name}:
postgres.{name}.describe_schema-获取表和列信息postgres.{name}.execute_query-执行SELECT查询
MySQL
对于每个命名的MySQL连接 {name}:
mysql.{name}.describe_schema-获取表和列信息mysql.{name}.execute_query-执行SELECT查询
SQLite
对于每个命名为的SQLite连接 {name}:
sqlite.{name}.describe_schema-获取表和列信息sqlite.{name}.execute_query-执行SELECT查询
安全功能
只读执行
所有查询都仅被验证为SELECT语句。以下操作被阻止:
- 插入、更新、删除
- 删除、创建、更改、截断
- 授予、撤销
- 文件操作(OUTFILE、DUMPFILE等)
查询限制
- 行限制:每个查询可配置的最大行数(默认值:1000)
- 超时:可配置的查询超时(默认值:30秒)
- 自动限制:没有LIMIT的查询会自动受到限制
秘密保护
所有敏感数据在输入模式中都标记为机密:
- API密钥
- 数据库密码
- 连接字符串
机密永远不会记录到数据集或错误消息中。
API密钥验证
所有MCP请求都需要有效的Bearer令牌:
curl -X POST https://your-actor.apify.actor/mcp \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{"method": "tools/list"}'查询日志记录
所有工具执行都会记录到Apify数据集以供审计。
日志条目格式
{
"timestamp": "2025-11-06T12:34:56.789Z",
"tool": "postgres.production.execute_query",
"dbType": "postgresql",
"dbName": "production",
"query": "SELECT * FROM users LIMIT 10",
"rowsReturned": 10,
"durationMs": 123,
"success": true
}查看日志
- 转到Apify控制台→ 存储 → 数据集
- 打开数据集:
logs-sql-mcp(或您配置的名称) - 按降序查看最新查询
地方发展
# Install dependencies
npm install
# Set up test database credentials in .env
echo "API_KEY=dev-test-key" > .env
# Run in development mode
npm run dev
# Test health endpoint
curl http://localhost:4321/
# Test MCP endpoint (requires database config)
curl -X POST http://localhost:4321/mcp \
-H "Authorization: Bearer dev-test-key" \
-H "Content-Type: application/json" \
-d '{"method": "tools/list", "params": {}}'建筑
┌─────────────────────────────────────────────────┐
│ AI Assistant (Claude/Cursor/Windsurf) │
└─────────────────┬───────────────────────────────┘
│ MCP Streamable HTTP
│ (Authorization: Bearer ...)
┌─────────────────▼───────────────────────────────┐
│ Apify Standby Actor (Always-On) │
│ ┌───────────────────────────────────────────┐ │
│ │ Express Server (Port 4321) │ │
│ │ ┌─────────────┐ ┌──────────────────┐ │ │
│ │ │ GET / │ │ POST /mcp │ │ │
│ │ │ (Health) │ │ (MCP Endpoint) │ │ │
│ │ └─────────────┘ └──────────────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼────────┐ │ │
│ │ │ API Key Auth │ │ │
│ │ └────────┬────────┘ │ │
│ │ ┌────────▼────────┐ │ │
│ │ │ MCP Server │ │ │
│ │ │ (Tool Router) │ │ │
│ │ └────────┬────────┘ │ │
│ └─────────────────────────┬──┴────────────┬─┘ │
│ ┌─────────────▼──┐ ┌─────────▼──┐ │
│ │ DB Adapters │ │ Dataset │ │
│ │ (PG/MySQL/ │ │ Logger │ │
│ │ SQLite) │ │ │ │
│ └────────┬───────┘ └─────┬──────┘ │
└───────────────────────┼──────────────┬─┼────────┘
│ │ │
┌──────────────┼──────┐ │ │
│ │ │ │ │
┌────▼────┐ ┌─────▼───┐ │ │ │
│ Postgres│ │ MySQL │ │ │ │
└─────────┘ └─────────┘ │ │ │
┌─────────▼───┐ │ │
│ SQLite │ │ │
└─────────────┘ │ │
┌───▼─▼──────┐
│ Apify │
│ Dataset │
└────────────┘文件结构
db-mcp/
├── .actor/
│ ├── actor.json # Standby configuration
│ └── input_schema.json # Input schema with secrets
├── src/
│ ├── main.ts # Express server & startup
│ ├── mcp-server.ts # MCP SDK integration
│ ├── types.ts # TypeScript interfaces
│ ├── auth/
│ │ └── apikey.ts # Bearer token auth
│ ├── databases/
│ │ ├── connection-manager.ts # Pool management
│ │ ├── postgres.ts # PostgreSQL adapter
│ │ ├── mysql.ts # MySQL adapter
│ │ └── sqlite.ts # SQLite adapter
│ └── logging/
│ └── dataset-logger.ts # Apify Dataset logger
├── Dockerfile
├── package.json
├── tsconfig.json
└── README.md故障排除
连接问题
问题:Actor无法连接到数据库
解决方案:
- 检查防火墙规则(必须允许Apify IP)
- 验证凭据是否正确
- 确保SSL设置符合您的数据库要求
- 检查数据库是否可从外部网络访问
身份验证错误
问题:401调用MCP端点时未经授权
解决方案:
- 验证Actor Input中的API密钥是否与您的客户端配置匹配
- 确保
Authorization: Bearer包含标题 - 检查API密钥中的打字错误
查询超时
问题:查询超时
解决方案:
- 增加
queryTimeout在Actor输入中 - 优化慢速查询(添加索引,减少扫描的数据)
- 考虑减少
maxRows限制
最佳实践
数据库用户权限
为MCP访问创建专用只读用户:
PostgreSQL:
CREATE USER readonly_user WITH PASSWORD 'secure_password';
GRANT CONNECT ON DATABASE myapp TO readonly_user;
GRANT USAGE ON SCHEMA public TO readonly_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_user;MySQL:
CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'secure_password';
GRANT SELECT ON myapp.* TO 'readonly_user'@'%';
FLUSH PRIVILEGES;API密钥生成
生成安全随机API密钥:
# macOS/Linux
openssl rand -base64 32
# Or use a password manager连接池
Actor自动管理连接池:
- PostgreSQL:每个数据库10个连接
- MySQL:每个数据库10个连接
- SQLite:每个文件一个连接(线程安全)
监控
健康检查
curl https://your-actor.apify.actor/退货:
{
"status": "ok",
"version": "1.0.0",
"server": "sql-databases-mcp",
"databases": {
"postgresql": ["production"],
"mysql": ["analytics"],
"sqlite": ["local"]
},
"timestamp": "2025-11-06T12:34:56.789Z"
}查询日志
通过Apify API访问日志:
curl "https://api.apify.com/v2/datasets/logs-sql-mcp/items?token=YOUR_APIFY_TOKEN&limit=100&desc=1"当前部署状态
✅ 生产就绪
SQL数据库MCP参与者是 全面运转的 并部署在Apify Standby上:
- 构建:1.0.11(最新版本)
- 状态:在Apify待机状态下全天候运行
- 连接:通过mcp-remote成功连接到Claude Desktop
- 工具:3个可用的数据库工具(db_ping、postgres_noneemployees_describe_schema、postgres.noneemployees_execute_query)
- 认证:OAuth通过Apify+可选的Bearer令牌进行本地开发
部署架构
Claude Desktop
↓ (mcp-remote with OAuth)
Apify Standby Actor
↓ (Streamable HTTP)
MCP Server (Express + MCP SDK)
↓ (Connection Pool)
PostgreSQL Database (Neon)如何使用
Actor已在Claude Desktop中配置。你可以:
- 查询数据库架构:
"Show me the database schema for neon-employees"- 执行查询:
"Query the neon-employees database and show me the first 10 rows from the employees table"- 测试连接性:
"Ping all database connections"发展历程和经验教训
初始挑战:60秒超时
问题:OAuth身份验证成功后,所有对Apify Standby Actor的MCP请求将在60秒后超时。
调查过程:
- 验证的健康检查端点工作正常(GET/)
- 已确认OAuth身份验证已成功完成
- 注意到超时具体发生在
initializeMCP请求 - 使用Codex分析请求流
根本原因: Express.js中间件 express.json() 正在消耗整个请求体流并将其存储在 req.body然而,我们的MCP传输处理程序正在调用:
await transport.handleRequest(req, res); // ❌ Missing parsed bodyMCP SDK StreamableHTTPServerTransport.handleRequest() 然后,方法尝试使用以下命令读取请求正文 getRawBody(req),但流已经被JSON中间件耗尽。这导致处理程序无限期地等待永远不会到达的数据,最终超时。
解决方案: 将已解析的正文传递给传输:
await transport.handleRequest(req, res, req.body); // ✅ Correct课程:使用消耗请求流的Express中间件时(如 express.json()),始终将解析后的正文传递给任何希望读取请求的下游处理程序。
第二个挑战:双重身份验证
问题:修复超时后,请求失败,出现401个未经授权的错误。
根本原因: 我们为本地开发实现了Bearer令牌身份验证中间件:
app.post('/mcp', auth.middleware(), mcpHandler);但是,在Apify Standby上运行时,该平台已经通过OAuth处理身份验证。我们额外的Bearer令牌检查拒绝了经过Apify验证的合法请求。
解决方案: 在Apify上运行时检测并跳过我们的自定义身份验证中间件:
const isApifyStandby = !!process.env.APIFY_IS_AT_HOME;
const mcpMiddleware = isApifyStandby ? [] : [auth.middleware()];
app.post('/mcp', ...mcpMiddleware, mcpHandler);课程:部署到具有内置身份验证的平台时,根据环境设置自定义身份验证条件。
第三个挑战:SSE流404错误
问题:成功连接并列出工具后,我们看到重复错误:
Error from remote server: StreamableHTTPError: Failed to open SSE stream: Not Found调查: 检查 Apify的官方演员mcp服务器 看看他们如何处理这个问题。
发现: MCP Streamable HTTP规范定义了两种操作模式:
- 仅POST模式:客户端通过POST发送所有请求,服务器直接响应
- Post+SSE模式:客户端通过POST发送请求,服务器可以通过GET(SSE流)推送通知
Apify的实现显式返回405 Method Not Allowed for GET/mcp:
app.get(Routes.MCP, async (_req: Request, res: Response) => {
// We don't support GET requests for this server
// The spec requires returning 405 Method Not Allowed in this case
res.status(405).set('Allow', 'POST').send('Method Not Allowed');
});解决方案: 采用了相同的方法:
app.get('/mcp', (req, res) => {
res.status(405).set('Allow', 'POST').send('Method Not Allowed');
});课程:MCP流式HTTP传输是灵活的,SSE流式传输是可选的。对于不受支持的方法返回405是向客户端指示这一点的正确方式,然后客户端将退回到仅POST模式。
第四个挑战:工具命名验证
问题:在开发早期,我们在Claude Desktop中遇到了“工具定义正则表达式模式错误”。
根本原因: 我们的工具名称使用了点:
name: "db.ping"
name: "postgres.production.describe_schema"Claude Desktop根据模式验证工具名称 ^[a-z0-9_]+$ (仅限小写字母、数字、下划线)。
解决方案: 将所有工具名称更改为使用下划线:
name: "db_ping"
name: "postgres_production_describe_schema"课程:在设计API合同时,始终检查客户端验证要求。MCP规范是灵活的,但个别客户可能有更严格的要求。
关键要点
- 流消耗:读取请求体的中间件(JSON解析器、体解析器)消耗流。始终将解析后的数据传递给下游处理程序。
- 平台身份验证:云平台通常提供身份验证。使您的自定义身份验证有条件,以避免双重身份验证问题。
- 规格灵活性:MCP Streamable HTTP规范支持仅POST和POST+SSE模式。实现您需要的内容,并使用适当的HTTP状态代码拒绝其余内容。
- 客户端验证:不同的MCP客户端可能有比规范更严格的验证。尽早与目标客户端进行测试。
- 参考实现:遇到问题时,检查官方参考实现(如Apify的actors-mcp服务器)。它们经常揭示仅从规范中不明显的最佳实践。
- 调试工具:使用以下工具
mcp-inspector和codex可以帮助识别仅从日志中无法立即发现的问题。
与Apify官方实施的比较
主要区别在于 @apify/actors mcp服务器:
| 特性 | 我们的实现 | Apify的实现 |
|---|---|---|
| 会话管理 | 无状态(每个请求的新传输) | 有状态(使用mcp会话id进行会话跟踪) |
| SSE支持 | 不支持(405) | 旧客户端使用单独的/sse端点 |
| 运输 | 单个/mcp端点(仅POST) | 多个端点(/mcp、/sse、/message) |
| 用例 | 直接数据库访问 | 优化Actor编排 |
| 认证 | 承载令牌(本地)/OAuth(Apify) | 仅限OAuth |
为什么不同? 我们的实现更简单,因为我们不需要服务器发起的通知。数据库查询仅是请求/响应。Apify的实现需要SSE来更新Actor状态和长时间运行的操作。
路线图
- \[\]用于连接管理和日志查看的Web UI
- \[\]会话管理以提高性能
- \[\]高级监控仪表板
- \[\]查询结果缓存
- \[\]支持更多数据库类型(MongoDB、Redis等)
- \[\]流式传输大型结果集
许可证
麻省理工学院
支持
对于问题和疑问:
- GitHub问题:\[您的仓库网址\]
- 细化文档:https://docs.apify.com/
- MCP规范:https://modelcontextprotocol.io/
