├── tests
├── integration
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_monitoring.py
│ ├── test_sqlite_config.py
│ ├── test_sqlite.py
│ ├── test_mysql.py
│ ├── test_postgres.py
│ ├── test_logging.py
│ └── test_prompts.py
├── unit
│ ├── test_log.py
│ └── test_stats.py
└── conftest.py
├── src
└── mcp_dbutils
│ ├── mysql
│ └── __init__.py
│ ├── sqlite
│ ├── __init__.py
│ └── config.py
│ ├── postgres
│ └── __init__.py
│ ├── log.py
│ └── __init__.py
├── .pre-commit-config.yaml
├── scripts
├── fix_remaining_issues.sh
├── fix_imports.sh
├── fix_zh_nav_links.py
├── sonar-ai-fix.fish
├── fix_en_nav_links.py
├── check_zh_docs.py
└── run_sonar_analysis.sh
├── .coveragerc
├── .github
├── workflows
│ ├── code-style.yml
│ ├── issue-translator.yml
│ └── release.yml
└── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── documentation_improvement_zh.md
│ ├── feature_request_zh.md
│ ├── documentation_improvement_ar.md
│ ├── feature_request_ar.md
│ ├── documentation_improvement_en.md
│ ├── documentation_improvement_ru.md
│ ├── documentation_improvement_es.md
│ ├── documentation_improvement_fr.md
│ ├── feature_request_en.md
│ ├── feature_request_ru.md
│ ├── security_vulnerability_zh.md
│ ├── feature_request_es.md
│ ├── feature_request_fr.md
│ ├── bug_report_zh.md
│ ├── performance_issue_zh.md
│ ├── security_vulnerability_ar.md
│ ├── bug_report_ar.md
│ ├── security_vulnerability_en.md
│ ├── security_vulnerability_ru.md
│ ├── bug_report_en.md
│ ├── performance_issue_ar.md
│ ├── bug_report_ru.md
│ ├── security_vulnerability_es.md
│ ├── security_vulnerability_fr.md
│ ├── performance_issue_en.md
│ ├── bug_report_es.md
│ ├── bug_report_fr.md
│ ├── performance_issue_es.md
│ ├── performance_issue_ru.md
│ └── performance_issue_fr.md
├── sonar-project.properties
├── Dockerfile
├── .gitignore
├── smithery.yaml
├── .releaserc.json
├── LICENSE
├── docs
├── index.md
├── ar
│ └── examples
│ │ ├── README.md
│ │ └── sqlite-examples.md
├── ru
│ └── examples
│ │ ├── README.md
│ │ └── sqlite-examples.md
├── es
│ └── examples
│ │ ├── README.md
│ │ └── sqlite-examples.md
├── fr
│ └── examples
│ │ ├── README.md
│ │ └── sqlite-examples.md
├── document-version-history.md
├── document-consistency-check.md
├── zh
│ ├── technical
│ │ ├── sonarcloud-integration.md
│ │ ├── testing.md
│ │ ├── architecture.md
│ │ ├── development.md
│ │ └── write-operations-design.md
│ ├── examples
│ │ └── sqlite-examples.md
│ ├── installation-platform-specific.md
│ └── configuration-write-operations.md
├── write-operations.md
└── en
│ ├── technical
│ ├── testing.md
│ └── sonarcloud-integration.md
│ └── examples
│ └── sqlite-examples.md
├── examples
└── config.yaml
├── config.yaml.example
├── pyproject.toml
└── README.md
/tests/integration/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/mcp_dbutils/mysql/__init__.py:
--------------------------------------------------------------------------------
1 | """MySQL module"""
2 |
3 | from .config import MySQLConfig
4 | from .handler import MySQLHandler
5 |
6 | __all__ = ['MySQLHandler', 'MySQLConfig']
7 |
--------------------------------------------------------------------------------
/src/mcp_dbutils/sqlite/__init__.py:
--------------------------------------------------------------------------------
1 | """SQLite module"""
2 |
3 | from .config import SQLiteConfig
4 | from .handler import SQLiteHandler
5 |
6 | __all__ = ['SQLiteHandler', 'SQLiteConfig']
7 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/astral-sh/ruff-pre-commit
3 | rev: v0.3.0
4 | hooks:
5 | - id: ruff
6 | args: [--fix]
7 | - id: ruff-format
8 |
--------------------------------------------------------------------------------
/src/mcp_dbutils/postgres/__init__.py:
--------------------------------------------------------------------------------
1 | """PostgreSQL module"""
2 |
3 | from .config import PostgreSQLConfig
4 | from .handler import PostgreSQLHandler
5 |
6 | __all__ = ['PostgreSQLHandler', 'PostgreSQLConfig']
7 |
--------------------------------------------------------------------------------
/scripts/fix_remaining_issues.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # 修复导入排序问题 (I001)
4 | echo "修复导入排序问题 (I001)..."
5 | ruff check --select I --fix src/ tests/
6 |
7 | # 修复print语句 (T201)
8 | echo "修复print语句 (T201)..."
9 | ruff check --select T201 --fix src/ tests/
10 |
11 | echo "剩余问题修复完成!"
12 |
--------------------------------------------------------------------------------
/tests/integration/conftest.py:
--------------------------------------------------------------------------------
1 | """Test fixtures and utility functions for pytest"""
2 |
3 |
4 | from .fixtures import TestConnectionHandler, mcp_config, mysql_db
5 |
6 | # Register fixtures
7 | mysql_db = mysql_db
8 | mcp_config = mcp_config
9 | TestConnectionHandler = TestConnectionHandler
10 |
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | source = src/mcp_dbutils
3 | omit =
4 | tests/*
5 | **/__init__.py
6 |
7 | [report]
8 | exclude_lines =
9 | pragma: no cover
10 | def __repr__
11 | raise NotImplementedError
12 | if __name__ == .__main__.:
13 | pass
14 | raise ImportError
15 |
16 | [html]
17 | directory = coverage_html
18 |
--------------------------------------------------------------------------------
/.github/workflows/code-style.yml:
--------------------------------------------------------------------------------
1 | name: Code Style
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | ruff:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 |
15 | - uses: astral-sh/ruff-action@v3.2.1
16 | with:
17 | version: latest
18 |
--------------------------------------------------------------------------------
/scripts/fix_imports.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # 修复导入排序问题 (I001)
4 | echo "修复导入排序问题 (I001)..."
5 | ruff check --select I --fix src/ tests/
6 |
7 | # 修复未使用的导入 (F401)
8 | echo "修复未使用的导入 (F401)..."
9 | ruff check --select F401 --fix src/ tests/
10 |
11 | # 修复过时的typing导入 (UP035)
12 | echo "修复过时的typing导入 (UP035)..."
13 | ruff check --select UP035 --fix src/ tests/
14 |
15 | echo "导入问题修复完成!"
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: MCP Database Utilities Discussions
4 | url: https://github.com/donghao1393/mcp-dbutils/discussions
5 | about: Please ask and answer questions here.
6 | - name: MCP Database Utilities Documentation
7 | url: https://github.com/donghao1393/mcp-dbutils/tree/main/docs
8 | about: Check the documentation for usage information.
9 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.organization=donghao1393
2 | sonar.projectKey=donghao1393_mcp-dbutils
3 | sonar.sources=src/mcp_dbutils
4 | sonar.tests=tests
5 | sonar.python.coverage.reportPaths=coverage.xml
6 | sonar.python.version=3.10
7 |
8 | # PR Analysis Configuration
9 | sonar.pullrequest.provider=github
10 | sonar.pullrequest.github.repository=donghao1393/mcp-dbutils
11 | sonar.pullrequest.github.endpoint=https://api.github.com/
12 |
13 | # Quality Gate Settings
14 | sonar.qualitygate.wait=true
15 |
--------------------------------------------------------------------------------
/.github/workflows/issue-translator.yml:
--------------------------------------------------------------------------------
1 | name: 'issue-translator'
2 | on:
3 | issue_comment:
4 | types: [created]
5 | issues:
6 | types: [opened]
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: usthe/issues-translate-action@v2.7
13 | with:
14 | IS_MODIFY_TITLE: false
15 | CUSTOM_BOT_NOTE: Bot检测到issue内容不是英文,自动翻译如下。Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
16 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
2 | # Use a base Python image
3 | FROM python:3.10-slim AS base
4 |
5 | # Set the working directory in the container
6 | WORKDIR /app
7 |
8 | # Copy the project file
9 | COPY pyproject.toml README.md src /app/
10 |
11 | # Install dependencies and the package
12 | RUN pip install hatchling && \
13 | hatchling build && \
14 | pip install dist/*.whl
15 |
16 | # Set the entry point to run the server
17 | ENTRYPOINT ["mcp-dbutils", "--config", "/app/config.yaml"]
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Python
2 | docs/local/
3 | __pycache__/
4 | *.py[cod]
5 | *$py.class
6 | *.so
7 | .Python
8 | build/
9 | .coverage
10 | coverage_html/
11 | develop-eggs/
12 | dist/
13 | downloads/
14 | eggs/
15 | .eggs/
16 | lib/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | wheels/
22 | share/python-wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 | uv.lock
28 |
29 | # Virtual Environment
30 | .env
31 | .venv
32 | env/
33 | venv/
34 | ENV/
35 | .python-version
36 |
37 | # IDE
38 | .idea/
39 | .vscode/
40 | *.swp
41 | *.swo
42 | memory-bank/
43 |
44 | # OS
45 | .DS_Store
46 | Thumbs.db
47 |
--------------------------------------------------------------------------------
/src/mcp_dbutils/log.py:
--------------------------------------------------------------------------------
1 | """日志处理模块"""
2 |
3 | import sys
4 | from collections.abc import Callable
5 | from datetime import datetime
6 |
7 |
8 | def create_logger(name: str, is_debug: bool = False) -> Callable:
9 | """创建stderr日志函数,用于本地调试
10 | Args:
11 | name: 服务名称
12 | is_debug: 是否输出debug级别日志
13 | """
14 | def log(level: str, message: str):
15 | """输出日志到stderr
16 | Args:
17 | level: 日志级别 (debug/info/warning/error)
18 | message: 日志内容
19 | """
20 | if level == "debug" and not is_debug:
21 | return
22 |
23 | timestamp = datetime.now().astimezone().isoformat(timespec='milliseconds')
24 | log_message = f"{timestamp} [{name}] [{level}] {message}"
25 |
26 | # 输出到stderr
27 | print(log_message, file=sys.stderr, flush=True)
28 |
29 | return log
30 |
--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------
1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
2 |
3 | startCommand:
4 | type: stdio
5 | configSchema:
6 | # JSON Schema defining the configuration options for the MCP.
7 | type: object
8 | required:
9 | - configPath
10 | properties:
11 | configPath:
12 | type: string
13 | description: The path to the YAML configuration file for database settings.
14 | debugMode:
15 | type: boolean
16 | default: false
17 | description: "Optional: Enable debug mode for detailed logging."
18 | commandFunction:
19 | # A function that produces the CLI command to start the MCP on stdio.
20 | |-
21 | (config) => ({ command: 'docker', args: ['run', '-i', '--rm', '-v', `${config.configPath}:/app/config.yaml`, 'mcp/dbutils', '--config', '/app/config.yaml'], env: { MCP_DEBUG: config.debugMode ? '1' : '0' } })
22 |
--------------------------------------------------------------------------------
/.releaserc.json:
--------------------------------------------------------------------------------
1 | {
2 | "branches": ["main"],
3 | "plugins": [
4 | "@semantic-release/commit-analyzer",
5 | "@semantic-release/release-notes-generator",
6 | "@semantic-release/changelog",
7 | ["@semantic-release/exec", {
8 | "verifyConditionsCmd": "uv --version",
9 | "prepareCmd": "sed -i.bak '0,/version = \".*\"/s//version = \"${nextRelease.version}\"/' pyproject.toml && rm -f pyproject.toml.bak",
10 | "publishCmd": "uv build"
11 | }],
12 | ["@semantic-release/git", {
13 | "assets": [
14 | "pyproject.toml",
15 | "CHANGELOG.md"
16 | ],
17 | "message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
18 | }],
19 | ["@semantic-release/github", {
20 | "assets": [
21 | {"path": "dist/*.whl", "label": "Python Wheel ${nextRelease.version}"},
22 | {"path": "dist/*.tar.gz", "label": "Source Distribution ${nextRelease.version}"}
23 | ]
24 | }]
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation_improvement_zh.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 文档改进
3 | about: 提出文档改进建议
4 | title: "[Docs] "
5 | labels: documentation
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## 文档问题
20 |
21 |
22 | ## 文档位置
23 |
24 |
25 | ## 建议的改进
26 |
27 |
28 | ## 附加信息
29 |
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request_zh.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 功能请求
3 | about: 为这个项目提出一个想法
4 | title: "[Feature] "
5 | labels: enhancement
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## 需求描述
20 |
21 |
22 | ## 解决方案描述
23 |
24 |
25 | ## 替代方案
26 |
27 |
28 | ## 使用场景
29 |
30 |
31 | ## 附加信息
32 |
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Dong Hao
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation_improvement_ar.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: تحسين الوثائق
3 | about: اقتراح تحسينات للوثائق
4 | title: "[Docs] "
5 | labels: documentation
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 |
20 |
21 | ## مشكلة التوثيق
22 |
23 |
24 | ## موقع الوثائق
25 |
26 |
27 | ## التحسين المقترح
28 |
29 |
30 | ## معلومات إضافية
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request_ar.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: طلب ميزة
3 | about: اقتراح فكرة لهذا المشروع
4 | title: "[Feature] "
5 | labels: enhancement
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 |
20 |
21 | ## بيان المشكلة
22 |
23 |
24 | ## الحل المقترح
25 |
26 |
27 | ## البدائل المدروسة
28 |
29 |
30 | ## حالة الاستخدام
31 |
32 |
33 | ## معلومات إضافية
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation_improvement_en.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Documentation Improvement
3 | about: Suggest improvements to the documentation
4 | title: "[Docs] "
5 | labels: documentation
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Documentation Issue
20 |
21 |
22 | ## Documentation Location
23 |
24 |
25 | ## Suggested Improvement
26 |
27 |
28 | ## Additional Information
29 |
30 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # MCP Database Utilities Documentation
2 |
3 | Welcome to the MCP Database Utilities documentation. Please select your preferred language:
4 |
5 | ## Available Languages
6 |
7 | - [English](en/installation.md)
8 | - [中文 (Chinese)](zh/installation.md)
9 | - [Français (French)](fr/installation.md)
10 | - [Español (Spanish)](es/installation.md)
11 | - [العربية (Arabic)](ar/installation.md)
12 | - [Русский (Russian)](ru/installation.md)
13 |
14 | ## About MCP Database Utilities
15 |
16 | MCP Database Utilities is a tool that enables AI assistants to safely access and analyze your databases. It supports SQLite, PostgreSQL, and MySQL databases, providing a secure way for AI to help you with data analysis without modifying your data.
17 |
18 | ## Key Features
19 |
20 | - **Read-only Access**: Ensures your data remains safe
21 | - **Multiple Database Support**: Works with SQLite, PostgreSQL, and MySQL
22 | - **Easy Configuration**: Simple YAML configuration file
23 | - **Secure Connections**: Supports SSL/TLS for secure database connections
24 | - **AI Integration**: Seamlessly works with MCP-compatible AI assistants
25 |
26 | ## Getting Started
27 |
28 | Select your preferred language above to access the installation guide and get started with MCP Database Utilities.
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation_improvement_ru.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Улучшение документации
3 | about: Предложить улучшения документации
4 | title: "[Docs] "
5 | labels: documentation
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Проблема с документацией
20 |
21 |
22 | ## Расположение документации
23 |
24 |
25 | ## Предлагаемое улучшение
26 |
27 |
28 | ## Дополнительная информация
29 |
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation_improvement_es.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Mejora de Documentación
3 | about: Sugerir mejoras a la documentación
4 | title: "[Docs] "
5 | labels: documentation
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Problema de Documentación
20 |
21 |
22 | ## Ubicación de la Documentación
23 |
24 |
25 | ## Mejora Sugerida
26 |
27 |
28 | ## Información Adicional
29 |
30 |
--------------------------------------------------------------------------------
/docs/ar/examples/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # وثائق MCP Database Utilities
4 |
5 | *[English](../../en/installation.md) | [中文](../../zh/installation.md) | [Français](../../fr/installation.md) | [Español](../../es/installation.md) | العربية | [Русский](../../ru/installation.md)*
6 |
7 | ## مرحبًا بك في الوثائق العربية
8 |
9 | مرحبًا بك في وثائق MCP Database Utilities باللغة العربية. ستساعدك هذه الوثائق على استخدام MCP Database Utilities للوصول إلى قواعد البيانات الخاصة بك وتحليلها بأمان باستخدام مساعدي الذكاء الاصطناعي.
10 |
11 | ## الأدلة الرئيسية
12 |
13 | - [دليل التثبيت](../installation.md) - تعليمات مفصلة لتثبيت وتكوين MCP Database Utilities
14 | - [دليل التكوين](../configuration.md) - أمثلة التكوين وأفضل الممارسات
15 | - [دليل الاستخدام](../usage.md) - سير العمل الأساسي وسيناريوهات الاستخدام الشائعة
16 |
17 | ## أمثلة حسب نوع قاعدة البيانات
18 |
19 | - [أمثلة SQLite](sqlite-examples.md) - أمثلة عملية للعمل مع قواعد بيانات SQLite
20 |
21 | ## الميزات الرئيسية
22 |
23 | - **وصول للقراءة فقط**: يضمن بقاء بياناتك آمنة
24 | - **دعم قواعد بيانات متعددة**: يعمل مع SQLite وPostgreSQL وMySQL
25 | - **تكوين سهل**: ملف تكوين YAML بسيط
26 | - **اتصالات آمنة**: يدعم SSL/TLS للاتصالات الآمنة بقواعد البيانات
27 | - **تكامل مع الذكاء الاصطناعي**: يعمل بسلاسة مع مساعدي الذكاء الاصطناعي المتوافقين مع MCP
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation_improvement_fr.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Amélioration de la Documentation
3 | about: Suggérer des améliorations à la documentation
4 | title: "[Docs] "
5 | labels: documentation
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Problème de Documentation
20 |
21 |
22 | ## Emplacement de la Documentation
23 |
24 |
25 | ## Amélioration Suggérée
26 |
27 |
28 | ## Informations Supplémentaires
29 |
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request_en.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Suggest an idea for this project
4 | title: "[Feature] "
5 | labels: enhancement
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Problem Statement
20 |
21 |
22 | ## Proposed Solution
23 |
24 |
25 | ## Alternatives Considered
26 |
27 |
28 | ## Use Case
29 |
30 |
31 | ## Additional Information
32 |
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request_ru.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Запрос функции
3 | about: Предложите идею для этого проекта
4 | title: "[Feature] "
5 | labels: enhancement
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Описание проблемы
20 |
21 |
22 | ## Предлагаемое решение
23 |
24 |
25 | ## Рассмотренные альтернативы
26 |
27 |
28 | ## Сценарий использования
29 |
30 |
31 | ## Дополнительная информация
32 |
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/security_vulnerability_zh.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 安全漏洞报告
3 | about: 报告安全相关的问题
4 | title: "[Security] "
5 | labels: security
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## 安全漏洞描述
20 |
21 |
22 | ## 漏洞类型
23 |
24 |
25 | ## 影响范围
26 |
27 |
28 | ## 复现步骤
29 |
30 | 1. 前往 '...'
31 | 2. 输入 '....'
32 | 3. 执行 '....'
33 | 4. 观察漏洞
34 |
35 | ## 建议的修复方案
36 |
37 |
38 | ## 环境信息
39 |
40 | - MCP数据库工具版本: [例如: 0.19.0]
41 | - 操作系统: [例如: Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Python版本: [例如: 3.10.5]
43 | - 数据库类型和版本: [例如: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 |
45 | ## 附加信息
46 |
47 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request_es.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Solicitud de Función
3 | about: Sugerir una idea para este proyecto
4 | title: "[Feature] "
5 | labels: enhancement
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Declaración del problema
20 |
21 |
22 | ## Solución propuesta
23 |
24 |
25 | ## Alternativas consideradas
26 |
27 |
28 | ## Caso de uso
29 |
30 |
31 | ## Información adicional
32 |
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request_fr.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Demande de Fonctionnalité
3 | about: Suggérer une idée pour ce projet
4 | title: "[Feature] "
5 | labels: enhancement
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Énoncé du problème
20 |
21 |
22 | ## Solution proposée
23 |
24 |
25 | ## Alternatives envisagées
26 |
27 |
28 | ## Cas d'utilisation
29 |
30 |
31 | ## Informations supplémentaires
32 |
33 |
--------------------------------------------------------------------------------
/docs/ru/examples/README.md:
--------------------------------------------------------------------------------
1 | # Документация MCP Database Utilities
2 |
3 | *[English](../../en/installation.md) | [中文](../../zh/installation.md) | [Français](../../fr/installation.md) | [Español](../../es/installation.md) | [العربية](../../ar/installation.md) | Русский*
4 |
5 | ## Добро пожаловать в русскую документацию
6 |
7 | Добро пожаловать в документацию MCP Database Utilities на русском языке. Эта документация поможет вам использовать MCP Database Utilities для безопасного доступа и анализа ваших баз данных с помощью ИИ-ассистентов.
8 |
9 | ## Основные руководства
10 |
11 | - [Руководство по установке](../installation.md) - Подробные инструкции по установке и настройке MCP Database Utilities
12 | - [Руководство по конфигурации](../configuration.md) - Примеры конфигурации и лучшие практики
13 | - [Руководство по использованию](../usage.md) - Основной рабочий процесс и распространенные сценарии использования
14 |
15 | ## Примеры по типу базы данных
16 |
17 | - [Примеры SQLite](sqlite-examples.md) - Практические примеры работы с базами данных SQLite
18 |
19 | ## Основные возможности
20 |
21 | - **Доступ только для чтения**: Гарантирует безопасность ваших данных
22 | - **Поддержка нескольких баз данных**: Работает с SQLite, PostgreSQL и MySQL
23 | - **Простая настройка**: Простой файл конфигурации YAML
24 | - **Безопасные соединения**: Поддержка SSL/TLS для безопасных соединений с базами данных
25 | - **Интеграция с ИИ**: Легко работает с ИИ-ассистентами, совместимыми с MCP
26 |
--------------------------------------------------------------------------------
/docs/es/examples/README.md:
--------------------------------------------------------------------------------
1 | # Documentación de MCP Database Utilities
2 |
3 | *[English](../../en/installation.md) | [中文](../../zh/installation.md) | [Français](../../fr/installation.md) | Español | [العربية](../../ar/installation.md) | [Русский](../../ru/installation.md)*
4 |
5 | ## Bienvenido a la Documentación en Español
6 |
7 | Bienvenido a la documentación en español de MCP Database Utilities. Esta documentación le ayudará a utilizar MCP Database Utilities para acceder y analizar sus bases de datos de manera segura con asistentes de IA.
8 |
9 | ## Guías Principales
10 |
11 | - [Guía de Instalación](../installation.md) - Instrucciones detalladas para instalar y configurar MCP Database Utilities
12 | - [Guía de Configuración](../configuration.md) - Ejemplos de configuración y mejores prácticas
13 | - [Guía de Uso](../usage.md) - Flujo de trabajo básico y escenarios de uso comunes
14 |
15 | ## Ejemplos por Tipo de Base de Datos
16 |
17 | - [Ejemplos de SQLite](sqlite-examples.md) - Ejemplos prácticos para trabajar con bases de datos SQLite
18 |
19 | ## Características principales
20 |
21 | - **Acceso de solo lectura**: Garantiza que sus datos permanezcan seguros
22 | - **Soporte para múltiples bases de datos**: Funciona con SQLite, PostgreSQL y MySQL
23 | - **Configuración sencilla**: Archivo de configuración YAML simple
24 | - **Conexiones seguras**: Admite SSL/TLS para conexiones seguras a bases de datos
25 | - **Integración con IA**: Funciona perfectamente con asistentes de IA compatibles con MCP
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report_zh.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug报告
3 | about: 创建一个报告来帮助我们改进
4 | title: "[Bug] "
5 | labels: bug
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## 问题描述
20 |
21 |
22 | ## 复现步骤
23 |
24 | 1. 前往 '...'
25 | 2. 点击 '....'
26 | 3. 滚动到 '....'
27 | 4. 看到错误
28 |
29 | ## 预期行为
30 |
31 |
32 | ## 实际行为
33 |
34 |
35 | ## 截图
36 |
37 |
38 | ## 环境信息
39 |
40 | - MCP数据库工具版本: [例如: 0.19.0]
41 | - 操作系统: [例如: Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Python版本: [例如: 3.10.5]
43 | - 数据库类型和版本: [例如: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 | - 使用的MCP客户端: [例如: Claude Desktop, VS Code, Cursor]
45 |
46 | ## 配置文件
47 |
48 | ```yaml
49 | connections:
50 | example_connection:
51 | type: sqlite
52 | path: ":memory:"
53 | ```
54 |
55 | ## 附加信息
56 |
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/performance_issue_zh.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 性能问题
3 | about: 报告性能相关的问题
4 | title: "[Performance] "
5 | labels: performance
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## 性能问题描述
20 |
21 |
22 | ## 复现步骤
23 |
24 | 1. 前往 '...'
25 | 2. 执行 '....'
26 | 3. 观察性能问题
27 |
28 | ## 性能数据
29 |
30 |
31 | ## 预期性能
32 |
33 |
34 | ## 环境信息
35 |
36 | - MCP数据库工具版本: [例如: 0.19.0]
37 | - 操作系统: [例如: Windows 10, macOS 12.0, Ubuntu 22.04]
38 | - Python版本: [例如: 3.10.5]
39 | - 数据库类型和版本: [例如: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
40 | - 使用的MCP客户端: [例如: Claude Desktop, VS Code, Cursor]
41 | - 硬件规格: [例如: CPU型号, 内存大小, 磁盘类型]
42 |
43 | ## 配置文件
44 |
45 | ```yaml
46 | connections:
47 | example_connection:
48 | type: sqlite
49 | path: ":memory:"
50 | ```
51 |
52 | ## 附加信息
53 |
54 |
--------------------------------------------------------------------------------
/docs/fr/examples/README.md:
--------------------------------------------------------------------------------
1 | # Documentation MCP Database Utilities
2 |
3 | *[English](../../en/installation.md) | [中文](../../zh/installation.md) | Français | [Español](../../es/installation.md) | [العربية](../../ar/installation.md) | [Русский](../../ru/installation.md)*
4 |
5 | ## Bienvenue dans la documentation française
6 |
7 | Bienvenue dans la documentation française de MCP Database Utilities. Cette documentation vous aidera à utiliser MCP Database Utilities pour accéder et analyser vos bases de données en toute sécurité avec des assistants IA.
8 |
9 | ## Guides principaux
10 |
11 | - [Guide d'installation](../installation.md) - Instructions détaillées pour installer et configurer MCP Database Utilities
12 | - [Guide de configuration](../configuration.md) - Exemples de configuration et meilleures pratiques
13 | - [Guide d'utilisation](../usage.md) - Flux de travail de base et scénarios d'utilisation courants
14 |
15 | ## Exemples par type de base de données
16 |
17 | - [Exemples SQLite](sqlite-examples.md) - Exemples pratiques pour travailler avec des bases de données SQLite
18 |
19 | ## Caractéristiques principales
20 |
21 | - **Accès en lecture seule**: Garantit que vos données restent sécurisées
22 | - **Support de plusieurs bases de données**: Fonctionne avec SQLite, PostgreSQL et MySQL
23 | - **Configuration simple**: Fichier de configuration YAML simple
24 | - **Connexions sécurisées**: Prend en charge SSL/TLS pour des connexions sécurisées aux bases de données
25 | - **Intégration avec l'IA**: Fonctionne parfaitement avec les assistants IA compatibles MCP
26 |
--------------------------------------------------------------------------------
/docs/document-version-history.md:
--------------------------------------------------------------------------------
1 | # 文档版本历史
2 |
3 | 本文件记录了 MCP 数据库工具文档的版本历史和重要更新。
4 |
5 | ## 版本命名规则
6 |
7 | 文档版本使用以下格式:`vX.Y.Z`,其中:
8 |
9 | - `X`:主版本号,表示重大结构或内容变更
10 | - `Y`:次版本号,表示功能添加或重要内容更新
11 | - `Z`:修订版本号,表示错误修复或小幅内容改进
12 |
13 | ## 版本历史
14 |
15 | ### v1.0.0 (2024-04-24)
16 |
17 | **主要更新**:
18 | - 完成文档重组,按照语言(中英文)和文档类型进行分类
19 | - 创建了详细的 PostgreSQL 和 MySQL 示例文档
20 | - 整合 STYLE_GUIDE.md 到开发指南中
21 | - 将 technical-guide.md 的内容分解到各个技术文档中
22 | - 处理 SonarCloud 集成文档,创建中英文版本
23 | - 更新 README 中的文档链接
24 |
25 | **新增文档**:
26 | - docs/zh/examples/postgresql-examples.md
27 | - docs/zh/examples/mysql-examples.md
28 | - docs/en/examples/postgresql-examples.md
29 | - docs/en/examples/mysql-examples.md
30 | - docs/zh/technical/sonarcloud-integration.md
31 | - docs/en/technical/sonarcloud-integration.md
32 |
33 | **删除文档**:
34 | - docs/STYLE_GUIDE.md
35 | - docs/technical-guide.md
36 | - docs/configuration-examples.md
37 | - docs/sonarcloud-ai-integration.md
38 |
39 | ### v1.1.0 (2024-04-25)
40 |
41 | **主要更新**:
42 | - 添加平台特定安装指南,针对不同操作系统提供详细安装说明
43 | - 创建高级 LLM 交互示例文档,展示与各类 LLM 的交互潜力
44 | - 进行文档一致性检查,确保所有文档符合统一标准
45 | - 实施文档版本控制,添加版本信息和更新历史
46 | - 更新 README 中的文档链接
47 |
48 | **新增文档**:
49 | - docs/zh/installation-platform-specific.md
50 | - docs/en/installation-platform-specific.md
51 | - docs/zh/examples/advanced-llm-interactions.md
52 | - docs/en/examples/advanced-llm-interactions.md
53 | - docs/document-consistency-check.md
54 | - docs/document-version-history.md
55 |
56 | ## 文档维护指南
57 |
58 | ### 更新文档版本
59 |
60 | 当对文档进行更新时,请遵循以下步骤:
61 |
62 | 1. 确定更新的性质(主要结构变更、功能添加或错误修复)
63 | 2. 根据更新性质,增加相应的版本号
64 | 3. 在本文件中添加新版本的条目,记录主要更新内容和变更的文件
65 | 4. 在更新的文档顶部更新版本号和最后更新日期
66 |
67 | ### 文档版本与软件版本的关系
68 |
69 | 文档版本与软件版本保持独立,但应在文档中明确说明其适用的软件版本范围。当软件发布新版本时,应相应地更新文档,并在版本历史中注明。
70 |
--------------------------------------------------------------------------------
/examples/config.yaml:
--------------------------------------------------------------------------------
1 | # MCP-DBUtils 配置文件示例
2 | # 此文件定义了数据库连接和相关配置
3 |
4 | # 审计日志配置
5 | audit:
6 | enabled: true
7 | file_storage:
8 | enabled: true
9 | path: "logs/audit"
10 | max_file_size: 10485760 # 10MB
11 | backup_count: 10
12 | memory_buffer:
13 | size: 1000 # 内存中保存的最近日志记录数量
14 | content:
15 | sanitize_sql: true # 是否对SQL语句进行脱敏处理
16 | include_user_context: true # 是否包含用户上下文信息
17 |
18 | # 数据库连接配置
19 | connections:
20 | # SQLite 示例
21 | sqlite_example:
22 | type: sqlite
23 | path: "examples/data/example.db"
24 | # 写操作配置(默认只读)
25 | writable: true
26 | # 细粒度写权限控制
27 | write_permissions:
28 | # 默认策略:read_only 或 allow_all
29 | default_policy: "read_only"
30 | # 表级权限
31 | tables:
32 | users:
33 | # 允许的操作类型
34 | operations: ["INSERT", "UPDATE"]
35 | logs:
36 | operations: ["INSERT", "UPDATE", "DELETE"]
37 |
38 | # MySQL 示例
39 | mysql_example:
40 | type: mysql
41 | host: localhost
42 | port: 3306
43 | database: example_db
44 | user: example_user
45 | password: example_password
46 | # 连接超时设置(秒)
47 | connection_timeout: 10
48 | # 查询超时设置(秒)
49 | query_timeout: 30
50 | # 空闲超时设置(秒)
51 | idle_timeout: 600
52 | # 写操作配置(默认只读)
53 | writable: false
54 |
55 | # PostgreSQL 示例
56 | postgres_example:
57 | type: postgres
58 | host: localhost
59 | port: 5432
60 | database: example_db
61 | user: example_user
62 | password: example_password
63 | # SSL配置
64 | ssl:
65 | enabled: true
66 | mode: require
67 | # 写操作配置
68 | writable: true
69 | # 细粒度写权限控制
70 | write_permissions:
71 | # 默认策略
72 | default_policy: "allow_all"
73 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/security_vulnerability_ar.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: تقرير ثغرة أمنية
3 | about: الإبلاغ عن مشاكل متعلقة بالأمان
4 | title: "[Security] "
5 | labels: security
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 |
20 |
21 | ## وصف الثغرة الأمنية
22 |
23 |
24 | ## نوع الثغرة
25 |
26 |
27 | ## التأثير
28 |
29 |
30 | ## خطوات إعادة الإنتاج
31 |
32 | 1. اذهب إلى '...'
33 | 2. أدخل '....'
34 | 3. نفذ '....'
35 | 4. لاحظ الثغرة
36 |
37 | ## الإصلاح المقترح
38 |
39 |
40 | ## البيئة
41 |
42 | - إصدار MCP Database Utilities: [مثال: 0.19.0]
43 | - نظام التشغيل: [مثال: Windows 10, macOS 12.0, Ubuntu 22.04]
44 | - إصدار Python: [مثال: 3.10.5]
45 | - نوع وإصدار قاعدة البيانات: [مثال: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
46 |
47 | ## معلومات إضافية
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/scripts/fix_zh_nav_links.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | 修复中文文档中的语言导航链接
4 |
5 | 用途:将中文文档中的语言导航链接中的"[中文]"修改为纯文本"中文"
6 | """
7 |
8 | import os
9 | import re
10 | from pathlib import Path
11 |
12 |
13 | def fix_zh_nav_links(docs_root: Path) -> int:
14 | """修复中文文档中的语言导航链接"""
15 | fixed_count = 0
16 | zh_dir = docs_root / "zh"
17 |
18 | if not zh_dir.exists():
19 | print("错误: 中文文档目录不存在")
20 | return 0
21 |
22 | # 递归查找所有中文markdown文件
23 | for md_file in zh_dir.glob("**/*.md"):
24 | with open(md_file, 'r', encoding='utf-8') as f:
25 | content = f.read()
26 |
27 | # 查找语言导航链接
28 | nav_line_match = re.search(r'\*\[(.*?)\](.*?)\s*\|\s*(.*?)\*', content)
29 | if nav_line_match:
30 | nav_line = nav_line_match.group(0)
31 |
32 | # 检查是否需要修复
33 | if "[中文]" in nav_line:
34 | # 替换 [中文](链接) 为 中文
35 | fixed_nav_line = re.sub(r'\[中文\]\([^)]*\)', '中文', nav_line)
36 |
37 | # 更新文件内容
38 | new_content = content.replace(nav_line, fixed_nav_line)
39 |
40 | with open(md_file, 'w', encoding='utf-8') as f:
41 | f.write(new_content)
42 |
43 | print(f"已修复: {md_file}")
44 | fixed_count += 1
45 |
46 | return fixed_count
47 |
48 | def main():
49 | docs_root = Path("docs")
50 | if not docs_root.exists():
51 | print("错误: 'docs' 目录不存在")
52 | return
53 |
54 | print("开始修复中文文档中的语言导航链接...\n")
55 |
56 | fixed_count = fix_zh_nav_links(docs_root)
57 |
58 | print(f"\n完成! 已修复 {fixed_count} 个文件。")
59 |
60 | if __name__ == "__main__":
61 | main()
62 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 |
7 | jobs:
8 | release:
9 | runs-on: ubuntu-latest
10 | concurrency: release
11 | environment:
12 | name: pypi
13 | url: https://pypi.org/p/mcp-dbutils
14 | permissions:
15 | id-token: write
16 | contents: write
17 | issues: write
18 | pull-requests: write
19 |
20 | steps:
21 | - uses: actions/checkout@v4
22 | with:
23 | fetch-depth: 0
24 |
25 | - name: Set up Python
26 | uses: actions/setup-python@v4
27 | with:
28 | python-version: '3.10'
29 |
30 | - name: Install uv
31 | run: |
32 | curl -LsSf https://astral.sh/uv/install.sh | sh
33 | echo "$HOME/.cargo/bin" >> $GITHUB_PATH
34 |
35 | - name: Setup Node.js
36 | uses: actions/setup-node@v4
37 | with:
38 | node-version: 'lts/*'
39 |
40 | - name: Install semantic-release
41 | run: |
42 | npm install -g semantic-release @semantic-release/git @semantic-release/changelog @semantic-release/exec
43 |
44 | - name: Release
45 | id: semantic-release
46 | env:
47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48 | run: npx semantic-release
49 |
50 | - name: Check if dist directory exists
51 | id: check_dist
52 | run: |
53 | if [ -d "dist" ] && [ "$(ls -A dist)" ]; then
54 | echo "dist_exists=true" >> $GITHUB_OUTPUT
55 | else
56 | echo "dist_exists=false" >> $GITHUB_OUTPUT
57 | echo "No distribution packages found in dist/ directory. Skipping PyPI publish."
58 | fi
59 |
60 | - name: Publish to PyPI
61 | if: steps.check_dist.outputs.dist_exists == 'true'
62 | uses: pypa/gh-action-pypi-publish@release/v1
63 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report_ar.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: تقرير خطأ
3 | about: إنشاء تقرير لمساعدتنا على التحسين
4 | title: "[Bug] "
5 | labels: bug
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 |
20 |
21 | ## الوصف
22 |
23 |
24 | ## خطوات إعادة الإنتاج
25 |
26 | 1. اذهب إلى '...'
27 | 2. انقر على '....'
28 | 3. قم بالتمرير لأسفل إلى '....'
29 | 4. شاهد الخطأ
30 |
31 | ## السلوك المتوقع
32 |
33 |
34 | ## السلوك الفعلي
35 |
36 |
37 | ## لقطات الشاشة
38 |
39 |
40 | ## البيئة
41 |
42 | - إصدار MCP Database Utilities: [مثال: 0.19.0]
43 | - نظام التشغيل: [مثال: Windows 10, macOS 12.0, Ubuntu 22.04]
44 | - إصدار Python: [مثال: 3.10.5]
45 | - نوع وإصدار قاعدة البيانات: [مثال: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
46 | - عميل MCP المستخدم: [مثال: Claude Desktop, VS Code, Cursor]
47 |
48 | ## التكوين
49 |
50 | ```yaml
51 | connections:
52 | example_connection:
53 | type: sqlite
54 | path: ":memory:"
55 | ```
56 |
57 | ## معلومات إضافية
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/security_vulnerability_en.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Security Vulnerability Report
3 | about: Report security-related issues
4 | title: "[Security] "
5 | labels: security
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Security Vulnerability Description
20 |
21 |
22 | ## Vulnerability Type
23 |
24 |
25 | ## Impact
26 |
27 |
28 | ## Steps to Reproduce
29 |
30 | 1. Go to '...'
31 | 2. Input '....'
32 | 3. Execute '....'
33 | 4. Observe vulnerability
34 |
35 | ## Suggested Fix
36 |
37 |
38 | ## Environment
39 |
40 | - MCP Database Utilities version: [e.g. 0.19.0]
41 | - OS: [e.g. Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Python version: [e.g. 3.10.5]
43 | - Database type and version: [e.g. SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 |
45 | ## Additional Information
46 |
47 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/security_vulnerability_ru.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Отчет об уязвимости безопасности
3 | about: Сообщить о проблемах, связанных с безопасностью
4 | title: "[Security] "
5 | labels: security
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Описание уязвимости безопасности
20 |
21 |
22 | ## Тип уязвимости
23 |
24 |
25 | ## Влияние
26 |
27 |
28 | ## Шаги для воспроизведения
29 |
30 | 1. Перейти к '...'
31 | 2. Ввести '....'
32 | 3. Выполнить '....'
33 | 4. Наблюдать уязвимость
34 |
35 | ## Предлагаемое исправление
36 |
37 |
38 | ## Окружение
39 |
40 | - Версия MCP Database Utilities: [например: 0.19.0]
41 | - ОС: [например: Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Версия Python: [например: 3.10.5]
43 | - Тип и версия базы данных: [например: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 |
45 | ## Дополнительная информация
46 |
47 |
--------------------------------------------------------------------------------
/src/mcp_dbutils/__init__.py:
--------------------------------------------------------------------------------
1 | """MCP Connection Utilities Service"""
2 |
3 | import argparse
4 | import asyncio
5 | import os
6 | import sys
7 | from importlib.metadata import metadata
8 | from pathlib import Path
9 |
10 | import yaml
11 |
12 | from .base import LOG_NAME, ConnectionServer
13 | from .log import create_logger
14 |
15 | # 获取包信息
16 | pkg_meta = metadata("mcp-dbutils")
17 |
18 | # 创建全局logger
19 | log = create_logger(LOG_NAME)
20 |
21 | async def run_server():
22 | """服务器运行逻辑"""
23 | parser = argparse.ArgumentParser(description='MCP Connection Server')
24 | parser.add_argument('--config', required=True, help='YAML配置文件路径')
25 | parser.add_argument('--local-host', help='本地主机地址')
26 |
27 | args = parser.parse_args()
28 |
29 | # 检查是否开启debug模式
30 | debug = os.getenv('MCP_DEBUG', '').lower() in ('1', 'true', 'yes')
31 |
32 | # 更新logger的debug状态
33 | global log
34 | log = create_logger(LOG_NAME, debug)
35 |
36 | log("info", f"MCP Connection Utilities Service v{pkg_meta['Version']}")
37 | if debug:
38 | log("debug", "Debug模式已开启")
39 |
40 | # 验证配置文件
41 | try:
42 | with open(args.config, 'r') as f:
43 | config = yaml.safe_load(f)
44 | if not config or 'connections' not in config:
45 | log("error", "配置文件必须包含 connections 配置")
46 | sys.exit(1)
47 | if not config['connections']:
48 | log("error", "配置文件必须包含至少一个连接配置")
49 | sys.exit(1)
50 | except Exception as e:
51 | log("error", f"读取配置文件失败: {str(e)}")
52 | sys.exit(1)
53 |
54 | # 创建并运行服务器
55 | try:
56 | server = ConnectionServer(args.config, debug)
57 | await server.run()
58 | except KeyboardInterrupt:
59 | log("info", "服务器已停止")
60 | except Exception as e:
61 | log("error", str(e))
62 | sys.exit(1)
63 |
64 | def main():
65 | """命令行入口函数"""
66 | asyncio.run(run_server())
67 |
68 | __all__ = ['main']
69 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report_en.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Create a report to help us improve
4 | title: "[Bug] "
5 | labels: bug
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Description
20 |
21 |
22 | ## Steps to Reproduce
23 |
24 | 1. Go to '...'
25 | 2. Click on '....'
26 | 3. Scroll down to '....'
27 | 4. See error
28 |
29 | ## Expected Behavior
30 |
31 |
32 | ## Actual Behavior
33 |
34 |
35 | ## Screenshots
36 |
37 |
38 | ## Environment
39 |
40 | - MCP Database Utilities version: [e.g. 0.19.0]
41 | - OS: [e.g. Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Python version: [e.g. 3.10.5]
43 | - Database type and version: [e.g. SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 | - MCP client used: [e.g. Claude Desktop, VS Code, Cursor]
45 |
46 | ## Configuration
47 |
48 | ```yaml
49 | connections:
50 | example_connection:
51 | type: sqlite
52 | path: ":memory:"
53 | ```
54 |
55 | ## Additional Information
56 |
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/performance_issue_ar.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: مشكلة في الأداء
3 | about: الإبلاغ عن مشاكل متعلقة بالأداء
4 | title: "[Performance] "
5 | labels: performance
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 |
20 |
21 | ## وصف مشكلة الأداء
22 |
23 |
24 | ## خطوات إعادة الإنتاج
25 |
26 | 1. اذهب إلى '...'
27 | 2. نفذ '....'
28 | 3. لاحظ مشكلة الأداء
29 |
30 | ## بيانات الأداء
31 |
32 |
33 | ## الأداء المتوقع
34 |
35 |
36 | ## البيئة
37 |
38 | - إصدار MCP Database Utilities: [مثال: 0.19.0]
39 | - نظام التشغيل: [مثال: Windows 10, macOS 12.0, Ubuntu 22.04]
40 | - إصدار Python: [مثال: 3.10.5]
41 | - نوع وإصدار قاعدة البيانات: [مثال: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
42 | - عميل MCP المستخدم: [مثال: Claude Desktop, VS Code, Cursor]
43 | - مواصفات الأجهزة: [مثال: طراز وحدة المعالجة المركزية، حجم الذاكرة، نوع القرص]
44 |
45 | ## التكوين
46 |
47 | ```yaml
48 | connections:
49 | example_connection:
50 | type: sqlite
51 | path: ":memory:"
52 | ```
53 |
54 | ## معلومات إضافية
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report_ru.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Отчет об ошибке
3 | about: Создайте отчет, чтобы помочь нам улучшить проект
4 | title: "[Bug] "
5 | labels: bug
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Описание
20 |
21 |
22 | ## Шаги для воспроизведения
23 |
24 | 1. Перейти к '...'
25 | 2. Нажать на '....'
26 | 3. Прокрутить до '....'
27 | 4. Увидеть ошибку
28 |
29 | ## Ожидаемое поведение
30 |
31 |
32 | ## Фактическое поведение
33 |
34 |
35 | ## Скриншоты
36 |
37 |
38 | ## Окружение
39 |
40 | - Версия MCP Database Utilities: [например: 0.19.0]
41 | - ОС: [например: Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Версия Python: [например: 3.10.5]
43 | - Тип и версия базы данных: [например: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 | - Используемый MCP клиент: [например: Claude Desktop, VS Code, Cursor]
45 |
46 | ## Конфигурация
47 |
48 | ```yaml
49 | connections:
50 | example_connection:
51 | type: sqlite
52 | path: ":memory:"
53 | ```
54 |
55 | ## Дополнительная информация
56 |
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/security_vulnerability_es.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Informe de Vulnerabilidad de Seguridad
3 | about: Informar problemas relacionados con la seguridad
4 | title: "[Security] "
5 | labels: security
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Descripción de la Vulnerabilidad de Seguridad
20 |
21 |
22 | ## Tipo de Vulnerabilidad
23 |
24 |
25 | ## Impacto
26 |
27 |
28 | ## Pasos para Reproducir
29 |
30 | 1. Ir a '...'
31 | 2. Ingresar '....'
32 | 3. Ejecutar '....'
33 | 4. Observar la vulnerabilidad
34 |
35 | ## Solución Sugerida
36 |
37 |
38 | ## Entorno
39 |
40 | - Versión de MCP Database Utilities: [ej. 0.19.0]
41 | - Sistema operativo: [ej. Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Versión de Python: [ej. 3.10.5]
43 | - Tipo y versión de base de datos: [ej. SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 |
45 | ## Información Adicional
46 |
47 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/security_vulnerability_fr.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Rapport de Vulnérabilité de Sécurité
3 | about: Signaler des problèmes liés à la sécurité
4 | title: "[Security] "
5 | labels: security
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Description de la Vulnérabilité de Sécurité
20 |
21 |
22 | ## Type de Vulnérabilité
23 |
24 |
25 | ## Impact
26 |
27 |
28 | ## Étapes pour Reproduire
29 |
30 | 1. Aller à '...'
31 | 2. Saisir '....'
32 | 3. Exécuter '....'
33 | 4. Observer la vulnérabilité
34 |
35 | ## Correction Suggérée
36 |
37 |
38 | ## Environnement
39 |
40 | - Version de MCP Database Utilities: [ex: 0.19.0]
41 | - Système d'exploitation: [ex: Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Version de Python: [ex: 3.10.5]
43 | - Type et version de base de données: [ex: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 |
45 | ## Informations Supplémentaires
46 |
47 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/performance_issue_en.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Performance Issue
3 | about: Report performance-related issues
4 | title: "[Performance] "
5 | labels: performance
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Performance Issue Description
20 |
21 |
22 | ## Steps to Reproduce
23 |
24 | 1. Go to '...'
25 | 2. Execute '....'
26 | 3. Observe performance issue
27 |
28 | ## Performance Data
29 |
30 |
31 | ## Expected Performance
32 |
33 |
34 | ## Environment
35 |
36 | - MCP Database Utilities version: [e.g. 0.19.0]
37 | - OS: [e.g. Windows 10, macOS 12.0, Ubuntu 22.04]
38 | - Python version: [e.g. 3.10.5]
39 | - Database type and version: [e.g. SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
40 | - MCP client used: [e.g. Claude Desktop, VS Code, Cursor]
41 | - Hardware specifications: [e.g. CPU model, memory size, disk type]
42 |
43 | ## Configuration
44 |
45 | ```yaml
46 | connections:
47 | example_connection:
48 | type: sqlite
49 | path: ":memory:"
50 | ```
51 |
52 | ## Additional Information
53 |
54 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report_es.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Informe de Error
3 | about: Crear un informe para ayudarnos a mejorar
4 | title: "[Bug] "
5 | labels: bug
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Descripción
20 |
21 |
22 | ## Pasos para reproducir
23 |
24 | 1. Ir a '...'
25 | 2. Hacer clic en '....'
26 | 3. Desplazarse hasta '....'
27 | 4. Ver el error
28 |
29 | ## Comportamiento esperado
30 |
31 |
32 | ## Comportamiento actual
33 |
34 |
35 | ## Capturas de pantalla
36 |
37 |
38 | ## Entorno
39 |
40 | - Versión de MCP Database Utilities: [ej. 0.19.0]
41 | - Sistema operativo: [ej. Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Versión de Python: [ej. 3.10.5]
43 | - Tipo y versión de base de datos: [ej. SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 | - Cliente MCP utilizado: [ej. Claude Desktop, VS Code, Cursor]
45 |
46 | ## Configuración
47 |
48 | ```yaml
49 | connections:
50 | example_connection:
51 | type: sqlite
52 | path: ":memory:"
53 | ```
54 |
55 | ## Información adicional
56 |
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report_fr.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Rapport de Bug
3 | about: Créer un rapport pour nous aider à améliorer
4 | title: "[Bug] "
5 | labels: bug
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Description
20 |
21 |
22 | ## Étapes pour reproduire
23 |
24 | 1. Aller à '...'
25 | 2. Cliquer sur '....'
26 | 3. Défiler jusqu'à '....'
27 | 4. Voir l'erreur
28 |
29 | ## Comportement attendu
30 |
31 |
32 | ## Comportement actuel
33 |
34 |
35 | ## Captures d'écran
36 |
37 |
38 | ## Environnement
39 |
40 | - Version de MCP Database Utilities: [ex: 0.19.0]
41 | - Système d'exploitation: [ex: Windows 10, macOS 12.0, Ubuntu 22.04]
42 | - Version de Python: [ex: 3.10.5]
43 | - Type et version de base de données: [ex: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
44 | - Client MCP utilisé: [ex: Claude Desktop, VS Code, Cursor]
45 |
46 | ## Configuration
47 |
48 | ```yaml
49 | connections:
50 | example_connection:
51 | type: sqlite
52 | path: ":memory:"
53 | ```
54 |
55 | ## Informations supplémentaires
56 |
57 |
--------------------------------------------------------------------------------
/config.yaml.example:
--------------------------------------------------------------------------------
1 | connections:
2 | # SQLite configuration examples
3 | local-db:
4 | type: sqlite
5 | path: /path/to/dev.db
6 | # Password is optional
7 | password:
8 |
9 | dev-sqlite:
10 | type: sqlite
11 | path: /path/to/prod.db
12 | password: optional_password # Optional
13 |
14 | # MySQL configuration examples
15 | # Standard configuration
16 | sandbox-mysql:
17 | type: mysql
18 | host: localhost
19 | port: 3306
20 | database: sandbox_db
21 | user: sandbox_user
22 | password: sandbox_pass
23 | charset: utf8mb4
24 |
25 | # URL configuration
26 | # Use mysql://host:port/dbname?charset=utf8mb4&ssl-mode=verify_identity
27 | integration-mysql:
28 | type: mysql
29 | url: mysql://mysql.example.com:3306/integration_db?charset=utf8mb4
30 | user: integration_user
31 | password: integration_pass
32 |
33 | # Full SSL configuration example
34 | test-mysql:
35 | type: mysql
36 | host: test-mysql.example.com
37 | port: 3306
38 | database: test_db
39 | user: test_user
40 | password: test_pass
41 | charset: utf8mb4
42 | ssl:
43 | mode: verify_identity
44 | ca: /path/to/ca.pem
45 | cert: /path/to/client-cert.pem
46 | key: /path/to/client-key.pem
47 |
48 | # PostgreSQL configuration examples
49 | # Standard configuration
50 | demo-db:
51 | type: postgres
52 | host: postgres.example.com
53 | port: 5432
54 | dbname: demo_db
55 | user: demo_user
56 | password: demo_pass
57 |
58 | # URL configuration
59 | # Use postgresql://host:port/dbname?sslmode=verify-full&sslcert=/path/to/cert.pem
60 | perf-db:
61 | type: postgres
62 | url: postgresql://postgres.example.com:5432/perf-db?sslmode=verify-full
63 | user: perf_user
64 | password: perf_pass
65 |
66 | # Full SSL configuration example
67 | security-db:
68 | type: postgres
69 | host: security-db.example.com
70 | port: 5432
71 | dbname: security_db
72 | user: security_user
73 | password: security_pass
74 | ssl:
75 | mode: verify-full
76 | cert: /path/to/client-cert.pem
77 | key: /path/to/client-key.pem
78 | root: /path/to/ca.crt
79 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/performance_issue_es.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Problema de Rendimiento
3 | about: Informar problemas relacionados con el rendimiento
4 | title: "[Performance] "
5 | labels: performance
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Descripción del Problema de Rendimiento
20 |
21 |
22 | ## Pasos para Reproducir
23 |
24 | 1. Ir a '...'
25 | 2. Ejecutar '....'
26 | 3. Observar el problema de rendimiento
27 |
28 | ## Datos de Rendimiento
29 |
30 |
31 | ## Rendimiento Esperado
32 |
33 |
34 | ## Entorno
35 |
36 | - Versión de MCP Database Utilities: [ej. 0.19.0]
37 | - Sistema operativo: [ej. Windows 10, macOS 12.0, Ubuntu 22.04]
38 | - Versión de Python: [ej. 3.10.5]
39 | - Tipo y versión de base de datos: [ej. SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
40 | - Cliente MCP utilizado: [ej. Claude Desktop, VS Code, Cursor]
41 | - Especificaciones de hardware: [ej. modelo de CPU, tamaño de memoria, tipo de disco]
42 |
43 | ## Configuración
44 |
45 | ```yaml
46 | connections:
47 | example_connection:
48 | type: sqlite
49 | path: ":memory:"
50 | ```
51 |
52 | ## Información Adicional
53 |
54 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/performance_issue_ru.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Проблема с производительностью
3 | about: Сообщить о проблемах, связанных с производительностью
4 | title: "[Performance] "
5 | labels: performance
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Описание проблемы с производительностью
20 |
21 |
22 | ## Шаги для воспроизведения
23 |
24 | 1. Перейти к '...'
25 | 2. Выполнить '....'
26 | 3. Наблюдать проблему с производительностью
27 |
28 | ## Данные о производительности
29 |
30 |
31 | ## Ожидаемая производительность
32 |
33 |
34 | ## Окружение
35 |
36 | - Версия MCP Database Utilities: [например: 0.19.0]
37 | - ОС: [например: Windows 10, macOS 12.0, Ubuntu 22.04]
38 | - Версия Python: [например: 3.10.5]
39 | - Тип и версия базы данных: [например: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
40 | - Используемый MCP клиент: [например: Claude Desktop, VS Code, Cursor]
41 | - Характеристики оборудования: [например: модель ЦП, объем памяти, тип диска]
42 |
43 | ## Конфигурация
44 |
45 | ```yaml
46 | connections:
47 | example_connection:
48 | type: sqlite
49 | path: ":memory:"
50 | ```
51 |
52 | ## Дополнительная информация
53 |
54 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/performance_issue_fr.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Problème de Performance
3 | about: Signaler des problèmes liés aux performances
4 | title: "[Performance] "
5 | labels: performance
6 | assignees: ''
7 | ---
8 |
9 |
18 |
19 | ## Description du Problème de Performance
20 |
21 |
22 | ## Étapes pour Reproduire
23 |
24 | 1. Aller à '...'
25 | 2. Exécuter '....'
26 | 3. Observer le problème de performance
27 |
28 | ## Données de Performance
29 |
30 |
31 | ## Performance Attendue
32 |
33 |
34 | ## Environnement
35 |
36 | - Version de MCP Database Utilities: [ex: 0.19.0]
37 | - Système d'exploitation: [ex: Windows 10, macOS 12.0, Ubuntu 22.04]
38 | - Version de Python: [ex: 3.10.5]
39 | - Type et version de base de données: [ex: SQLite 3.39.0, PostgreSQL 14.5, MySQL 8.0.30]
40 | - Client MCP utilisé: [ex: Claude Desktop, VS Code, Cursor]
41 | - Spécifications matérielles: [ex: modèle de CPU, taille de la mémoire, type de disque]
42 |
43 | ## Configuration
44 |
45 | ```yaml
46 | connections:
47 | example_connection:
48 | type: sqlite
49 | path: ":memory:"
50 | ```
51 |
52 | ## Informations Supplémentaires
53 |
54 |
--------------------------------------------------------------------------------
/docs/document-consistency-check.md:
--------------------------------------------------------------------------------
1 | # 文档一致性检查报告
2 |
3 | 本报告记录了对 MCP 数据库工具文档的一致性检查结果,旨在确保所有文档符合统一的标准和风格。
4 |
5 | ## 检查标准
6 |
7 | 检查基于以下标准:
8 |
9 | 1. **格式一致性**
10 | - 标题层级使用(# 一级标题,## 二级标题,等)
11 | - 代码块使用 ```语言 格式
12 | - 列表格式统一(有序/无序)
13 | - 表格格式统一
14 |
15 | 2. **术语一致性**
16 | - 产品名称:统一使用"MCP 数据库工具"或"MCP Database Utilities"
17 | - 技术术语:确保相同概念使用相同术语
18 |
19 | 3. **风格一致性**
20 | - 语气:保持专业、清晰、简洁
21 | - 表达方式:使用主动语态
22 | - 示例风格:保持一致的示例格式
23 |
24 | 4. **链接一致性**
25 | - 确保所有内部链接有效
26 | - 确保所有外部链接有效
27 | - 链接文本描述性强
28 |
29 | 5. **内容完整性**
30 | - 中英文文档内容对应
31 | - 文档覆盖所有必要信息
32 |
33 | ## 检查结果
34 |
35 | ### 中文文档
36 |
37 | | 文档 | 格式一致性 | 术语一致性 | 风格一致性 | 链接一致性 | 内容完整性 | 需要改进的地方 |
38 | |------|------------|------------|------------|------------|------------|----------------|
39 | | docs/zh/configuration.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
40 | | docs/zh/installation.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
41 | | docs/zh/usage.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
42 | | docs/zh/technical/architecture.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
43 | | docs/zh/technical/security.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
44 | | docs/zh/technical/development.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
45 | | docs/zh/technical/testing.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
46 | | docs/zh/technical/sonarcloud-integration.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
47 | | docs/zh/examples/sqlite-examples.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
48 | | docs/zh/examples/postgresql-examples.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
49 | | docs/zh/examples/mysql-examples.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
50 |
51 | ### 英文文档
52 |
53 | | 文档 | 格式一致性 | 术语一致性 | 风格一致性 | 链接一致性 | 内容完整性 | 需要改进的地方 |
54 | |------|------------|------------|------------|------------|------------|----------------|
55 | | docs/en/configuration.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
56 | | docs/en/installation.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
57 | | docs/en/usage.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
58 | | docs/en/technical/architecture.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
59 | | docs/en/technical/security.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
60 | | docs/en/technical/development.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
61 | | docs/en/technical/testing.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
62 | | docs/en/technical/sonarcloud-integration.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
63 | | docs/en/examples/sqlite-examples.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
64 | | docs/en/examples/postgresql-examples.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
65 | | docs/en/examples/mysql-examples.md | ✅ | ✅ | ✅ | ✅ | ✅ | 无 |
66 |
67 | ## 总体评估
68 |
69 | 经过检查,我们的文档整体一致性良好。在最近的文档重组过程中,我们已经解决了大部分一致性问题,包括:
70 |
71 | 1. 统一了文档结构,按照语言和文档类型进行分类
72 | 2. 统一了文档格式,包括标题层级、代码块、列表和表格格式
73 | 3. 统一了术语使用,确保相同概念使用相同术语
74 | 4. 统一了文档风格,保持专业、清晰、简洁的语气
75 | 5. 确保了所有链接的有效性
76 | 6. 确保了中英文文档内容的对应性
77 |
78 | ## 建议
79 |
80 | 虽然当前文档已经具有良好的一致性,但我们仍可以考虑以下改进:
81 |
82 | 1. **添加文档版本信息**:在每个文档顶部添加版本号和最后更新日期
83 | 2. **添加视觉元素**:在适当的地方添加图表、流程图等视觉元素,提升文档可读性
84 | 3. **添加平台特定指南**:为不同操作系统创建专门的安装和配置指南
85 | 4. **丰富交互示例**:添加更多与各类 LLM 交互的示例,展示产品的潜力
86 |
87 | 这些改进将在后续工作中逐步实施。
88 |
--------------------------------------------------------------------------------
/docs/zh/technical/sonarcloud-integration.md:
--------------------------------------------------------------------------------
1 | # SonarCloud AI 集成指南
2 |
3 | *[English](../../en/technical/sonarcloud-integration.md) | 中文 | [Français](../../fr/technical/sonarcloud-integration.md) | [Español](../../es/technical/sonarcloud-integration.md) | [العربية](../../ar/technical/sonarcloud-integration.md) | [Русский](../../ru/technical/sonarcloud-integration.md)*
4 |
5 | 本文档介绍如何使用 SonarCloud 分析结果与 AI 集成,以便自动获取代码质量问题并使用 AI 辅助修复。
6 |
7 | ## 功能概述
8 |
9 | 该集成方案通过以下步骤工作:
10 |
11 | ```mermaid
12 | graph TD
13 | A[代码开发] --> B[SonarCloud 分析]
14 | B --> C{检测到问题?}
15 | C -->|是| D[AI 分析问题]
16 | D --> E[修复建议]
17 | E --> F[实施修复]
18 | F --> A
19 | C -->|否| G[AI 优化分析]
20 | G --> H[优化建议]
21 | H --> A
22 | ```
23 |
24 | 1. GitHub Actions 工作流在 CI/CD 过程中运行 SonarCloud 分析
25 | 2. 分析完成后,工作流提取 SonarCloud 问题并生成两种格式的报告:
26 | - JSON 格式:包含完整的原始数据,适合 AI 深入分析
27 | - Markdown 格式:格式化的人类可读报告,包含问题摘要和详细信息
28 | 3. 这两个报告作为工作流构件(artifacts)上传
29 | 4. 使用提供的 Fish 函数,可以轻松下载这些报告并提供给 AI 进行分析和修复建议
30 |
31 | ## 使用方法
32 |
33 | ### 1. 设置 Fish 函数
34 |
35 | 将 `sonar-ai-fix` 函数添加到您的 Fish 配置中:
36 |
37 | ```fish
38 | # 在 ~/.config/fish/config.fish 中添加
39 | source /path/to/mcp-dbutils/scripts/sonar-ai-fix.fish
40 | ```
41 |
42 | 或者,您可以直接运行脚本来临时加载函数:
43 |
44 | ```bash
45 | source scripts/sonar-ai-fix.fish
46 | ```
47 |
48 | ### 2. 下载 SonarCloud 分析报告
49 |
50 | 在项目根目录中运行:
51 |
52 | ```bash
53 | sonar-ai-fix
54 | ```
55 |
56 | 这将下载最新的 SonarCloud 分析报告,并将其保存为两个文件:
57 | - `sonar_report.md`:Markdown 格式的报告
58 | - `sonar_issues.json`:JSON 格式的原始数据
59 |
60 | ### 3. 使用 AI 分析和修复问题
61 |
62 | 有两种方式使用这些报告:
63 |
64 | #### 方式一:使用 Markdown 报告(推荐)
65 |
66 | 1. 打开 `sonar_report.md` 文件:
67 | ```bash
68 | bat sonar_report.md
69 | ```
70 |
71 | 2. 将内容复制给 AI(如 Claude),并请求修复建议:
72 | ```
73 | 这是我项目的 SonarCloud 分析报告,请帮我分析这些问题并提供修复建议。
74 |
75 | [粘贴 sonar_report.md 内容]
76 | ```
77 |
78 | #### 方式二:使用 JSON 数据进行深入分析
79 |
80 | 对于需要更深入分析的情况,可以使用 JSON 数据:
81 |
82 | 1. 打开 JSON 文件:
83 | ```bash
84 | bat sonar_issues.json
85 | ```
86 |
87 | 2. 将内容提供给 AI 进行更详细的分析:
88 | ```
89 | 这是我项目的 SonarCloud 原始分析数据,请帮我深入分析这些问题并提供修复建议。
90 |
91 | [粘贴 sonar_issues.json 内容]
92 | ```
93 |
94 | ## 工作原理
95 |
96 | ### GitHub Actions 工作流
97 |
98 | 在 `.github/workflows/quality-assurance.yml` 中,我们添加了两个关键步骤:
99 |
100 | 1. **提取 SonarCloud 问题**:
101 | - 使用 SonarCloud API 获取未解决的问题
102 | - 将问题格式化为 JSON 和 Markdown 格式
103 |
104 | 2. **上传报告构件**:
105 | - 将生成的报告作为工作流构件上传
106 | - 使构件可以通过 GitHub CLI 下载
107 |
108 | ### Fish 函数
109 |
110 | `sonar-ai-fix.fish` 脚本提供了一个方便的函数,用于:
111 |
112 | - 检查当前目录是否是项目目录
113 | - 获取最新的工作流运行 ID
114 | - 下载 SonarCloud 问题报告构件
115 | - 将报告保存到当前目录
116 | - 提供使用说明
117 |
118 | ## 注意事项
119 |
120 | - 确保您已安装并配置 GitHub CLI (`gh`)
121 | - 确保您有足够的权限访问 GitHub 仓库和工作流
122 | - 报告中的问题链接指向 SonarCloud 网站,需要有权限访问项目
123 | - 此功能最适合与本地 AI 工具(如 Claude Desktop)配合使用
124 |
--------------------------------------------------------------------------------
/tests/unit/test_log.py:
--------------------------------------------------------------------------------
1 | """Test logging module"""
2 |
3 | import io
4 | import sys
5 | from datetime import datetime
6 |
7 | import pytest
8 |
9 | from mcp_dbutils.log import create_logger
10 |
11 |
12 | def test_log_basic_output():
13 | """Test basic log output functionality"""
14 | # 捕获stderr输出
15 | stderr = io.StringIO()
16 | sys.stderr = stderr
17 |
18 | # 创建logger
19 | logger = create_logger("test")
20 |
21 | # 测试日志输出
22 | test_message = "Test log message"
23 | logger("info", test_message)
24 |
25 | # 验证输出
26 | output = stderr.getvalue()
27 | assert "test" in output
28 | assert "info" in output
29 | assert test_message in output
30 | assert output.count("\n") == 1 # 确保只有一行输出
31 |
32 | # 还原stderr
33 | sys.stderr = sys.__stderr__
34 |
35 | def test_log_debug_mode():
36 | """Test debug mode behavior"""
37 | stderr = io.StringIO()
38 | sys.stderr = stderr
39 |
40 | # 创建debug模式的logger
41 | logger = create_logger("test", is_debug=True)
42 |
43 | # 测试debug日志
44 | debug_message = "Debug message"
45 | logger("debug", debug_message)
46 |
47 | # 验证debug消息被输出
48 | output = stderr.getvalue()
49 | assert debug_message in output
50 | assert "debug" in output
51 |
52 | # 清空输出缓冲
53 | stderr.truncate(0)
54 | stderr.seek(0)
55 |
56 | # 创建非debug模式的logger
57 | logger = create_logger("test", is_debug=False)
58 |
59 | # 测试debug日志不被输出
60 | logger("debug", debug_message)
61 | assert not stderr.getvalue()
62 |
63 | sys.stderr = sys.__stderr__
64 |
65 | def test_log_timestamp():
66 | """Test log timestamp format"""
67 | stderr = io.StringIO()
68 | sys.stderr = stderr
69 |
70 | logger = create_logger("test")
71 | logger("info", "Test message")
72 |
73 | output = stderr.getvalue()
74 |
75 | # 验证时间戳格式 (ISO格式带毫秒)
76 | timestamp = output.split()[0]
77 | try:
78 | datetime.fromisoformat(timestamp.rstrip('Z'))
79 | except ValueError:
80 | pytest.fail(f"Invalid timestamp format: {timestamp}")
81 |
82 | sys.stderr = sys.__stderr__
83 |
84 | def test_log_multiple_levels():
85 | """Test different log levels"""
86 | stderr = io.StringIO()
87 | sys.stderr = stderr
88 |
89 | logger = create_logger("test")
90 |
91 | # 测试不同级别的日志
92 | levels = ["info", "warning", "error"]
93 | messages = {
94 | "info": "Info message",
95 | "warning": "Warning message",
96 | "error": "Error message"
97 | }
98 |
99 | for level in levels:
100 | logger(level, messages[level])
101 |
102 | output = stderr.getvalue()
103 |
104 | # 验证所有级别的消息都被正确记录
105 | for level, message in messages.items():
106 | assert f"[{level}]" in output
107 | assert message in output
108 |
109 | sys.stderr = sys.__stderr__
110 |
--------------------------------------------------------------------------------
/docs/zh/technical/testing.md:
--------------------------------------------------------------------------------
1 | # 测试指南
2 |
3 | *[English](../../en/technical/testing.md) | 中文 | [Français](../../fr/technical/testing.md) | [Español](../../es/technical/testing.md) | [العربية](../../ar/technical/testing.md) | [Русский](../../ru/technical/testing.md)*
4 |
5 | ## 测试框架
6 |
7 | MCP数据库工具使用以下测试框架和工具:
8 |
9 | - **pytest**:主要测试框架
10 | - **pytest-asyncio**:用于异步测试支持
11 | - **pytest-docker**:用于数据库集成测试
12 | - **pytest-cov**:用于代码覆盖率分析
13 |
14 | ## 测试结构
15 |
16 | 测试目录结构如下:
17 |
18 | ```
19 | tests/
20 | ├── unit/ # 单元测试
21 | ├── integration/ # 集成测试
22 | │ ├── fixtures.py # 测试辅助类
23 | │ └── conftest.py # pytest配置和工具
24 | ```
25 |
26 | ## 运行测试
27 |
28 | ### 运行所有测试
29 |
30 | ```bash
31 | # 安装测试依赖
32 | uv pip install -e ".[test]"
33 |
34 | # 运行所有测试
35 | pytest
36 | ```
37 |
38 | ### 运行特定测试
39 |
40 | ```bash
41 | # 运行单元测试
42 | pytest tests/unit/
43 |
44 | # 运行特定测试文件
45 | pytest tests/unit/test_base.py
46 |
47 | # 运行特定测试函数
48 | pytest tests/unit/test_base.py::test_function_name
49 | ```
50 |
51 | ### 生成覆盖率报告
52 |
53 | ```bash
54 | # 生成覆盖率报告
55 | pytest --cov=src/mcp_dbutils --cov-report=term --cov-report=xml:coverage.xml tests/
56 | ```
57 |
58 | ## 测试类型
59 |
60 | ### 单元测试
61 |
62 | 单元测试位于 `tests/unit/` 目录,专注于测试单个组件的功能,通常使用模拟对象替代外部依赖。
63 |
64 | 示例:
65 |
66 | ```python
67 | def test_database_handler_factory():
68 | # 测试数据库处理器工厂函数
69 | config = {"type": "sqlite", "path": ":memory:"}
70 | handler = create_handler(config)
71 | assert isinstance(handler, SQLiteHandler)
72 | ```
73 |
74 | ### 集成测试
75 |
76 | 集成测试位于 `tests/integration/` 目录,测试多个组件的交互,通常使用真实的数据库连接。
77 |
78 | 示例:
79 |
80 | ```python
81 | @pytest.mark.asyncio
82 | async def test_sqlite_query_execution(sqlite_handler):
83 | # 测试SQLite查询执行
84 | result = await sqlite_handler.execute_query("SELECT 1 as test")
85 | assert "test" in result
86 | assert result["test"] == 1
87 | ```
88 |
89 | ## 测试辅助工具
90 |
91 | ### fixtures.py
92 |
93 | `tests/integration/fixtures.py` 文件包含测试辅助类和函数,如:
94 |
95 | - `TestConnectionHandler`:用于测试连接处理器
96 | - `MockSession`:模拟MCP会话
97 | - `create_test_database`:创建测试数据库
98 |
99 | ### conftest.py
100 |
101 | `tests/conftest.py` 文件包含pytest配置和全局fixture:
102 |
103 | ```python
104 | @pytest.fixture
105 | async def sqlite_handler():
106 | """提供SQLite测试处理器"""
107 | config = {"type": "sqlite", "path": ":memory:"}
108 | handler = SQLiteHandler(config)
109 | yield handler
110 | await handler.cleanup()
111 | ```
112 |
113 | ## 最佳实践
114 |
115 | 1. **测试覆盖率**:保持至少80%的代码覆盖率
116 | 2. **隔离测试**:确保测试不依赖于其他测试的状态
117 | 3. **清理资源**:使用fixture的teardown机制清理资源
118 | 4. **模拟外部依赖**:使用unittest.mock模拟外部依赖
119 | 5. **测试异常情况**:测试错误处理和边缘情况
120 | 6. **参数化测试**:使用pytest.mark.parametrize测试多种输入
121 |
122 | ## SonarCloud集成
123 |
124 | 测试结果会自动上传到SonarCloud进行分析。SonarCloud会检查:
125 |
126 | - 代码覆盖率
127 | - 测试成功率
128 | - 代码质量问题
129 | - 安全漏洞
130 |
131 | 您可以在[SonarCloud仪表板](https://sonarcloud.io/dashboard?id=donghao1393_mcp-dbutils)上查看测试结果和代码质量报告。
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "mcp-dbutils"
3 | version = "1.0.4"
4 | description = "MCP Database Utilities Service"
5 | readme = "README.md"
6 | license = "MIT"
7 | authors = [
8 | {name = "Dong Hao"}
9 | ]
10 | dependencies = [
11 | "mcp>=1.7.1",
12 | "typer>=0.9.0",
13 | "psycopg2-binary>=2.9.10",
14 | "python-dotenv>=1.0.1",
15 | "pyyaml>=6.0.2",
16 | "mysql-connector-python>=8.2.0",
17 | ]
18 | requires-python = ">=3.10"
19 |
20 | [build-system]
21 | requires = ["hatchling"]
22 | build-backend = "hatchling.build"
23 |
24 | [project.scripts]
25 | mcp-dbutils = "mcp_dbutils:main"
26 |
27 | [tool.semantic_release]
28 | version_variables = [
29 | "pyproject.toml:project.version"
30 | ]
31 | version_toml = [
32 | "pyproject.toml:project.version"
33 | ]
34 | commit_parser = "conventional"
35 | major_on_zero = false
36 | branch = "main"
37 | changelog_components = "semantic_release.changelog.changelog"
38 | build_command = "uv build"
39 |
40 | [project.optional-dependencies]
41 | test = [
42 | "pytest>=7.0.0",
43 | "pytest-asyncio>=0.23.0",
44 | "pytest-docker>=2.0.0",
45 | "docker>=7.0.0",
46 | "aiosqlite>=0.19.0",
47 | "testcontainers>=3.7.0",
48 | "pytest-cov>=4.1.0",
49 | "ruff>=0.3.0",
50 | "pre-commit>=3.6.0"
51 | ]
52 |
53 | [tool.pytest.ini_options]
54 | asyncio_mode = "strict"
55 | asyncio_default_fixture_loop_scope = "function"
56 | markers = [
57 | "no_collect: marks test classes that should not be collected as test cases"
58 | ]
59 | filterwarnings = [
60 | "ignore::pytest.PytestCollectionWarning"
61 | ]
62 |
63 | # Ruff配置
64 | [tool.ruff]
65 | # 目标Python版本
66 | target-version = "py310"
67 | # 行长度限制
68 | line-length = 88
69 | # 排除的文件和目录
70 | exclude = [
71 | ".git",
72 | ".venv",
73 | "__pycache__",
74 | "build",
75 | "dist",
76 | ]
77 |
78 | # Lint配置
79 | [tool.ruff.lint]
80 | # 选择的规则集
81 | select = [
82 | "E", # pycodestyle错误
83 | "F", # pyflakes
84 | "I", # isort
85 | "N", # pep8-naming
86 | "UP", # pyupgrade
87 | "B", # flake8-bugbear
88 | "C4", # flake8-comprehensions
89 | "SIM", # flake8-simplify
90 | "T20", # flake8-print
91 | ]
92 | # 忽略的规则 - 暂时忽略,后续PR中逐步修复
93 | ignore = [
94 | "E501", # 行太长
95 | "B904", # 在except子句中使用raise ... from err
96 | "UP035", # 使用新的typing语法
97 | "UP006", # 使用新的类型注解语法
98 | "UP007", # 使用X | Y替代Union
99 | "F401", # 未使用的导入
100 | "F541", # f-string没有占位符
101 | "UP015", # 不必要的mode参数
102 | "UP032", # 使用f-string替代format
103 | "B905", # zip()没有strict参数
104 | "SIM105", # 使用contextlib.suppress
105 | "UP038", # 在isinstance调用中使用X | Y
106 | "F821", # 未定义的名称
107 | "F841", # 未使用的局部变量
108 | "E402", # 模块级导入不在文件顶部
109 | "T201", # print语句 - 在日志模块中是必要的
110 | ]
111 |
112 | # isort配置
113 | [tool.ruff.lint.isort]
114 | known-first-party = ["mcp_dbutils"]
115 |
116 | # 格式化配置
117 | [tool.ruff.format]
118 | quote-style = "double"
119 | indent-style = "space"
120 | line-ending = "auto"
121 |
--------------------------------------------------------------------------------
/tests/unit/test_stats.py:
--------------------------------------------------------------------------------
1 | """Unit tests for resource monitoring functionality"""
2 |
3 | from datetime import datetime
4 |
5 | from mcp_dbutils.stats import ResourceStats
6 |
7 |
8 | def test_connection_tracking():
9 | """Test connection tracking functionality"""
10 | stats = ResourceStats()
11 |
12 | # Test initial state
13 | assert stats.active_connections == 0
14 | assert stats.total_connections == 0
15 | assert stats.connection_start_time is None
16 |
17 | # Test connection start
18 | stats.record_connection_start()
19 | assert stats.active_connections == 1
20 | assert stats.total_connections == 1
21 | assert isinstance(stats.connection_start_time, datetime)
22 |
23 | # Test multiple connections
24 | stats.record_connection_start()
25 | assert stats.active_connections == 2
26 | assert stats.total_connections == 2
27 |
28 | # Test connection end
29 | stats.record_connection_end()
30 | assert stats.active_connections == 1
31 | assert stats.total_connections == 2 # Total should not decrease
32 |
33 | # Test connection cleanup
34 | stats.record_connection_end()
35 | assert stats.active_connections == 0
36 | assert stats.total_connections == 2
37 |
38 | def test_query_tracking():
39 | """Test query execution tracking"""
40 | stats = ResourceStats()
41 |
42 | # Test initial state
43 | assert stats.query_count == 0
44 | assert stats.last_query_time is None
45 |
46 | # Test query recording
47 | stats.record_query()
48 | assert stats.query_count == 1
49 | assert isinstance(stats.last_query_time, datetime)
50 |
51 | # Test multiple queries
52 | stats.record_query()
53 | assert stats.query_count == 2
54 |
55 | def test_error_tracking():
56 | """Test error tracking functionality"""
57 | stats = ResourceStats()
58 |
59 | # Test initial state
60 | assert stats.error_count == 0
61 | assert stats.last_error_time is None
62 | assert stats.error_types == {}
63 |
64 | # Test error recording
65 | stats.record_error("DatabaseError")
66 | assert stats.error_count == 1
67 | assert isinstance(stats.last_error_time, datetime)
68 | assert stats.error_types["DatabaseError"] == 1
69 |
70 | # Test multiple errors
71 | stats.record_error("ConfigurationError")
72 | stats.record_error("DatabaseError")
73 | assert stats.error_count == 3
74 | assert stats.error_types["DatabaseError"] == 2
75 | assert stats.error_types["ConfigurationError"] == 1
76 |
77 | def test_stats_serialization():
78 | """Test statistics serialization to dict"""
79 | stats = ResourceStats()
80 |
81 | # Setup some data
82 | stats.record_connection_start()
83 | stats.record_query()
84 | stats.record_error("TestError")
85 |
86 | # Test serialization
87 | data = stats.to_dict()
88 | assert isinstance(data, dict)
89 | assert data["active_connections"] == 1
90 | assert data["total_connections"] == 1
91 | assert data["query_count"] == 1
92 | assert data["error_count"] == 1
93 | assert isinstance(data["connection_duration"], (int, float))
94 | assert data["error_types"]["TestError"] == 1
95 |
--------------------------------------------------------------------------------
/tests/integration/test_monitoring.py:
--------------------------------------------------------------------------------
1 | """Integration tests for resource monitoring"""
2 |
3 | import tempfile
4 |
5 | import pytest
6 | import yaml
7 |
8 | from mcp_dbutils.base import ConnectionHandlerError, ConnectionServer
9 |
10 |
11 | @pytest.mark.asyncio
12 | async def test_sqlite_monitoring(sqlite_db, mcp_config):
13 | """Test resource monitoring with SQLite"""
14 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
15 | yaml.dump(mcp_config, tmp)
16 | tmp.flush()
17 | server = ConnectionServer(config_path=tmp.name)
18 |
19 | async with server.get_handler("test_sqlite") as handler:
20 | # Connection stats
21 | stats = handler.stats
22 | assert stats.active_connections == 1
23 | assert stats.total_connections == 1
24 |
25 | # Execute queries and check stats
26 | await handler.execute_query("SELECT * FROM products")
27 | assert stats.query_count == 1
28 |
29 | await handler.execute_query("SELECT name FROM products")
30 | assert stats.query_count == 2
31 |
32 | # Test error recording
33 | try:
34 | await handler.execute_query("SELECT * FROM nonexistent")
35 | except ConnectionHandlerError:
36 | pass
37 |
38 | assert stats.error_count == 1
39 | assert "ConnectionHandlerError" in stats.error_types
40 |
41 | # After context exit, connection should be closed
42 | assert stats.active_connections == 0
43 |
44 | @pytest.mark.asyncio
45 | async def test_postgres_monitoring(postgres_db, mcp_config):
46 | """Test resource monitoring with PostgreSQL"""
47 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
48 | yaml.dump(mcp_config, tmp)
49 | tmp.flush()
50 | server = ConnectionServer(config_path=tmp.name)
51 |
52 | async with server.get_handler("test_pg") as handler:
53 | # Connection stats
54 | stats = handler.stats
55 | assert stats.active_connections == 1
56 | assert stats.total_connections == 1
57 |
58 | # Execute queries and check stats
59 | await handler.execute_query("SELECT * FROM users")
60 | assert stats.query_count == 1
61 |
62 | await handler.execute_query("SELECT name FROM users")
63 | assert stats.query_count == 2
64 |
65 | # Test error recording
66 | try:
67 | await handler.execute_query("SELECT * FROM nonexistent")
68 | except ConnectionHandlerError:
69 | pass
70 |
71 | assert stats.error_count == 1
72 | assert "ConnectionHandlerError" in stats.error_types
73 |
74 | # Test stats serialization
75 | stats_dict = stats.to_dict()
76 | assert stats_dict["query_count"] == 3 # Two successful queries + one failed query
77 | assert stats_dict["error_count"] == 1
78 | assert isinstance(stats_dict["connection_duration"], (int, float))
79 |
80 | # After context exit, connection should be closed
81 | assert stats.active_connections == 0
82 |
--------------------------------------------------------------------------------
/scripts/sonar-ai-fix.fish:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env fish
2 |
3 | function sonar-ai-fix
4 | set -l options (fish_opt --short=h --long=help)
5 | set options $options (fish_opt --short=p --long=pr --required-val)
6 | set options $options (fish_opt --short=o --long=output --required-val)
7 |
8 | argparse $options -- $argv
9 |
10 | # 显示帮助信息
11 | if set -q _flag_help
12 | echo "用法: sonar-ai-fix [选项]"
13 | echo ""
14 | echo "选项:"
15 | echo " -h, --help 显示帮助信息"
16 | echo " -p, --pr PR_NUMBER 获取特定PR的SonarCloud报告"
17 | echo " -o, --output PREFIX 设置输出文件名前缀 (默认: sonar)"
18 | echo ""
19 | echo "示例:"
20 | echo " sonar-ai-fix # 获取最新的SonarCloud报告"
21 | echo " sonar-ai-fix --pr 42 # 获取PR #42的SonarCloud报告"
22 | echo " sonar-ai-fix -o pr42 # 将输出文件保存为pr42_report.md和pr42_issues.json"
23 | return 0
24 | end
25 |
26 | # 设置输出文件名前缀
27 | set -l OUTPUT_PREFIX "sonar"
28 | if set -q _flag_output
29 | set OUTPUT_PREFIX $_flag_output
30 | end
31 |
32 | # 检查当前目录是否是项目目录
33 | if not test -f "pyproject.toml"; or not test -d "src/mcp_dbutils"
34 | echo "错误: 请在项目根目录运行此命令"
35 | echo "当前目录不是mcp-dbutils项目目录"
36 | return 1
37 | end
38 |
39 | # 下载最新的构件
40 | echo "正在下载 SonarCloud 分析报告..."
41 |
42 | # 获取工作流运行ID
43 | set -l RUN_ID
44 |
45 | if set -q _flag_pr
46 | echo "获取PR #$_flag_pr的SonarCloud报告..."
47 | set RUN_ID (gh run list --workflow "Quality Assurance" --branch "pull/$_flag_pr/head" --limit 1 --json databaseId --jq '.[0].databaseId')
48 | else
49 | echo "获取最新的SonarCloud报告..."
50 | set RUN_ID (gh run list --workflow "Quality Assurance" --limit 1 --json databaseId --jq '.[0].databaseId')
51 | end
52 |
53 | if test -z "$RUN_ID"
54 | echo "错误: 无法获取工作流运行ID"
55 | return 1
56 | else
57 | echo "RUN_ID: $RUN_ID"
58 | end
59 |
60 | # 创建临时目录存放下载的文件
61 | set TEMP_DIR (mktemp -d)
62 |
63 | # 下载构件
64 | gh run download $RUN_ID --name sonarcloud-issues --dir $TEMP_DIR
65 |
66 | if test $status -ne 0
67 | echo "错误: 下载构件失败"
68 | rm -rf $TEMP_DIR
69 | return 1
70 | end
71 |
72 | # 检查文件是否存在
73 | if not test -f "$TEMP_DIR/sonar_report.md"
74 | echo "错误: 未找到 sonar_report.md 文件"
75 | rm -rf $TEMP_DIR
76 | return 1
77 | end
78 |
79 | if not test -f "$TEMP_DIR/sonar_issues.json"
80 | echo "错误: 未找到 sonar_issues.json 文件"
81 | rm -rf $TEMP_DIR
82 | return 1
83 | end
84 |
85 | # 复制文件到当前目录
86 | set -l REPORT_FILE "$OUTPUT_PREFIX"_report.md
87 | set -l ISSUES_FILE "$OUTPUT_PREFIX"_issues.json
88 |
89 | cp "$TEMP_DIR/sonar_report.md" ./$REPORT_FILE
90 | cp "$TEMP_DIR/sonar_issues.json" ./$ISSUES_FILE
91 |
92 | # 清理临时目录
93 | rm -rf $TEMP_DIR
94 |
95 | echo "已下载 SonarCloud 分析报告:"
96 | echo "- $REPORT_FILE: Markdown格式的报告,适合人类阅读"
97 | echo "- $ISSUES_FILE: JSON格式的原始数据,适合AI处理"
98 | echo ""
99 | echo "使用方法:"
100 | echo "1. 查看报告: cat $REPORT_FILE"
101 | echo "2. 提供给AI: 将$REPORT_FILE的内容复制给AI,请求修复建议"
102 | echo "3. 高级分析: 将$ISSUES_FILE提供给AI进行更深入的分析"
103 | end
104 |
--------------------------------------------------------------------------------
/docs/write-operations.md:
--------------------------------------------------------------------------------
1 | # 数据库写操作功能
2 |
3 | MCP-DBUtils 2.0.0 版本引入了数据库写操作功能,允许在严格控制的条件下执行数据库写操作(INSERT、UPDATE、DELETE)。
4 |
5 | ## 功能特点
6 |
7 | 1. **默认只读**:所有数据库连接默认为只读模式,必须显式配置才能启用写操作。
8 | 2. **细粒度权限控制**:支持表级和操作级的细粒度权限控制。
9 | 3. **审计日志**:所有写操作都会记录详细的审计日志,包括操作类型、影响的表、SQL语句、执行结果等。
10 | 4. **交互式确认**:执行写操作时需要显式确认,防止意外修改数据。
11 | 5. **事务支持**:支持事务操作,确保数据一致性。
12 |
13 | ## 配置写操作
14 |
15 | 在配置文件中,可以为每个数据库连接单独配置写操作权限:
16 |
17 | ```yaml
18 | connections:
19 | example_db:
20 | type: sqlite
21 | path: "data/example.db"
22 | # 启用写操作
23 | writable: true
24 | # 细粒度写权限控制
25 | write_permissions:
26 | # 默认策略:read_only 或 allow_all
27 | default_policy: "read_only"
28 | # 表级权限
29 | tables:
30 | users:
31 | # 允许的操作类型
32 | operations: ["INSERT", "UPDATE"]
33 | logs:
34 | operations: ["INSERT", "UPDATE", "DELETE"]
35 | ```
36 |
37 | ### 配置选项
38 |
39 | - `writable`:是否允许写操作,默认为 `false`(只读)。
40 | - `write_permissions`:细粒度写权限配置。
41 | - `default_policy`:默认策略,可选值为 `read_only`(只读)或 `allow_all`(允许所有写操作)。
42 | - `tables`:表级权限配置,可以为每个表指定允许的操作类型。
43 |
44 | ### 表名大小写处理
45 |
46 | MCP-DBUtils 在处理表名时采用大小写不敏感的比较策略:
47 |
48 | - 在配置文件中,表名可以使用任意大小写(如 `users`、`Users` 或 `USERS`)。
49 | - 在 SQL 语句中,表名同样可以使用任意大小写。
50 | - 系统会自动将表名转换为小写进行比较,确保大小写不影响权限检查。
51 |
52 | 例如,以下配置和 SQL 语句都能正确匹配:
53 |
54 | ```yaml
55 | # 配置文件中使用小写表名
56 | tables:
57 | users:
58 | operations: ["INSERT", "UPDATE"]
59 | ```
60 |
61 | ```sql
62 | -- SQL 语句中使用大写表名,仍然能正确匹配权限
63 | INSERT INTO USERS (id, name) VALUES (1, 'test');
64 | ```
65 |
66 | ## 使用写操作工具
67 |
68 | MCP-DBUtils 提供了 `dbutils-execute-write` 工具用于执行写操作:
69 |
70 | ```json
71 | {
72 | "name": "dbutils-execute-write",
73 | "arguments": {
74 | "connection": "example_db",
75 | "sql": "INSERT INTO logs (event, timestamp) VALUES ('event1', CURRENT_TIMESTAMP)",
76 | "confirmation": "CONFIRM_WRITE"
77 | }
78 | }
79 | ```
80 |
81 | ### 参数说明
82 |
83 | - `connection`:数据库连接名称。
84 | - `sql`:SQL写操作语句(INSERT、UPDATE、DELETE)。
85 | - `confirmation`:确认字符串,必须为 `CONFIRM_WRITE`。
86 |
87 | ## 审计日志
88 |
89 | 所有写操作都会记录详细的审计日志,可以通过 `dbutils-get-audit-logs` 工具查询:
90 |
91 | ```json
92 | {
93 | "name": "dbutils-get-audit-logs",
94 | "arguments": {
95 | "connection": "example_db",
96 | "table": "logs",
97 | "operation_type": "INSERT",
98 | "status": "SUCCESS",
99 | "limit": 100
100 | }
101 | }
102 | ```
103 |
104 | ### 参数说明
105 |
106 | - `connection`:(可选)按数据库连接名称过滤。
107 | - `table`:(可选)按表名过滤。
108 | - `operation_type`:(可选)按操作类型过滤(INSERT、UPDATE、DELETE)。
109 | - `status`:(可选)按操作状态过滤(SUCCESS、FAILED)。
110 | - `limit`:(可选)返回记录数量限制,默认为 100。
111 |
112 | ### 审计日志配置
113 |
114 | 可以在配置文件中自定义审计日志行为:
115 |
116 | ```yaml
117 | audit:
118 | enabled: true
119 | file_storage:
120 | enabled: true
121 | path: "logs/audit"
122 | max_file_size: 10485760 # 10MB
123 | backup_count: 10
124 | memory_buffer:
125 | size: 1000 # 内存中保存的最近日志记录数量
126 | content:
127 | sanitize_sql: true # 是否对SQL语句进行脱敏处理
128 | include_user_context: true # 是否包含用户上下文信息
129 | ```
130 |
131 | ## 安全最佳实践
132 |
133 | 1. **最小权限原则**:只为必要的表和操作启用写权限。
134 | 2. **定期审计**:定期检查审计日志,监控数据库写操作。
135 | 3. **使用事务**:对于多步骤操作,使用事务确保数据一致性。
136 | 4. **参数化查询**:使用参数化查询防止SQL注入攻击。
137 | 5. **备份数据**:在执行重要写操作前备份数据。
138 |
139 | ## 注意事项
140 |
141 | - 写操作功能是一项高风险功能,请谨慎使用。
142 | - 所有写操作都会记录审计日志,包括操作类型、影响的表、SQL语句、执行结果等。
143 | - 执行写操作时需要显式确认,防止意外修改数据。
144 | - 默认情况下,所有数据库连接都是只读的,必须显式配置才能启用写操作。
145 |
--------------------------------------------------------------------------------
/scripts/fix_en_nav_links.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | 修复英文文档中的语言导航链接
4 |
5 | 用途:将英文文档中的语言导航链接中的"[English]"修改为纯文本"English"
6 | """
7 |
8 | import os
9 | import re
10 | from pathlib import Path
11 |
12 |
13 | def fix_en_nav_links(docs_root: Path) -> int:
14 | """修复英文文档中的语言导航链接"""
15 | fixed_count = 0
16 | en_dir = docs_root / "en"
17 |
18 | if not en_dir.exists():
19 | print("错误: 英文文档目录不存在")
20 | return 0
21 |
22 | # 递归查找所有英文markdown文件
23 | for md_file in en_dir.glob("**/*.md"):
24 | with open(md_file, 'r', encoding='utf-8') as f:
25 | content = f.read()
26 |
27 | # 查找语言导航链接
28 | nav_line_match = re.search(r'\*\[(.*?)\](.*?)\s*\|\s*(.*?)\*', content)
29 | if nav_line_match:
30 | nav_line = nav_line_match.group(0)
31 |
32 | # 检查是否需要修复
33 | if "[English]" in nav_line:
34 | # 替换 [English](链接) 为 English
35 | fixed_nav_line = re.sub(r'\[English\]\([^)]*\)', 'English', nav_line)
36 |
37 | # 更新文件内容
38 | new_content = content.replace(nav_line, fixed_nav_line)
39 |
40 | with open(md_file, 'w', encoding='utf-8') as f:
41 | f.write(new_content)
42 |
43 | print(f"已修复: {md_file}")
44 | fixed_count += 1
45 | else:
46 | # 如果没有找到语言导航链接,添加一个
47 | lines = content.split('\n')
48 | title_line = None
49 |
50 | # 查找标题行
51 | for i, line in enumerate(lines):
52 | if line.startswith('# '):
53 | title_line = i
54 | break
55 |
56 | if title_line is not None:
57 | # 获取文件相对路径
58 | relative_path = md_file.relative_to(en_dir)
59 | depth = len(relative_path.parts)
60 | prefix = "../" * depth
61 |
62 | # 构建语言导航链接
63 | nav_line = f"*English | [{LANGUAGE_NAMES['zh']}]({prefix}zh/{relative_path}) | [{LANGUAGE_NAMES['fr']}]({prefix}fr/{relative_path}) | [{LANGUAGE_NAMES['es']}]({prefix}es/{relative_path}) | [{LANGUAGE_NAMES['ar']}]({prefix}ar/{relative_path}) | [{LANGUAGE_NAMES['ru']}]({prefix}ru/{relative_path})*"
64 |
65 | # 插入语言导航链接
66 | lines.insert(title_line + 1, "")
67 | lines.insert(title_line + 2, nav_line)
68 | lines.insert(title_line + 3, "")
69 |
70 | # 更新文件内容
71 | new_content = '\n'.join(lines)
72 |
73 | with open(md_file, 'w', encoding='utf-8') as f:
74 | f.write(new_content)
75 |
76 | print(f"已添加语言导航链接: {md_file}")
77 | fixed_count += 1
78 |
79 | return fixed_count
80 |
81 | # 语言显示名称
82 | LANGUAGE_NAMES = {
83 | "en": "English",
84 | "zh": "中文",
85 | "fr": "Français",
86 | "es": "Español",
87 | "ar": "العربية",
88 | "ru": "Русский"
89 | }
90 |
91 | def main():
92 | docs_root = Path("docs")
93 | if not docs_root.exists():
94 | print("错误: 'docs' 目录不存在")
95 | return
96 |
97 | print("开始修复英文文档中的语言导航链接...\n")
98 |
99 | fixed_count = fix_en_nav_links(docs_root)
100 |
101 | print(f"\n完成! 已修复 {fixed_count} 个文件。")
102 |
103 | if __name__ == "__main__":
104 | main()
105 |
--------------------------------------------------------------------------------
/scripts/check_zh_docs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | 中文文档一致性检查工具
4 |
5 | 用途:检查中文文档是否符合一致性标准,以便作为其他语言的模板
6 | """
7 |
8 | import os
9 | import re
10 | import sys
11 | from pathlib import Path
12 | from typing import Dict, List, Set, Tuple
13 |
14 |
15 | def check_zh_docs(docs_root: Path) -> List[Tuple[str, str]]:
16 | """检查所有中文文档的一致性"""
17 | issues = []
18 | zh_dir = docs_root / "zh"
19 |
20 | if not zh_dir.exists():
21 | return [("docs/zh", "中文文档目录不存在")]
22 |
23 | # 递归查找所有中文markdown文件
24 | for md_file in zh_dir.glob("**/*.md"):
25 | relative_path = md_file.relative_to(zh_dir)
26 |
27 | # 检查文件内容
28 | with open(md_file, 'r', encoding='utf-8') as f:
29 | content = f.read()
30 |
31 | # 检查标题
32 | if not content.startswith("# "):
33 | issues.append((str(md_file), "文档应以H1标题开始"))
34 |
35 | # 检查语言导航链接
36 | nav_line_match = re.search(r'\*\[(.*?)\](.*?)\s*\|\s*(.*?)\*', content)
37 | if not nav_line_match:
38 | issues.append((str(md_file), "缺少语言导航链接"))
39 | else:
40 | nav_line = nav_line_match.group(0)
41 |
42 | # 检查当前语言(中文)是否为纯文本
43 | if "[中文]" in nav_line:
44 | issues.append((str(md_file), "当前语言'中文'不应该是链接"))
45 | elif "中文" not in nav_line:
46 | issues.append((str(md_file), "语言导航链接中缺少'中文'"))
47 |
48 | # 检查相对路径是否正确
49 | depth = len(relative_path.parts)
50 | correct_prefix = "../" * depth
51 |
52 | # 检查是否使用了正确的相对路径格式
53 | if depth > 0:
54 | for lang in ["en", "fr", "es", "ar", "ru"]:
55 | lang_text = {
56 | "en": "English",
57 | "fr": "Français",
58 | "es": "Español",
59 | "ar": "العربية",
60 | "ru": "Русский"
61 | }[lang]
62 |
63 | # 查找该语言的链接
64 | lang_link_match = re.search(rf'\[{lang_text}\]\((.*?)\)', nav_line)
65 | if lang_link_match:
66 | link_path = lang_link_match.group(1)
67 | if not link_path.startswith(correct_prefix):
68 | issues.append((str(md_file), f"'{lang_text}'链接的相对路径不正确,应使用'{correct_prefix}'"))
69 |
70 | # 检查Mermaid图表
71 | if "```mermaid" in content:
72 | # 确保mermaid图表格式正确
73 | mermaid_blocks = re.findall(r'```mermaid\n(.*?)```', content, re.DOTALL)
74 | for block in mermaid_blocks:
75 | if not block.strip():
76 | issues.append((str(md_file), "存在空的Mermaid图表"))
77 |
78 | return issues
79 |
80 | def main():
81 | docs_root = Path("docs")
82 | if not docs_root.exists():
83 | print("错误: 'docs' 目录不存在")
84 | sys.exit(1)
85 |
86 | print("检查中文文档一致性...\n")
87 |
88 | issues = check_zh_docs(docs_root)
89 | if issues:
90 | print("发现问题:")
91 | for file, issue in issues:
92 | print(f" - {file}: {issue}")
93 | print(f"\n总计: {len(issues)} 个问题")
94 | sys.exit(1)
95 | else:
96 | print("恭喜!中文文档检查通过,可以作为模板。")
97 | sys.exit(0)
98 |
99 | if __name__ == "__main__":
100 | main()
101 |
--------------------------------------------------------------------------------
/docs/zh/technical/architecture.md:
--------------------------------------------------------------------------------
1 | # 架构
2 |
3 | *[English](../../en/technical/architecture.md) | 中文 | [Français](../../fr/technical/architecture.md) | [Español](../../es/technical/architecture.md) | [العربية](../../ar/technical/architecture.md) | [Русский](../../ru/technical/architecture.md)*
4 |
5 | 本文档描述了 MCP 数据库工具的技术架构,解释了各个组件如何交互以为 AI 助手提供安全的数据库访问。
6 |
7 | ## 架构概述
8 |
9 | MCP 数据库工具采用模块化架构设计,优先考虑安全性、隔离性和灵活性。系统由几个不同的层组成,它们共同工作以提供对数据库的安全只读访问。
10 |
11 | ## 核心概念:抽象层设计
12 |
13 | ```mermaid
14 | graph TD
15 | Client[客户端] --> DatabaseServer[数据库服务器]
16 | subgraph MCP 服务器
17 | DatabaseServer
18 | DatabaseHandler[数据库处理器]
19 | PostgresHandler[PostgreSQL处理器]
20 | SQLiteHandler[SQLite处理器]
21 | MySQLHandler[MySQL处理器]
22 | DatabaseServer --> DatabaseHandler
23 | DatabaseHandler --> PostgresHandler
24 | DatabaseHandler --> SQLiteHandler
25 | DatabaseHandler --> MySQLHandler
26 | end
27 | PostgresHandler --> PostgreSQL[(PostgreSQL)]
28 | SQLiteHandler --> SQLite[(SQLite)]
29 | MySQLHandler --> MySQL[(MySQL)]
30 | ```
31 |
32 | 抽象层设计是MCP数据库工具的核心架构概念。就像通用遥控器可以控制不同设备一样,用户只需要了解基本操作,而无需理解底层复杂性。
33 |
34 | ### 1. 简化用户交互
35 | - 用户只需知道数据库配置名称(例如"my_postgres")
36 | - 无需处理连接参数和实现细节
37 | - MCP服务器自动处理数据库连接和查询
38 |
39 | ### 2. 统一接口设计
40 | - DatabaseHandler抽象类定义了统一的操作接口
41 | - 所有特定数据库实现(PostgreSQL/SQLite/MySQL)遵循相同的接口
42 | - 用户以相同的方式与不同数据库交互
43 |
44 | ### 3. 配置和实现分离
45 | - 复杂的数据库配置参数封装在配置文件中
46 | - 运行时通过简单的数据库名称访问
47 | - 可以轻松管理和修改数据库配置,而不影响业务代码
48 |
49 | ## 系统组件
50 | 1. DatabaseServer
51 | - MCP服务器的核心组件
52 | - 处理资源和工具请求
53 | - 管理数据库连接生命周期
54 |
55 | 2. DatabaseHandler
56 | - 定义统一接口的抽象基类
57 | - 包括get_tables()、get_schema()、execute_query()等方法
58 | - 由PostgreSQL、SQLite和MySQL处理器实现
59 |
60 | 3. 配置系统
61 | - 基于YAML的配置文件
62 | - 支持多个数据库配置
63 | - 类型安全的配置验证
64 |
65 | 4. 错误处理和日志记录
66 | - 统一的错误处理机制
67 | - 详细的日志输出
68 | - 敏感信息掩码处理
69 |
70 | ## API文档
71 |
72 | ### DatabaseServer
73 | 核心服务器类,提供:
74 | - 资源列表检索
75 | - 工具调用处理(list_tables、query等)
76 | - 数据库处理器管理
77 |
78 | ### MCP工具
79 |
80 | #### dbutils-list-tables
81 | 列出指定数据库中的所有表。
82 | - 参数:
83 | * connection: 数据库连接名称
84 | - 返回:包含表名列表的文本内容
85 |
86 | #### dbutils-run-query
87 | 在指定数据库上执行SQL查询。
88 | - 参数:
89 | * connection: 数据库连接名称
90 | * sql: 要执行的SQL查询(仅SELECT)
91 | - 返回:格式化文本形式的查询结果
92 |
93 | #### dbutils-get-stats
94 | 获取表统计信息。
95 | - 参数:
96 | * connection: 数据库连接名称
97 | * table: 表名
98 | - 返回:包括行数、大小、列统计信息等
99 |
100 | #### dbutils-list-constraints
101 | 列出表约束(主键、外键等)。
102 | - 参数:
103 | * connection: 数据库连接名称
104 | * table: 表名
105 | - 返回:详细的约束信息
106 |
107 | #### dbutils-explain-query
108 | 获取查询执行计划和成本估算。
109 | - 参数:
110 | * connection: 数据库连接名称
111 | * sql: 要解释的SQL查询
112 | - 返回:格式化的执行计划
113 |
114 | #### dbutils-get-performance
115 | 获取数据库性能统计信息。
116 | - 参数:
117 | * connection: 数据库连接名称
118 | - 返回:详细的性能统计信息,包括查询时间、查询类型、错误率和资源使用情况
119 |
120 | #### dbutils-analyze-query
121 | 分析SQL查询的性能并提供优化建议。
122 | - 参数:
123 | * connection: 数据库连接名称
124 | * sql: 要分析的SQL查询
125 | - 返回:包含执行计划、时间信息和优化建议的查询分析
126 |
127 | ### DatabaseHandler
128 | 定义接口的抽象基类:
129 | - get_tables():获取表资源列表
130 | - get_schema():获取表结构
131 | - execute_query():执行SQL查询
132 | - cleanup():资源清理
133 |
134 | ### PostgreSQL实现
135 | 提供PostgreSQL特定功能:
136 | - 远程连接支持
137 | - 表描述信息
138 | - 约束查询
139 |
140 | ### SQLite实现
141 | 提供SQLite特定功能:
142 | - 文件路径处理
143 | - URI方案支持
144 | - 密码保护支持(可选)
145 |
146 | ### MySQL实现
147 | 提供MySQL特定功能:
148 | - 远程连接支持
149 | - 字符集配置
150 | - SSL/TLS安全连接
151 | - URL和标准连接方法
152 |
153 | ## 高级功能
154 |
155 | ### 数据处理器
156 |
157 | 数据处理器负责后处理数据库查询结果,提供易读格式,并支持多种输出选项:
158 |
159 | - 表格格式数据
160 | - 树状数据层次结构
161 | - 特殊资源类型处理(二进制数据、图像等)
162 |
163 | ### 工具定义
164 |
165 | MCP工具定义在`src/mcp_dbutils/tools.py`文件中,包括:
166 |
167 | - `list_resources`:列出数据库资源
168 | - `read_resource`:读取单个表或视图内容
169 | - `call_tool`:执行自定义SQL查询
170 | - `get_schema`:获取表或视图结构
171 | - `get_info`:获取资源详细信息
--------------------------------------------------------------------------------
/docs/zh/technical/development.md:
--------------------------------------------------------------------------------
1 | # 开发指南
2 |
3 | *[English](../../en/technical/development.md) | 中文 | [Français](../../fr/technical/development.md) | [Español](../../es/technical/development.md) | [العربية](../../ar/technical/development.md) | [Русский](../../ru/technical/development.md)*
4 |
5 | 本文档提供了有关开发流程、代码标准和为 MCP 数据库工具项目做贡献的最佳实践的详细信息。
6 |
7 | ## 代码质量
8 |
9 | ### 质量门禁
10 | 我们使用SonarCloud维护高代码质量标准。所有拉取请求必须通过以下质量门禁:
11 |
12 | - 代码覆盖率:≥ 80%
13 | - 代码质量:
14 | * 无阻断或严重问题
15 | * 主要问题少于10个
16 | * 代码重复率 < 3%
17 | - 安全性:
18 | * 无安全漏洞
19 | * 无安全热点
20 |
21 | ### 自动化检查
22 | 我们的CI/CD流程自动执行:
23 | 1. 完整测试套件执行
24 | 2. 代码覆盖率分析
25 | 3. SonarCloud静态代码分析
26 | 4. 质量门禁验证
27 |
28 | 不满足这些标准的拉取请求将自动被阻止合并。
29 |
30 | ### 代码风格
31 |
32 | 我们使用Ruff进行代码风格检查和格式化,确保代码质量和一致性。
33 |
34 | #### 基本规则
35 |
36 | 1. **行长度**:最大88个字符
37 | 2. **缩进**:使用4个空格(不使用制表符)
38 | 3. **引号**:使用双引号作为字符串引号
39 | 4. **命名规范**:
40 | - 类名:使用CamelCase(如`DatabaseHandler`)
41 | - 函数和变量:使用snake_case(如`execute_query`)
42 | - 常量:使用大写加下划线(如`MAX_CONNECTIONS`)
43 | - 私有方法和属性:使用单下划线前缀(如`_connect`)
44 |
45 | #### 导入规则
46 |
47 | 1. 导入顺序:
48 | - 标准库
49 | - 第三方库
50 | - 本地应用/库
51 |
52 | 2. 每个导入组之间应有一个空行
53 |
54 | #### 代码组织
55 |
56 | 1. 类定义之间应有两个空行
57 | 2. 方法定义之间应有一个空行
58 | 3. 相关的代码应该分组在一起
59 |
60 | #### Ruff规则集
61 |
62 | 本项目使用以下Ruff规则集:
63 |
64 | - `E`: pycodestyle错误
65 | - `F`: pyflakes
66 | - `I`: isort
67 | - `N`: pep8-naming
68 | - `UP`: pyupgrade
69 | - `B`: flake8-bugbear
70 | - `C4`: flake8-comprehensions
71 | - `SIM`: flake8-simplify
72 | - `T20`: flake8-print
73 |
74 | ### 本地开发
75 |
76 | #### 安装工具
77 |
78 | ```bash
79 | # 安装Ruff
80 | uv pip install ruff
81 |
82 | # 安装pre-commit
83 | uv pip install pre-commit
84 | pre-commit install
85 | ```
86 |
87 | #### 代码检查
88 |
89 | ```bash
90 | # 检查整个项目
91 | ruff check .
92 |
93 | # 自动修复问题
94 | ruff check --fix .
95 | ```
96 |
97 | #### 代码格式化
98 |
99 | ```bash
100 | # 检查格式
101 | ruff format --check .
102 |
103 | # 自动格式化
104 | ruff format .
105 | ```
106 |
107 | #### 使用pre-commit
108 |
109 | 项目已配置pre-commit钩子,提交代码时会自动运行Ruff检查和格式化。
110 |
111 | ```bash
112 | # 手动运行pre-commit
113 | pre-commit run --all-files
114 | ```
115 |
116 | #### 测试与覆盖率
117 |
118 | ```bash
119 | # 运行带覆盖率的测试
120 | pytest --cov=src/mcp_dbutils --cov-report=xml:coverage.xml tests/
121 | ```
122 |
123 | #### 其他开发工具
124 |
125 | 1. 在IDE中使用SonarLint及早发现问题
126 | 2. 在PR评论中查看SonarCloud分析结果
127 |
128 | ### 常见问题
129 |
130 | #### 如何忽略特定规则?
131 |
132 | 在代码中使用注释忽略特定行的规则:
133 |
134 | ```python
135 | # 忽略整行
136 | some_code_here # noqa
137 |
138 | # 忽略特定规则
139 | some_code_here # noqa: E501
140 |
141 | # 忽略多个规则
142 | some_code_here # noqa: E501, F401
143 | ```
144 |
145 | #### 如何在项目级别忽略规则?
146 |
147 | 在`pyproject.toml`的`[tool.ruff]`部分添加:
148 |
149 | ```toml
150 | ignore = ["E501"]
151 | ```
152 |
153 | #### 如何处理第三方库导入问题?
154 |
155 | 如果第三方库导入顺序有问题,可以在`pyproject.toml`中配置:
156 |
157 | ```toml
158 | [tool.ruff.isort]
159 | known-third-party = ["third_party_lib"]
160 | ```
161 |
162 | ### CI/CD 集成
163 |
164 | GitHub Actions 会在每次推送和 PR 时自动运行 Ruff 检查和格式化,确保代码符合规范。
165 |
166 | #### 自动化流程
167 |
168 | 每个 PR 会触发以下自动化检查:
169 |
170 | 1. **代码风格检查**:使用 Ruff 验证代码是否符合项目风格规范
171 | 2. **单元测试**:运行所有测试确保功能正常
172 | 3. **代码覆盖率**:确保测试覆盖率达到要求
173 | 4. **SonarCloud 分析**:进行深度代码质量和安全性分析
174 |
175 | #### 如何查看 CI 结果
176 |
177 | 1. 在 GitHub PR 页面查看 "Checks" 标签页
178 | 2. 点击具体的检查查看详细信息
179 | 3. 对于 SonarCloud 分析,可以点击链接查看完整报告
180 |
181 | ## 版本更新
182 |
183 | MCP数据库工具会定期发布更新,包含新功能、性能改进和错误修复。大多数情况下,更新过程由MCP客户端自动管理,您无需手动干预。
184 |
185 | ### 获取最新版本
186 |
187 | - **使用MCP客户端**:大多数MCP客户端(如Claude Desktop、Cursor等)会自动更新到最新版本
188 |
189 | - **手动检查更新**:
190 | - 访问[GitHub仓库](https://github.com/donghao1393/mcp-dbutils)查看最新版本
191 | - 阅读[发布说明](https://github.com/donghao1393/mcp-dbutils/releases)了解新功能和变更
192 |
193 | - **问题报告**:
194 | - 如果您在更新后遇到问题,请[提交issue](https://github.com/donghao1393/mcp-dbutils/issues)
--------------------------------------------------------------------------------
/docs/zh/examples/sqlite-examples.md:
--------------------------------------------------------------------------------
1 | # SQLite 示例
2 |
3 | *[English](../../en/examples/sqlite-examples.md) | 中文 | [Français](../../fr/examples/sqlite-examples.md) | [Español](../../es/examples/sqlite-examples.md) | [العربية](../../ar/examples/sqlite-examples.md) | [Русский](../../ru/examples/sqlite-examples.md)*
4 |
5 | 本文档提供了使用 MCP 数据库工具操作 SQLite 数据库的实用示例。
6 |
7 | ## 基本配置
8 |
9 | ```yaml
10 | connections:
11 | my-sqlite:
12 | type: sqlite
13 | path: /path/to/database.db
14 | ```
15 |
16 | ## 常见操作
17 |
18 | ### 列出表格
19 |
20 | **您**:"列出我的 SQLite 数据库中的所有表。"
21 |
22 | **AI**:"以下是您的 SQLite 数据库中的表:
23 | - users(用户)
24 | - products(产品)
25 | - orders(订单)
26 | - categories(类别)"
27 |
28 | ### 查看表结构
29 |
30 | **您**:"显示 users 表的结构。"
31 |
32 | **AI**:"users 表的结构如下:
33 | - id (INTEGER, PRIMARY KEY)
34 | - username (TEXT, NOT NULL)
35 | - email (TEXT, NOT NULL, UNIQUE)
36 | - created_at (TIMESTAMP)
37 | - last_login (TIMESTAMP)
38 | - status (TEXT)"
39 |
40 | ### 基本查询
41 |
42 | **您**:"显示按最后登录日期排序的前 5 名用户。"
43 |
44 | **AI**:"以下是按最后登录日期排序的前 5 名用户:
45 |
46 | | id | username | email | last_login |
47 | |----|----------|-------|------------|
48 | | 42 | johndoe | john@example.com | 2023-11-25 14:32:15 |
49 | | 17 | janedoe | jane@example.com | 2023-11-24 09:45:22 |
50 | | 31 | bobsmith | bob@example.com | 2023-11-23 18:12:05 |
51 | | 8 | alicejones | alice@example.com | 2023-11-22 11:30:47 |
52 | | 53 | mikebrown | mike@example.com | 2023-11-21 16:08:33 |"
53 |
54 | ## 高级查询
55 |
56 | ### 表连接
57 |
58 | **您**:"显示最近 3 个订单及其用户信息。"
59 |
60 | **AI**:"以下是最近 3 个订单及其用户信息:
61 |
62 | | order_id | order_date | username | email | total_amount |
63 | |----------|------------|----------|-------|--------------|
64 | | 1042 | 2023-11-25 | johndoe | john@example.com | ¥125.99 |
65 | | 1041 | 2023-11-24 | alicejones | alice@example.com | ¥89.50 |
66 | | 1040 | 2023-11-23 | bobsmith | bob@example.com | ¥212.75 |"
67 |
68 | ### 聚合函数
69 |
70 | **您**:"每个类别的平均订单金额是多少?"
71 |
72 | **AI**:"以下是每个类别的平均订单金额:
73 |
74 | | category | average_amount |
75 | |----------|----------------|
76 | | Electronics(电子产品) | ¥245.75 |
77 | | Clothing(服装) | ¥78.30 |
78 | | Books(图书) | ¥32.50 |
79 | | Home & Kitchen(家居与厨房) | ¥124.90 |
80 | | Sports & Outdoors(运动与户外) | ¥156.25 |"
81 |
82 | ## 性能分析
83 |
84 | ### 查询执行计划
85 |
86 | **您**:"解释这个查询的执行计划:SELECT * FROM orders WHERE user_id = 42"
87 |
88 | **AI**:"该查询的执行计划:
89 | ```
90 | QUERY PLAN
91 | ------------------------------------------------------------
92 | SEARCH TABLE orders USING INDEX idx_user_id (user_id=?)
93 | ```
94 |
95 | 此查询使用 `idx_user_id` 索引高效地查找 user_id 为 42 的订单。"
96 |
97 | ### 表统计信息
98 |
99 | **您**:"获取 orders 表的统计信息。"
100 |
101 | **AI**:"orders 表的统计信息:
102 | - 行数:1,245
103 | - 大小:2.3 MB
104 | - 索引:3 个(主键、idx_user_id、idx_order_date)
105 | - 平均行长度:1.9 KB"
106 |
107 | ## 使用 SQLite 特有功能
108 |
109 | ### 使用 FTS(全文搜索)
110 |
111 | **您**:"搜索包含'无线耳机'的产品。"
112 |
113 | **AI**:"以下是匹配'无线耳机'的产品:
114 |
115 | | product_id | name | description | price |
116 | |------------|------|-------------|-------|
117 | | 123 | 高级无线耳机 | 带有 30 小时电池续航的降噪无线耳机 | ¥199.99 |
118 | | 145 | 运动无线耳机 | 防水运动无线耳机 | ¥89.99 |
119 | | 187 | 经济型无线耳机 | 音质优良的经济实惠无线耳机 | ¥49.99 |"
120 |
121 | ### 使用 JSON 函数
122 |
123 | **您**:"显示偏好设置中包含'premium'的用户。"
124 |
125 | **AI**:"以下是偏好设置中包含'premium'的用户:
126 |
127 | | id | username | preferences |
128 | |----|----------|-------------|
129 | | 42 | johndoe | {\"subscription\": \"premium\", \"theme\": \"dark\"} |
130 | | 17 | janedoe | {\"subscription\": \"premium\", \"theme\": \"light\"} |
131 | | 53 | mikebrown | {\"subscription\": \"premium\", \"theme\": \"auto\"} |"
132 |
133 | ## 故障排除
134 |
135 | ### 常见问题
136 |
137 | 1. **文件未找到**
138 | - 确保 SQLite 数据库文件的路径正确
139 | - 检查文件权限
140 | - 验证文件是否存在
141 |
142 | 2. **数据库锁定**
143 | - SQLite 一次只允许一个写入者
144 | - 确保没有其他进程正在写入数据库
145 | - 考虑使用 WAL 模式以获得更好的并发性
146 |
147 | 3. **性能问题**
148 | - 为经常查询的列添加索引
149 | - 使用 EXPLAIN QUERY PLAN 识别慢查询
150 | - 考虑对重复查询使用预处理语句
--------------------------------------------------------------------------------
/tests/integration/test_sqlite_config.py:
--------------------------------------------------------------------------------
1 | """Test SQLite configuration functionality"""
2 | from pathlib import Path
3 |
4 | import pytest
5 | import yaml
6 |
7 | from mcp_dbutils.sqlite.config import SQLiteConfig, parse_jdbc_url
8 |
9 |
10 | def test_parse_jdbc_url():
11 | """Test JDBC URL parsing"""
12 | # Test basic URL
13 | url = "jdbc:sqlite:/path/to/test.db"
14 | params = parse_jdbc_url(url)
15 | assert params["path"] == "/path/to/test.db"
16 | assert params["parameters"] == {}
17 |
18 | # Test URL with file: prefix
19 | url = "jdbc:sqlite:file:/path/to/test.db"
20 | params = parse_jdbc_url(url)
21 | assert params["path"] == "/path/to/test.db"
22 | assert params["parameters"] == {}
23 |
24 | # Test URL with parameters
25 | url = "jdbc:sqlite:/path/to/test.db?mode=ro&cache=shared"
26 | params = parse_jdbc_url(url)
27 | assert params["path"] == "/path/to/test.db"
28 | assert params["parameters"] == {"mode": "ro", "cache": "shared"}
29 |
30 | # Test invalid format
31 | with pytest.raises(ValueError, match="Invalid SQLite JDBC URL format"):
32 | parse_jdbc_url("sqlite:/path/to/test.db")
33 |
34 | # Test missing path
35 | with pytest.raises(ValueError, match="SQLite file path must be specified"):
36 | parse_jdbc_url("jdbc:sqlite:")
37 |
38 | def test_from_jdbc_url():
39 | """Test SQLiteConfig creation from JDBC URL"""
40 | url = "jdbc:sqlite:/path/to/test.db"
41 | config = SQLiteConfig.from_jdbc_url(url)
42 |
43 | assert str(Path(config.path)) == str(Path("/path/to/test.db"))
44 | assert config.password is None
45 | assert config.uri is True
46 | assert config.type == "sqlite"
47 |
48 | # Test with password
49 | config = SQLiteConfig.from_jdbc_url(url, password="test_pass")
50 | assert config.password == "test_pass"
51 | assert config.uri is True
52 |
53 | def test_from_yaml_with_jdbc_url(tmp_path):
54 | """Test SQLiteConfig creation from YAML with JDBC URL"""
55 | config_data = {
56 | "connections": {
57 | "test_db": {
58 | "type": "sqlite",
59 | "jdbc_url": "jdbc:sqlite:/path/to/test.db",
60 | "password": "test_pass"
61 | }
62 | }
63 | }
64 |
65 | config_file = tmp_path / "config.yaml"
66 | with open(config_file, "w") as f:
67 | yaml.dump(config_data, f)
68 |
69 | config = SQLiteConfig.from_yaml(str(config_file), "test_db")
70 | assert str(Path(config.path)) == str(Path("/path/to/test.db"))
71 | assert config.password == "test_pass"
72 | assert config.uri is True
73 | assert config.type == "sqlite"
74 |
75 | def test_required_fields_validation(tmp_path):
76 | """Test validation of required configuration fields"""
77 | # Missing type
78 | config_data = {
79 | "connections": {
80 | "test_db": {
81 | "jdbc_url": "jdbc:sqlite:/path/to/test.db"
82 | }
83 | }
84 | }
85 |
86 | config_file = tmp_path / "config.yaml"
87 | with open(config_file, "w") as f:
88 | yaml.dump(config_data, f)
89 |
90 | with pytest.raises(ValueError, match="missing required 'type' field"):
91 | SQLiteConfig.from_yaml(str(config_file), "test_db")
92 |
93 | # Wrong type
94 | config_data["connections"]["test_db"]["type"] = "postgres"
95 |
96 | with open(config_file, "w") as f:
97 | yaml.dump(config_data, f)
98 |
99 | with pytest.raises(ValueError, match="Configuration is not SQLite type"):
100 | SQLiteConfig.from_yaml(str(config_file), "test_db")
101 |
102 | # Standard config (non-JDBC) missing path
103 | config_data["connections"]["test_db"] = {
104 | "type": "sqlite"
105 | }
106 |
107 | with open(config_file, "w") as f:
108 | yaml.dump(config_data, f)
109 |
110 | with pytest.raises(ValueError, match="must include 'path' field"):
111 | SQLiteConfig.from_yaml(str(config_file), "test_db")
112 |
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | import tempfile
2 | from collections.abc import AsyncGenerator
3 | from pathlib import Path
4 | from typing import Dict
5 | from urllib.parse import urlparse
6 |
7 | import aiosqlite
8 | import psycopg2
9 | import pytest
10 | from pytest_asyncio import fixture
11 | from testcontainers.postgres import PostgresContainer
12 |
13 | # Enable pytest-asyncio for testing
14 | pytest.register_assert_rewrite("tests")
15 | pytestmark = pytest.mark.asyncio
16 |
17 | def parse_postgres_url(url: str) -> Dict[str, str]:
18 | """Parse postgres URL into connection parameters"""
19 | # Remove postgres+psycopg2:// prefix if present
20 | if url.startswith('postgresql+psycopg2://'):
21 | url = url.replace('postgresql+psycopg2://', 'postgresql://')
22 |
23 | parsed = urlparse(url)
24 | params = {
25 | 'dbname': parsed.path[1:], # Remove leading '/'
26 | 'user': parsed.username,
27 | 'password': parsed.password,
28 | 'host': parsed.hostname,
29 | 'port': parsed.port or 5432 # Default port if not specified
30 | }
31 | return {k: v for k, v in params.items() if v is not None}
32 |
33 | @fixture(scope="function")
34 | async def postgres_db() -> AsyncGenerator[Dict[str, str], None]:
35 | """
36 | Create a temporary PostgreSQL database for testing.
37 | """
38 | postgres = PostgresContainer("postgres:15-alpine")
39 | postgres.start()
40 |
41 | try:
42 | url = postgres.get_connection_url()
43 | # Get connection parameters from URL
44 | conn_params = parse_postgres_url(url)
45 |
46 | # Create direct connection using psycopg2
47 | conn = psycopg2.connect(**conn_params)
48 | cur = conn.cursor()
49 |
50 | # Create test data
51 | cur.execute("""
52 | CREATE TABLE users (
53 | id SERIAL PRIMARY KEY,
54 | name TEXT NOT NULL,
55 | email TEXT UNIQUE
56 | );
57 |
58 | INSERT INTO users (name, email) VALUES
59 | ('Alice', 'alice@test.com'),
60 | ('Bob', 'bob@test.com');
61 | """)
62 | conn.commit()
63 | cur.close()
64 | conn.close()
65 |
66 | # Parse URL into connection parameters
67 | conn_params = parse_postgres_url(url)
68 | conn_info = {
69 | "type": "postgres",
70 | **conn_params
71 | }
72 | yield conn_info
73 |
74 | finally:
75 | postgres.stop()
76 |
77 | @fixture(scope="function")
78 | async def sqlite_db() -> AsyncGenerator[Dict[str, str], None]:
79 | """
80 | Create a temporary SQLite database for testing.
81 | """
82 | with tempfile.NamedTemporaryFile(suffix='.db', delete=False) as tmp:
83 | db_path = Path(tmp.name)
84 |
85 | # Create test database file and data
86 | async with aiosqlite.connect(db_path) as db:
87 | await db.execute("""
88 | CREATE TABLE products (
89 | id INTEGER PRIMARY KEY AUTOINCREMENT,
90 | name TEXT NOT NULL,
91 | price REAL NOT NULL
92 | );
93 | """)
94 | await db.execute("""
95 | INSERT INTO products (name, price) VALUES
96 | ('Widget', 9.99),
97 | ('Gadget', 19.99);
98 | """)
99 | await db.commit()
100 |
101 | conn_info = {
102 | "type": "sqlite",
103 | "path": str(db_path)
104 | }
105 | yield conn_info
106 |
107 | # Clean up
108 | try:
109 | db_path.unlink()
110 | except FileNotFoundError:
111 | pass
112 |
113 | @fixture(scope="function")
114 | async def mcp_config(postgres_db, sqlite_db) -> Dict:
115 | """
116 | Generate MCP server configuration for testing.
117 | """
118 | return {
119 | "connections": {
120 | "test_pg": postgres_db,
121 | "test_sqlite": sqlite_db
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/tests/integration/test_sqlite.py:
--------------------------------------------------------------------------------
1 | import tempfile
2 |
3 | import pytest
4 | import yaml
5 |
6 | from mcp_dbutils.base import (
7 | ConnectionHandlerError,
8 | ConnectionServer,
9 | )
10 |
11 |
12 | @pytest.mark.asyncio
13 | async def test_list_tables(sqlite_db, mcp_config):
14 | """Test listing tables in SQLite database"""
15 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
16 | yaml.dump(mcp_config, tmp)
17 | tmp.flush()
18 | server = ConnectionServer(config_path=tmp.name)
19 | async with server.get_handler("test_sqlite") as handler:
20 | tables = await handler.get_tables()
21 | table_names = [table.name.replace(" schema", "") for table in tables]
22 | assert "products" in table_names
23 |
24 | # Check schema information
25 | schema_str = await handler.get_schema("products")
26 | schema = eval(schema_str)
27 | assert schema["columns"][0]["name"] == "id"
28 | assert schema["columns"][0]["type"] == "INTEGER"
29 | assert schema["columns"][1]["name"] == "name"
30 | assert schema["columns"][1]["type"] == "TEXT"
31 | assert schema["columns"][2]["name"] == "price"
32 | assert schema["columns"][2]["type"] == "REAL"
33 | assert schema["columns"][0]["primary_key"] is True
34 |
35 | @pytest.mark.asyncio
36 | async def test_execute_query(sqlite_db, mcp_config):
37 | """Test executing SELECT queries"""
38 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
39 | yaml.dump(mcp_config, tmp)
40 | tmp.flush()
41 | server = ConnectionServer(config_path=tmp.name)
42 | async with server.get_handler("test_sqlite") as handler:
43 | # Simple SELECT
44 | result_str = await handler.execute_query("SELECT name FROM products ORDER BY price")
45 | result = eval(result_str)
46 | assert len(result["rows"]) == 2
47 | assert result["rows"][0]["name"] == "Widget" # $9.99
48 | assert result["rows"][1]["name"] == "Gadget" # $19.99
49 |
50 | # SELECT with WHERE clause
51 | result_str = await handler.execute_query(
52 | "SELECT * FROM products WHERE price < 10.00"
53 | )
54 | result = eval(result_str)
55 | assert len(result["rows"]) == 1
56 | assert result["rows"][0]["name"] == "Widget"
57 | assert float(result["rows"][0]["price"]) == 9.99
58 |
59 | @pytest.mark.asyncio
60 | async def test_non_select_query(sqlite_db, mcp_config):
61 | """Test executing non-SELECT queries"""
62 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
63 | yaml.dump(mcp_config, tmp)
64 | tmp.flush()
65 | server = ConnectionServer(config_path=tmp.name)
66 | async with server.get_handler("test_sqlite") as handler:
67 | # 我们现在允许非SELECT查询
68 | result = await handler.execute_query("DELETE FROM products")
69 | assert result == "Query executed successfully"
70 |
71 | @pytest.mark.asyncio
72 | async def test_invalid_query(sqlite_db, mcp_config):
73 | """Test handling of invalid SQL queries"""
74 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
75 | yaml.dump(mcp_config, tmp)
76 | tmp.flush()
77 | server = ConnectionServer(config_path=tmp.name)
78 | async with server.get_handler("test_sqlite") as handler:
79 | with pytest.raises(ConnectionHandlerError):
80 | await handler.execute_query("SELECT * FROM nonexistent_table")
81 |
82 | @pytest.mark.asyncio
83 | async def test_connection_cleanup(sqlite_db, mcp_config):
84 | """Test that database connections are properly cleaned up"""
85 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
86 | yaml.dump(mcp_config, tmp)
87 | tmp.flush()
88 | server = ConnectionServer(config_path=tmp.name)
89 | async with server.get_handler("test_sqlite") as handler:
90 | await handler.get_tables()
91 |
--------------------------------------------------------------------------------
/docs/en/technical/testing.md:
--------------------------------------------------------------------------------
1 | # Testing Guide
2 |
3 | *English | [中文](../../zh/technical/testing.md) | [Français](../../fr/technical/testing.md) | [Español](../../es/technical/testing.md) | [العربية](../../ar/technical/testing.md) | [Русский](../../ru/technical/testing.md)*
4 |
5 | ## Testing Framework
6 |
7 | MCP Database Utilities uses the following testing frameworks and tools:
8 |
9 | - **pytest**: Main testing framework
10 | - **pytest-asyncio**: For asynchronous testing support
11 | - **pytest-docker**: For database integration testing
12 | - **pytest-cov**: For code coverage analysis
13 |
14 | ## Test Structure
15 |
16 | The test directory structure is as follows:
17 |
18 | ```
19 | tests/
20 | ├── unit/ # Unit tests
21 | ├── integration/ # Integration tests
22 | │ ├── fixtures.py # Test helpers
23 | │ └── conftest.py # pytest configuration and utilities
24 | ```
25 |
26 | ## Running Tests
27 |
28 | ### Running All Tests
29 |
30 | ```bash
31 | # Install test dependencies
32 | uv pip install -e ".[test]"
33 |
34 | # Run all tests
35 | pytest
36 | ```
37 |
38 | ### Running Specific Tests
39 |
40 | ```bash
41 | # Run unit tests
42 | pytest tests/unit/
43 |
44 | # Run specific test file
45 | pytest tests/unit/test_base.py
46 |
47 | # Run specific test function
48 | pytest tests/unit/test_base.py::test_function_name
49 | ```
50 |
51 | ### Generating Coverage Reports
52 |
53 | ```bash
54 | # Generate coverage report
55 | pytest --cov=src/mcp_dbutils --cov-report=term --cov-report=xml:coverage.xml tests/
56 | ```
57 |
58 | ## Test Types
59 |
60 | ### Unit Tests
61 |
62 | Unit tests are located in the `tests/unit/` directory and focus on testing individual component functionality, typically using mock objects to replace external dependencies.
63 |
64 | Example:
65 |
66 | ```python
67 | def test_database_handler_factory():
68 | # Test database handler factory function
69 | config = {"type": "sqlite", "path": ":memory:"}
70 | handler = create_handler(config)
71 | assert isinstance(handler, SQLiteHandler)
72 | ```
73 |
74 | ### Integration Tests
75 |
76 | Integration tests are located in the `tests/integration/` directory and test the interaction between multiple components, typically using real database connections.
77 |
78 | Example:
79 |
80 | ```python
81 | @pytest.mark.asyncio
82 | async def test_sqlite_query_execution(sqlite_handler):
83 | # Test SQLite query execution
84 | result = await sqlite_handler.execute_query("SELECT 1 as test")
85 | assert "test" in result
86 | assert result["test"] == 1
87 | ```
88 |
89 | ## Test Helpers
90 |
91 | ### fixtures.py
92 |
93 | The `tests/integration/fixtures.py` file contains test helper classes and functions, such as:
94 |
95 | - `TestConnectionHandler`: For testing connection handlers
96 | - `MockSession`: Mock MCP session
97 | - `create_test_database`: Create test databases
98 |
99 | ### conftest.py
100 |
101 | The `tests/conftest.py` file contains pytest configuration and global fixtures:
102 |
103 | ```python
104 | @pytest.fixture
105 | async def sqlite_handler():
106 | """Provide SQLite test handler"""
107 | config = {"type": "sqlite", "path": ":memory:"}
108 | handler = SQLiteHandler(config)
109 | yield handler
110 | await handler.cleanup()
111 | ```
112 |
113 | ## Best Practices
114 |
115 | 1. **Test Coverage**: Maintain at least 80% code coverage
116 | 2. **Isolated Tests**: Ensure tests don't depend on the state of other tests
117 | 3. **Resource Cleanup**: Use fixture teardown mechanisms to clean up resources
118 | 4. **Mock External Dependencies**: Use unittest.mock to mock external dependencies
119 | 5. **Test Error Cases**: Test error handling and edge cases
120 | 6. **Parameterized Tests**: Use pytest.mark.parametrize to test multiple inputs
121 |
122 | ## SonarCloud Integration
123 |
124 | Test results are automatically uploaded to SonarCloud for analysis. SonarCloud checks:
125 |
126 | - Code coverage
127 | - Test success rate
128 | - Code quality issues
129 | - Security vulnerabilities
130 |
131 | You can view test results and code quality reports on the [SonarCloud dashboard](https://sonarcloud.io/dashboard?id=donghao1393_mcp-dbutils).
--------------------------------------------------------------------------------
/tests/integration/test_mysql.py:
--------------------------------------------------------------------------------
1 | """Test MySQL integration"""
2 |
3 | import tempfile
4 |
5 | import pytest
6 | import yaml
7 |
8 | from mcp_dbutils.base import (
9 | ConnectionHandlerError,
10 | ConnectionServer,
11 | )
12 | from mcp_dbutils.log import create_logger
13 |
14 | # 创建测试用的 logger
15 | logger = create_logger("test-mysql", True) # debug=True 以显示所有日志
16 |
17 | @pytest.mark.asyncio
18 | async def test_list_tables(mysql_db, mcp_config):
19 | """Test listing tables in MySQL database"""
20 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
21 | config_data = mcp_config
22 | logger("debug", f"MySQL config: {config_data}")
23 | yaml.dump(config_data, tmp)
24 | tmp.flush()
25 | server = ConnectionServer(config_path=tmp.name)
26 | async with server.get_handler("test_mysql") as handler:
27 | tables = await handler.get_tables()
28 | table_names = [table.name.replace(" schema", "") for table in tables]
29 | assert "users" in table_names
30 |
31 | # Check schema information
32 | schema_str = await handler.get_schema("users")
33 | schema = eval(schema_str)
34 | assert schema["columns"][0]["name"] == "id"
35 | assert schema["columns"][0]["type"] == "int"
36 | assert schema["columns"][1]["name"] == "name"
37 | assert schema["columns"][1]["type"] == "varchar"
38 | assert schema["columns"][2]["name"] == "email"
39 | assert schema["columns"][2]["type"] == "varchar"
40 |
41 | @pytest.mark.asyncio
42 | async def test_execute_query(mysql_db, mcp_config):
43 | """Test executing SELECT queries"""
44 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
45 | yaml.dump(mcp_config, tmp)
46 | tmp.flush()
47 | server = ConnectionServer(config_path=tmp.name)
48 | async with server.get_handler("test_mysql") as handler:
49 | # Simple SELECT
50 | result_str = await handler.execute_query("SELECT name FROM users ORDER BY name")
51 | result = eval(result_str)
52 | assert len(result["rows"]) == 2
53 | assert result["rows"][0]["name"] == "Alice"
54 | assert result["rows"][1]["name"] == "Bob"
55 |
56 | # SELECT with WHERE clause
57 | result_str = await handler.execute_query(
58 | "SELECT * FROM users WHERE email = 'alice@test.com'"
59 | )
60 | result = eval(result_str)
61 | assert len(result["rows"]) == 1
62 | assert result["rows"][0]["name"] == "Alice"
63 |
64 | @pytest.mark.asyncio
65 | async def test_non_select_query(mysql_db, mcp_config):
66 | """Test executing non-SELECT queries"""
67 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
68 | yaml.dump(mcp_config, tmp)
69 | tmp.flush()
70 | server = ConnectionServer(config_path=tmp.name)
71 | async with server.get_handler("test_mysql") as handler:
72 | # 我们现在允许非SELECT查询
73 | result = await handler.execute_query("DELETE FROM users")
74 | assert result == "Query executed successfully"
75 |
76 | @pytest.mark.asyncio
77 | async def test_invalid_query(mysql_db, mcp_config):
78 | """Test handling of invalid SQL queries"""
79 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
80 | yaml.dump(mcp_config, tmp)
81 | tmp.flush()
82 | server = ConnectionServer(config_path=tmp.name)
83 | async with server.get_handler("test_mysql") as handler:
84 | with pytest.raises(ConnectionHandlerError):
85 | await handler.execute_query("SELECT * FROM nonexistent_table")
86 |
87 | @pytest.mark.asyncio
88 | async def test_connection_cleanup(mysql_db, mcp_config):
89 | """Test that database connections are properly cleaned up"""
90 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
91 | yaml.dump(mcp_config, tmp)
92 | tmp.flush()
93 | server = ConnectionServer(config_path=tmp.name)
94 | async with server.get_handler("test_mysql") as handler:
95 | await handler.get_tables()
96 |
--------------------------------------------------------------------------------
/tests/integration/test_postgres.py:
--------------------------------------------------------------------------------
1 | import tempfile
2 |
3 | import pytest
4 | import yaml
5 |
6 | from mcp_dbutils.base import (
7 | ConnectionHandlerError,
8 | ConnectionServer,
9 | )
10 | from mcp_dbutils.log import create_logger
11 |
12 | # 创建测试用的 logger
13 | logger = create_logger("test-postgres", True) # debug=True 以显示所有日志
14 |
15 | @pytest.mark.asyncio
16 | async def test_list_tables(postgres_db, mcp_config):
17 | """Test listing tables in PostgreSQL database"""
18 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
19 | config_data = mcp_config
20 | logger("debug", f"PostgreSQL config: {config_data}")
21 | yaml.dump(config_data, tmp)
22 | tmp.flush()
23 | server = ConnectionServer(config_path=tmp.name)
24 | async with server.get_handler("test_pg") as handler:
25 | tables = await handler.get_tables()
26 | table_names = [table.name.replace(" schema", "") for table in tables]
27 | assert "users" in table_names
28 |
29 | # Check schema information
30 | schema_str = await handler.get_schema("users")
31 | schema = eval(schema_str)
32 | assert schema["columns"][0]["name"] == "id"
33 | assert schema["columns"][0]["type"] == "integer"
34 | assert schema["columns"][1]["name"] == "name"
35 | assert schema["columns"][1]["type"] == "text"
36 | assert schema["columns"][2]["name"] == "email"
37 | assert schema["columns"][2]["type"] == "text"
38 |
39 | @pytest.mark.asyncio
40 | async def test_execute_query(postgres_db, mcp_config):
41 | """Test executing SELECT queries"""
42 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
43 | yaml.dump(mcp_config, tmp)
44 | tmp.flush()
45 | server = ConnectionServer(config_path=tmp.name)
46 | async with server.get_handler("test_pg") as handler:
47 | # Simple SELECT
48 | result_str = await handler.execute_query("SELECT name FROM users ORDER BY name")
49 | result = eval(result_str)
50 | assert len(result["rows"]) == 2
51 | assert result["rows"][0]["name"] == "Alice"
52 | assert result["rows"][1]["name"] == "Bob"
53 |
54 | # SELECT with WHERE clause
55 | result_str = await handler.execute_query(
56 | "SELECT * FROM users WHERE email = 'alice@test.com'"
57 | )
58 | result = eval(result_str)
59 | assert len(result["rows"]) == 1
60 | assert result["rows"][0]["name"] == "Alice"
61 |
62 | @pytest.mark.asyncio
63 | async def test_non_select_query(postgres_db, mcp_config):
64 | """Test that non-SELECT queries are rejected"""
65 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
66 | yaml.dump(mcp_config, tmp)
67 | tmp.flush()
68 | server = ConnectionServer(config_path=tmp.name)
69 | async with server.get_handler("test_pg") as handler:
70 | with pytest.raises(ConnectionHandlerError, match="cannot execute DELETE in a read-only transaction"):
71 | await handler.execute_query("DELETE FROM users")
72 |
73 | @pytest.mark.asyncio
74 | async def test_invalid_query(postgres_db, mcp_config):
75 | """Test handling of invalid SQL queries"""
76 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
77 | yaml.dump(mcp_config, tmp)
78 | tmp.flush()
79 | server = ConnectionServer(config_path=tmp.name)
80 | async with server.get_handler("test_pg") as handler:
81 | with pytest.raises(ConnectionHandlerError):
82 | await handler.execute_query("SELECT * FROM nonexistent_table")
83 |
84 | @pytest.mark.asyncio
85 | async def test_connection_cleanup(postgres_db, mcp_config):
86 | """Test that database connections are properly cleaned up"""
87 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
88 | yaml.dump(mcp_config, tmp)
89 | tmp.flush()
90 | server = ConnectionServer(config_path=tmp.name)
91 | async with server.get_handler("test_pg") as handler:
92 | await handler.get_tables()
93 |
--------------------------------------------------------------------------------
/scripts/run_sonar_analysis.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # 本地SonarQube代码分析脚本
3 | # 用法: ./run_sonar_analysis.sh [项目Key]
4 |
5 | # 设置默认值和颜色
6 | PROJECT_KEY=${1:-"local-project"}
7 | PROJECT_NAME=${PROJECT_KEY}
8 | SONAR_CONTAINER="sonarqube"
9 | SONAR_PORT=9000
10 | SONAR_URL="http://localhost:${SONAR_PORT}"
11 | ADMIN_PASSWORD="adminPassword123!"
12 | TOKEN_NAME="local-analysis-token"
13 | RED='\033[0;31m'
14 | GREEN='\033[0;32m'
15 | YELLOW='\033[0;33m'
16 | BLUE='\033[0;34m'
17 | NC='\033[0m' # No Color
18 |
19 | # 函数定义
20 | log_info() {
21 | echo -e "${BLUE}[INFO]${NC} $1"
22 | }
23 |
24 | log_success() {
25 | echo -e "${GREEN}[SUCCESS]${NC} $1"
26 | }
27 |
28 | log_warning() {
29 | echo -e "${YELLOW}[WARNING]${NC} $1"
30 | }
31 |
32 | log_error() {
33 | echo -e "${RED}[ERROR]${NC} $1"
34 | exit 1
35 | }
36 |
37 | wait_for_sonarqube() {
38 | log_info "等待SonarQube启动..."
39 | local retries=0
40 | local max_retries=30
41 |
42 | while [ $retries -lt $max_retries ]; do
43 | if curl -s -f -X GET "${SONAR_URL}/api/system/status" | grep -q "UP"; then
44 | log_success "SonarQube服务已启动"
45 | return 0
46 | fi
47 | retries=$((retries+1))
48 | log_info "尝试 $retries/$max_retries - 仍在等待..."
49 | sleep 10
50 | done
51 |
52 | log_error "等待SonarQube启动超时"
53 | return 1
54 | }
55 |
56 | # 检查Docker是否已安装
57 | if ! command -v docker &> /dev/null; then
58 | log_error "未安装Docker。请先安装Docker后再运行此脚本。"
59 | fi
60 |
61 | # 1. 检查是否已有SonarQube容器在运行
62 | if docker ps -a | grep -q ${SONAR_CONTAINER}; then
63 | log_info "检测到SonarQube容器已存在"
64 | if docker ps | grep -q ${SONAR_CONTAINER}; then
65 | log_info "SonarQube容器已在运行"
66 | else
67 | log_info "重新启动SonarQube容器..."
68 | if ! docker start ${SONAR_CONTAINER}; then
69 | log_error "启动SonarQube容器失败"
70 | fi
71 | fi
72 | else
73 | log_info "创建并启动SonarQube容器..."
74 | if ! docker run -d --name ${SONAR_CONTAINER} -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true -p ${SONAR_PORT}:9000 sonarqube:latest; then
75 | log_error "创建SonarQube容器失败"
76 | fi
77 | log_success "SonarQube容器已创建"
78 | fi
79 |
80 | # 2. 等待SonarQube启动
81 | wait_for_sonarqube
82 |
83 | # 3. 尝试使用默认密码登录,如果成功则更改密码
84 | if curl -s -u admin:admin "${SONAR_URL}/api/system/ping" | grep -q "pong"; then
85 | log_info "使用默认密码登录成功,正在更改密码..."
86 | curl -s -X POST -u admin:admin "${SONAR_URL}/api/users/change_password?login=admin&previousPassword=admin&password=${ADMIN_PASSWORD}" > /dev/null
87 | log_success "密码已更改"
88 | else
89 | log_info "已经更改过密码,使用现有密码继续"
90 | fi
91 |
92 | # 4. 创建令牌
93 | log_info "创建分析令牌..."
94 | TOKEN=$(curl -s -X POST -u admin:${ADMIN_PASSWORD} "${SONAR_URL}/api/user_tokens/generate?name=${TOKEN_NAME}" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
95 |
96 | if [ -z "$TOKEN" ]; then
97 | # 尝试获取现有令牌
98 | log_warning "创建令牌失败,可能已存在同名令牌,尝试重新生成..."
99 | # 删除旧令牌
100 | curl -s -X POST -u admin:${ADMIN_PASSWORD} "${SONAR_URL}/api/user_tokens/revoke?name=${TOKEN_NAME}" > /dev/null
101 | # 创建新令牌
102 | TOKEN=$(curl -s -X POST -u admin:${ADMIN_PASSWORD} "${SONAR_URL}/api/user_tokens/generate?name=${TOKEN_NAME}" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
103 |
104 | if [ -z "$TOKEN" ]; then
105 | log_error "无法生成分析令牌"
106 | fi
107 | fi
108 |
109 | log_success "令牌已生成: ${TOKEN}"
110 |
111 | # 5. 创建或更新项目
112 | log_info "创建项目 ${PROJECT_KEY}..."
113 | curl -s -X POST -u admin:${ADMIN_PASSWORD} "${SONAR_URL}/api/projects/create?name=${PROJECT_NAME}&project=${PROJECT_KEY}" > /dev/null
114 | log_success "项目已创建/更新"
115 |
116 | # 6. 运行分析
117 | log_info "开始代码分析..."
118 | docker run --rm --network=host \
119 | -v $(pwd):/usr/src \
120 | sonarsource/sonar-scanner-cli \
121 | -Dsonar.projectKey=${PROJECT_KEY} \
122 | -Dsonar.projectName=${PROJECT_NAME} \
123 | -Dsonar.sources=src \
124 | -Dsonar.tests=tests \
125 | -Dsonar.host.url=${SONAR_URL} \
126 | -Dsonar.token=${TOKEN}
127 |
128 | log_success "分析完成! 查看结果: ${SONAR_URL}/dashboard?id=${PROJECT_KEY}"
129 | echo ""
130 | log_info "提示:"
131 | echo " - 要停止SonarQube容器: docker stop ${SONAR_CONTAINER}"
132 | echo " - 要删除SonarQube容器: docker rm ${SONAR_CONTAINER}"
133 | echo ""
134 | log_info "您可能需要针对特定项目结构调整分析参数"
--------------------------------------------------------------------------------
/docs/en/technical/sonarcloud-integration.md:
--------------------------------------------------------------------------------
1 | # SonarCloud AI Integration Guide
2 |
3 | *English | [中文](../../zh/technical/sonarcloud-integration.md) | [Français](../../fr/technical/sonarcloud-integration.md) | [Español](../../es/technical/sonarcloud-integration.md) | [العربية](../../ar/technical/sonarcloud-integration.md) | [Русский](../../ru/technical/sonarcloud-integration.md)*
4 |
5 | This document explains how to integrate SonarCloud analysis results with AI to automatically retrieve code quality issues and use AI to assist with fixes.
6 |
7 | ## Feature Overview
8 |
9 | This integration works through the following steps:
10 |
11 | ```mermaid
12 | graph TD
13 | A[Code Development] --> B[SonarCloud Analysis]
14 | B --> C{Issues Detected?}
15 | C -->|Yes| D[AI Analysis of Issues]
16 | D --> E[Fix Suggestions]
17 | E --> F[Implement Fixes]
18 | F --> A
19 | C -->|No| G[AI Optimization Analysis]
20 | G --> H[Optimization Suggestions]
21 | H --> A
22 | ```
23 |
24 | 1. GitHub Actions workflow runs SonarCloud analysis during the CI/CD process
25 | 2. After analysis is complete, the workflow extracts SonarCloud issues and generates reports in two formats:
26 | - JSON format: Contains complete raw data, suitable for in-depth AI analysis
27 | - Markdown format: Formatted human-readable report with issue summaries and details
28 | 3. These two reports are uploaded as workflow artifacts
29 | 4. Using the provided Fish function, you can easily download these reports and provide them to AI for analysis and fix suggestions
30 |
31 | ## Usage Instructions
32 |
33 | ### 1. Set Up the Fish Function
34 |
35 | Add the `sonar-ai-fix` function to your Fish configuration:
36 |
37 | ```fish
38 | # Add to ~/.config/fish/config.fish
39 | source /path/to/mcp-dbutils/scripts/sonar-ai-fix.fish
40 | ```
41 |
42 | Alternatively, you can run the script directly to load the function temporarily:
43 |
44 | ```bash
45 | source scripts/sonar-ai-fix.fish
46 | ```
47 |
48 | ### 2. Download SonarCloud Analysis Reports
49 |
50 | In the project root directory, run:
51 |
52 | ```bash
53 | sonar-ai-fix
54 | ```
55 |
56 | This will download the latest SonarCloud analysis reports and save them as two files:
57 | - `sonar_report.md`: Markdown formatted report
58 | - `sonar_issues.json`: Raw data in JSON format
59 |
60 | ### 3. Use AI to Analyze and Fix Issues
61 |
62 | There are two ways to use these reports:
63 |
64 | #### Option 1: Use the Markdown Report (Recommended)
65 |
66 | 1. Open the `sonar_report.md` file:
67 | ```bash
68 | bat sonar_report.md
69 | ```
70 |
71 | 2. Copy the content to an AI (like Claude) and request fix suggestions:
72 | ```
73 | This is the SonarCloud analysis report for my project. Please analyze these issues and provide fix suggestions.
74 |
75 | [Paste sonar_report.md content]
76 | ```
77 |
78 | #### Option 2: Use JSON Data for In-Depth Analysis
79 |
80 | For situations requiring more in-depth analysis, you can use the JSON data:
81 |
82 | 1. Open the JSON file:
83 | ```bash
84 | bat sonar_issues.json
85 | ```
86 |
87 | 2. Provide the content to AI for more detailed analysis:
88 | ```
89 | This is the raw SonarCloud analysis data for my project. Please perform an in-depth analysis of these issues and provide fix suggestions.
90 |
91 | [Paste sonar_issues.json content]
92 | ```
93 |
94 | ## How It Works
95 |
96 | ### GitHub Actions Workflow
97 |
98 | In `.github/workflows/quality-assurance.yml`, we've added two key steps:
99 |
100 | 1. **Extract SonarCloud Issues**:
101 | - Uses the SonarCloud API to get unresolved issues
102 | - Formats issues into JSON and Markdown formats
103 |
104 | 2. **Upload Report Artifacts**:
105 | - Uploads the generated reports as workflow artifacts
106 | - Makes artifacts downloadable via GitHub CLI
107 |
108 | ### Fish Function
109 |
110 | The `sonar-ai-fix.fish` script provides a convenient function that:
111 |
112 | - Checks if the current directory is a project directory
113 | - Gets the latest workflow run ID
114 | - Downloads the SonarCloud issues report artifacts
115 | - Saves the reports to the current directory
116 | - Provides usage instructions
117 |
118 | ## Important Notes
119 |
120 | - Ensure you have GitHub CLI (`gh`) installed and configured
121 | - Ensure you have sufficient permissions to access the GitHub repository and workflows
122 | - Issue links in the reports point to the SonarCloud website, which requires project access permissions
123 | - This feature works best with local AI tools (like Claude Desktop)
124 |
--------------------------------------------------------------------------------
/tests/integration/test_logging.py:
--------------------------------------------------------------------------------
1 | """Test MCP logging functionality"""
2 |
3 | from unittest.mock import MagicMock, patch
4 |
5 | import pytest
6 |
7 | from mcp_dbutils.base import ConnectionServer
8 |
9 | from . import conftest
10 |
11 | TestConnectionHandler = conftest.TestConnectionHandler
12 |
13 | @pytest.mark.asyncio
14 | async def test_handler_logging():
15 | """Test logging in ConnectionHandler"""
16 |
17 | # 创建一个模拟的session
18 | mock_session = MagicMock()
19 | mock_session.request_context.session.send_log_message = MagicMock()
20 |
21 | # 创建测试handler
22 | handler = TestConnectionHandler("test_config.yaml", "test_conn")
23 | handler._session = mock_session
24 |
25 | # 测试不同级别的日志
26 | test_levels = ["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"]
27 |
28 | for level in test_levels:
29 | mock_session.request_context.session.send_log_message.reset_mock()
30 | message = f"Test {level} message"
31 | handler.send_log(level, message)
32 |
33 | # 验证MCP日志消息被发送
34 | mock_session.request_context.session.send_log_message.assert_called_with(
35 | level=level,
36 | data=message
37 | )
38 |
39 | @pytest.mark.asyncio
40 | async def test_server_logging():
41 | """Test logging in ConnectionServer"""
42 |
43 | # 创建一个模拟的Server和Logger
44 | mock_server = MagicMock()
45 | mock_logger = MagicMock()
46 |
47 | # 设置mock session和send_log_message
48 | mock_send_log = MagicMock()
49 | mock_server.session = MagicMock()
50 | mock_server.session.send_log_message = mock_send_log
51 |
52 | # 创建补丁
53 | patches = [
54 | patch("mcp_dbutils.base.Server", return_value=mock_server),
55 | patch("mcp_dbutils.base.create_logger", return_value=mock_logger)
56 | ]
57 |
58 | # 启动所有补丁
59 | for p in patches:
60 | p.start()
61 |
62 | try:
63 | server = ConnectionServer("test_config.yaml")
64 |
65 | # 测试不同级别的日志
66 | test_levels = ["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"]
67 |
68 | for level in test_levels:
69 | # 重置mock计数
70 | mock_logger.reset_mock()
71 | mock_send_log.reset_mock()
72 |
73 | message = f"Test {level} message"
74 | server.send_log(level, message)
75 |
76 | # 验证本地日志被写入
77 | mock_logger.assert_called_once_with(level, message)
78 |
79 | # 验证MCP日志消息被发送
80 | mock_send_log.assert_called_once_with(
81 | level=level,
82 | data=message
83 | )
84 | finally:
85 | # 停止所有补丁
86 | for p in patches:
87 | p.stop()
88 |
89 | @pytest.mark.asyncio
90 | async def test_handler_session_inheritance():
91 | """Test session inheritance in handlers"""
92 |
93 | # 创建一个模拟的Server
94 | mock_server = MagicMock()
95 | mock_session = MagicMock()
96 | mock_request_context = MagicMock()
97 | mock_request_context.session = mock_session
98 | mock_session.request_context = mock_request_context
99 | mock_session.send_log_message = MagicMock()
100 | mock_server.session = mock_session
101 |
102 | # 创建测试配置文件内容
103 | test_config = {
104 | "connections": {
105 | "test_conn": {
106 | "type": "sqlite" # 使用sqlite类型
107 | }
108 | }
109 | }
110 |
111 | test_handler = TestConnectionHandler("test_config.yaml", "test_conn")
112 | test_handler.stats.to_dict = MagicMock(return_value={}) # 简化统计信息
113 |
114 | with patch("mcp.server.Server", return_value=mock_server), \
115 | patch("builtins.open"), \
116 | patch("yaml.safe_load", return_value=test_config), \
117 | patch("mcp_dbutils.sqlite.handler.SQLiteHandler", return_value=test_handler):
118 |
119 | server = ConnectionServer("test_config.yaml")
120 | server.server = mock_server # 确保server有正确的session
121 |
122 | # 使用get_handler创建handler
123 | async with server.get_handler("test_conn") as handler:
124 | # 重置所有mock
125 | mock_session.send_log_message.reset_mock()
126 | mock_session.request_context.session.send_log_message.reset_mock()
127 |
128 | # 发送测试日志
129 | message = "Test message"
130 | handler.send_log("info", message)
131 |
132 | # 验证日志消息通过server的session发送
133 | mock_session.request_context.session.send_log_message.assert_called_with(
134 | level="info",
135 | data=message
136 | )
137 |
--------------------------------------------------------------------------------
/docs/zh/technical/write-operations-design.md:
--------------------------------------------------------------------------------
1 | # 数据库写操作功能设计
2 |
3 | ## 1. 概述
4 |
5 | MCP数据库工具目前仅支持只读操作,为了增强功能灵活性,我们计划添加可选的数据库写操作支持。该功能将默认保持禁用状态,只有在用户通过配置文件明确启用后才会激活。
6 |
7 | ## 2. 设计目标
8 |
9 | - **安全优先**:默认禁用写操作,需要明确配置才能启用
10 | - **细粒度控制**:支持表级和操作级的权限控制
11 | - **审计追踪**:记录所有写操作,便于审计和问题排查
12 | - **用户友好**:提供清晰的配置方式和文档
13 | - **向后兼容**:现有的只读功能不受影响
14 |
15 | ## 3. 安全模型
16 |
17 | 安全模型基于以下几个层次的保护:
18 |
19 | ### 3.1 连接级权限
20 |
21 | 每个数据库连接默认为只读模式。要启用写操作,必须在配置文件中明确设置`writable: true`。
22 |
23 | ```yaml
24 | connections:
25 | example_db:
26 | type: postgres
27 | # 其他连接信息...
28 | writable: true # 明确启用写操作
29 | ```
30 |
31 | ### 3.2 表级权限
32 |
33 | 对于启用了写操作的连接,可以进一步限制哪些表允许写操作:
34 |
35 | ```yaml
36 | connections:
37 | example_db:
38 | # 基本连接信息...
39 | writable: true
40 | write_permissions:
41 | tables:
42 | users: # 允许对users表进行写操作
43 | operations: [INSERT, UPDATE]
44 | logs: # 允许对logs表进行写操作
45 | operations: [INSERT]
46 | ```
47 |
48 | 如果未指定表级权限,则默认策略由`default_policy`决定:
49 |
50 | ```yaml
51 | write_permissions:
52 | default_policy: read_only # 或 allow_all
53 | ```
54 |
55 | ### 3.3 操作级权限
56 |
57 | 对于每个允许写操作的表,可以指定允许的操作类型(INSERT、UPDATE、DELETE):
58 |
59 | ```yaml
60 | tables:
61 | users:
62 | operations: [INSERT, UPDATE] # 只允许插入和更新,不允许删除
63 | ```
64 |
65 | 如果未指定操作级权限,则默认允许所有写操作(INSERT、UPDATE、DELETE)。
66 |
67 | ## 4. 审计日志
68 |
69 | 所有写操作都将被记录到审计日志中,包括以下信息:
70 |
71 | - 操作时间戳
72 | - 连接名称
73 | - 表名
74 | - 操作类型(INSERT/UPDATE/DELETE)
75 | - SQL语句(可能会脱敏)
76 | - 影响的行数
77 | - 操作结果(成功/失败)
78 |
79 | 审计日志将通过以下方式提供访问:
80 |
81 | 1. **MCP资源**:通过`dbutils://audit-logs/{connection_name}`资源URI访问
82 | 2. **日志文件**:写入到本地日志文件
83 | 3. **API**:提供编程接口访问审计日志
84 |
85 | ## 5. 配置格式
86 |
87 | 完整的配置格式示例:
88 |
89 | ```yaml
90 | connections:
91 | sqlite_example:
92 | type: sqlite
93 | database: ":memory:"
94 | # 未指定writable,默认为false(只读)
95 |
96 | postgres_example:
97 | type: postgres
98 | host: localhost
99 | port: 5432
100 | database: mydb
101 | user: postgres
102 | password: ******
103 | writable: true # 启用写操作
104 |
105 | # 细粒度权限控制(可选)
106 | write_permissions:
107 | # 表级权限
108 | tables:
109 | users:
110 | operations: [INSERT, UPDATE] # 操作级权限
111 | logs:
112 | operations: [INSERT]
113 | temp_data:
114 | operations: [INSERT, UPDATE, DELETE]
115 |
116 | # 默认策略(可选,默认为read_only)
117 | default_policy: read_only # 或 allow_all
118 | ```
119 |
120 | ## 6. API设计
121 |
122 | ### 6.1 新增工具
123 |
124 | 添加以下MCP工具:
125 |
126 | ```python
127 | types.Tool(
128 | name="dbutils-execute-write",
129 | description="执行数据库写操作(INSERT、UPDATE、DELETE)。仅适用于配置了writable=true的连接。所有操作都会被记录到审计日志中。",
130 | inputSchema={
131 | "type": "object",
132 | "properties": {
133 | "connection": {
134 | "type": "string",
135 | "description": "数据库连接名称",
136 | },
137 | "sql": {
138 | "type": "string",
139 | "description": "SQL写操作语句(INSERT、UPDATE、DELETE)",
140 | },
141 | "confirmation": {
142 | "type": "string",
143 | "description": "输入'CONFIRM_WRITE'确认执行写操作",
144 | },
145 | },
146 | "required": ["connection", "sql", "confirmation"],
147 | },
148 | )
149 | ```
150 |
151 | ### 6.2 新增资源
152 |
153 | 添加以下MCP资源:
154 |
155 | ```python
156 | @mcp.resource("dbutils://audit-logs/{connection_name}")
157 | def get_audit_logs(connection_name: str) -> str:
158 | """获取指定连接的审计日志"""
159 | logs = audit_logger.get_logs(connection_name)
160 | return format_logs(logs)
161 |
162 | @mcp.resource("dbutils://audit-logs/{connection_name}/{table_name}")
163 | def get_table_audit_logs(connection_name: str, table_name: str) -> str:
164 | """获取指定表的审计日志"""
165 | logs = audit_logger.get_logs(connection_name, table_name)
166 | return format_logs(logs)
167 | ```
168 |
169 | ## 7. 实现计划
170 |
171 | 1. **配置解析**:
172 | - 在`config.py`中添加对新配置项的解析
173 | - 确保默认值为安全的只读模式
174 |
175 | 2. **基础类扩展**:
176 | - 在`base.py`中扩展`DatabaseHandler`类,添加写操作相关方法
177 | - 添加权限检查逻辑
178 |
179 | 3. **数据库特定实现**:
180 | - 在各数据库模块中实现写操作方法
181 | - 处理数据库特定的事务管理
182 |
183 | 4. **审计日志系统**:
184 | - 实现审计日志记录和存储
185 | - 添加MCP资源端点
186 |
187 | 5. **新工具添加**:
188 | - 添加`dbutils-execute-write`工具
189 | - 实现权限检查和审计日志集成
190 |
191 | ## 8. 向后兼容性
192 |
193 | 这是一个breaking change,因为它改变了项目的核心安全模型(从"只读"到"可配置读写")。我们将:
194 |
195 | 1. **版本号升级**:按照语义化版本规范,这应该是一个主版本号升级(例如从1.x.x到2.0.0)
196 |
197 | 2. **明确的更新日志**:
198 | ```markdown
199 | # 2.0.0 (2025-XX-XX)
200 |
201 | ## Breaking Changes
202 |
203 | - 添加了可选的数据库写入功能。默认行为保持不变(只读),但现在可以通过配置启用写操作。
204 | - 新增了写操作相关的配置选项和工具。
205 | ```
206 |
207 | 3. **迁移指南**:提供从只读版本迁移到新版本的详细指南,强调安全配置的重要性
208 |
209 | ## 9. 安全考虑
210 |
211 | 1. **明确的文档警告**:
212 | - 在文档中明确说明启用写操作的风险
213 | - 提供最佳实践建议
214 |
215 | 2. **沙箱环境**:
216 | - 建议用户在生产环境中使用只读连接
217 | - 写操作最好用于开发或测试环境
218 |
219 | 3. **权限最小化**:
220 | - 建议使用有限权限的数据库用户
221 | - 只授予必要的表和操作权限
222 |
--------------------------------------------------------------------------------
/docs/en/examples/sqlite-examples.md:
--------------------------------------------------------------------------------
1 | # SQLite Examples
2 |
3 | *English | [中文](../../zh/examples/sqlite-examples.md) | [Français](../../fr/examples/sqlite-examples.md) | [Español](../../es/examples/sqlite-examples.md) | [العربية](../../ar/examples/sqlite-examples.md) | [Русский](../../ru/examples/sqlite-examples.md)*
4 |
5 | This document provides practical examples for working with SQLite databases using MCP Database Utilities.
6 |
7 | ## Basic Configuration
8 |
9 | ```yaml
10 | connections:
11 | my-sqlite:
12 | type: sqlite
13 | path: /path/to/database.db
14 | ```
15 |
16 | ## Common Operations
17 |
18 | ### Listing Tables
19 |
20 | **You**: "List all tables in my SQLite database."
21 |
22 | **AI**: "Here are the tables in your SQLite database:
23 | - users
24 | - products
25 | - orders
26 | - categories"
27 |
28 | ### Viewing Table Structure
29 |
30 | **You**: "Show me the structure of the users table."
31 |
32 | **AI**: "The users table has the following structure:
33 | - id (INTEGER, PRIMARY KEY)
34 | - username (TEXT, NOT NULL)
35 | - email (TEXT, NOT NULL, UNIQUE)
36 | - created_at (TIMESTAMP)
37 | - last_login (TIMESTAMP)
38 | - status (TEXT)"
39 |
40 | ### Basic Query
41 |
42 | **You**: "Show me the top 5 users by last login date."
43 |
44 | **AI**: "Here are the top 5 users by last login date:
45 |
46 | | id | username | email | last_login |
47 | |----|----------|-------|------------|
48 | | 42 | johndoe | john@example.com | 2023-11-25 14:32:15 |
49 | | 17 | janedoe | jane@example.com | 2023-11-24 09:45:22 |
50 | | 31 | bobsmith | bob@example.com | 2023-11-23 18:12:05 |
51 | | 8 | alicejones | alice@example.com | 2023-11-22 11:30:47 |
52 | | 53 | mikebrown | mike@example.com | 2023-11-21 16:08:33 |"
53 |
54 | ## Advanced Queries
55 |
56 | ### Joining Tables
57 |
58 | **You**: "Show me the last 3 orders with user information."
59 |
60 | **AI**: "Here are the last 3 orders with user information:
61 |
62 | | order_id | order_date | username | email | total_amount |
63 | |----------|------------|----------|-------|--------------|
64 | | 1042 | 2023-11-25 | johndoe | john@example.com | $125.99 |
65 | | 1041 | 2023-11-24 | alicejones | alice@example.com | $89.50 |
66 | | 1040 | 2023-11-23 | bobsmith | bob@example.com | $212.75 |"
67 |
68 | ### Aggregate Functions
69 |
70 | **You**: "What's the average order amount per category?"
71 |
72 | **AI**: "Here's the average order amount per category:
73 |
74 | | category | average_amount |
75 | |----------|----------------|
76 | | Electronics | $245.75 |
77 | | Clothing | $78.30 |
78 | | Books | $32.50 |
79 | | Home & Kitchen | $124.90 |
80 | | Sports & Outdoors | $156.25 |"
81 |
82 | ## Performance Analysis
83 |
84 | ### Query Execution Plan
85 |
86 | **You**: "Explain the execution plan for: SELECT * FROM orders WHERE user_id = 42"
87 |
88 | **AI**: "Execution plan for the query:
89 | ```
90 | QUERY PLAN
91 | ------------------------------------------------------------
92 | SEARCH TABLE orders USING INDEX idx_user_id (user_id=?)
93 | ```
94 |
95 | This query uses the index `idx_user_id` to efficiently find orders for user_id 42."
96 |
97 | ### Table Statistics
98 |
99 | **You**: "Get statistics for the orders table."
100 |
101 | **AI**: "Statistics for the orders table:
102 | - Row count: 1,245
103 | - Size: 2.3 MB
104 | - Indexes: 3 (primary key, idx_user_id, idx_order_date)
105 | - Average row length: 1.9 KB"
106 |
107 | ## Working with SQLite-Specific Features
108 |
109 | ### Using FTS (Full-Text Search)
110 |
111 | **You**: "Search for products containing 'wireless headphones'."
112 |
113 | **AI**: "Here are products matching 'wireless headphones':
114 |
115 | | product_id | name | description | price |
116 | |------------|------|-------------|-------|
117 | | 123 | Premium Wireless Headphones | Noise-cancelling wireless headphones with 30-hour battery life | $199.99 |
118 | | 145 | Sport Wireless Headphones | Water-resistant wireless headphones for sports | $89.99 |
119 | | 187 | Budget Wireless Headphones | Affordable wireless headphones with good sound quality | $49.99 |"
120 |
121 | ### Using JSON Functions
122 |
123 | **You**: "Show me users with 'premium' in their preferences."
124 |
125 | **AI**: "Here are users with 'premium' in their preferences:
126 |
127 | | id | username | preferences |
128 | |----|----------|-------------|
129 | | 42 | johndoe | {\"subscription\": \"premium\", \"theme\": \"dark\"} |
130 | | 17 | janedoe | {\"subscription\": \"premium\", \"theme\": \"light\"} |
131 | | 53 | mikebrown | {\"subscription\": \"premium\", \"theme\": \"auto\"} |"
132 |
133 | ## Troubleshooting
134 |
135 | ### Common Issues
136 |
137 | 1. **File Not Found**
138 | - Ensure the path to your SQLite database file is correct
139 | - Check file permissions
140 | - Verify the file exists
141 |
142 | 2. **Locked Database**
143 | - SQLite allows only one writer at a time
144 | - Ensure no other process is writing to the database
145 | - Consider using WAL mode for better concurrency
146 |
147 | 3. **Performance Issues**
148 | - Add indexes for frequently queried columns
149 | - Use EXPLAIN QUERY PLAN to identify slow queries
150 | - Consider using prepared statements for repeated queries
--------------------------------------------------------------------------------
/docs/ar/examples/sqlite-examples.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # أمثلة SQLite
4 |
5 | *[English](../../en/examples/sqlite-examples.md) | [中文](../../zh/examples/sqlite-examples.md) | [Français](../../fr/examples/sqlite-examples.md) | [Español](../../es/examples/sqlite-examples.md) | العربية | [Русский](../../ru/examples/sqlite-examples.md)*
6 |
7 | يقدم هذا المستند أمثلة عملية للعمل مع قواعد بيانات SQLite باستخدام MCP Database Utilities.
8 |
9 | ## التكوين الأساسي
10 |
11 | ```yaml
12 | connections:
13 | my-sqlite:
14 | type: sqlite
15 | path: /path/to/database.db
16 | ```
17 |
18 | ## العمليات الشائعة
19 |
20 | ### سرد الجداول
21 |
22 | **أنت**: "قم بسرد جميع الجداول في قاعدة بيانات SQLite الخاصة بي."
23 |
24 | **الذكاء الاصطناعي**: "إليك الجداول في قاعدة بيانات SQLite الخاصة بك:
25 | - المستخدمون
26 | - المنتجات
27 | - الطلبات
28 | - الفئات"
29 |
30 | ### عرض بنية الجدول
31 |
32 | **أنت**: "أظهر لي بنية جدول المستخدمين."
33 |
34 | **الذكاء الاصطناعي**: "جدول المستخدمين له البنية التالية:
35 | - id (INTEGER, PRIMARY KEY)
36 | - username (TEXT, NOT NULL)
37 | - email (TEXT, NOT NULL, UNIQUE)
38 | - created_at (TIMESTAMP)
39 | - last_login (TIMESTAMP)
40 | - status (TEXT)"
41 |
42 | ### استعلام أساسي
43 |
44 | **أنت**: "أظهر لي أهم 5 مستخدمين حسب تاريخ آخر تسجيل دخول."
45 |
46 | **الذكاء الاصطناعي**: "إليك أهم 5 مستخدمين حسب تاريخ آخر تسجيل دخول:
47 |
48 | | id | username | email | last_login |
49 | |----|----------|-------|------------|
50 | | 42 | johndoe | john@example.com | 2023-11-25 14:32:15 |
51 | | 17 | janedoe | jane@example.com | 2023-11-24 09:45:22 |
52 | | 31 | bobsmith | bob@example.com | 2023-11-23 18:12:05 |
53 | | 8 | alicejones | alice@example.com | 2023-11-22 11:30:47 |
54 | | 53 | mikebrown | mike@example.com | 2023-11-21 16:08:33 |"
55 |
56 | ## استعلامات متقدمة
57 |
58 | ### ربط الجداول
59 |
60 | **أنت**: "أظهر لي آخر 3 طلبات مع معلومات المستخدم."
61 |
62 | **الذكاء الاصطناعي**: "إليك آخر 3 طلبات مع معلومات المستخدم:
63 |
64 | | order_id | order_date | username | email | total_amount |
65 | |----------|------------|----------|-------|--------------|
66 | | 1042 | 2023-11-25 | johndoe | john@example.com | $125.99 |
67 | | 1041 | 2023-11-24 | alicejones | alice@example.com | $89.50 |
68 | | 1040 | 2023-11-23 | bobsmith | bob@example.com | $212.75 |"
69 |
70 | ### دوال التجميع
71 |
72 | **أنت**: "ما هو متوسط مبلغ الطلب حسب الفئة؟"
73 |
74 | **الذكاء الاصطناعي**: "إليك متوسط مبلغ الطلب حسب الفئة:
75 |
76 | | الفئة | متوسط_المبلغ |
77 | |----------|----------------|
78 | | الإلكترونيات | $245.75 |
79 | | الملابس | $78.30 |
80 | | الكتب | $32.50 |
81 | | المنزل والمطبخ | $124.90 |
82 | | الرياضة والهواء الطلق | $156.25 |"
83 |
84 | ## تحليل الأداء
85 |
86 | ### خطة تنفيذ الاستعلام
87 |
88 | **أنت**: "اشرح خطة التنفيذ لـ: SELECT * FROM orders WHERE user_id = 42"
89 |
90 | **الذكاء الاصطناعي**: "خطة التنفيذ للاستعلام:
91 | ```
92 | QUERY PLAN
93 | ------------------------------------------------------------
94 | SEARCH TABLE orders USING INDEX idx_user_id (user_id=?)
95 | ```
96 |
97 | يستخدم هذا الاستعلام الفهرس `idx_user_id` للعثور بكفاءة على الطلبات للمستخدم ذي المعرف 42."
98 |
99 | ### إحصائيات الجدول
100 |
101 | **أنت**: "احصل على إحصائيات لجدول الطلبات."
102 |
103 | **الذكاء الاصطناعي**: "إحصائيات لجدول الطلبات:
104 | - عدد الصفوف: 1,245
105 | - الحجم: 2.3 ميجابايت
106 | - الفهارس: 3 (المفتاح الأساسي، idx_user_id، idx_order_date)
107 | - متوسط طول الصف: 1.9 كيلوبايت"
108 |
109 | ## العمل مع ميزات SQLite المحددة
110 |
111 | ### استخدام FTS (البحث النصي الكامل)
112 |
113 | **أنت**: "ابحث عن المنتجات التي تحتوي على 'سماعات لاسلكية'."
114 |
115 | **الذكاء الاصطناعي**: "إليك المنتجات التي تطابق 'سماعات لاسلكية':
116 |
117 | | product_id | الاسم | الوصف | السعر |
118 | |------------|------|-------------|-------|
119 | | 123 | سماعات لاسلكية فاخرة | سماعات لاسلكية مع إلغاء الضوضاء و30 ساعة من عمر البطارية | $199.99 |
120 | | 145 | سماعات لاسلكية رياضية | سماعات لاسلكية مقاومة للماء للرياضة | $89.99 |
121 | | 187 | سماعات لاسلكية اقتصادية | سماعات لاسلكية بأسعار معقولة مع جودة صوت جيدة | $49.99 |"
122 |
123 | ### استخدام دوال JSON
124 |
125 | **أنت**: "أظهر لي المستخدمين الذين لديهم 'premium' في تفضيلاتهم."
126 |
127 | **الذكاء الاصطناعي**: "إليك المستخدمين الذين لديهم 'premium' في تفضيلاتهم:
128 |
129 | | id | username | التفضيلات |
130 | |----|----------|-------------|
131 | | 42 | johndoe | {\"subscription\": \"premium\", \"theme\": \"dark\"} |
132 | | 17 | janedoe | {\"subscription\": \"premium\", \"theme\": \"light\"} |
133 | | 53 | mikebrown | {\"subscription\": \"premium\", \"theme\": \"auto\"} |"
134 |
135 | ## استكشاف الأخطاء وإصلاحها
136 |
137 | ### المشكلات الشائعة
138 |
139 | 1. **الملف غير موجود**
140 | - تأكد من صحة المسار إلى ملف قاعدة بيانات SQLite الخاص بك
141 | - تحقق من أذونات الملف
142 | - تحقق من وجود الملف
143 |
144 | 2. **قاعدة البيانات مقفلة**
145 | - تسمح SQLite بكاتب واحد فقط في المرة الواحدة
146 | - تأكد من عدم وجود عملية أخرى تكتب في قاعدة البيانات
147 | - فكر في استخدام وضع WAL لتحسين التزامن
148 |
149 | 3. **مشاكل الأداء**
150 | - أضف فهارس للأعمدة التي يتم الاستعلام عنها بشكل متكرر
151 | - استخدم EXPLAIN QUERY PLAN لتحديد الاستعلامات البطيئة
152 | - فكر في استخدام العبارات المعدة للاستعلامات المتكررة
153 |
154 |
155 |
--------------------------------------------------------------------------------
/docs/zh/installation-platform-specific.md:
--------------------------------------------------------------------------------
1 | # 平台特定安装指南
2 |
3 | *[English](../en/installation-platform-specific.md) | 中文 | [Français](../fr/installation-platform-specific.md) | [Español](../es/installation-platform-specific.md) | [العربية](../ar/installation-platform-specific.md) | [Русский](../ru/installation-platform-specific.md)*
4 |
5 | 本文档提供了在不同操作系统上安装和配置 MCP 数据库工具的详细指南。
6 |
7 | ## Linux 安装指南
8 |
9 | ### 前提条件
10 |
11 | - Python 3.10 或更高版本
12 | - pip 或 uv 包管理器
13 |
14 | ### 使用 uv 安装(推荐)
15 |
16 | 1. 安装 uv(如果尚未安装):
17 |
18 | ```bash
19 | curl -sSf https://raw.githubusercontent.com/astral-sh/uv/main/install.sh | bash
20 | ```
21 |
22 | 2. 使用 uv 安装 MCP 数据库工具:
23 |
24 | ```bash
25 | uv pip install mcp-dbutils
26 | ```
27 |
28 | 3. 验证安装:
29 |
30 | ```bash
31 | python -c "import mcp_dbutils; print(mcp_dbutils.__version__)"
32 | ```
33 |
34 | ### 使用虚拟环境安装
35 |
36 | 1. 创建虚拟环境:
37 |
38 | ```bash
39 | python3 -m venv mcp-env
40 | source mcp-env/bin/activate
41 | ```
42 |
43 | 2. 安装 MCP 数据库工具:
44 |
45 | ```bash
46 | pip install mcp-dbutils
47 | ```
48 |
49 | ### 离线安装
50 |
51 | 1. 在有网络连接的环境中下载包及其依赖:
52 |
53 | ```bash
54 | uv pip download mcp-dbutils -d ./mcp-packages
55 | ```
56 |
57 | 2. 将 `mcp-packages` 目录复制到目标环境
58 |
59 | 3. 在目标环境中安装:
60 |
61 | ```bash
62 | uv pip install --no-index --find-links=./mcp-packages mcp-dbutils
63 | ```
64 |
65 | 或使用离线运行模式:
66 |
67 | ```bash
68 | uv --directory /path/to/local/mcp-dbutils run mcp-dbutils
69 | ```
70 |
71 | ### 特定 Linux 发行版注意事项
72 |
73 | #### Ubuntu/Debian
74 |
75 | 确保安装了 Python 开发包:
76 |
77 | ```bash
78 | sudo apt update
79 | sudo apt install -y python3-dev
80 | ```
81 |
82 | #### CentOS/RHEL
83 |
84 | 确保安装了 Python 开发包:
85 |
86 | ```bash
87 | sudo yum install -y python3-devel
88 | ```
89 |
90 | #### Arch Linux
91 |
92 | 确保安装了 Python:
93 |
94 | ```bash
95 | sudo pacman -S python-pip
96 | ```
97 |
98 | ## macOS 安装指南
99 |
100 | ### 前提条件
101 |
102 | - Python 3.10 或更高版本
103 | - pip 或 uv 包管理器
104 | - Homebrew(推荐,用于安装 Python)
105 |
106 | ### 使用 uv 安装(推荐)
107 |
108 | 1. 安装 uv(如果尚未安装):
109 |
110 | ```bash
111 | curl -sSf https://raw.githubusercontent.com/astral-sh/uv/main/install.sh | bash
112 | ```
113 |
114 | 2. 使用 uv 安装 MCP 数据库工具:
115 |
116 | ```bash
117 | uv pip install mcp-dbutils
118 | ```
119 |
120 | ### 使用 Homebrew 安装 Python
121 |
122 | 如果尚未安装 Python,可以使用 Homebrew 安装:
123 |
124 | ```bash
125 | brew install python
126 | ```
127 |
128 | ### Apple Silicon (M1/M2/M3) 特别说明
129 |
130 | 对于 Apple Silicon 芯片的 Mac:
131 |
132 | 1. 确保使用 ARM64 版本的 Python:
133 |
134 | ```bash
135 | which python3
136 | # 应该显示 /opt/homebrew/bin/python3 而不是 /usr/local/bin/python3
137 | ```
138 |
139 | 2. 如果遇到安装问题,可以尝试使用 Rosetta 2:
140 |
141 | ```bash
142 | arch -x86_64 uv pip install mcp-dbutils
143 | ```
144 |
145 | ## Windows 安装指南
146 |
147 | ### 前提条件
148 |
149 | - Python 3.10 或更高版本
150 | - pip 或 uv 包管理器
151 |
152 | ### 使用 uv 安装(推荐)
153 |
154 | 1. 安装 uv(如果尚未安装):
155 |
156 | 在 PowerShell 中运行(需要管理员权限):
157 |
158 | ```powershell
159 | iwr -useb https://raw.githubusercontent.com/astral-sh/uv/main/install.ps1 | iex
160 | ```
161 |
162 | 2. 使用 uv 安装 MCP 数据库工具:
163 |
164 | ```powershell
165 | uv pip install mcp-dbutils
166 | ```
167 |
168 | ### 使用虚拟环境安装
169 |
170 | 1. 创建虚拟环境:
171 |
172 | ```powershell
173 | python -m venv mcp-env
174 | .\mcp-env\Scripts\Activate.ps1
175 | ```
176 |
177 | 2. 安装 MCP 数据库工具:
178 |
179 | ```powershell
180 | pip install mcp-dbutils
181 | ```
182 |
183 |
184 |
185 | ### WSL (Windows Subsystem for Linux) 安装
186 |
187 | 如果您更喜欢在 Linux 环境中工作,可以使用 WSL:
188 |
189 | 1. 安装 WSL(在 PowerShell 中运行,需要管理员权限):
190 |
191 | ```powershell
192 | wsl --install
193 | ```
194 |
195 | 2. 安装完成后,启动 WSL 并按照上面的 Linux 安装指南进行操作
196 |
197 | ## Docker 安装指南
198 |
199 | ### 使用 Docker 镜像
200 |
201 | 1. 获取项目代码:
202 | ```bash
203 | git clone https://github.com/donghao1393/mcp-dbutils.git
204 | ```
205 | 或从 [Releases 页面](https://github.com/donghao1393/mcp-dbutils/releases) 下载最新版本的压缩包并解压
206 |
207 | 2. 进入项目目录:
208 | ```bash
209 | cd mcp-dbutils
210 | ```
211 |
212 | 3. 构建 MCP 数据库工具镜像:
213 | ```bash
214 | docker build -t mcp/dbutils .
215 | ```
216 |
217 | 4. 在 AI 应用中配置使用该镜像(参见[安装指南](installation.md)中的方式 B)
218 |
219 | > **注意**:
220 | > - 项目根目录中已包含 Dockerfile,无需手动创建
221 | > - 每次需要更新到最新版本时,您需要重新获取最新代码并重新构建镜像
222 | > - 这是一个 MCP 服务,主要用于在 AI 应用中被 LLM 调用,而不是直接作为独立服务运行
223 |
224 | ## 故障排除
225 |
226 | ### 常见问题
227 |
228 | 1. **连接数据库时出现驱动程序错误**
229 |
230 | MCP 数据库工具会根据您配置的数据库类型自动尝试导入相应的驱动程序。如果遇到驱动程序错误,您可能需要安装相应的 Python 数据库适配器:
231 |
232 | ```bash
233 | # 如果您需要连接 PostgreSQL
234 | uv pip install psycopg2-binary
235 |
236 | # 如果您需要连接 MySQL
237 | uv pip install mysqlclient
238 |
239 | # 如果您需要连接 SQLite (通常已包含在 Python 中)
240 | uv pip install pysqlite3
241 | ```
242 |
243 | 注意:MCP 数据库工具本身不包含这些数据库,它只是提供与您已有数据库的连接。
244 |
245 | 2. **权限错误**
246 |
247 | - Linux/macOS:确保配置文件和数据库文件具有正确的权限
248 | - Windows:以管理员身份运行命令提示符或 PowerShell
249 |
250 | 3. **版本兼容性问题**
251 |
252 | 确保使用 Python 3.10 或更高版本:
253 |
254 | ```bash
255 | python --version
256 | ```
257 |
258 | ### 获取帮助
259 |
260 | 如果您遇到安装问题,可以:
261 |
262 | 1. 查看[GitHub Issues](https://github.com/donghao1393/mcp-dbutils/issues)中是否有类似问题
263 | 2. 提交新的 Issue,详细描述您的问题和环境
264 | 3. 在[Smithery](https://smithery.ai/server/@donghao1393/mcp-dbutils)上寻求帮助
265 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MCP 数据库工具
2 |
3 |
4 | [](https://github.com/donghao1393/mcp-dbutils/actions)
5 | [](https://github.com/donghao1393/mcp-dbutils/actions)
6 | [](https://sonarcloud.io/dashboard?id=donghao1393_mcp-dbutils)
7 |
8 |
9 | [](https://pypi.org/project/mcp-dbutils/)
10 | [](https://pypi.org/project/mcp-dbutils/)
11 | [](https://smithery.ai/server/@donghao1393/mcp-dbutils)
12 |
13 |
14 | [](https://www.python.org/)
15 | [](LICENSE)
16 | [](https://github.com/donghao1393/mcp-dbutils/stargazers)
17 |
18 | [English](README_EN.md) | [Français](README_FR.md) | [Español](README_ES.md) | [العربية](README_AR.md) | [Русский](README_RU.md) | [文档导航](#文档导航)
19 |
20 | 
21 |
22 | ## 简介
23 |
24 | MCP Database Utilities 是一个多功能的 MCP 服务,它使您的 AI 能够通过统一的连接配置安全地访问各种类型的数据库(SQLite、MySQL、PostgreSQL 等)进行数据分析。
25 |
26 | 您可以将其视为 AI 系统和数据库之间的安全桥梁,允许 AI 在不直接访问数据库或冒数据修改风险的情况下读取和分析您的数据。
27 |
28 | ### 核心特性
29 |
30 | - **安全优先**:严格只读操作,无直接数据库访问,隔离连接,按需连接,自动超时
31 | - **隐私保障**:本地处理,最小数据暴露,凭证保护,敏感数据屏蔽
32 | - **多数据库支持**:使用相同的接口连接 SQLite、MySQL、PostgreSQL
33 | - **简单配置**:所有数据库连接使用单个 YAML 文件
34 | - **高级功能**:表格浏览、架构分析和查询执行
35 |
36 | > 🔒 **安全说明**:MCP 数据库工具采用安全优先的架构设计,非常适合注重数据保护的企业、初创公司和个人用户。详细了解我们的[安全架构](docs/zh/technical/security.md)。
37 |
38 | ## 快速入门
39 |
40 | 我们提供了多种安装方式,包括 uvx、Docker 和 Smithery。详细的安装和配置步骤请参阅[安装指南](docs/zh/installation.md)。
41 |
42 | ### 基本步骤
43 |
44 | 1. **安装**:选择适合您的安装方式([详细说明](docs/zh/installation.md))
45 | 2. **配置**:创建包含数据库连接信息的 YAML 文件([配置指南](docs/zh/configuration.md))
46 | 3. **连接**:将配置添加到您的 AI 客户端
47 | 4. **使用**:开始与您的数据库交互([使用指南](docs/zh/usage.md))
48 |
49 | ### 示例交互
50 |
51 | **您**:"能否列出我的数据库中的所有表?"
52 |
53 | **AI**:"以下是您的数据库中的表:
54 | - customers(客户)
55 | - products(产品)
56 | - orders(订单)
57 | - inventory(库存)"
58 |
59 | **您**:"customers 表的结构是什么样的?"
60 |
61 | **AI**:"customers 表有以下结构:
62 | - id(整数,主键)
63 | - name(文本)
64 | - email(文本)
65 | - registration_date(日期)"
66 |
67 | ## 文档导航
68 |
69 | ### 入门指南
70 | - [安装指南](docs/zh/installation.md) - 详细的安装步骤和配置说明
71 | - [平台特定安装指南](docs/zh/installation-platform-specific.md) - 针对不同操作系统的安装说明
72 | - [配置指南](docs/zh/configuration.md) - 数据库连接配置示例和最佳实践
73 | - [使用指南](docs/zh/usage.md) - 基本操作流程和常见使用场景
74 |
75 | ### 技术文档
76 | - [架构设计](docs/zh/technical/architecture.md) - 系统架构和组件说明
77 | - [安全架构](docs/zh/technical/security.md) - 安全特性和保护机制
78 | - [开发指南](docs/zh/technical/development.md) - 代码质量和开发流程
79 | - [测试指南](docs/zh/technical/testing.md) - 测试框架和最佳实践
80 | - [SonarCloud 集成](docs/zh/technical/sonarcloud-integration.md) - SonarCloud 与 AI 集成指南
81 |
82 | ### 示例文档
83 | - [SQLite 示例](docs/zh/examples/sqlite-examples.md) - SQLite 数据库操作示例
84 | - [PostgreSQL 示例](docs/zh/examples/postgresql-examples.md) - PostgreSQL 数据库操作示例
85 | - [MySQL 示例](docs/zh/examples/mysql-examples.md) - MySQL 数据库操作示例
86 | - [高级 LLM 交互示例](docs/zh/examples/advanced-llm-interactions.md) - 与各类 LLM 的高级交互示例
87 |
88 | ### 多语言文档
89 | - **英语** - [English Documentation](docs/en/)
90 | - **法语** - [Documentation Française](docs/fr/)
91 | - **西班牙语** - [Documentación en Español](docs/es/)
92 | - **阿拉伯语** - [التوثيق باللغة العربية](docs/ar/)
93 | - **俄语** - [Документация на русском](docs/ru/)
94 |
95 | ### 支持与反馈
96 | - [GitHub Issues](https://github.com/donghao1393/mcp-dbutils/issues) - 报告问题或请求功能
97 | - [Smithery](https://smithery.ai/server/@donghao1393/mcp-dbutils) - 简化安装和更新
98 |
99 | ## 可用工具
100 |
101 | MCP 数据库工具提供了多种工具,使 AI 能够与您的数据库交互:
102 |
103 | - **dbutils-list-connections**:列出配置中的所有可用数据库连接,包括数据库类型、主机、端口和数据库名称等详细信息,同时隐藏密码等敏感信息。
104 | - **dbutils-list-tables**:列出指定数据库连接中的所有表,包括表名、URI和可用的表描述,按数据库类型分组以便于识别。
105 | - **dbutils-run-query**:执行只读SQL查询(仅SELECT),支持包括JOIN、GROUP BY和聚合函数在内的复杂查询,返回包含列名和数据行的结构化结果。
106 | - **dbutils-describe-table**:提供表结构的详细信息,包括列名、数据类型、是否可为空、默认值和注释,以易于阅读的格式呈现。
107 | - **dbutils-get-ddl**:获取创建指定表的完整DDL(数据定义语言)语句,包括所有列定义、约束和索引。
108 | - **dbutils-list-indexes**:列出指定表上的所有索引,包括索引名称、类型(唯一/非唯一)、索引方法和包含的列,按索引名称分组。
109 | - **dbutils-get-stats**:获取表的统计信息,包括估计行数、平均行长度、数据大小和索引大小。
110 | - **dbutils-list-constraints**:列出表上的所有约束,包括主键、外键、唯一约束和检查约束,对于外键约束还显示引用的表和列。
111 | - **dbutils-explain-query**:获取SQL查询的执行计划,显示数据库引擎将如何处理查询,包括访问方法、连接类型和估计成本。
112 | - **dbutils-get-performance**:获取数据库连接的性能指标,包括查询计数、平均执行时间、内存使用情况和错误统计。
113 | - **dbutils-analyze-query**:分析SQL查询的性能特性,提供执行计划、实际执行时间和具体的优化建议。
114 |
115 | 有关这些工具的详细说明和使用示例,请参阅[使用指南](docs/zh/usage.md)。
116 |
117 | ## 星标历史
118 |
119 | [](https://starchart.cc/donghao1393/mcp-dbutils)
120 |
121 | ## 许可证
122 |
123 | 本项目采用 MIT 许可证 - 有关详细信息,请参阅 [LICENSE](LICENSE) 文件。
124 |
--------------------------------------------------------------------------------
/tests/integration/test_prompts.py:
--------------------------------------------------------------------------------
1 | """Integration tests for prompts functionality"""
2 |
3 | import asyncio
4 | import tempfile
5 |
6 | import anyio
7 | import mcp.types as types
8 | import pytest
9 | import yaml
10 | from mcp import ClientSession
11 |
12 | from mcp_dbutils.base import ConnectionServer
13 | from mcp_dbutils.log import create_logger
14 |
15 | # 创建测试用的 logger
16 | logger = create_logger("test-prompts", True) # debug=True 以显示所有日志
17 |
18 | @pytest.mark.asyncio
19 | async def test_prompts_capability(sqlite_db, mcp_config):
20 | """Test that prompts capability is properly set"""
21 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
22 | yaml.dump(mcp_config, tmp)
23 | tmp.flush()
24 | server = ConnectionServer(config_path=tmp.name)
25 |
26 | # Get initialization options and verify prompts capability
27 | init_options = server.server.create_initialization_options()
28 | assert init_options.capabilities is not None
29 | assert init_options.capabilities.prompts is not None
30 |
31 | @pytest.mark.asyncio
32 | async def test_list_prompts(sqlite_db, mcp_config):
33 | """Test that list_prompts returns an empty list"""
34 | with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as tmp:
35 | yaml.dump(mcp_config, tmp)
36 | tmp.flush()
37 | server = ConnectionServer(config_path=tmp.name)
38 |
39 | # Create bidirectional streams with proper types
40 | # Client -> Server stream (server receives messages and exceptions)
41 | client_to_server_send, client_to_server_recv = anyio.create_memory_object_stream[types.JSONRPCMessage | Exception](10)
42 |
43 | # Server -> Client stream (client receives messages)
44 | server_to_client_send, server_to_client_recv = anyio.create_memory_object_stream[types.JSONRPCMessage](10)
45 |
46 | # Start server in background task with proper stream connections
47 | server_task = asyncio.create_task(
48 | server.server.run(
49 | client_to_server_recv, # Server reads from client
50 | server_to_client_send, # Server writes to client
51 | server.server.create_initialization_options(),
52 | raise_exceptions=True # 让错误更容易调试
53 | )
54 | )
55 |
56 | try:
57 | try:
58 | # Initialize client with proper stream connections
59 | logger("debug", "Creating client session")
60 | client = ClientSession(
61 | server_to_client_recv, # Client reads from server
62 | client_to_server_send # Client writes to server
63 | )
64 |
65 | async with client:
66 | # Initialize the session
67 | logger("debug", "Initializing client session")
68 | init_response = await client.initialize()
69 | logger("debug", f"Client session initialized with response: {init_response}")
70 |
71 | # Test prompts list with timeout
72 | logger("debug", "Sending prompts/list request")
73 | try:
74 | # 使用 SDK 的 list_prompts 方法
75 | response = await asyncio.wait_for(client.list_prompts(), timeout=3.0)
76 | logger("debug", f"Got response: {response}")
77 |
78 | # 验证响应
79 | assert isinstance(response.prompts, list)
80 | assert len(response.prompts) == 0
81 | logger("debug", "Test completed successfully")
82 | except asyncio.TimeoutError:
83 | logger("error", "Request timed out after 3 seconds")
84 | raise
85 | except Exception as e:
86 | logger("error", f"Request failed: {str(e)}")
87 | logger("error", f"Request error type: {type(e)}")
88 | raise
89 |
90 | except Exception as e:
91 | logger("error", f"Test failed with error: {str(e)}")
92 | logger("error", f"Error type: {type(e)}")
93 | raise
94 |
95 | except asyncio.TimeoutError:
96 | logger("error", "Test timed out")
97 | raise RuntimeError("Test timed out after 3 seconds")
98 |
99 | finally:
100 | # Clean up
101 | logger("debug", "Starting cleanup")
102 | server_task.cancel()
103 | try:
104 | await server_task
105 | except asyncio.CancelledError:
106 | logger("debug", "Server task cancelled")
107 | except Exception as e:
108 | logger("error", f"Error during server cleanup: {str(e)}")
109 |
110 | # Close streams
111 | try:
112 | await client_to_server_send.aclose()
113 | await client_to_server_recv.aclose()
114 | await server_to_client_send.aclose()
115 | await server_to_client_recv.aclose()
116 | logger("debug", "All streams closed")
117 | except Exception as e:
118 | logger("error", f"Error during stream cleanup: {str(e)}")
119 |
--------------------------------------------------------------------------------
/docs/ru/examples/sqlite-examples.md:
--------------------------------------------------------------------------------
1 | # Примеры SQLite
2 |
3 | *[English](../../en/examples/sqlite-examples.md) | [中文](../../zh/examples/sqlite-examples.md) | [Français](../../fr/examples/sqlite-examples.md) | [Español](../../es/examples/sqlite-examples.md) | [العربية](../../ar/examples/sqlite-examples.md) | Русский*
4 |
5 | Этот документ предоставляет практические примеры работы с базами данных SQLite с использованием MCP Database Utilities.
6 |
7 | ## Базовая конфигурация
8 |
9 | ```yaml
10 | connections:
11 | my-sqlite:
12 | type: sqlite
13 | path: /path/to/database.db
14 | ```
15 |
16 | ## Распространенные операции
17 |
18 | ### Перечисление таблиц
19 |
20 | **Вы**: "Перечислите все таблицы в моей базе данных SQLite."
21 |
22 | **ИИ**: "Вот таблицы в вашей базе данных SQLite:
23 | - пользователи
24 | - продукты
25 | - заказы
26 | - категории"
27 |
28 | ### Просмотр структуры таблицы
29 |
30 | **Вы**: "Покажите мне структуру таблицы пользователей."
31 |
32 | **ИИ**: "Таблица пользователей имеет следующую структуру:
33 | - id (INTEGER, PRIMARY KEY)
34 | - username (TEXT, NOT NULL)
35 | - email (TEXT, NOT NULL, UNIQUE)
36 | - created_at (TIMESTAMP)
37 | - last_login (TIMESTAMP)
38 | - status (TEXT)"
39 |
40 | ### Базовый запрос
41 |
42 | **Вы**: "Покажите мне топ-5 пользователей по дате последнего входа."
43 |
44 | **ИИ**: "Вот топ-5 пользователей по дате последнего входа:
45 |
46 | | id | username | email | last_login |
47 | |----|----------|-------|------------|
48 | | 42 | johndoe | john@example.com | 2023-11-25 14:32:15 |
49 | | 17 | janedoe | jane@example.com | 2023-11-24 09:45:22 |
50 | | 31 | bobsmith | bob@example.com | 2023-11-23 18:12:05 |
51 | | 8 | alicejones | alice@example.com | 2023-11-22 11:30:47 |
52 | | 53 | mikebrown | mike@example.com | 2023-11-21 16:08:33 |"
53 |
54 | ## Продвинутые запросы
55 |
56 | ### Объединение таблиц
57 |
58 | **Вы**: "Покажите мне последние 3 заказа с информацией о пользователе."
59 |
60 | **ИИ**: "Вот последние 3 заказа с информацией о пользователе:
61 |
62 | | order_id | order_date | username | email | total_amount |
63 | |----------|------------|----------|-------|--------------|
64 | | 1042 | 2023-11-25 | johndoe | john@example.com | $125.99 |
65 | | 1041 | 2023-11-24 | alicejones | alice@example.com | $89.50 |
66 | | 1040 | 2023-11-23 | bobsmith | bob@example.com | $212.75 |"
67 |
68 | ### Функции агрегации
69 |
70 | **Вы**: "Какова средняя сумма заказа по категории?"
71 |
72 | **ИИ**: "Вот средняя сумма заказа по категории:
73 |
74 | | категория | средняя_сумма |
75 | |----------|----------------|
76 | | Электроника | $245.75 |
77 | | Одежда | $78.30 |
78 | | Книги | $32.50 |
79 | | Дом и кухня | $124.90 |
80 | | Спорт и отдых | $156.25 |"
81 |
82 | ## Анализ производительности
83 |
84 | ### План выполнения запроса
85 |
86 | **Вы**: "Объясните план выполнения для: SELECT * FROM orders WHERE user_id = 42"
87 |
88 | **ИИ**: "План выполнения для запроса:
89 | ```
90 | QUERY PLAN
91 | ------------------------------------------------------------
92 | SEARCH TABLE orders USING INDEX idx_user_id (user_id=?)
93 | ```
94 |
95 | Этот запрос использует индекс `idx_user_id` для эффективного поиска заказов для user_id 42."
96 |
97 | ### Статистика таблицы
98 |
99 | **Вы**: "Получите статистику для таблицы заказов."
100 |
101 | **ИИ**: "Статистика для таблицы заказов:
102 | - Количество строк: 1,245
103 | - Размер: 2.3 МБ
104 | - Индексы: 3 (первичный ключ, idx_user_id, idx_order_date)
105 | - Средняя длина строки: 1.9 КБ"
106 |
107 | ## Работа с особенностями SQLite
108 |
109 | ### Использование FTS (Полнотекстовый поиск)
110 |
111 | **Вы**: "Найдите продукты, содержащие 'беспроводные наушники'."
112 |
113 | **ИИ**: "Вот продукты, соответствующие 'беспроводные наушники':
114 |
115 | | product_id | название | описание | цена |
116 | |------------|------|-------------|-------|
117 | | 123 | Премиум Беспроводные Наушники | Беспроводные наушники с шумоподавлением и 30 часами работы от батареи | $199.99 |
118 | | 145 | Спортивные Беспроводные Наушники | Водонепроницаемые беспроводные наушники для спорта | $89.99 |
119 | | 187 | Бюджетные Беспроводные Наушники | Доступные беспроводные наушники с хорошим качеством звука | $49.99 |"
120 |
121 | ### Использование функций JSON
122 |
123 | **Вы**: "Покажите мне пользователей с 'premium' в их предпочтениях."
124 |
125 | **ИИ**: "Вот пользователи с 'premium' в их предпочтениях:
126 |
127 | | id | username | предпочтения |
128 | |----|----------|-------------|
129 | | 42 | johndoe | {\"subscription\": \"premium\", \"theme\": \"dark\"} |
130 | | 17 | janedoe | {\"subscription\": \"premium\", \"theme\": \"light\"} |
131 | | 53 | mikebrown | {\"subscription\": \"premium\", \"theme\": \"auto\"} |"
132 |
133 | ## Устранение неполадок
134 |
135 | ### Распространенные проблемы
136 |
137 | 1. **Файл не найден**
138 | - Убедитесь, что путь к вашему файлу базы данных SQLite правильный
139 | - Проверьте разрешения файла
140 | - Убедитесь, что файл существует
141 |
142 | 2. **База данных заблокирована**
143 | - SQLite позволяет только одному писателю за раз
144 | - Убедитесь, что никакой другой процесс не пишет в базу данных
145 | - Рассмотрите использование режима WAL для лучшей конкурентности
146 |
147 | 3. **Проблемы с производительностью**
148 | - Добавьте индексы для часто запрашиваемых столбцов
149 | - Используйте EXPLAIN QUERY PLAN для выявления медленных запросов
150 | - Рассмотрите использование подготовленных операторов для повторяющихся запросов
151 |
--------------------------------------------------------------------------------
/src/mcp_dbutils/sqlite/config.py:
--------------------------------------------------------------------------------
1 | """SQLite configuration module"""
2 |
3 | from dataclasses import dataclass
4 | from pathlib import Path
5 | from typing import Any, Dict, Literal, Optional
6 | from urllib.parse import parse_qs, urlparse
7 |
8 | from ..config import ConnectionConfig, WritePermissions
9 |
10 |
11 | def parse_jdbc_url(jdbc_url: str) -> Dict[str, str]:
12 | """Parse JDBC URL into connection parameters
13 |
14 | Args:
15 | jdbc_url: JDBC URL (e.g. jdbc:sqlite:file:/path/to/sqlite.db or jdbc:sqlite:/path/to/sqlite.db)
16 |
17 | Returns:
18 | Dictionary of connection parameters
19 |
20 | Raises:
21 | ValueError: If URL format is invalid
22 | """
23 | if not jdbc_url.startswith('jdbc:sqlite:'):
24 | raise ValueError("Invalid SQLite JDBC URL format")
25 |
26 | # Remove jdbc:sqlite: prefix
27 | url = jdbc_url[12:]
28 |
29 | # Handle file: prefix
30 | if url.startswith('file:'):
31 | url = url[5:]
32 |
33 | # Parse URL
34 | parsed = urlparse(url)
35 | path = parsed.path
36 |
37 | # Extract query parameters
38 | params = {}
39 | if parsed.query:
40 | query_params = parse_qs(parsed.query)
41 | for key, values in query_params.items():
42 | params[key] = values[0]
43 |
44 | if not path:
45 | raise ValueError("SQLite file path must be specified in URL")
46 |
47 | return {
48 | 'path': path,
49 | 'parameters': params
50 | }
51 |
52 | @dataclass
53 | class SQLiteConfig(ConnectionConfig):
54 | path: str
55 | password: Optional[str] = None
56 | uri: bool = True # Enable URI mode to support parameters like password
57 | type: Literal['sqlite'] = 'sqlite'
58 | writable: bool = False # Whether write operations are allowed
59 | write_permissions: Optional[WritePermissions] = None # Write permissions configuration
60 |
61 | @classmethod
62 | def from_jdbc_url(cls, jdbc_url: str, password: Optional[str] = None) -> 'SQLiteConfig':
63 | """Create configuration from JDBC URL
64 |
65 | Args:
66 | jdbc_url: JDBC URL (e.g. jdbc:sqlite:file:/path/to/sqlite.db)
67 | password: Optional password for database encryption
68 |
69 | Returns:
70 | SQLiteConfig instance
71 |
72 | Raises:
73 | ValueError: If URL format is invalid
74 | """
75 | params = parse_jdbc_url(jdbc_url)
76 |
77 | config = cls(
78 | path=params['path'],
79 | password=password,
80 | uri=True
81 | )
82 | config.debug = cls.get_debug_mode()
83 | return config
84 |
85 | @property
86 | def absolute_path(self) -> str:
87 | """Return absolute path to SQLite database file"""
88 | return str(Path(self.path).expanduser().resolve())
89 |
90 | def get_connection_params(self) -> Dict[str, Any]:
91 | """Get sqlite3 connection parameters"""
92 | if not self.password:
93 | return {'database': self.absolute_path, 'uri': self.uri}
94 |
95 | # Use URI format if password is provided
96 | uri = f"file:{self.absolute_path}?mode=rw"
97 | if self.password:
98 | uri += f"&password={self.password}"
99 |
100 | return {
101 | 'database': uri,
102 | 'uri': True
103 | }
104 |
105 | def get_masked_connection_info(self) -> Dict[str, Any]:
106 | """Return connection information for logging"""
107 | info = {
108 | 'database': self.absolute_path,
109 | 'uri': self.uri
110 | }
111 | if self.password:
112 | info['password'] = '******'
113 | return info
114 |
115 | @classmethod
116 | def from_yaml(cls, yaml_path: str, db_name: str, **kwargs) -> 'SQLiteConfig':
117 | """Create SQLite configuration from YAML
118 |
119 | Args:
120 | yaml_path: Path to YAML configuration file
121 | db_name: Connection configuration name
122 | """
123 | configs = cls.load_yaml_config(yaml_path)
124 |
125 | if db_name not in configs:
126 | available_dbs = list(configs.keys())
127 | raise ValueError(f"Connection configuration not found: {db_name}. Available configurations: {available_dbs}")
128 |
129 | db_config = configs[db_name]
130 |
131 | if 'type' not in db_config:
132 | raise ValueError("Connection configuration must include 'type' field")
133 | if db_config['type'] != 'sqlite':
134 | raise ValueError(f"Configuration is not SQLite type: {db_config['type']}")
135 |
136 | # Check if using JDBC URL configuration
137 | if 'jdbc_url' in db_config:
138 | params = parse_jdbc_url(db_config['jdbc_url'])
139 | config = cls(
140 | path=params['path'],
141 | password=db_config.get('password')
142 | )
143 | else:
144 | if 'path' not in db_config:
145 | raise ValueError("SQLite configuration must include 'path' field")
146 | config = cls(
147 | path=db_config['path'],
148 | password=db_config.get('password'),
149 | uri=True
150 | )
151 |
152 | # Parse write permissions
153 | config.writable = db_config.get('writable', False)
154 | if config.writable and 'write_permissions' in db_config:
155 | config.write_permissions = WritePermissions(db_config['write_permissions'])
156 |
157 | config.debug = cls.get_debug_mode()
158 | return config
159 |
--------------------------------------------------------------------------------
/docs/es/examples/sqlite-examples.md:
--------------------------------------------------------------------------------
1 | # Ejemplos de SQLite
2 |
3 | *[English](../../en/examples/sqlite-examples.md) | [中文](../../zh/examples/sqlite-examples.md) | [Français](../../fr/examples/sqlite-examples.md) | Español | [العربية](../../ar/examples/sqlite-examples.md) | [Русский](../../ru/examples/sqlite-examples.md)*
4 |
5 | Este documento proporciona ejemplos prácticos para trabajar con bases de datos SQLite usando MCP Database Utilities.
6 |
7 | ## Configuración Básica
8 |
9 | ```yaml
10 | connections:
11 | my-sqlite:
12 | type: sqlite
13 | path: /path/to/database.db
14 | ```
15 |
16 | ## Operaciones Comunes
17 |
18 | ### Listar Tablas
19 |
20 | **Usted**: "Lista todas las tablas en mi base de datos SQLite."
21 |
22 | **IA**: "Aquí están las tablas en su base de datos SQLite:
23 | - usuarios
24 | - productos
25 | - pedidos
26 | - categorias"
27 |
28 | ### Ver Estructura de Tabla
29 |
30 | **Usted**: "Muéstrame la estructura de la tabla usuarios."
31 |
32 | **IA**: "La tabla usuarios tiene la siguiente estructura:
33 | - id (INTEGER, PRIMARY KEY)
34 | - username (TEXT, NOT NULL)
35 | - email (TEXT, NOT NULL, UNIQUE)
36 | - created_at (TIMESTAMP)
37 | - last_login (TIMESTAMP)
38 | - status (TEXT)"
39 |
40 | ### Consulta Básica
41 |
42 | **Usted**: "Muéstrame los 5 principales usuarios por fecha de último inicio de sesión."
43 |
44 | **IA**: "Aquí están los 5 principales usuarios por fecha de último inicio de sesión:
45 |
46 | | id | username | email | last_login |
47 | |----|----------|-------|------------|
48 | | 42 | johndoe | john@example.com | 2023-11-25 14:32:15 |
49 | | 17 | janedoe | jane@example.com | 2023-11-24 09:45:22 |
50 | | 31 | bobsmith | bob@example.com | 2023-11-23 18:12:05 |
51 | | 8 | alicejones | alice@example.com | 2023-11-22 11:30:47 |
52 | | 53 | mikebrown | mike@example.com | 2023-11-21 16:08:33 |"
53 |
54 | ## Consultas Avanzadas
55 |
56 | ### Uniendo Tablas
57 |
58 | **Usted**: "Muéstrame los últimos 3 pedidos con información de usuario."
59 |
60 | **IA**: "Aquí están los últimos 3 pedidos con información de usuario:
61 |
62 | | order_id | order_date | username | email | total_amount |
63 | |----------|------------|----------|-------|--------------|
64 | | 1042 | 2023-11-25 | johndoe | john@example.com | $125.99 |
65 | | 1041 | 2023-11-24 | alicejones | alice@example.com | $89.50 |
66 | | 1040 | 2023-11-23 | bobsmith | bob@example.com | $212.75 |"
67 |
68 | ### Funciones de Agregación
69 |
70 | **Usted**: "¿Cuál es el monto promedio de pedido por categoría?"
71 |
72 | **IA**: "Aquí está el monto promedio de pedido por categoría:
73 |
74 | | categoría | monto_promedio |
75 | |----------|----------------|
76 | | Electrónica | $245.75 |
77 | | Ropa | $78.30 |
78 | | Libros | $32.50 |
79 | | Hogar y Cocina | $124.90 |
80 | | Deportes y Aire Libre | $156.25 |"
81 |
82 | ## Análisis de Rendimiento
83 |
84 | ### Plan de Ejecución de Consulta
85 |
86 | **Usted**: "Explica el plan de ejecución para: SELECT * FROM pedidos WHERE user_id = 42"
87 |
88 | **IA**: "Plan de ejecución para la consulta:
89 | ```
90 | QUERY PLAN
91 | ------------------------------------------------------------
92 | SEARCH TABLE pedidos USING INDEX idx_user_id (user_id=?)
93 | ```
94 |
95 | Esta consulta usa el índice `idx_user_id` para encontrar eficientemente pedidos para user_id 42."
96 |
97 | ### Estadísticas de Tabla
98 |
99 | **Usted**: "Obtén estadísticas para la tabla pedidos."
100 |
101 | **IA**: "Estadísticas para la tabla pedidos:
102 | - Recuento de filas: 1,245
103 | - Tamaño: 2.3 MB
104 | - Índices: 3 (clave primaria, idx_user_id, idx_order_date)
105 | - Longitud promedio de fila: 1.9 KB"
106 |
107 | ## Trabajando con Características Específicas de SQLite
108 |
109 | ### Usando FTS (Búsqueda de Texto Completo)
110 |
111 | **Usted**: "Busca productos que contengan 'auriculares inalámbricos'."
112 |
113 | **IA**: "Aquí están los productos que coinciden con 'auriculares inalámbricos':
114 |
115 | | product_id | nombre | descripción | precio |
116 | |------------|------|-------------|-------|
117 | | 123 | Auriculares Inalámbricos Premium | Auriculares inalámbricos con cancelación de ruido y 30 horas de batería | $199.99 |
118 | | 145 | Auriculares Inalámbricos Deportivos | Auriculares inalámbricos resistentes al agua para deportes | $89.99 |
119 | | 187 | Auriculares Inalámbricos Económicos | Auriculares inalámbricos asequibles con buena calidad de sonido | $49.99 |"
120 |
121 | ### Usando Funciones JSON
122 |
123 | **Usted**: "Muéstrame usuarios con 'premium' en sus preferencias."
124 |
125 | **IA**: "Aquí están los usuarios con 'premium' en sus preferencias:
126 |
127 | | id | username | preferencias |
128 | |----|----------|-------------|
129 | | 42 | johndoe | {\"subscription\": \"premium\", \"theme\": \"dark\"} |
130 | | 17 | janedoe | {\"subscription\": \"premium\", \"theme\": \"light\"} |
131 | | 53 | mikebrown | {\"subscription\": \"premium\", \"theme\": \"auto\"} |"
132 |
133 | ## Solución de Problemas
134 |
135 | ### Problemas Comunes
136 |
137 | 1. **Archivo No Encontrado**
138 | - Asegúrese de que la ruta a su archivo de base de datos SQLite sea correcta
139 | - Verifique los permisos del archivo
140 | - Verifique que el archivo exista
141 |
142 | 2. **Base de Datos Bloqueada**
143 | - SQLite permite solo un escritor a la vez
144 | - Asegúrese de que ningún otro proceso esté escribiendo en la base de datos
145 | - Considere usar el modo WAL para mejor concurrencia
146 |
147 | 3. **Problemas de Rendimiento**
148 | - Agregue índices para columnas consultadas frecuentemente
149 | - Use EXPLAIN QUERY PLAN para identificar consultas lentas
150 | - Considere usar declaraciones preparadas para consultas repetidas
151 |
--------------------------------------------------------------------------------
/docs/fr/examples/sqlite-examples.md:
--------------------------------------------------------------------------------
1 | # Exemples SQLite
2 |
3 | *[English](../../en/examples/sqlite-examples.md) | [中文](../../zh/examples/sqlite-examples.md) | Français | [Español](../../es/examples/sqlite-examples.md) | [العربية](../../ar/examples/sqlite-examples.md) | [Русский](../../ru/examples/sqlite-examples.md)*
4 |
5 | Ce document fournit des exemples pratiques pour travailler avec des bases de données SQLite en utilisant MCP Database Utilities.
6 |
7 | ## Configuration de base
8 |
9 | ```yaml
10 | connections:
11 | my-sqlite:
12 | type: sqlite
13 | path: /path/to/database.db
14 | ```
15 |
16 | ## Opérations courantes
17 |
18 | ### Lister les tables
19 |
20 | **Vous**: "Listez toutes les tables dans ma base de données SQLite."
21 |
22 | **IA**: "Voici les tables dans votre base de données SQLite:
23 | - utilisateurs
24 | - produits
25 | - commandes
26 | - catégories"
27 |
28 | ### Afficher la structure d'une table
29 |
30 | **Vous**: "Montrez-moi la structure de la table utilisateurs."
31 |
32 | **IA**: "La table utilisateurs a la structure suivante:
33 | - id (INTEGER, PRIMARY KEY)
34 | - username (TEXT, NOT NULL)
35 | - email (TEXT, NOT NULL, UNIQUE)
36 | - created_at (TIMESTAMP)
37 | - last_login (TIMESTAMP)
38 | - status (TEXT)"
39 |
40 | ### Requête de base
41 |
42 | **Vous**: "Montrez-moi les 5 premiers utilisateurs par date de dernière connexion."
43 |
44 | **IA**: "Voici les 5 premiers utilisateurs par date de dernière connexion:
45 |
46 | | id | username | email | last_login |
47 | |----|----------|-------|------------|
48 | | 42 | johndoe | john@example.com | 2023-11-25 14:32:15 |
49 | | 17 | janedoe | jane@example.com | 2023-11-24 09:45:22 |
50 | | 31 | bobsmith | bob@example.com | 2023-11-23 18:12:05 |
51 | | 8 | alicejones | alice@example.com | 2023-11-22 11:30:47 |
52 | | 53 | mikebrown | mike@example.com | 2023-11-21 16:08:33 |"
53 |
54 | ## Requêtes avancées
55 |
56 | ### Jointure de tables
57 |
58 | **Vous**: "Montrez-moi les 3 dernières commandes avec les informations utilisateur."
59 |
60 | **IA**: "Voici les 3 dernières commandes avec les informations utilisateur:
61 |
62 | | order_id | order_date | username | email | total_amount |
63 | |----------|------------|----------|-------|--------------|
64 | | 1042 | 2023-11-25 | johndoe | john@example.com | 125,99 € |
65 | | 1041 | 2023-11-24 | alicejones | alice@example.com | 89,50 € |
66 | | 1040 | 2023-11-23 | bobsmith | bob@example.com | 212,75 € |"
67 |
68 | ### Fonctions d'agrégation
69 |
70 | **Vous**: "Quel est le montant moyen des commandes par catégorie?"
71 |
72 | **IA**: "Voici le montant moyen des commandes par catégorie:
73 |
74 | | catégorie | montant_moyen |
75 | |----------|----------------|
76 | | Électronique | 245,75 € |
77 | | Vêtements | 78,30 € |
78 | | Livres | 32,50 € |
79 | | Maison et cuisine | 124,90 € |
80 | | Sports et loisirs | 156,25 € |"
81 |
82 | ## Analyse de performance
83 |
84 | ### Plan d'exécution de requête
85 |
86 | **Vous**: "Expliquez le plan d'exécution pour: SELECT * FROM orders WHERE user_id = 42"
87 |
88 | **IA**: "Plan d'exécution pour la requête:
89 | ```
90 | QUERY PLAN
91 | ------------------------------------------------------------
92 | SEARCH TABLE orders USING INDEX idx_user_id (user_id=?)
93 | ```
94 |
95 | Cette requête utilise l'index `idx_user_id` pour rechercher efficacement les commandes pour user_id 42."
96 |
97 | ### Statistiques de table
98 |
99 | **Vous**: "Obtenez les statistiques pour la table commandes."
100 |
101 | **IA**: "Statistiques pour la table commandes:
102 | - Nombre de lignes: 1 245
103 | - Taille: 2,3 Mo
104 | - Indices: 3 (clé primaire, idx_user_id, idx_order_date)
105 | - Longueur moyenne de ligne: 1,9 Ko"
106 |
107 | ## Travailler avec les fonctionnalités SQLite
108 |
109 | ### Utilisation de FTS (Recherche en texte intégral)
110 |
111 | **Vous**: "Trouvez les produits contenant 'écouteurs sans fil'."
112 |
113 | **IA**: "Voici les produits correspondant à 'écouteurs sans fil':
114 |
115 | | product_id | nom | description | prix |
116 | |------------|------|-------------|-------|
117 | | 123 | Écouteurs Sans Fil Premium | Écouteurs sans fil avec réduction de bruit et 30 heures d'autonomie | 199,99 € |
118 | | 145 | Écouteurs Sans Fil Sport | Écouteurs sans fil étanches pour le sport | 89,99 € |
119 | | 187 | Écouteurs Sans Fil Budget | Écouteurs sans fil abordables avec une bonne qualité sonore | 49,99 € |"
120 |
121 | ### Utilisation des fonctions JSON
122 |
123 | **Vous**: "Montrez-moi les utilisateurs avec 'premium' dans leurs préférences."
124 |
125 | **IA**: "Voici les utilisateurs avec 'premium' dans leurs préférences:
126 |
127 | | id | username | préférences |
128 | |----|----------|-------------|
129 | | 42 | johndoe | {\"abonnement\": \"premium\", \"thème\": \"sombre\"} |
130 | | 17 | janedoe | {\"abonnement\": \"premium\", \"thème\": \"clair\"} |
131 | | 53 | mikebrown | {\"abonnement\": \"premium\", \"thème\": \"auto\"} |"
132 |
133 | ## Dépannage
134 |
135 | ### Problèmes courants
136 |
137 | 1. **Fichier non trouvé**
138 | - Assurez-vous que le chemin vers votre fichier de base de données SQLite est correct
139 | - Vérifiez les permissions du fichier
140 | - Assurez-vous que le fichier existe
141 |
142 | 2. **Base de données verrouillée**
143 | - SQLite ne permet qu'un seul écrivain à la fois
144 | - Assurez-vous qu'aucun autre processus n'écrit dans la base de données
145 | - Envisagez d'utiliser le mode WAL pour une meilleure concurrence
146 |
147 | 3. **Problèmes de performance**
148 | - Ajoutez des index pour les colonnes fréquemment interrogées
149 | - Utilisez EXPLAIN QUERY PLAN pour identifier les requêtes lentes
150 | - Envisagez d'utiliser des instructions préparées pour les requêtes répétitives
151 |
--------------------------------------------------------------------------------
/docs/zh/configuration-write-operations.md:
--------------------------------------------------------------------------------
1 | # 数据库写操作配置指南
2 |
3 | 本文档详细介绍如何配置MCP数据库工具的写操作功能。默认情况下,所有数据库连接都是只读的,需要通过明确的配置才能启用写操作。
4 |
5 | > ⚠️ **安全警告**:启用数据库写操作可能导致数据丢失或损坏。请确保您了解相关风险,并采取适当的安全措施。建议在生产环境中保持只读模式,或使用严格的权限控制。
6 |
7 | ## 1. 基本配置
8 |
9 | 要启用数据库写操作,需要在连接配置中添加`writable: true`参数:
10 |
11 | ```yaml
12 | connections:
13 | example_db:
14 | type: postgres
15 | host: localhost
16 | port: 5432
17 | database: mydb
18 | user: postgres
19 | password: secret
20 | writable: true # 启用写操作
21 | ```
22 |
23 | 如果未指定`writable`参数,或设置为`false`,则连接将保持只读模式:
24 |
25 | ```yaml
26 | connections:
27 | readonly_db:
28 | type: mysql
29 | host: localhost
30 | port: 3306
31 | database: mydb
32 | user: root
33 | password: secret
34 | # 未指定writable,默认为false(只读)
35 | ```
36 |
37 | ## 2. 细粒度权限控制
38 |
39 | 对于启用了写操作的连接,您可以进一步控制哪些表允许哪些写操作。
40 |
41 | ### 2.1 表级权限
42 |
43 | 通过`write_permissions.tables`配置特定表的写权限:
44 |
45 | ```yaml
46 | connections:
47 | example_db:
48 | # 基本连接信息...
49 | writable: true
50 | write_permissions:
51 | tables:
52 | users: # 允许对users表进行写操作
53 | operations: [INSERT, UPDATE]
54 | logs: # 允许对logs表进行写操作
55 | operations: [INSERT]
56 | ```
57 |
58 | 在上面的例子中:
59 | - `users`表允许INSERT和UPDATE操作,但不允许DELETE
60 | - `logs`表只允许INSERT操作
61 | - 未明确指定的表将遵循默认策略
62 |
63 | ### 2.2 默认策略
64 |
65 | 通过`default_policy`设置未明确指定的表的默认权限策略:
66 |
67 | ```yaml
68 | write_permissions:
69 | default_policy: read_only # 未指定的表默认只读
70 | ```
71 |
72 | 可选的默认策略值:
73 | - `read_only`:未明确指定的表默认只读(推荐)
74 | - `allow_all`:未明确指定的表默认允许所有写操作
75 |
76 | 如果未设置`default_policy`,则默认为`read_only`。
77 |
78 | ### 2.3 操作级权限
79 |
80 | 对于每个允许写操作的表,可以指定允许的操作类型:
81 |
82 | ```yaml
83 | tables:
84 | users:
85 | operations: [INSERT, UPDATE] # 只允许插入和更新,不允许删除
86 | ```
87 |
88 | 可用的操作类型:
89 | - `INSERT`:允许插入新数据
90 | - `UPDATE`:允许更新现有数据
91 | - `DELETE`:允许删除数据
92 |
93 | 如果未指定`operations`,则默认允许所有写操作(INSERT、UPDATE、DELETE)。
94 |
95 | ### 2.4 表名大小写处理
96 |
97 | MCP-DBUtils 在处理表名时采用大小写不敏感的比较策略:
98 |
99 | - 在配置文件中,表名可以使用任意大小写(如 `users`、`Users` 或 `USERS`)。
100 | - 在 SQL 语句中,表名同样可以使用任意大小写。
101 | - 系统会自动将表名转换为小写进行比较,确保大小写不影响权限检查。
102 |
103 | 例如,以下配置和 SQL 语句都能正确匹配:
104 |
105 | ```yaml
106 | # 配置文件中使用小写表名
107 | tables:
108 | users:
109 | operations: [INSERT, UPDATE]
110 | ```
111 |
112 | ```sql
113 | -- SQL 语句中使用大写表名,仍然能正确匹配权限
114 | INSERT INTO USERS (id, name) VALUES (1, 'test');
115 | ```
116 |
117 | ## 3. 完整配置示例
118 |
119 | 以下是一个包含多种配置场景的完整示例:
120 |
121 | ```yaml
122 | connections:
123 | # 示例1:只读连接(默认)
124 | readonly_sqlite:
125 | type: sqlite
126 | database: ":memory:"
127 | # 未指定writable,默认为false(只读)
128 |
129 | # 示例2:可写连接,无细粒度控制
130 | simple_writable_mysql:
131 | type: mysql
132 | host: localhost
133 | port: 3306
134 | database: simple_db
135 | user: root
136 | password: secret
137 | writable: true
138 | # 未指定write_permissions,所有表都可写
139 |
140 | # 示例3:可写连接,有表级和操作级控制
141 | controlled_postgres:
142 | type: postgres
143 | host: localhost
144 | port: 5432
145 | database: controlled_db
146 | user: postgres
147 | password: postgres
148 | writable: true
149 |
150 | write_permissions:
151 | # 表级权限
152 | tables:
153 | users:
154 | operations: [INSERT, UPDATE] # 只允许插入和更新
155 | logs:
156 | operations: [INSERT] # 只允许插入
157 | temp_data:
158 | operations: [INSERT, UPDATE, DELETE] # 允许所有写操作
159 |
160 | # 默认策略
161 | default_policy: read_only # 未指定的表默认只读
162 |
163 | # 示例4:可写连接,只有默认策略
164 | all_writable_postgres:
165 | type: postgres
166 | host: localhost
167 | port: 5432
168 | database: all_writable_db
169 | user: postgres
170 | password: postgres
171 | writable: true
172 |
173 | write_permissions:
174 | default_policy: allow_all # 所有表默认可写
175 | ```
176 |
177 | ## 4. 最佳实践
178 |
179 | ### 4.1 安全建议
180 |
181 | 1. **默认只读**:
182 | - 除非明确需要写操作,否则保持默认的只读模式
183 | - 生产环境建议使用只读连接
184 |
185 | 2. **最小权限原则**:
186 | - 只为必要的表启用写操作
187 | - 只允许必要的操作类型(如只允许INSERT而不允许DELETE)
188 |
189 | 3. **数据库用户权限**:
190 | - 使用权限有限的数据库用户
191 | - 不要使用数据库管理员账户
192 |
193 | 4. **审计日志**:
194 | - 定期检查审计日志,监控写操作
195 | - 设置异常操作警报
196 |
197 | ### 4.2 配置建议
198 |
199 | 1. **明确配置**:
200 | - 总是明确设置`writable`参数,即使使用默认值
201 | - 明确设置`default_policy`,避免依赖默认行为
202 |
203 | 2. **分离环境**:
204 | - 为开发、测试和生产环境使用不同的配置文件
205 | - 生产环境配置应该更加严格
206 |
207 | 3. **注释配置**:
208 | - 为每个启用写操作的连接添加注释,说明原因
209 | - 记录配置更改的时间和负责人
210 |
211 | ## 5. 故障排查
212 |
213 | ### 5.1 常见问题
214 |
215 | 1. **写操作被拒绝**:
216 | - 检查连接是否设置了`writable: true`
217 | - 检查表是否在允许的表列表中
218 | - 检查操作类型是否被允许
219 |
220 | 2. **权限错误**:
221 | - 检查数据库用户是否有足够的权限
222 | - 检查数据库服务器的权限设置
223 |
224 | 3. **审计日志问题**:
225 | - 检查日志目录的写入权限
226 | - 检查磁盘空间是否充足
227 |
228 | ### 5.2 错误消息解释
229 |
230 | | 错误消息 | 可能的原因 | 解决方案 |
231 | |---------|-----------|---------|
232 | | "Connection is not configured for write operations" | 连接未设置`writable: true` | 在配置文件中添加`writable: true` |
233 | | "No permission to perform [操作] on table [表名]" | 表未被允许执行该操作 | 在`write_permissions.tables`中添加表和操作 |
234 | | "Operation not confirmed" | 未提供正确的确认参数 | 在工具调用中添加`confirmation: "CONFIRM_WRITE"` |
235 | | "No permission to perform [操作] on table [大写表名]" | SQL语句中使用了大写表名,但配置中使用小写表名 | 系统已支持大小写不敏感的表名比较,此问题在v1.0.1及以上版本已修复 |
236 |
237 | ## 6. 配置迁移
238 |
239 | 如果您从早期版本升级,需要注意以下几点:
240 |
241 | 1. 默认情况下,所有连接保持只读模式,与早期版本行为一致
242 | 2. 要启用写操作,需要明确添加新的配置参数
243 | 3. 建议在升级后检查所有配置文件,确保安全设置符合预期
244 |
245 | ## 7. 相关资源
246 |
247 | - [数据库写操作功能设计](./technical/write-operations-design.md)
248 | - [安全架构](./technical/security.md)
249 | - [审计日志指南](./technical/audit-logging.md)
250 |
--------------------------------------------------------------------------------