使用 Python 项目管理工具 uv 快速创建 MCP 服务(Cherry Studio、Trae 添加 MCP 服务)

文章目录

  • 下载Trae
  • [uv 工具教程参考我的这篇文章](#uv 工具教程参考我的这篇文章)
  • [创建 uv 项目](#创建 uv 项目)
  • main.py
  • [Cherry Studio 添加 MCP 服务](#Cherry Studio 添加 MCP 服务)
    • [DeepSeek API](#DeepSeek API)
    • [配置 DeepSeek API](#配置 DeepSeek API)
    • [调用 MCP 服务](#调用 MCP 服务)
  • [Trae 添加 MCP 服务](#Trae 添加 MCP 服务)
  • 使用智能体
    • [调用 MCP 创建 demo 表](#调用 MCP 创建 demo 表)
    • [查询 demo 表结构信息](#查询 demo 表结构信息)
    • [demo 表插入 2 条测试数据](#demo 表插入 2 条测试数据)
    • [查询 demo 表中的数据](#查询 demo 表中的数据)

下载Trae

uv 工具教程参考我的这篇文章

创建 uv 项目

bash 复制代码
uv init demo
cd demo
  • 添加依赖项
bash 复制代码
uv add 'mcp[cli]'

main.py

python 复制代码
import asyncio
import argparse
import sqlite3
import logging
from contextlib import closing
from pathlib import Path
from pydantic import AnyUrl
from typing import Any

from mcp.server import InitializationOptions
from mcp.server.lowlevel import Server, NotificationOptions
from mcp.server.stdio import stdio_server
import mcp.types as types

logger = logging.getLogger('mcp_sqlite_server')
logger.info("Starting MCP SQLite Server")

class SqliteDatabase:
    def __init__(self, db_path: str):
        self.db_path = str(Path(db_path).expanduser())
        Path(self.db_path).parent.mkdir(parents=True, exist_ok=True)
        self._init_database()
        self.insights: list[str] = []

    def _init_database(self):
        """Initialize connection to the SQLite database"""
        logger.debug("Initializing database connection")
        with closing(sqlite3.connect(self.db_path)) as conn:
            conn.row_factory = sqlite3.Row
            conn.close()

    def _synthesize_memo(self) -> str:
        """Synthesizes business insights into a formatted memo"""
        logger.debug(f"Synthesizing memo with {len(self.insights)} insights")
        if not self.insights:
            return "No business insights have been discovered yet."

        insights = "\n".join(f"- {insight}" for insight in self.insights)

        memo = "📊 Business Intelligence Memo 📊\n\n"
        memo += "Key Insights Discovered:\n\n"
        memo += insights

        if len(self.insights) > 1:
            memo += "\nSummary:\n"
            memo += f"Analysis has revealed {len(self.insights)} key business insights that suggest opportunities for strategic optimization and growth."

        logger.debug("Generated basic memo format")
        return memo

    def _execute_query(self, query: str, params: dict[str, Any] | None = None) -> list[dict[str, Any]]:
        """Execute a SQL query and return results as a list of dictionaries"""
        logger.debug(f"Executing query: {query}")
        try:
            with closing(sqlite3.connect(self.db_path)) as conn:
                conn.row_factory = sqlite3.Row
                with closing(conn.cursor()) as cursor:
                    if params:
                        cursor.execute(query, params)
                    else:
                        cursor.execute(query)

                    if query.strip().upper().startswith(('INSERT', 'UPDATE', 'DELETE', 'CREATE', 'DROP', 'ALTER')):
                        conn.commit()
                        affected = cursor.rowcount
                        logger.debug(f"Write query affected {affected} rows")
                        return [{"affected_rows": affected}]

                    results = [dict(row) for row in cursor.fetchall()]
                    logger.debug(f"Read query returned {len(results)} rows")
                    return results
        except Exception as e:
            logger.error(f"Database error executing query: {e}")
            raise

async def main(db_path: str):
    logger.info(f"Starting SQLite MCP Server with DB path: {db_path}")

    db = SqliteDatabase(db_path)
    server = Server("sqlite-manager")

    logger.debug("Registering handlers")

    @server.list_resources()
    async def handle_list_resources() -> list[types.Resource]:
        logger.debug("Handling list_resources request")
        return [
            types.Resource(
                uri=AnyUrl("memo://insights"),
                name="Business Insights Memo",
                description="A living document of discovered business insights",
                mimeType="text/plain",
            )
        ]
    
    @server.read_resource()
    async def handle_read_resource(uri: AnyUrl) -> str:
        logger.debug(f"Handling read_resource request for URI: {uri}")
        if uri.scheme != "memo":
            logger.error(f"Unsupported URI scheme: {uri.scheme}")
            raise ValueError(f"Unsupported URI scheme: {uri.scheme}")

        path = str(uri).replace("memo://", "")
        if not path or path != "insights":
            logger.error(f"Unknown resource path: {path}")
            raise ValueError(f"Unknown resource path: {path}")

        return db._synthesize_memo()
    
    @server.list_tools()
    async def handle_list_tools() -> list[types.Tool]:
        """List available tools"""
        return [
            types.Tool(
                name="read_query",
                description="Execute a SELECT query on the SQLite database",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "query": {"type": "string", "description": "SELECT SQL query to execute"},
                    },
                    "required": ["query"],
                },
            ),
            types.Tool(
                name="write_query",
                description="Execute an INSERT, UPDATE, or DELETE query on the SQLite database",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "query": {"type": "string", "description": "SQL query to execute"},
                    },
                    "required": ["query"],
                },
            ),
            types.Tool(
                name="create_table",
                description="Create a new table in the SQLite database",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "query": {"type": "string", "description": "CREATE TABLE SQL statement"},
                    },
                    "required": ["query"],
                },
            ),
            types.Tool(
                name="list_tables",
                description="List all tables in the SQLite database",
                inputSchema={
                    "type": "object",
                    "properties": {},
                },
            ),
            types.Tool(
                name="describe_table",
                description="Get the schema information for a specific table",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "table_name": {"type": "string", "description": "Name of the table to describe"},
                    },
                    "required": ["table_name"],
                },
            ),
            types.Tool(
                name="append_insight",
                description="Add a business insight to the memo",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "insight": {"type": "string", "description": "Business insight discovered from data analysis"},
                    },
                    "required": ["insight"],
                },
            ),
        ]

    @server.call_tool()
    async def handle_call_tool(
        name: str, arguments: dict[str, Any] | None
    ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
        """Handle tool execution requests"""
        try:
            if name == "list_tables":
                results = db._execute_query(
                    "SELECT name FROM sqlite_master WHERE type='table'"
                )
                return [types.TextContent(type="text", text=str(results))]

            elif name == "describe_table":
                if not arguments or "table_name" not in arguments:
                    raise ValueError("Missing table_name argument")
                results = db._execute_query(
                    f"PRAGMA table_info({arguments['table_name']})"
                )
                return [types.TextContent(type="text", text=str(results))]

            elif name == "append_insight":
                if not arguments or "insight" not in arguments:
                    raise ValueError("Missing insight argument")

                db.insights.append(arguments["insight"])
                _ = db._synthesize_memo()

                # Notify clients that the memo resource has changed
                await server.request_context.session.send_resource_updated(AnyUrl("memo://insights"))

                return [types.TextContent(type="text", text="Insight added to memo")]

            if not arguments:
                raise ValueError("Missing arguments")

            if name == "read_query":
                if not arguments["query"].strip().upper().startswith("SELECT"):
                    raise ValueError("Only SELECT queries are allowed for read_query")
                results = db._execute_query(arguments["query"])
                return [types.TextContent(type="text", text=str(results))]

            elif name == "write_query":
                if arguments["query"].strip().upper().startswith("SELECT"):
                    raise ValueError("SELECT queries are not allowed for write_query")
                results = db._execute_query(arguments["query"])
                return [types.TextContent(type="text", text=str(results))]

            elif name == "create_table":
                if not arguments["query"].strip().upper().startswith("CREATE TABLE"):
                    raise ValueError("Only CREATE TABLE statements are allowed")
                db._execute_query(arguments["query"])
                return [types.TextContent(type="text", text="Table created successfully")]

            else:
                raise ValueError(f"Unknown tool: {name}")

        except sqlite3.Error as e:
            return [types.TextContent(type="text", text=f"Database error: {str(e)}")]
        except Exception as e:
            return [types.TextContent(type="text", text=f"Error: {str(e)}")]

    async with stdio_server() as (read_stream, write_stream):
        logger.info("Server running with stdio transport")
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="sqlite",
                server_version="0.1.0",
                capabilities=server.get_capabilities(
                    notification_options=NotificationOptions(),
                    experimental_capabilities={},
                ),
            ),
        )

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='SQLite MCP Server')
    parser.add_argument('--db-path', default="./sqlite_mcp_server.db", help='Path to SQLite database file')
    args = parser.parse_args()
    asyncio.run(main(args.db_path))

