doris-mcp-server 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ from .config import DB_CONFIG, MCP_SERVER_NAME, DEBUG
2
+
3
+ __all__ = ["DB_CONFIG", "MCP_SERVER_NAME", "DEBUG"]
@@ -0,0 +1,37 @@
1
+ # config.py
2
+ import os
3
+ from dotenv import load_dotenv
4
+ from pathlib import Path
5
+ import shutil
6
+
7
+ # 确定.env路径和.env.example路径
8
+ env_dir = Path(__file__).resolve().parent
9
+ env_path = env_dir / ".env"
10
+ env_example_path = env_dir / ".env.example"
11
+
12
+ # 如果.env不存在,尝试从.env.example复制一份
13
+ if not env_path.exists():
14
+ if env_example_path.exists():
15
+ shutil.copy(env_example_path, env_path)
16
+ print(f"未找到 .env 文件,已自动从 .env.example 创建 {env_path}")
17
+ print(f"请根据实际情况编辑 {env_path},填写正确的数据库连接信息。")
18
+ else:
19
+ raise FileNotFoundError(
20
+ f"❌ 配置文件 {env_path} 不存在,且找不到示例文件 {env_example_path}。\n"
21
+ f"请手动创建 .env 文件或联系开发者提供模板。"
22
+ )
23
+
24
+ # 加载.env
25
+ load_dotenv(dotenv_path=env_path)
26
+
27
+ # 读取配置项
28
+ DB_CONFIG = {
29
+ "host": os.getenv("DB_HOST", "localhost"),
30
+ "port": int(os.getenv("DB_PORT", 9030)),
31
+ "user": os.getenv("DB_USER", "root"),
32
+ "password": os.getenv("DB_PASSWORD", ""),
33
+ "database": os.getenv("DB_NAME", ""),
34
+ }
35
+
36
+ MCP_SERVER_NAME = os.getenv("MCP_SERVER_NAME", "DorisAnalytics")
37
+ DEBUG = os.getenv("DEBUG", "false").lower() in ["1", "true", "yes"]
@@ -0,0 +1,4 @@
1
+ from .db import DorisConnector
2
+ from .tools import run_select_query, preview_table, describe_table,list_all_tables
3
+
4
+ __all__ = [DorisConnector, run_select_query, preview_table, describe_table, list_all_tables]
@@ -0,0 +1,57 @@
1
+ import pymysql
2
+ from pymysql.cursors import DictCursor
3
+ from doris_mcp_server.config import DB_CONFIG
4
+
5
+
6
+ class DorisConnector:
7
+ def __init__(self):
8
+ self.connection = None
9
+ self._connect()
10
+
11
+ def _connect(self):
12
+ try:
13
+ self.connection = pymysql.connect(
14
+ host=DB_CONFIG["host"],
15
+ port=DB_CONFIG["port"],
16
+ user=DB_CONFIG["user"],
17
+ password=DB_CONFIG["password"],
18
+ database=DB_CONFIG["database"],
19
+ cursorclass=DictCursor,
20
+ autocommit=True
21
+ )
22
+ print(f"[DorisConnector] Connected to {DB_CONFIG['host']}:{DB_CONFIG['port']}")
23
+ except Exception as e:
24
+ print(f"[DorisConnector] Connection failed: {e}")
25
+ raise
26
+
27
+ def close(self):
28
+ if self.connection:
29
+ self.connection.close()
30
+ print("[DorisConnector] Connection closed.")
31
+
32
+ def execute_query(self, sql: str) -> list[dict]:
33
+ if not self.connection:
34
+ self._connect()
35
+ try:
36
+ with self.connection.cursor() as cursor:
37
+ cursor.execute(sql)
38
+ result = cursor.fetchall()
39
+ return result
40
+ except Exception as e:
41
+ print(f"[DorisConnector] Query failed: {e}")
42
+ raise
43
+
44
+ def get_table_schema(self, table_name: str) -> list[dict]:
45
+ """
46
+ 获取指定表的字段信息,包括字段名、类型、是否为空、默认值等
47
+ """
48
+ sql = f"DESCRIBE {table_name};"
49
+ return self.execute_query(sql)
50
+
51
+ def list_tables(self, db: str) -> list[str]:
52
+ """
53
+ 获取当前数据库中所有表的列表
54
+ """
55
+ sql = f"SHOW TABLES IN {db};"
56
+ result = self.execute_query(sql)
57
+ return [row[f'Tables_in_{DB_CONFIG["database"]}'] for row in result]
@@ -0,0 +1,94 @@
1
+ import re
2
+ from doris_mcp_server.db import DorisConnector
3
+ from doris_mcp_server.mcp_app import mcp
4
+ from doris_mcp_server.config import DB_CONFIG
5
+
6
+
7
+
8
+
9
+ def _is_safe_select(sql: str) -> bool:
10
+ """
11
+ 检查 SQL 是否为安全的 SELECT 查询
12
+ """
13
+ sql = sql.strip().lower()
14
+ return sql.startswith("select") and not re.search(r"\b(update|delete|insert|drop|alter|create|replace|truncate)\b", sql)
15
+
16
+
17
+
18
+ @mcp.tool(name="run_select_query")
19
+ def run_select_query(sql: str) -> str:
20
+ """
21
+ 执行只读 SELECT 查询并返回格式化结果。
22
+ """
23
+ if not _is_safe_select(sql):
24
+ return "仅允许只读 SELECT 查询,不支持修改型语句。"
25
+
26
+ db = DorisConnector()
27
+ try:
28
+ rows = db.execute_query(sql)
29
+ if not rows:
30
+ return "查询结果为空。"
31
+
32
+ headers = rows[0].keys()
33
+ lines = [" | ".join(headers)]
34
+ lines.append("-" * len(lines[0]))
35
+ for row in rows:
36
+ lines.append(" | ".join(str(row[col]) for col in headers))
37
+ return "\n".join(lines)
38
+ except Exception as e:
39
+ return f"查询失败: {str(e)}"
40
+
41
+
42
+
43
+ @mcp.tool(name="preview_table")
44
+ def preview_table(table_name: str) -> str:
45
+ """
46
+ 预览指定表前 10 行数据。
47
+ """
48
+ try:
49
+ sql = f"SELECT * FROM {table_name} LIMIT 10;"
50
+ return run_select_query(sql)
51
+ except Exception as e:
52
+ return f"预览失败: {str(e)}"
53
+
54
+
55
+
56
+
57
+ @mcp.tool(name="describe_table")
58
+ def describe_table(table_name: str) -> str:
59
+ """
60
+ 返回指定表的字段结构,包括字段名、类型、是否为 null、默认值和注释。
61
+ """
62
+ db = DorisConnector()
63
+ try:
64
+ schema = db.get_table_schema(table_name)
65
+ if not schema:
66
+ return f"表 `{table_name}` 不存在或无法获取结构信息。"
67
+
68
+ headers = ["Field", "Type", "Null", "Key", "Default", "Extra"]
69
+ lines = [" | ".join(headers)]
70
+ lines.append("-" * len(lines[0]))
71
+
72
+ for row in schema:
73
+ line = " | ".join(str(row.get(h, "")) for h in headers)
74
+ lines.append(line)
75
+
76
+ return "\n".join(lines)
77
+
78
+ except Exception as e:
79
+ return f"获取表结构失败: {str(e)}"
80
+
81
+
82
+
83
+
84
+ @mcp.tool(name="list_all_tables")
85
+ def list_all_tables(db_name: str = DB_CONFIG["database"]) -> str:
86
+ """
87
+ 列出当前数据库的所有表。
88
+ """
89
+ db = DorisConnector()
90
+ try:
91
+ tables = db.list_tables(db_name)
92
+ return "\n".join(tables)
93
+ except Exception as e:
94
+ return f"无法获取表列表: {str(e)}"
@@ -0,0 +1,7 @@
1
+ # mcp_app.py
2
+ from mcp.server.fastmcp import FastMCP
3
+ from doris_mcp_server.config import MCP_SERVER_NAME
4
+
5
+
6
+ # 实例化唯一的 MCP Server
7
+ mcp = FastMCP(MCP_SERVER_NAME)
@@ -0,0 +1,3 @@
1
+ from .general_prompts import query_table_overview, summarize_column, groupby_analysis, trend_analysis, outlier_analysis
2
+
3
+ __all__ = [query_table_overview, summarize_column, groupby_analysis, trend_analysis, outlier_analysis]
@@ -0,0 +1,9 @@
1
+ from doris_mcp_server.mcp_app import mcp
2
+
3
+ # 1. 自定义数据预处理提示
4
+ @mcp.prompt()
5
+ def customize_prompt() -> str:
6
+ """
7
+ 自定义提示
8
+ """
9
+ return None
@@ -0,0 +1,68 @@
1
+ from doris_mcp_server.mcp_app import mcp
2
+ from mcp.server.fastmcp.prompts import base
3
+
4
+
5
+
6
+ # 1. 简单表格查询模板
7
+ @mcp.prompt()
8
+ def query_table_overview(table_name: str) -> str:
9
+ """
10
+ 查看表格的结构和前几行数据
11
+ """
12
+ return (
13
+ f"请查询 `{table_name}` 表的结构信息,并展示前 10 行数据。"
14
+ f"\n确保格式清晰,使用表格展示内容。"
15
+ )
16
+
17
+ @mcp.prompt(name = "table_comment_overview", description = "查看表的注释信息")
18
+ def query_table_comment(table_name: str) -> str:
19
+ """
20
+ 查看表格的注释信息
21
+ """
22
+ return f"请查询 `{table_name}` 表的注释信息,这些信息用于描述表的用途。"
23
+
24
+ # 2. 汇总统计模板
25
+ @mcp.prompt()
26
+ def summarize_column(column: str, table: str) -> str:
27
+ """
28
+ 统计某列的常见汇总信息
29
+ """
30
+ return f"请统计 `{table}` 表中 `{column}` 列的最大值、最小值、平均值、标准差与总和。"
31
+
32
+
33
+ # 3. 分组聚合模板
34
+ @mcp.prompt()
35
+ def groupby_analysis(group_col: str, target_col: str, table: str) -> str:
36
+ """
37
+ 对某字段进行分组聚合分析
38
+ """
39
+ return (
40
+ f"请对 `{table}` 表按 `{group_col}` 分组,统计每组在 `{target_col}` 上的均值与总和,"
41
+ f"并按总和降序排序。"
42
+ )
43
+
44
+
45
+ # 4. 数据趋势分析模板(近7日、近30日)
46
+ @mcp.prompt()
47
+ def trend_analysis(date_col: str, metric_col: str, table: str, days: int = 7) -> str:
48
+ """
49
+ 绘制最近几天某指标的趋势
50
+ """
51
+ return (
52
+ f"请分析 `{table}` 表中最近 {days} 天的 `{metric_col}` 变化趋势,"
53
+ f"日期字段为 `{date_col}`。可视化建议使用折线图。"
54
+ )
55
+
56
+
57
+ # 5. 多轮对话模板:异常值分析
58
+ @mcp.prompt()
59
+ def outlier_analysis() -> list[base.Message]:
60
+ return [
61
+ base.UserMessage("我想分析某个表中的异常值"),
62
+ base.AssistantMessage("好的,请告诉我要分析哪个表,以及哪一列?"),
63
+ base.UserMessage("表是 user_metrics,列是 daily_usage"),
64
+ base.AssistantMessage(
65
+ "请稍等,我将检测 `user_metrics` 表中 `daily_usage` 列的异常值,"
66
+ "可能使用箱线图或 3σ 原则。"
67
+ ),
68
+ ]
@@ -0,0 +1,4 @@
1
+ from .resources import all_table_schemas
2
+ from .resources import table_schema
3
+
4
+ __all__ = [all_table_schemas, table_schema]
@@ -0,0 +1,116 @@
1
+ from doris_mcp_server.mcp_app import mcp
2
+ from doris_mcp_server.db import DorisConnector
3
+ from doris_mcp_server.config import DB_CONFIG
4
+ from typing import Optional
5
+
6
+ def _get_table_schemas(db_name: str) -> dict[str, str]:
7
+ """
8
+ 获取所有表的结构信息,返回一个字典:
9
+ {
10
+ "table_name": "字段名 | 类型 | 是否为空 ... \n ...",
11
+ ...
12
+ }
13
+ """
14
+ db = DorisConnector()
15
+ tables = db.list_tables(db_name)
16
+ result = {}
17
+
18
+ for table in tables:
19
+ try:
20
+ schema = db.get_table_schema(table)
21
+ if not schema:
22
+ continue
23
+
24
+ headers = ["Field", "Type", "Null", "Key", "Default", "Extra"]
25
+ lines = [" | ".join(headers)]
26
+ lines.append("-" * len(lines[0]))
27
+
28
+ for row in schema:
29
+ line = " | ".join(str(row.get(h, "")) for h in headers)
30
+ lines.append(line)
31
+
32
+ result[table] = "\n".join(lines)
33
+
34
+ except Exception as e:
35
+ result[table] = f"无法获取表结构: {str(e)}"
36
+
37
+ return result
38
+
39
+
40
+
41
+
42
+ def _get_table_comments(db_name: str) -> dict[str, str]:
43
+ """
44
+ 获取所有表的注释信息,返回一个字典:
45
+ {
46
+ "table_name": "表注释",
47
+ ...
48
+ }
49
+ """
50
+ db = DorisConnector()
51
+ sql = f"""
52
+ SELECT TABLE_NAME, TABLE_COMMENT
53
+ FROM information_schema.TABLES
54
+ WHERE TABLE_SCHEMA = '{db_name}'
55
+ """
56
+ try:
57
+ results = db.execute_query(sql)
58
+ return {row["TABLE_NAME"]: row["TABLE_COMMENT"] or "无注释" for row in results}
59
+ except Exception as e:
60
+ return {"error": f"无法获取表注释信息: {str(e)}"}
61
+
62
+
63
+
64
+
65
+ @mcp.resource("doris://schema/{db_name}")
66
+ def all_table_schemas(db_name: str = DB_CONFIG["database"]) -> str:
67
+ """
68
+ 返回指定数据库下所有表的结构。
69
+ """
70
+ schemas = _get_table_schemas(db_name)
71
+
72
+ content = []
73
+ for table_name, schema_text in schemas.items():
74
+ content.append(f"# 表: {table_name}\n{schema_text}\n")
75
+
76
+ return "\n\n".join(content)
77
+
78
+
79
+
80
+
81
+ @mcp.resource("doris://schema/{table}")
82
+ def table_schema(table: str) -> Optional[str]:
83
+ """
84
+ 返回单个表的字段结构信息。
85
+ """
86
+ db = DorisConnector()
87
+ try:
88
+ schema = db.get_table_schema(table)
89
+ if not schema:
90
+ return f"表 `{table}` 不存在或无结构信息。"
91
+
92
+ headers = ["Field", "Type", "Null", "Key", "Default", "Extra"]
93
+ lines = [" | ".join(headers)]
94
+ lines.append("-" * len(lines[0]))
95
+
96
+ for row in schema:
97
+ lines.append(" | ".join(str(row.get(h, "")) for h in headers))
98
+
99
+ return f"# 表: {table}\n" + "\n".join(lines)
100
+
101
+ except Exception as e:
102
+ return f"无法获取表 `{table}` 的结构信息: {str(e)}"
103
+
104
+
105
+
106
+
107
+ @mcp.resource("doris://table-comments/{db_name}")
108
+ def all_table_comments(db_name: str = DB_CONFIG["database"]) -> str:
109
+ """
110
+ 返回指定数据库下所有表的注释信息。
111
+ """
112
+ comments = _get_table_comments(db_name)
113
+ content = []
114
+ for table_name, comment in comments.items():
115
+ content.append(f"- {table_name}: {comment}")
116
+ return "\n".join(content)
@@ -0,0 +1,50 @@
1
+ from doris_mcp_server.mcp_app import mcp
2
+ from doris_mcp_server.db import tools, DorisConnector
3
+ from doris_mcp_server.res import resources
4
+ from doris_mcp_server.prompts import general_prompts, customize_prompts
5
+ import traceback
6
+
7
+
8
+ class MCPDorisServer:
9
+
10
+ def __init__(self):
11
+ self.server = mcp
12
+
13
+
14
+ def _test_db_connection(self):
15
+ """
16
+ 测试数据库连接是否成功。
17
+ """
18
+ try:
19
+ conn = DorisConnector()
20
+ result = conn.execute_query("SELECT 1")
21
+ if result:
22
+ print("✅ Database connection successful.")
23
+ else:
24
+ raise Exception("Database connection test failed: please config .env file.")
25
+ conn.close()
26
+ except Exception as e:
27
+ print("❌ Database connection test failed.")
28
+ raise e
29
+
30
+
31
+ def run(self):
32
+ """
33
+ 启动 MCP Server
34
+ """
35
+ try:
36
+ print("🚀 Doris MCP Server is starting...")
37
+ self._test_db_connection()
38
+ self.server.run()
39
+ except Exception as e:
40
+ print("🚨 Doris MCP Server failed to start.")
41
+ print(f"Error: {e}")
42
+ traceback.print_exc()
43
+
44
+
45
+ def main():
46
+ app = MCPDorisServer()
47
+ app.run()
48
+
49
+ if __name__ == "__main__":
50
+ main()
@@ -0,0 +1,81 @@
1
+ import asyncio
2
+ import argparse
3
+ import json
4
+ from mcp import ClientSession
5
+ from mcp.client.stdio import stdio_client
6
+ from mcp import StdioServerParameters
7
+
8
+ async def test_resources(session: ClientSession):
9
+ print("== 列出所有资源 ==")
10
+ resources = await session.list_resources()
11
+ for res in resources.resources:
12
+ print(f"- {res.uri} ({res.name})")
13
+
14
+ if resources.resources:
15
+ print("\n== 读取第一个资源 ==")
16
+ uri = resources.resources[0].uri
17
+ content, mime_type = await session.read_resource(uri)
18
+ print(f"内容类型: {mime_type}\n内容预览:\n{content[:500]}...")
19
+
20
+ async def test_tools(session: ClientSession):
21
+ print("== 列出所有工具 ==")
22
+ tools = await session.list_tools()
23
+ for tool in tools.tools:
24
+ print(f"- {tool.name}: {tool.description}")
25
+
26
+ if tools.tools:
27
+ tool = tools.tools[0]
28
+ print(f"\n== 调用第一个工具:{tool.name} ==")
29
+
30
+ # 构造默认的空参数,如果需要可以在这里根据schema生成
31
+ args = {}
32
+ for key, schema in tool.inputSchema.get("properties", {}).items():
33
+ if schema.get("type") == "string":
34
+ args[key] = "test"
35
+ elif schema.get("type") == "integer":
36
+ args[key] = 1
37
+ elif schema.get("type") == "number":
38
+ args[key] = 1.0
39
+ elif schema.get("type") == "boolean":
40
+ args[key] = True
41
+ else:
42
+ args[key] = None
43
+
44
+ print(f"调用参数: {json.dumps(args)}")
45
+ result = await session.call_tool(tool.name, arguments=args)
46
+ print(f"返回结果: {result}")
47
+
48
+ async def test_prompts(session: ClientSession):
49
+ print("== 列出所有提示词 (prompts) ==")
50
+ prompts = await session.list_prompts()
51
+ for prompt in prompts.prompts:
52
+ print(f"- {prompt.name}: {prompt.description}")
53
+
54
+ if prompts.prompts:
55
+ prompt = prompts.prompts[0]
56
+ print(f"\n== 获取第一个提示词:{prompt.name} ==")
57
+ response = await session.get_prompt(prompt.name, arguments={})
58
+ print("提示词返回内容:")
59
+ print(response)
60
+
61
+ async def main():
62
+ parser = argparse.ArgumentParser(description="MCP Server 测试工具")
63
+ parser.add_argument("--server", type=str, required=True, help="Server 启动脚本路径,例如 server.py")
64
+ parser.add_argument("--test", type=str, required=True, choices=["resources", "tools", "prompts", "all"], help="要测试的功能")
65
+ args = parser.parse_args()
66
+
67
+ # 连接到 MCP Server
68
+ server_params = StdioServerParameters(command="python", args=[args.server])
69
+ async with stdio_client(server_params) as (read_stream, write_stream):
70
+ async with ClientSession(read_stream, write_stream) as session:
71
+ await session.initialize()
72
+
73
+ if args.test in ["resources", "all"]:
74
+ await test_resources(session)
75
+ if args.test in ["tools", "all"]:
76
+ await test_tools(session)
77
+ if args.test in ["prompts", "all"]:
78
+ await test_prompts(session)
79
+
80
+ if __name__ == "__main__":
81
+ asyncio.run(main())
@@ -0,0 +1,336 @@
1
+ Metadata-Version: 2.4
2
+ Name: doris-mcp-server
3
+ Version: 0.0.1
4
+ Summary: An MCP server for analytics on Apache Doris database.
5
+ Project-URL: Homepage, https://github.com/NomotoK/doris-mcp-server
6
+ Project-URL: Repository, https://github.com/NomotoK/doris-mcp-server
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: httpx>=0.28.1
11
+ Requires-Dist: mcp[cli]>=1.6.0
12
+ Requires-Dist: pandas>=2.2.3
13
+ Requires-Dist: pyarrow>=19.0.1
14
+ Requires-Dist: pymysql>=1.1.1
15
+ Dynamic: license-file
16
+
17
+ # **📖 Doris-MCP-Server**
18
+
19
+ A lightweight **MCP server** designed for connecting to **Apache Doris** or other **MySQL compatible** database schemas, providing tools and prompts for LLM applications.
20
+
21
+ This server enables LLMs and MCP clients to explore database schemas, run read-only SQL queries, and leverage pre-built analytical prompts — all through a standardized, secure MCP interface.
22
+
23
+ > [!WARNING]
24
+ > This is an early developer version of doris-mcp-server. Some functions may not operate properly and minor bugs may exist. If you have any quesions, please open an [issue](https://github.com/NomotoK/Doris-MCP-Server/issues).
25
+
26
+ ## **🚀 Features**
27
+
28
+ ### **🛠️ Tools**
29
+
30
+ - Execute **read-only SQL queries** against your Doris database.
31
+ - Perform **data analysis operations** such as retrieving yearly, monthly, and daily usage data.
32
+ - Query metadata such as **database schemas**, **table structures**, and **resource usage**.
33
+
34
+ ### **🧠 Prompts**
35
+
36
+ - Built-in prompt templates to assist LLMs in asking **analytics questions**.
37
+ - Support for **user-defined** and **general-purpose** SQL analysis prompts.
38
+
39
+ ### **🗂️ Resources**
40
+
41
+ - Expose your Doris **database schema** as **structured resources**.
42
+ - Allow LLMs to **contextually access** table and field definitions to improve query understanding.
43
+
44
+ ## **📦 Installation Options**
45
+
46
+ We recommend using [uv](https://docs.astral.sh/uv/) to manage your Python environment.
47
+
48
+ ### **Option 1: Install via shell script**
49
+
50
+ > **Recommended for server deployment**
51
+
52
+ This is the easiest way to install. Please copy the `setup.sh` file in project and run it locally. For more information please refer: [Doris MCP install guide](INSTALL.md)
53
+
54
+ 1. Copy the `setup.sh` to local.
55
+ 2. Make the script executable:
56
+
57
+ ```bash
58
+ chmod +x setup.sh
59
+ ```
60
+
61
+ 3. Run the script:
62
+
63
+ ```bash
64
+ ./setup.sh
65
+ ```
66
+
67
+ The script will automatically install the server and help you walk through database configuration.
68
+ ### **Option 2: Install via `pip`**
69
+
70
+ > **Recommended for production usage**
71
+
72
+ ```bash
73
+ pip install doris-mcp-server
74
+ ```
75
+
76
+ ✅ After installation, the command-line tool server will be available to launch the MCP server.
77
+
78
+ ### **Option 3: Clone the source and install manually**
79
+
80
+ > **Recommended if you want to modify the server**
81
+
82
+ 1. Fork and clone the repository:
83
+
84
+ ```bash
85
+ git clone https://github.com/YOUR_USERNAME/doris-mcp-server.git
86
+ cd doris-mcp-server
87
+ ```
88
+
89
+ 1. Set up a local Python environment using [uv](https://github.com/astral-sh/uv):
90
+
91
+ ```bash
92
+ uv venv
93
+ uv pip install -e .
94
+ ```
95
+
96
+ 1. Add this server to your LLM client or Run the server:
97
+
98
+ ```bash
99
+ uv run server
100
+ ```
101
+
102
+ ### **Option 4: Install using uv directly**
103
+
104
+ > **For local editable installations**
105
+
106
+ ```bash
107
+ uv pip install 'git+https://github.com/YOUR_USERNAME/doris-mcp-server.git'
108
+ ```
109
+
110
+ ## **⚙️ Post-Installation Setup**
111
+
112
+ ### **Step 1: Configure `.env` file**
113
+
114
+ Doris-MCP-Server uses .env file to configure database connection info. Please follow these steps to finish configuration:
115
+
116
+ #### **Configure through shell script**
117
+
118
+ This is the most recommended and easiest way to setup. Please refer to [Doris MCP install guide](INSTALL.md).
119
+
120
+ #### **Configure manually**
121
+
122
+ After installing, navigate to the `doris_mcp_server/config/` directory inside your project directory. If you are using pip, your package will be installed in Python site-packages:
123
+
124
+ - **Mac/Linux:** `/Users/YOUR_USERNAME/.local/lib/python3.x/site-packages/doris_mcp_server/config/`
125
+
126
+ - **Windows:** `C:\Users\YOUR_USERNAME\AppData\Local\Programs\Python\Python3x\Lib\site-packages\doris_mcp_server\config\`
127
+
128
+ You can run the following command to locate pip install location:
129
+
130
+ ```bash
131
+ pip show doris-mcp-server
132
+ ```
133
+
134
+ You will find a `.env.example` file:
135
+
136
+ 1. Copy `.env.example` to `.env`:
137
+
138
+ ```bash
139
+ cp .env.example .env
140
+ ```
141
+
142
+ 2. Edit .env to set your **Doris** database connection information:
143
+
144
+ ```bash
145
+ DB_HOST=your-doris-host
146
+ DB_PORT=9030
147
+ DB_USER=your-username
148
+ DB_PASSWORD=your-password
149
+ DB_NAME=your-database
150
+
151
+ MCP_SERVER_NAME=DorisAnalytics
152
+ DEBUG=false
153
+ ```
154
+
155
+ > [!NOTE]
156
+ > If `.env `is missing, the server will attempt to auto-create it from `.env.example` but you must manually fill in correct credentials.
157
+
158
+ ### **Step 2: Configure MCP Client**
159
+
160
+ To connect this server to an MCP-compatible client (e.g., Claude Desktop, CherryStudio, Cline), you need to modify your MCP client configuration JSON.
161
+
162
+ Example if you are using CherryStudio:
163
+
164
+ - name: doris-mcp-server
165
+ - type: stdio
166
+ - command: absolute/path/to/your/uv
167
+ - arguments:
168
+
169
+ ```bash
170
+ --directory
171
+ /Users/hailin/dev/Doris-MCP-Server
172
+ run
173
+ server
174
+ ```
175
+
176
+
177
+ Example if you are installing with pip (`mcp_setting.json`):
178
+
179
+ ```json
180
+ {
181
+ "mcpServers": {
182
+ "DorisAnalytics": {
183
+ "command": "server",
184
+ "args": [],
185
+ "transportType": "stdio"
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ Alternatively, if you prefer a more robust form:
192
+
193
+ ```json
194
+ {
195
+ "mcpServers": {
196
+ "DorisAnalytics": {
197
+ "command": "python",
198
+ "args": ["-m", "doris_mcp_server.server"],
199
+ "transportType": "stdio"
200
+ }
201
+ }
202
+ }
203
+ ```
204
+
205
+ If you are installing with source code or using `setup.sh`:
206
+
207
+ ```json
208
+ {
209
+ "mcpServers": {
210
+ "DorisAnalytics": {
211
+ "disabled": false,
212
+ "timeout": 60,
213
+ "command": "absolute/path/to/uv",
214
+ "args": [
215
+ "--directory",
216
+ "absolute/path/to/mcp/server",
217
+ "run",
218
+ "server"
219
+ ],
220
+ "transportType": "stdio"
221
+ }
222
+ }
223
+
224
+ }
225
+ ```
226
+
227
+ For more information on how to configure your client, please refer to :
228
+
229
+ [For Server Developers - Model Context Protocol - Claude](https://modelcontextprotocol.io/quickstart/server)
230
+
231
+
232
+ [配置和使用 MCP | CherryStudio](https://docs.cherry-ai.com/advanced-basic/mcp/config)
233
+
234
+ ✅ Now your LLM client will discover Doris Analytics tools, prompts, and resources through the MCP server.
235
+
236
+ ---
237
+
238
+ ## **🖥️ Usage**
239
+
240
+ ### **Testing MCP server**
241
+
242
+ Before you start, you can run the `test.py` in the project `src/doris-mcp-server` directory to directly call the MCP Server functional interface to test resources, tools, etc. without using LLM (such as Claude, GPT, etc. models). You can control what functions to test by passing arguments through the command line.
243
+
244
+ Test all resources exposed by the server:
245
+
246
+ ```bash
247
+ python test.py --server server.py --test resources
248
+ ```
249
+
250
+ or test all the tools provided by the server:
251
+
252
+ ```bash
253
+ python test.py --server server.py --test tools
254
+ ```
255
+
256
+ or test all functions of resources, tools, and prompt words at one time:
257
+
258
+ ```bash
259
+ python test.py --server server.py --test all
260
+ ```
261
+
262
+ ### **Testing Database connection and run server**
263
+
264
+ Launch the MCP server by running the command:
265
+
266
+ ```bash
267
+ server
268
+ ```
269
+
270
+ Or manually:
271
+
272
+ ```bash
273
+ python -m doris_mcp_server.server
274
+ ```
275
+
276
+ The server immediately attempts to connect to the database. If the connection is successful, after startup, you should see:
277
+
278
+ ```bash
279
+ 🚀 Doris MCP Server is starting...
280
+ [DorisConnector] Connected to 127.0.0.1:9030
281
+ ✅ Database connection successful.
282
+ [DorisConnector] Connection closed.
283
+ ```
284
+
285
+ You can now use the tools and prompts inside your MCP client.
286
+
287
+ ## **📚 Project Structure Overview**
288
+
289
+ ```bash
290
+ src/
291
+ └── doris_mcp_server/
292
+ ├── config/ # Configuration files
293
+ │ ├── __init__.py
294
+ │ ├── config.py # Loads environment variables
295
+ │ ├── .env.example # Environment variables template
296
+ │ └── .env # Stores your database credentials
297
+
298
+ ├── db/ # Database interaction logic
299
+ │ ├── __init__.py
300
+ │ ├── db.py # Doris database connection class
301
+ │ └── tools.py # SQL query execution tools
302
+
303
+ ├── res/ # Resource definitions (e.g., schemas)
304
+ │ ├── __init__.py
305
+ │ └── resources.py
306
+
307
+ ├── prompts/ # Prebuilt prompt templates
308
+ │ ├── __init__.py
309
+ │ ├── general_prompts.py
310
+ │ └── customize_prompts.py
311
+
312
+ ├── server.py # Main entry point to start the MCP server
313
+ ├── mcp_app.py # MCP object
314
+ └── test.py # Unit test script
315
+ README.md # Documentation
316
+ INSTALL.md # Installation guide
317
+ LISENCE # Lisence
318
+ setup.sh # Auto setup wizard
319
+ pyproject.toml # Project build configuration
320
+ .gitignore # Git ignore settings
321
+ ```
322
+
323
+ ## **📜 License**
324
+
325
+ This project is licensed under the [MIT License](LICENSE).
326
+
327
+ ## **🌟Acknowledgements**
328
+
329
+ - Built using the [MCP Python SDK](https://pypi.org/project/mcp/).
330
+ - Inspired by MCP official examples and best practices.
331
+
332
+ ---
333
+
334
+ ## **🤝 Contributions**
335
+
336
+ Contributions are welcome! Feel free to open issues or submit pull requests.
@@ -0,0 +1,19 @@
1
+ doris_mcp_server/mcp_app.py,sha256=foC-XmqvnvQAkr907NKR2XUfI24h2YXga12j-Tsyn1g,169
2
+ doris_mcp_server/server.py,sha256=cC1ZzmAAFQ9CUxyzCkgorb06gSSclfswGbG67XYYIuc,1301
3
+ doris_mcp_server/test.py,sha256=hFF3pAm90qyL4NwopL32VUJvveB0XEYrxcVh00FA8HQ,3154
4
+ doris_mcp_server/config/__init__.py,sha256=J374zeXcbI6HL_uRiXeEfCYRDfAL_tAGCoVowl2yjDg,106
5
+ doris_mcp_server/config/config.py,sha256=7z_gBIVxlJJP9AdA2kj8e8ri0BmBb9dsv4MzXCUxmlY,1270
6
+ doris_mcp_server/db/__init__.py,sha256=ZxL_6uwaeh4fk3U_WQjHByqNXsOD3XMaEKgGT2jyf2k,207
7
+ doris_mcp_server/db/db.py,sha256=-aFcas-DOb14WwaOVXcDM47SGwPGS2M0o25Eg1RQCY4,1875
8
+ doris_mcp_server/db/tools.py,sha256=BPRbFCjeqvf36REJjgOKJVCqJ12XrkGBzkL59CzRp5Q,2539
9
+ doris_mcp_server/prompts/__init__.py,sha256=e_7tmLCopR6D64s_6Jq8te_IZzMbrT_RnIokdKuHjdQ,223
10
+ doris_mcp_server/prompts/customize_prompts.py,sha256=W6Y4DZuIimV57YK_5wg5hN8d60S7IuH7gOqrADA_pVY,174
11
+ doris_mcp_server/prompts/general_prompts.py,sha256=piMc4mO20g6UBIFtIZIM4y6tMfd4mxDEGa4_gN09rpA,2240
12
+ doris_mcp_server/res/__init__.py,sha256=U4NpXKN4pvCg0l3Wq9419ILQSQrIci0UQk4uz75dSGo,121
13
+ doris_mcp_server/res/resources.py,sha256=Te3clplmUj4_fGt2YHzFurpPltBCduf3Ti69zs6zGg8,3168
14
+ doris_mcp_server-0.0.1.dist-info/licenses/LICENSE,sha256=-I3M16s57QqzUxQs9Ai0nXVmDv9q6STMtca5uJNRN44,1067
15
+ doris_mcp_server-0.0.1.dist-info/METADATA,sha256=lTWVg5vlf8nQeipzF6i9aXiP9GGAWEquRP2CkEPuNjw,9140
16
+ doris_mcp_server-0.0.1.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
17
+ doris_mcp_server-0.0.1.dist-info/entry_points.txt,sha256=i6FD1xPvTFUklYP1i5EhiL6Xj6yGykpXmCnvmA-YDJQ,56
18
+ doris_mcp_server-0.0.1.dist-info/top_level.txt,sha256=dB0Q4-0nUE-o5baiKfwFXE4pVR4q0vDsdGc9XQh2YrE,17
19
+ doris_mcp_server-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ server = doris_mcp_server.server:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hailin Xie
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.
@@ -0,0 +1 @@
1
+ doris_mcp_server