adbpg-mcp-server 1.0.7__py3-none-any.whl → 2.0.0__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,201 @@
1
+ import json
2
+ import logging
3
+ from mcp.types import Tool, TextContent
4
+ from .adbpg import DatabaseManager
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ def get_memory_tools() -> list[Tool]:
9
+ return [
10
+ Tool(
11
+ name = "adbpg_llm_memory_add",
12
+ description = "Execute llm_memory add operation",
13
+ # 参数:messages json, user_id text, run_id text, agent_id text, metadata json
14
+ # 增加新的记忆
15
+ inputSchema={
16
+ "type": "object",
17
+ "properties": {
18
+ "messages": {
19
+ "type": "array",
20
+ "items": {
21
+ "type": "object",
22
+ "properties": {
23
+ "role": {"type": "string"},
24
+ "content": {"type": "string"}
25
+ },
26
+ "required": ["role", "content"]
27
+ },
28
+ "description": "List of messages objects (e.g., conversation history)"
29
+ },
30
+ "user_id": {
31
+ "type": "string",
32
+ "description": "the user_id"
33
+ },
34
+ "run_id": {
35
+ "type": "string",
36
+ "description": "the run_id"
37
+ },
38
+ "agent_id": {
39
+ "type": "string",
40
+ "description": "the agent_id"
41
+ },
42
+ "metadata": {
43
+ "type": "object",
44
+ "description": "the metatdata json"
45
+ },
46
+ "memory_type": {
47
+ "type": "string",
48
+ "description": "the memory_type text"
49
+ },
50
+ "prompt": {
51
+ "type": "string",
52
+ "description": "the prompt"
53
+ }
54
+ },
55
+ "required": ["messages"]
56
+ }
57
+ ),
58
+ Tool(
59
+ name = "adbpg_llm_memory_get_all",
60
+ description = "Execute llm_memory get_all operation",
61
+ # 参数:user_id text, run_id text, agent_id text
62
+ # 获取某个用户或者某个agent的所有记忆
63
+ inputSchema={
64
+ "type": "object",
65
+ "properties": {
66
+ "user_id": {
67
+ "type": "string",
68
+ "description": "The user_id"
69
+ },
70
+ "run_id": {
71
+ "type": "string",
72
+ "description": "The run_id"
73
+ },
74
+ "agent_id": {
75
+ "type": "string",
76
+ "description": "The agent_id"
77
+ }
78
+ },
79
+ "required": []
80
+ }
81
+ ),
82
+ Tool(
83
+ name = "adbpg_llm_memory_search",
84
+ description = "Execute llm_memory search operation",
85
+ # 参数:query text, user_id text, run_id text, agent_id text, filter json
86
+ # 获取与给定 query 相关的记忆
87
+ inputSchema={
88
+ "type": "object",
89
+ "properties": {
90
+ "query": {
91
+ "type": "string",
92
+ "description": "llm_memory relevant query"
93
+ },
94
+ "user_id": {
95
+ "type": "string",
96
+ "description": "The search of user_id"
97
+ },
98
+ "run_id": {
99
+ "type": "string",
100
+ "description": "The search of run_id"
101
+ },
102
+ "agent_id": {
103
+ "type": "string",
104
+ "description": "The search of agent_id"
105
+ },
106
+ "filter": {
107
+ "type": "object",
108
+ "description": "The search of filter"
109
+ }
110
+ },
111
+ "required": ["query"]
112
+ }
113
+ ),
114
+ Tool(
115
+ name = "adbpg_llm_memory_delete_all",
116
+ description = "Execute llm_memory delete_all operation",
117
+ # 参数:user_id text, run_id text, agent_id text
118
+ # 删除某个用户或者agent的所有记忆
119
+ inputSchema={
120
+ "type": "object",
121
+ "properties": {
122
+ "user_id": {
123
+ "type": "string",
124
+ "description": "The user_id"
125
+ },
126
+ "run_id": {
127
+ "type": "string",
128
+ "description": "The run_id"
129
+ },
130
+ "agent_id": {
131
+ "type": "string",
132
+ "description": "The agent_id"
133
+ }
134
+ },
135
+ "required": []
136
+ }
137
+ )
138
+ ]
139
+
140
+ def _execute_memory_tool(sql: str, params: list, db: DatabaseManager) -> list[TextContent]:
141
+ try:
142
+ conn = db.get_llm_memory_connection()
143
+ with conn.cursor() as cursor:
144
+ cursor.execute(sql, params)
145
+ if cursor.description:
146
+ json_result = cursor.fetchone()[0]
147
+ return [TextContent(type="text", text=json_result)]
148
+ else:
149
+ return [TextContent(type="text", text="LLM memory tool executed successfully.")]
150
+ except Exception as e:
151
+ return [TextContent(type="text", text=f"Error executing LLM memory tool: {str(e)}")]
152
+
153
+
154
+ async def call_memory_tool(name: str, arguments: dict, db: DatabaseManager) -> list[TextContent]:
155
+ """调用 LLM Memory 工具"""
156
+ user_id = arguments.get("user_id")
157
+ run_id = arguments.get("run_id")
158
+ agent_id = arguments.get("agent_id")
159
+
160
+ if name == "adbpg_llm_memory_add":
161
+ messages = arguments.get("messages")
162
+ if not messages:
163
+ raise ValueError("messages is required")
164
+ if not any([user_id, run_id, agent_id]):
165
+ raise ValueError("At least one of user_id, run_id, or agent_id must be provided.")
166
+ sql = "SELECT adbpg_llm_memory.add(%s::json, %s::text, %s::text, %s::text, %s::json, %s::text, %s::text)"
167
+ params = [
168
+ json.dumps(messages, ensure_ascii=False),
169
+ user_id, run_id, agent_id,
170
+ json.dumps(arguments.get("metadata"),ensure_ascii=False) if arguments.get("metadata") else None,
171
+ arguments.get("memory_type"),
172
+ arguments.get("prompt")
173
+ ]
174
+
175
+ elif name == "adbpg_llm_memory_search":
176
+ query = arguments.get("query")
177
+ if not query:
178
+ raise ValueError("query is required")
179
+ if not any([user_id, run_id, agent_id]):
180
+ raise ValueError("At least one of user_id, run_id, or agent_id must be provided.")
181
+ sql = "SELECT adbpg_llm_memory.search(%s::text, %s::text, %s::text, %s::text, %s::json)"
182
+ params = [
183
+ query, user_id, run_id, agent_id,
184
+ json.dumps(arguments.get("filter"), ensure_ascii=False) if arguments.get("filter") else None
185
+ ]
186
+
187
+ elif name == "adbpg_llm_memory_get_all":
188
+ if not any([user_id, run_id, agent_id]):
189
+ raise ValueError("At least one of user_id, run_id, or agent_id must be provided.")
190
+ sql = "SELECT adbpg_llm_memory.get_all(%s::text, %s::text, %s::text)"
191
+ params = [user_id, run_id, agent_id]
192
+
193
+ elif name == "adbpg_llm_memory_delete_all":
194
+ if not any([user_id, run_id, agent_id]):
195
+ raise ValueError("At least one of user_id, run_id, or agent_id must be provided.")
196
+ sql = "SELECT adbpg_llm_memory.delete_all(%s::text, %s::text, %s::text)"
197
+ params = [user_id, run_id, agent_id]
198
+ else:
199
+ raise ValueError(f"Unknown memory tool: {name}")
200
+
201
+ return _execute_memory_tool(sql, params, db)
@@ -0,0 +1,206 @@
1
+ import requests
2
+ import logging
3
+ import json
4
+ import click
5
+ import contextlib
6
+ import uvicorn
7
+ import sys
8
+ import mcp.types as types
9
+ from pydantic import AnyUrl
10
+ from collections.abc import AsyncIterator
11
+ from mcp.server.lowlevel import Server
12
+ from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
13
+ from mcp.types import Resource, Tool, TextContent, ResourceTemplate
14
+ from starlette.applications import Starlette
15
+ from starlette.routing import Mount
16
+ from .adbpg import DatabaseManager
17
+ from . import adbpg_basic_operation, adbpg_graphrag, adbpg_memory
18
+ from .adbpg_config import settings
19
+
20
+
21
+ db_manager: DatabaseManager | None = None
22
+ graphrag_is_available = False
23
+ llm_memory_is_available = False
24
+
25
+ logging.basicConfig(
26
+ level=logging.DEBUG,
27
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
28
+ )
29
+ logger = logging.getLogger("ADBPG MCP Server")
30
+
31
+ def initialize_services():
32
+ """初始化数据库、GraphRAG 和 LLM Memory"""
33
+ global db_manager, graphrag_is_available, llm_memory_is_available
34
+
35
+ if not settings.db_env_ready:
36
+ logger.error("Cannot start server: Database environment is not configured.")
37
+ sys.exit(1)
38
+
39
+ db_manager = DatabaseManager(settings)
40
+
41
+ # 测试主连接
42
+ try:
43
+ db_manager.get_basic_connection()
44
+ logger.info("Successfully connected to database.")
45
+ except Exception as e:
46
+ logger.error(f"Failed to connect to database: {e}")
47
+ sys.exit(1)
48
+
49
+ # 初始化 GraphRAG
50
+ if settings.graphrag_env_ready:
51
+ try:
52
+ db_manager.get_graphrag_connection()
53
+ graphrag_is_available = True
54
+ logger.info("GraphRAG initialized successfully.")
55
+ except Exception as e:
56
+ logger.error(f"Failed to initialize GraphRAG: {e}")
57
+ graphrag_is_available = False
58
+
59
+ # 初始化 LLM Memory
60
+ if settings.memory_env_ready:
61
+ try:
62
+ db_manager.get_llm_memory_connection()
63
+ llm_memory_is_available = True
64
+ logger.info("LLM Memory initialized successfully.")
65
+ except Exception as e:
66
+ logger.error(f"Failed to initialize LLM Memory: {e}")
67
+ llm_memory_is_available = False
68
+
69
+
70
+
71
+ def run_http_server(host, port):
72
+
73
+ # 创建MCP服务端
74
+ app = Server("adbpg-mcp-server")
75
+ initialize_services()
76
+ @app.list_resources()
77
+ async def list_resources() -> list[Resource]:
78
+ """列出可用的基本资源"""
79
+ return await adbpg_basic_operation.list_resources()
80
+
81
+ @app.list_resource_templates()
82
+ async def list_resource_templates() -> list[ResourceTemplate]:
83
+ """
84
+ 定义动态资源模板
85
+
86
+ 返回:
87
+ list[ResourceTemplate]: 资源模板列表
88
+ 包含以下模板:
89
+ - 列出schema中的表
90
+ - 获取表DDL
91
+ - 获取表统计信息
92
+ """
93
+ return await adbpg_basic_operation.list_resource_templates()
94
+
95
+ @app.read_resource()
96
+ async def read_resource(uri: AnyUrl) -> str:
97
+ """
98
+ 读取资源内容
99
+
100
+ 参数:
101
+ uri (AnyUrl): 资源URI
102
+
103
+ 返回:
104
+ str: 资源内容
105
+
106
+ 支持的URI格式:
107
+ - adbpg:///schemas: 列出所有schema
108
+ - adbpg:///{schema}/tables: 列出指定schema中的表
109
+ - adbpg:///{schema}/{table}/ddl: 获取表的DDL
110
+ - adbpg:///{schema}/{table}/statistics: 获取表的统计信息
111
+ """
112
+ if not db_manager:
113
+ raise Exception("Database connection not established")
114
+ return await adbpg_basic_operation.read_resource(uri, db_manager)
115
+
116
+ # 工具调用
117
+ @app.call_tool()
118
+ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
119
+ """
120
+ 执行工具操作
121
+
122
+ 参数:
123
+ name (str): 工具名称
124
+ arguments (dict): 工具参数
125
+
126
+ 返回:
127
+ list[TextContent]: 执行结果
128
+ """
129
+ if not db_manager:
130
+ raise Exception("Database manager not initialized")
131
+
132
+ try:
133
+ # 分发到 Basic Operation
134
+ if name in [t.name for t in adbpg_basic_operation.get_basic_tools()]:
135
+ query, params, needs_json_agg = await adbpg_basic_operation.call_basic_tool(name, arguments, db_manager)
136
+ conn = db_manager.get_basic_connection()
137
+ with conn.cursor() as cursor:
138
+ cursor.execute(query, params)
139
+ if needs_json_agg:
140
+ json_result = cursor.fetchone()[0]
141
+ return [TextContent(type="text", text=json.dumps(json_result, ensure_ascii=False, indent=2))]
142
+ else:
143
+ return [TextContent(type="text", text="Tool executed successfully.")]
144
+
145
+ # 分发到 GraphRAG
146
+ elif name in [t.name for t in adbpg_graphrag.get_graphrag_tools()]:
147
+ if not graphrag_is_available:
148
+ raise ValueError("GraphRAG tool is not available due to configuration or initialization errors.")
149
+ return await adbpg_graphrag.call_graphrag_tool(name, arguments, db_manager)
150
+
151
+ # 分发到 LLM Memory
152
+ elif name in [t.name for t in adbpg_memory.get_memory_tools()]:
153
+ if not llm_memory_is_available:
154
+ raise ValueError("LLM Memory tool is not available due to configuration or initialization errors.")
155
+ return await adbpg_memory.call_memory_tool(name, arguments, db_manager)
156
+
157
+ else:
158
+ raise ValueError(f"Unknown tool: {name}")
159
+
160
+ except Exception as e:
161
+ logger.error(f"Error calling tool '{name}': {e}", exc_info=True)
162
+ return [TextContent(type="text", text=f"Error executing tool '{name}': {str(e)}")]
163
+
164
+ # 工具列表
165
+ @app.list_tools()
166
+ async def list_tools() -> list[Tool]:
167
+ """
168
+ 列出可用的工具
169
+ """
170
+ tools = adbpg_basic_operation.get_basic_tools()
171
+
172
+ if graphrag_is_available:
173
+ tools.extend(adbpg_graphrag.get_graphrag_tools())
174
+ if llm_memory_is_available:
175
+ tools.extend(adbpg_memory.get_memory_tools())
176
+ return tools
177
+
178
+ #----------管理请求会话--------------
179
+ session_manager = StreamableHTTPSessionManager(
180
+ app=app,
181
+ event_store=None, #无状态,不保存历史事件
182
+ stateless=True
183
+ )
184
+ async def handle_streamable_http(scope, receive, send):
185
+ await session_manager.handle_request(scope, receive, send)
186
+
187
+ @contextlib.asynccontextmanager
188
+ async def lifespan(app):
189
+ async with session_manager.run():
190
+ logger.info("ADBPG MCP Server Started! ")
191
+ try:
192
+ yield
193
+ finally:
194
+ logger.info("ADBPG MCP Server shutting down…")
195
+
196
+ # 将MCP服务挂载到/mcp路径上,用户访问整个路径时,就会进入刚才创建的MCP HTTP会话管理器
197
+ starlette_app = Starlette(
198
+ debug=False,
199
+ routes=[Mount("/mcp", app=handle_streamable_http)],
200
+ lifespan=lifespan,
201
+ )
202
+
203
+ # 利用uvicorn启动ASGI服务器并监听指定端口
204
+ uvicorn.run(starlette_app, host=host, port=port)
205
+
206
+ return 0
@@ -0,0 +1,216 @@
1
+ import asyncio
2
+ import logging
3
+ import os
4
+ import sys
5
+ import json
6
+ import psycopg
7
+ import re
8
+ import ast
9
+ from psycopg import OperationalError as Error
10
+ from psycopg import Connection
11
+ from mcp.server import Server
12
+ from mcp.types import Resource, Tool, TextContent, ResourceTemplate
13
+ from pydantic import AnyUrl
14
+ from dotenv import load_dotenv
15
+ from mcp.server.stdio import stdio_server
16
+
17
+ # 配置日志,输出到标准错误
18
+ logging.basicConfig(
19
+ level=logging.DEBUG,
20
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
21
+ stream=sys.stderr
22
+ )
23
+ logger = logging.getLogger("adbpg-mcp-server")
24
+
25
+ SERVER_VERSION = "0.2.0"
26
+
27
+ from .adbpg_config import settings
28
+ from .adbpg import DatabaseManager
29
+ from . import adbpg_basic_operation, adbpg_graphrag, adbpg_memory
30
+
31
+
32
+ # 初始化服务器
33
+ try:
34
+ app = Server("adbpg-mcp-server")
35
+ logger.info("MCP server initialized")
36
+ except Exception as e:
37
+ logger.error(f"Error initializing MCP server: {e}")
38
+ sys.exit(1)
39
+ db_manager: DatabaseManager | None = None
40
+ graphrag_is_available = False
41
+ llm_memory_is_available = False
42
+
43
+ @app.list_resources()
44
+ async def list_resources() -> list[Resource]:
45
+ """列出可用的基本资源"""
46
+ return await adbpg_basic_operation.list_resources()
47
+
48
+ @app.list_resource_templates()
49
+ async def list_resource_templates() -> list[ResourceTemplate]:
50
+ """
51
+ 定义动态资源模板
52
+
53
+ 返回:
54
+ list[ResourceTemplate]: 资源模板列表
55
+ 包含以下模板:
56
+ - 列出schema中的表
57
+ - 获取表DDL
58
+ - 获取表统计信息
59
+ """
60
+ return await adbpg_basic_operation.list_resource_templates()
61
+
62
+
63
+ @app.read_resource()
64
+ async def read_resource(uri: AnyUrl) -> str:
65
+ """
66
+ 读取资源内容
67
+
68
+ 参数:
69
+ uri (AnyUrl): 资源URI
70
+
71
+ 返回:
72
+ str: 资源内容
73
+
74
+ 支持的URI格式:
75
+ - adbpg:///schemas: 列出所有schema
76
+ - adbpg:///{schema}/tables: 列出指定schema中的表
77
+ - adbpg:///{schema}/{table}/ddl: 获取表的DDL
78
+ - adbpg:///{schema}/{table}/statistics: 获取表的统计信息
79
+ """
80
+ if not db_manager:
81
+ raise Exception("Database connection not established")
82
+ return await adbpg_basic_operation.read_resource(uri, db_manager)
83
+
84
+ @app.list_tools()
85
+ async def list_tools() -> list[Tool]:
86
+ """
87
+ 列出可用的工具
88
+ """
89
+ tools = adbpg_basic_operation.get_basic_tools()
90
+ #tools.extend(adbpg_graphrag.get_graphrag_tools())
91
+ #tools.extend(adbpg_memory.get_memory_tools())
92
+
93
+ if graphrag_is_available:
94
+ tools.extend(adbpg_graphrag.get_graphrag_tools())
95
+ if llm_memory_is_available:
96
+ tools.extend(adbpg_memory.get_memory_tools())
97
+ return tools
98
+ @app.call_tool()
99
+ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
100
+ """
101
+ 执行工具操作
102
+
103
+ 参数:
104
+ name (str): 工具名称
105
+ arguments (dict): 工具参数
106
+
107
+ 返回:
108
+ list[TextContent]: 执行结果
109
+ """
110
+ if not db_manager:
111
+ raise Exception("Database manager not initialized")
112
+
113
+ try:
114
+ # 分发到 Basic Operation
115
+ if name in [t.name for t in adbpg_basic_operation.get_basic_tools()]:
116
+ query, params, needs_json_agg = await adbpg_basic_operation.call_basic_tool(name, arguments, db_manager)
117
+ conn = db_manager.get_basic_connection()
118
+ with conn.cursor() as cursor:
119
+ cursor.execute(query, params)
120
+ if needs_json_agg:
121
+ json_result = cursor.fetchone()[0]
122
+ return [TextContent(type="text", text=json.dumps(json_result, ensure_ascii=False, indent=2))]
123
+ else:
124
+ return [TextContent(type="text", text="Tool executed successfully.")]
125
+
126
+ # 分发到 GraphRAG
127
+ elif name in [t.name for t in adbpg_graphrag.get_graphrag_tools()]:
128
+ if not graphrag_is_available:
129
+ raise ValueError("GraphRAG tool is not available due to configuration or initialization errors.")
130
+ return await adbpg_graphrag.call_graphrag_tool(name, arguments, db_manager)
131
+
132
+ # 分发到 LLM Memory
133
+ elif name in [t.name for t in adbpg_memory.get_memory_tools()]:
134
+ if not llm_memory_is_available:
135
+ raise ValueError("LLM Memory tool is not available due to configuration or initialization errors.")
136
+ return await adbpg_memory.call_memory_tool(name, arguments, db_manager)
137
+
138
+ else:
139
+ raise ValueError(f"Unknown tool: {name}")
140
+
141
+ except Exception as e:
142
+ logger.error(f"Error calling tool '{name}': {e}", exc_info=True)
143
+ return [TextContent(type="text", text=f"Error executing tool '{name}': {str(e)}")]
144
+
145
+ # --- 服务器生命周期 ---
146
+ def initialize_services():
147
+ """初始化数据库、GraphRAG 和 LLM Memory"""
148
+ global db_manager, graphrag_is_available, llm_memory_is_available
149
+
150
+ if not settings.db_env_ready:
151
+ logger.error("Cannot start server: Database environment is not configured.")
152
+ sys.exit(1)
153
+
154
+ db_manager = DatabaseManager(settings)
155
+
156
+ # 测试主连接
157
+ try:
158
+ db_manager.get_basic_connection()
159
+ logger.info("Successfully connected to database.")
160
+ except Exception as e:
161
+ logger.error(f"Failed to connect to database: {e}")
162
+ sys.exit(1)
163
+
164
+ # 初始化 GraphRAG
165
+ if settings.graphrag_env_ready:
166
+ try:
167
+ db_manager.get_graphrag_connection()
168
+ graphrag_is_available = True
169
+ logger.info("GraphRAG initialized successfully.")
170
+ except Exception as e:
171
+ logger.error(f"Failed to initialize GraphRAG: {e}")
172
+ graphrag_is_available = False
173
+
174
+ # 初始化 LLM Memory
175
+ if settings.memory_env_ready:
176
+ try:
177
+ db_manager.get_llm_memory_connection()
178
+ llm_memory_is_available = True
179
+ logger.info("LLM Memory initialized successfully.")
180
+ except Exception as e:
181
+ logger.error(f"Failed to initialize LLM Memory: {e}")
182
+ llm_memory_is_available = False
183
+
184
+ async def main():
185
+ """服务器主入口点"""
186
+ try:
187
+ initialize_services()
188
+ logger.info("Starting ADBPG MCP server...")
189
+
190
+ # 使用 stdio 传输
191
+ async with stdio_server() as (read_stream, write_stream):
192
+ try:
193
+ logger.info("Running MCP server with stdio transport...")
194
+ await app.run(
195
+ read_stream=read_stream,
196
+ write_stream=write_stream,
197
+ initialization_options=app.create_initialization_options()
198
+ )
199
+ except Exception as e:
200
+ logger.error(f"Error running server: {str(e)}")
201
+ raise
202
+ except Exception as e:
203
+ logger.error(f"Server initialization error: {str(e)}")
204
+ raise
205
+
206
+ finally:
207
+ if db_manager:
208
+ db_manager.close_all()
209
+
210
+ def run_stdio_server():
211
+ """同步运行入口点"""
212
+ try:
213
+ asyncio.run(main())
214
+ except Exception as e:
215
+ logger.error(f"Fatal error: {e}")
216
+ sys.exit(1)