Cherry Studio 添加 MCP 服务

bash 复制代码
--directory
~/TraeProjects/demo
run
main.py
--db-path
~/TraeProjects/demo/test.db


DeepSeek API

配置 DeepSeek API

调用 MCP 服务


Trae 添加 MCP 服务

添加 MCP

json 复制代码
{
  "mcpServers": {
    "sqlite-server": {
      "command": "uv",
      "args": [
        "--directory",
        "~/TraeProjects/demo",
        "run",
        "main.py",
        "--db-path",
        "~/TraeProjects/demo/test.db"
      ]
    }
  }
}


创建智能体

使用智能体

调用 MCP 创建 demo 表

查询 demo 表结构信息

demo 表插入 2 条测试数据

查询 demo 表中的数据

相关推荐
ynchyong4 小时前
SQLAlchemy 更新操作:values() 与 ordered_values() 的隐藏差异
python·sqlalchemy·update·values·ordered_values
hoaxxcj4 小时前
DeepSeek Harness 本地部署与第三方插件排障实录:从 fetch failed 到 preset not found
人工智能·windows·开源·ai agent·deepseek
statistican_ABin4 小时前
中国互联网与数字生活分析报告—基于1990-2023年世界银行互联网数据的多维度分析
python
对角4 小时前
摸鱼神器:一边写代码,一边刷剧,从此没有一点摸鱼时间会被浪费!
ai编程·deepseek·vibecoding
“AI国潮设计-小江”4 小时前
【Python/SDXL实战】潮汕国潮IP视觉落地:普宁美食猫IP & 创意甜品设计(附ComfyUI工作流思路)
开发语言·人工智能·python·prompt·aigc
Allen_LVyingbo4 小时前
医疗人工智能项目全生命周期管理系统:监管知识建模、工程实现与实证评估(下)
大数据·数据库·人工智能·python·自然语言处理·自动化
wuhuhuan5 小时前
Case Generator 平台升级
python·测试工具·自动化
RobinDevNotes5 小时前
用 Profile 揪出大模型训练性能瓶颈
python·性能优化
李航19835 小时前
用 DeepDraw 几何引擎开发建筑设计软件(六):创建画线工具
python·软件构建
AI 编程助手GPT5 小时前
Python 备份 SQLite:为什么复制了 .db,恢复后还是少数据?
人工智能·python·ai·chatgpt