Postgres MCP专家DBA

一个专门的MCP服务器和Gradio UI,将您的本地LLM(通过Ollama)转变为世界级的Postgres DBA。

  • by akvdevav
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 akvdevav/postgres-mcp-server-with-chat-client

使用说明

🐘 Postgres MCP专家DBA

一个专门的MCP(模型上下文协议)服务器和Gradio UI,将您的本地LLM(通过Ollama)变成世界级的Postgres DBA。

特征

  • 模式感知:AI会自动检查您的表和索引。
  • 数据检查:执行只读查询以解决问题。
  • 性能分析:使用分析查询执行计划 EXPLAIN ANALYZE.
  • 健康监测:检查数据库大小、活动连接和长时间运行的查询。

先决条件

  1. PostgreSQL:正在运行的实例(每个用户请求的默认端口5433)。
  2. 奥拉玛:已在本地安装并运行。
  3. 模型:下载请求的型号: ollama pull gpt-oss:20b (或任何支持工具调用的模型,如 llama3.1).

设置

  1. 安装依赖项:

    pip install -r requirements.txt
    
  2. 配置环境: 编辑 .env 包含数据库凭据的文件:

    DB_PORT=5433
    DB_USER=admin
    DB_PASSWORD=password
    DB_NAME=postgres
    DB_HOST=localhost
    OLLAMA_MODEL=gpt-oss:20b
    

运行应用程序

启动Gradio界面:

python3 app.py

该应用程序将于 http://localhost:7860.

用紫外线运行

uv run --with-requirements requirements.txt  app.py

原理

  • server.py:使用实现MCP服务器 FastMCP.
  • app.py:充当MCP客户端和Gradio UI。它使用 ollama Python SDK与本地模型交互,编排对MCP服务器的工具调用。

现在,您可以提出以下问题:

  • 我的数据库现在的健康状况如何?

  • 你能列出所有数据库中的所有角色和权限吗

  • 显示我最常用的表及其模式。

  • 为什么以下查询需要这么长时间?[您的问题]

  • 根据常见查询为“users”表建议索引策略。

  • 我有什么桌子?

  • 每个表有多少行?

  • 我们是否有任何臃肿的表或性能问题?

  • 为什么以下查询需要这么长时间?[资产估值为( 选择 p.user_id, SUM(p.quantities*a.current _ price)总计_资产值 来自投资组合p 加入资产a ON p.asset_id=a.asset_id 按p.user_id分组 ), 现金平衡AS( 选择 user_id, 总和(余额)为总现金 来自账户 货币=“美元” 按用户id分组 ) 选择 u.user_id, u.full_name, u.电子邮件, COALECE(c.total_cash,0)表示total_cash_usd, COALESCE(v.total_asset_value,0)作为total_portfolio_sd, (COALENCE(c.total_cash,0)+COALESCE(v.total_asset_value,0))作为total_net_vorth 来自用户u 左加入现金平衡c ON u.user_id=c.user_id 左加入资产估值v ON u.user_id=v.user_id 其中u.kyc_status=真 按总数排序_net_vorth DESC 限制100;]

  • 你能为postgresworkshop模式中的索引提供建议吗。

Why is the following query taking so long?  [SELECT
    u.full_name,
    u.email,
    e.title,
    e.event_date,
    r.registration_date,
    -- The Correlated Subquery (will now actually execute)
    (
        SELECT COUNT(*)
        FROM registrations r2
        JOIN events e2 ON r2.event_id = e2.event_id
        WHERE r2.user_id = u.user_id
          AND e2.category = e.category
          AND r2.registration_id != r.registration_id
          AND EXTRACT(MONTH FROM r2.registration_date) = EXTRACT(MONTH FROM r.registration_date)
    ) AS similar_monthly_registrations
FROM users u
JOIN registrations r ON u.user_id = r.user_id
JOIN events e ON r.event_id = e.event_id
WHERE
    -- 1. Non-SARGable Date Math
    EXTRACT(ISODOW FROM r.registration_date) = EXTRACT(ISODOW FROM e.event_date)

    -- 2. Non-SARGable Date Differences
    AND (r.registration_date::date - u.signup_date::date) > 100

    -- 3. The FIXED String Match (Checks if the last digit of user_id is in the event title)
    AND e.title ILIKE '%' || RIGHT(u.user_id::text, 1) || '%'
ORDER BY
    -- 4. Sorting by the computed subquery
    similar_monthly_registrations DESC,
    e.event_date DESC
LIMIT 50;]# postgres-mcp-server-with-chat-client