├── 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://img.shields.io/github/workflow/status/donghao1393/mcp-dbutils/Quality%20Assurance?label=tests)](https://github.com/donghao1393/mcp-dbutils/actions) 5 | [![覆盖率](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/donghao1393/bdd0a63ec2a816539ff8c136ceb41e48/raw/coverage.json)](https://github.com/donghao1393/mcp-dbutils/actions) 6 | [![质量门禁状态](https://sonarcloud.io/api/project_badges/measure?project=donghao1393_mcp-dbutils&metric=alert_status)](https://sonarcloud.io/dashboard?id=donghao1393_mcp-dbutils) 7 | 8 | 9 | [![PyPI 版本](https://img.shields.io/pypi/v/mcp-dbutils)](https://pypi.org/project/mcp-dbutils/) 10 | [![PyPI 下载量](https://img.shields.io/pypi/dm/mcp-dbutils)](https://pypi.org/project/mcp-dbutils/) 11 | [![Smithery](https://smithery.ai/badge/@donghao1393/mcp-dbutils)](https://smithery.ai/server/@donghao1393/mcp-dbutils) 12 | 13 | 14 | [![Python](https://img.shields.io/badge/Python-3.10%2B-blue)](https://www.python.org/) 15 | [![许可证](https://img.shields.io/github/license/donghao1393/mcp-dbutils)](LICENSE) 16 | [![GitHub 星标](https://img.shields.io/github/stars/donghao1393/mcp-dbutils?style=social)](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 | ![Image](https://github.com/user-attachments/assets/26c4f1a1-7b19-4bdd-b9fd-34ad198b0ce3) 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.svg?variant=adaptive)](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 | --------------------------------------------------------------------------------