sqlsaber 0.3.0__tar.gz → 0.4.1__tar.gz
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.
Potentially problematic release.
This version of sqlsaber might be problematic. Click here for more details.
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/CHANGELOG.md +16 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/PKG-INFO +72 -3
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/README.md +70 -2
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/pyproject.toml +4 -1
- sqlsaber-0.4.1/src/sqlsaber/agents/mcp.py +21 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/cli/commands.py +3 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/cli/interactive.py +9 -6
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/database/schema.py +2 -2
- sqlsaber-0.4.1/src/sqlsaber/mcp/__init__.py +5 -0
- sqlsaber-0.4.1/src/sqlsaber/mcp/mcp.py +138 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/uv.lock +171 -1
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/.github/workflows/publish.yml +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/.gitignore +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/.python-version +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/CLAUDE.md +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/LICENSE +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/pytest.ini +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/__main__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/agents/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/agents/anthropic.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/agents/base.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/agents/streaming.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/cli/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/cli/database.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/cli/display.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/cli/memory.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/cli/models.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/cli/streaming.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/config/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/config/api_keys.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/config/database.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/config/settings.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/database/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/database/connection.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/memory/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/memory/manager.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/memory/storage.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/models/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/models/events.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/src/sqlsaber/models/types.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/conftest.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/test_cli/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/test_cli/test_commands.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/test_config/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/test_config/test_database.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/test_config/test_settings.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/test_database/__init__.py +0 -0
- {sqlsaber-0.3.0 → sqlsaber-0.4.1}/tests/test_database/test_connection.py +0 -0
|
@@ -4,6 +4,22 @@ All notable changes to SQLSaber will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.4.1] - 2025-06-26
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Show connected database information at the start of a session
|
|
12
|
+
- Update welcome message for clarity
|
|
13
|
+
|
|
14
|
+
## [0.4.0] - 2025-06-25
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- MCP (Model Context Protocol) server support
|
|
19
|
+
- `saber-mcp` console script for running MCP server
|
|
20
|
+
- MCP tools: `get_databases()`, `list_tables()`, `introspect_schema()`, `execute_sql()`
|
|
21
|
+
- Instructions and documentation for configuring MCP clients (Claude Code, etc.)
|
|
22
|
+
|
|
7
23
|
## [0.3.0] - 2025-06-25
|
|
8
24
|
|
|
9
25
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlsaber
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: SQLSaber - Agentic SQL assistant like Claude Code
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -8,6 +8,7 @@ Requires-Dist: aiomysql>=0.2.0
|
|
|
8
8
|
Requires-Dist: aiosqlite>=0.21.0
|
|
9
9
|
Requires-Dist: anthropic>=0.54.0
|
|
10
10
|
Requires-Dist: asyncpg>=0.30.0
|
|
11
|
+
Requires-Dist: fastmcp>=2.9.0
|
|
11
12
|
Requires-Dist: httpx>=0.28.1
|
|
12
13
|
Requires-Dist: keyring>=25.6.0
|
|
13
14
|
Requires-Dist: pandas>=2.0.0
|
|
@@ -23,7 +24,28 @@ Description-Content-Type: text/markdown
|
|
|
23
24
|
|
|
24
25
|
SQLSaber is an agentic SQL assistant. Think Claude Code but for SQL.
|
|
25
26
|
|
|
26
|
-
Ask your questions in natural language and it will gather the right context and answer your query by writing SQL and analyzing the results.
|
|
27
|
+
Ask your questions in natural language and it will gather the right context automatically and answer your query by writing SQL and analyzing the results.
|
|
28
|
+
|
|
29
|
+
## Table of Contents
|
|
30
|
+
|
|
31
|
+
- [Features](#features)
|
|
32
|
+
- [Installation](#installation)
|
|
33
|
+
- [Configuration](#configuration)
|
|
34
|
+
- [Database Connection](#database-connection)
|
|
35
|
+
- [AI Model Configuration](#ai-model-configuration)
|
|
36
|
+
- [Memory Management](#memory-management)
|
|
37
|
+
- [Usage](#usage)
|
|
38
|
+
- [Interactive Mode](#interactive-mode)
|
|
39
|
+
- [Single Query](#single-query)
|
|
40
|
+
- [Database Selection](#database-selection)
|
|
41
|
+
- [Examples](#examples)
|
|
42
|
+
- [MCP Server Integration](#mcp-server-integration)
|
|
43
|
+
- [Starting the MCP Server](#starting-the-mcp-server)
|
|
44
|
+
- [Configuring MCP Clients](#configuring-mcp-clients)
|
|
45
|
+
- [Available MCP Tools](#available-mcp-tools)
|
|
46
|
+
- [How It Works](#how-it-works)
|
|
47
|
+
- [Contributing](#contributing)
|
|
48
|
+
- [License](#license)
|
|
27
49
|
|
|
28
50
|
## Features
|
|
29
51
|
|
|
@@ -34,19 +56,29 @@ Ask your questions in natural language and it will gather the right context and
|
|
|
34
56
|
- 💬 Interactive REPL mode
|
|
35
57
|
- 🎨 Beautiful formatted output with syntax highlighting
|
|
36
58
|
- 🗄️ Support for PostgreSQL, SQLite, and MySQL
|
|
59
|
+
- 🔌 MCP (Model Context Protocol) server support
|
|
37
60
|
|
|
38
61
|
## Installation
|
|
39
62
|
|
|
63
|
+
### `uv`
|
|
64
|
+
|
|
40
65
|
```bash
|
|
41
66
|
uv tool install sqlsaber
|
|
42
67
|
```
|
|
43
68
|
|
|
44
|
-
|
|
69
|
+
### `pipx`
|
|
45
70
|
|
|
46
71
|
```bash
|
|
47
72
|
pipx install sqlsaber
|
|
48
73
|
```
|
|
49
74
|
|
|
75
|
+
### `brew`
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
brew install uv
|
|
79
|
+
uv tool install sqlsaber
|
|
80
|
+
```
|
|
81
|
+
|
|
50
82
|
## Configuration
|
|
51
83
|
|
|
52
84
|
### Database Connection
|
|
@@ -140,6 +172,43 @@ saber query "show me the distribution of customer ages"
|
|
|
140
172
|
saber query "which products had the highest sales growth last quarter?"
|
|
141
173
|
```
|
|
142
174
|
|
|
175
|
+
## MCP Server Integration
|
|
176
|
+
|
|
177
|
+
SQLSaber includes an MCP (Model Context Protocol) server that allows AI agents like Claude Code to directly leverage tools available in SQLSaber.
|
|
178
|
+
|
|
179
|
+
### Starting the MCP Server
|
|
180
|
+
|
|
181
|
+
Run the MCP server using uvx:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
uvx --from sqlsaber saber-mcp
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Configuring MCP Clients
|
|
188
|
+
|
|
189
|
+
#### Claude Code
|
|
190
|
+
|
|
191
|
+
Add SQLSaber as an MCP server in Claude Code:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
claude mcp add -- uvx --from sqlsaber saber-mcp
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### Other MCP Clients
|
|
198
|
+
|
|
199
|
+
For other MCP clients, configure them to run the command: `uvx --from sqlsaber saber-mcp`
|
|
200
|
+
|
|
201
|
+
### Available MCP Tools
|
|
202
|
+
|
|
203
|
+
Once connected, the MCP client will have access to these tools:
|
|
204
|
+
|
|
205
|
+
- `get_databases()` - Lists all configured databases
|
|
206
|
+
- `list_tables(database)` - Get all tables in a database with row counts
|
|
207
|
+
- `introspect_schema(database, table_pattern?)` - Get detailed schema information
|
|
208
|
+
- `execute_sql(database, query, limit?)` - Execute SQL queries (read-only)
|
|
209
|
+
|
|
210
|
+
The MCP server uses your existing SQLSaber database configurations, so make sure to set up your databases using `saber db add` first.
|
|
211
|
+
|
|
143
212
|
## How It Works
|
|
144
213
|
|
|
145
214
|
SQLSaber uses an intelligent three-step process optimized for minimal token usage:
|
|
@@ -4,7 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
SQLSaber is an agentic SQL assistant. Think Claude Code but for SQL.
|
|
6
6
|
|
|
7
|
-
Ask your questions in natural language and it will gather the right context and answer your query by writing SQL and analyzing the results.
|
|
7
|
+
Ask your questions in natural language and it will gather the right context automatically and answer your query by writing SQL and analyzing the results.
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Features](#features)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Configuration](#configuration)
|
|
14
|
+
- [Database Connection](#database-connection)
|
|
15
|
+
- [AI Model Configuration](#ai-model-configuration)
|
|
16
|
+
- [Memory Management](#memory-management)
|
|
17
|
+
- [Usage](#usage)
|
|
18
|
+
- [Interactive Mode](#interactive-mode)
|
|
19
|
+
- [Single Query](#single-query)
|
|
20
|
+
- [Database Selection](#database-selection)
|
|
21
|
+
- [Examples](#examples)
|
|
22
|
+
- [MCP Server Integration](#mcp-server-integration)
|
|
23
|
+
- [Starting the MCP Server](#starting-the-mcp-server)
|
|
24
|
+
- [Configuring MCP Clients](#configuring-mcp-clients)
|
|
25
|
+
- [Available MCP Tools](#available-mcp-tools)
|
|
26
|
+
- [How It Works](#how-it-works)
|
|
27
|
+
- [Contributing](#contributing)
|
|
28
|
+
- [License](#license)
|
|
8
29
|
|
|
9
30
|
## Features
|
|
10
31
|
|
|
@@ -15,19 +36,29 @@ Ask your questions in natural language and it will gather the right context and
|
|
|
15
36
|
- 💬 Interactive REPL mode
|
|
16
37
|
- 🎨 Beautiful formatted output with syntax highlighting
|
|
17
38
|
- 🗄️ Support for PostgreSQL, SQLite, and MySQL
|
|
39
|
+
- 🔌 MCP (Model Context Protocol) server support
|
|
18
40
|
|
|
19
41
|
## Installation
|
|
20
42
|
|
|
43
|
+
### `uv`
|
|
44
|
+
|
|
21
45
|
```bash
|
|
22
46
|
uv tool install sqlsaber
|
|
23
47
|
```
|
|
24
48
|
|
|
25
|
-
|
|
49
|
+
### `pipx`
|
|
26
50
|
|
|
27
51
|
```bash
|
|
28
52
|
pipx install sqlsaber
|
|
29
53
|
```
|
|
30
54
|
|
|
55
|
+
### `brew`
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
brew install uv
|
|
59
|
+
uv tool install sqlsaber
|
|
60
|
+
```
|
|
61
|
+
|
|
31
62
|
## Configuration
|
|
32
63
|
|
|
33
64
|
### Database Connection
|
|
@@ -121,6 +152,43 @@ saber query "show me the distribution of customer ages"
|
|
|
121
152
|
saber query "which products had the highest sales growth last quarter?"
|
|
122
153
|
```
|
|
123
154
|
|
|
155
|
+
## MCP Server Integration
|
|
156
|
+
|
|
157
|
+
SQLSaber includes an MCP (Model Context Protocol) server that allows AI agents like Claude Code to directly leverage tools available in SQLSaber.
|
|
158
|
+
|
|
159
|
+
### Starting the MCP Server
|
|
160
|
+
|
|
161
|
+
Run the MCP server using uvx:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
uvx --from sqlsaber saber-mcp
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Configuring MCP Clients
|
|
168
|
+
|
|
169
|
+
#### Claude Code
|
|
170
|
+
|
|
171
|
+
Add SQLSaber as an MCP server in Claude Code:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
claude mcp add -- uvx --from sqlsaber saber-mcp
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Other MCP Clients
|
|
178
|
+
|
|
179
|
+
For other MCP clients, configure them to run the command: `uvx --from sqlsaber saber-mcp`
|
|
180
|
+
|
|
181
|
+
### Available MCP Tools
|
|
182
|
+
|
|
183
|
+
Once connected, the MCP client will have access to these tools:
|
|
184
|
+
|
|
185
|
+
- `get_databases()` - Lists all configured databases
|
|
186
|
+
- `list_tables(database)` - Get all tables in a database with row counts
|
|
187
|
+
- `introspect_schema(database, table_pattern?)` - Get detailed schema information
|
|
188
|
+
- `execute_sql(database, query, limit?)` - Execute SQL queries (read-only)
|
|
189
|
+
|
|
190
|
+
The MCP server uses your existing SQLSaber database configurations, so make sure to set up your databases using `saber db add` first.
|
|
191
|
+
|
|
124
192
|
## How It Works
|
|
125
193
|
|
|
126
194
|
SQLSaber uses an intelligent three-step process optimized for minimal token usage:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sqlsaber"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.1"
|
|
4
4
|
description = "SQLSaber - Agentic SQL assistant like Claude Code"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -16,6 +16,7 @@ dependencies = [
|
|
|
16
16
|
"aiomysql>=0.2.0",
|
|
17
17
|
"aiosqlite>=0.21.0",
|
|
18
18
|
"pandas>=2.0.0",
|
|
19
|
+
"fastmcp>=2.9.0",
|
|
19
20
|
]
|
|
20
21
|
|
|
21
22
|
[tool.uv]
|
|
@@ -32,3 +33,5 @@ packages = ["src/sqlsaber"]
|
|
|
32
33
|
sqlsaber = "sqlsaber.cli.commands:main"
|
|
33
34
|
saber = "sqlsaber.cli.commands:main"
|
|
34
35
|
sql = "sqlsaber.cli.commands:main"
|
|
36
|
+
sqlsaber-mcp = "sqlsaber.mcp.mcp:main"
|
|
37
|
+
saber-mcp = "sqlsaber.mcp.mcp:main"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Generic SQL agent implementation for MCP tools."""
|
|
2
|
+
|
|
3
|
+
from typing import AsyncIterator
|
|
4
|
+
from sqlsaber.agents.base import BaseSQLAgent
|
|
5
|
+
from sqlsaber.database.connection import BaseDatabaseConnection
|
|
6
|
+
from sqlsaber.models.events import StreamEvent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MCPSQLAgent(BaseSQLAgent):
|
|
10
|
+
"""MCP SQL Agent for MCP tool operations without LLM-specific logic."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db_connection: BaseDatabaseConnection):
|
|
13
|
+
super().__init__(db_connection)
|
|
14
|
+
|
|
15
|
+
async def query_stream(
|
|
16
|
+
self, user_query: str, use_history: bool = True
|
|
17
|
+
) -> AsyncIterator[StreamEvent]:
|
|
18
|
+
"""Not implemented for generic agent as it's only used for tool operations."""
|
|
19
|
+
raise NotImplementedError(
|
|
20
|
+
"MCPSQLAgent does not support query streaming. Use specific agent implementations for conversation."
|
|
21
|
+
)
|
|
@@ -117,6 +117,9 @@ def query(
|
|
|
117
117
|
if query_text:
|
|
118
118
|
# Single query mode with streaming
|
|
119
119
|
streaming_handler = StreamingQueryHandler(console)
|
|
120
|
+
console.print(
|
|
121
|
+
f"[bold blue]Connected to:[/bold blue] {db_name} {agent._get_database_type_name()}\n"
|
|
122
|
+
)
|
|
120
123
|
await streaming_handler.execute_streaming_query(query_text, agent)
|
|
121
124
|
else:
|
|
122
125
|
# Interactive mode
|
|
@@ -20,21 +20,24 @@ class InteractiveSession:
|
|
|
20
20
|
|
|
21
21
|
def show_welcome_message(self):
|
|
22
22
|
"""Display welcome message for interactive mode."""
|
|
23
|
+
# Show database information
|
|
24
|
+
db_name = getattr(self.agent, "database_name", None) or "Unknown"
|
|
25
|
+
db_type = self.agent._get_database_type_name()
|
|
26
|
+
|
|
23
27
|
self.console.print(
|
|
24
28
|
Panel.fit(
|
|
25
29
|
"[bold green]SQLSaber - Use the agent Luke![/bold green]\n\n"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
30
|
+
"[bold]Your agentic SQL assistant.[/bold]\n\n\n"
|
|
31
|
+
"[dim]Use 'clear' to reset conversation, 'exit' or 'quit' to leave.[/dim]\n\n"
|
|
32
|
+
"[dim]Start a message with '#' to add something to agent's memory for this database.[/dim]",
|
|
29
33
|
border_style="green",
|
|
30
34
|
)
|
|
31
35
|
)
|
|
32
|
-
|
|
33
36
|
self.console.print(
|
|
34
|
-
"[
|
|
37
|
+
f"[bold blue]Connected to:[/bold blue] {db_name} ({db_type})\n"
|
|
35
38
|
)
|
|
36
39
|
self.console.print(
|
|
37
|
-
"[dim]
|
|
40
|
+
"[dim]Press Esc-Enter or Meta-Enter to submit your query.[/dim]\n"
|
|
38
41
|
)
|
|
39
42
|
|
|
40
43
|
async def run(self):
|
|
@@ -201,8 +201,8 @@ class PostgreSQLSchemaIntrospector(BaseSchemaIntrospector):
|
|
|
201
201
|
t.table_type,
|
|
202
202
|
COALESCE(ts.approximate_row_count, 0) as row_count
|
|
203
203
|
FROM information_schema.tables t
|
|
204
|
-
LEFT JOIN table_stats ts
|
|
205
|
-
ON t.table_schema = ts.schemaname
|
|
204
|
+
LEFT JOIN table_stats ts
|
|
205
|
+
ON t.table_schema = ts.schemaname
|
|
206
206
|
AND t.table_name = ts.tablename
|
|
207
207
|
WHERE t.table_schema NOT IN ('pg_catalog', 'information_schema')
|
|
208
208
|
ORDER BY t.table_schema, t.table_name;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""FastMCP server implementation for SQLSaber."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from fastmcp import FastMCP
|
|
7
|
+
|
|
8
|
+
from sqlsaber.agents.mcp import MCPSQLAgent
|
|
9
|
+
from sqlsaber.config.database import DatabaseConfigManager
|
|
10
|
+
from sqlsaber.database.connection import DatabaseConnection
|
|
11
|
+
|
|
12
|
+
INSTRUCTIONS = """
|
|
13
|
+
This server provides helpful resources and tools that will help you address users queries on their database.
|
|
14
|
+
|
|
15
|
+
- Get all databases using `get_databases()`
|
|
16
|
+
- Call `list_tables()` to get a list of all tables in the database with row counts. Use this first to discover available tables.
|
|
17
|
+
- Call `introspect_schema()` to introspect database schema to understand table structures.
|
|
18
|
+
- Call `execute_sql()` to execute SQL queries against the database and retrieve results.
|
|
19
|
+
|
|
20
|
+
Guidelines:
|
|
21
|
+
- Use list_tables first, then introspect_schema for specific tables only
|
|
22
|
+
- Use table patterns like 'sample%' or '%experiment%' to filter related tables
|
|
23
|
+
- Use proper JOIN syntax and avoid cartesian products
|
|
24
|
+
- Include appropriate WHERE clauses to limit results
|
|
25
|
+
- Handle errors gracefully and suggest fixes
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# Create the FastMCP server instance
|
|
29
|
+
mcp = FastMCP(name="SQL Assistant", instructions=INSTRUCTIONS)
|
|
30
|
+
|
|
31
|
+
# Initialize the database config manager
|
|
32
|
+
config_manager = DatabaseConfigManager()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def _create_agent_for_database(database_name: str) -> Optional[MCPSQLAgent]:
|
|
36
|
+
"""Create a MCPSQLAgent for the specified database."""
|
|
37
|
+
try:
|
|
38
|
+
# Look up configured database connection
|
|
39
|
+
db_config = config_manager.get_database(database_name)
|
|
40
|
+
if not db_config:
|
|
41
|
+
return None
|
|
42
|
+
connection_string = db_config.to_connection_string()
|
|
43
|
+
|
|
44
|
+
# Create database connection
|
|
45
|
+
db_conn = DatabaseConnection(connection_string)
|
|
46
|
+
|
|
47
|
+
# Create and return the agent
|
|
48
|
+
agent = MCPSQLAgent(db_conn)
|
|
49
|
+
return agent
|
|
50
|
+
|
|
51
|
+
except Exception:
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@mcp.tool
|
|
56
|
+
def get_databases() -> dict:
|
|
57
|
+
"""List all configured databases with their types."""
|
|
58
|
+
databases = []
|
|
59
|
+
for db_config in config_manager.list_databases():
|
|
60
|
+
databases.append(
|
|
61
|
+
{
|
|
62
|
+
"name": db_config.name,
|
|
63
|
+
"type": db_config.type,
|
|
64
|
+
"database": db_config.database,
|
|
65
|
+
"host": db_config.host,
|
|
66
|
+
"port": db_config.port,
|
|
67
|
+
"is_default": db_config.name == config_manager.get_default_name(),
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return {"databases": databases, "count": len(databases)}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@mcp.tool
|
|
75
|
+
async def list_tables(database: str) -> str:
|
|
76
|
+
"""
|
|
77
|
+
Get a list of all tables in the database with row counts. Use this first to discover available tables.
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
agent = await _create_agent_for_database(database)
|
|
81
|
+
if not agent:
|
|
82
|
+
return json.dumps(
|
|
83
|
+
{"error": f"Database '{database}' not found or could not connect"}
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
result = await agent.list_tables()
|
|
87
|
+
await agent.db.close()
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
return json.dumps({"error": f"Error listing tables: {str(e)}"})
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@mcp.tool
|
|
95
|
+
async def introspect_schema(database: str, table_pattern: Optional[str] = None) -> str:
|
|
96
|
+
"""
|
|
97
|
+
Introspect database schema to understand table structures. Use optional pattern to filter tables (e.g., 'public.users', 'user%', '%order%').
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
agent = await _create_agent_for_database(database)
|
|
101
|
+
if not agent:
|
|
102
|
+
return json.dumps(
|
|
103
|
+
{"error": f"Database '{database}' not found or could not connect"}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
result = await agent.introspect_schema(table_pattern)
|
|
107
|
+
await agent.db.close()
|
|
108
|
+
return result
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
return json.dumps({"error": f"Error introspecting schema: {str(e)}"})
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@mcp.tool
|
|
115
|
+
async def execute_sql(database: str, query: str, limit: Optional[int] = 100) -> str:
|
|
116
|
+
"""Execute a SQL query against the specified database."""
|
|
117
|
+
try:
|
|
118
|
+
agent = await _create_agent_for_database(database)
|
|
119
|
+
if not agent:
|
|
120
|
+
return json.dumps(
|
|
121
|
+
{"error": f"Database '{database}' not found or could not connect"}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
result = await agent.execute_sql(query, limit)
|
|
125
|
+
await agent.db.close()
|
|
126
|
+
return result
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
return json.dumps({"error": f"Error executing SQL: {str(e)}"})
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main():
|
|
133
|
+
"""Entry point for the MCP server console script."""
|
|
134
|
+
mcp.run()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
main()
|
|
@@ -91,6 +91,18 @@ wheels = [
|
|
|
91
91
|
{ url = "https://files.pythonhosted.org/packages/c8/a4/cec76b3389c4c5ff66301cd100fe88c318563ec8a520e0b2e792b5b84972/asyncpg-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:f59b430b8e27557c3fb9869222559f7417ced18688375825f8f12302c34e915e", size = 621623 },
|
|
92
92
|
]
|
|
93
93
|
|
|
94
|
+
[[package]]
|
|
95
|
+
name = "authlib"
|
|
96
|
+
version = "1.6.0"
|
|
97
|
+
source = { registry = "https://pypi.org/simple" }
|
|
98
|
+
dependencies = [
|
|
99
|
+
{ name = "cryptography" },
|
|
100
|
+
]
|
|
101
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a2/9d/b1e08d36899c12c8b894a44a5583ee157789f26fc4b176f8e4b6217b56e1/authlib-1.6.0.tar.gz", hash = "sha256:4367d32031b7af175ad3a323d571dc7257b7099d55978087ceae4a0d88cd3210", size = 158371 }
|
|
102
|
+
wheels = [
|
|
103
|
+
{ url = "https://files.pythonhosted.org/packages/84/29/587c189bbab1ccc8c86a03a5d0e13873df916380ef1be461ebe6acebf48d/authlib-1.6.0-py2.py3-none-any.whl", hash = "sha256:91685589498f79e8655e8a8947431ad6288831d643f11c55c2143ffcc738048d", size = 239981 },
|
|
104
|
+
]
|
|
105
|
+
|
|
94
106
|
[[package]]
|
|
95
107
|
name = "certifi"
|
|
96
108
|
version = "2025.6.15"
|
|
@@ -109,6 +121,8 @@ dependencies = [
|
|
|
109
121
|
]
|
|
110
122
|
sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 }
|
|
111
123
|
wheels = [
|
|
124
|
+
{ url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 },
|
|
125
|
+
{ url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 },
|
|
112
126
|
{ url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 },
|
|
113
127
|
{ url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 },
|
|
114
128
|
{ url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 },
|
|
@@ -116,6 +130,10 @@ wheels = [
|
|
|
116
130
|
{ url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 },
|
|
117
131
|
{ url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 },
|
|
118
132
|
{ url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 },
|
|
133
|
+
{ url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 },
|
|
134
|
+
{ url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 },
|
|
135
|
+
{ url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 },
|
|
136
|
+
{ url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 },
|
|
119
137
|
{ url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 },
|
|
120
138
|
{ url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 },
|
|
121
139
|
{ url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 },
|
|
@@ -123,6 +141,8 @@ wheels = [
|
|
|
123
141
|
{ url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 },
|
|
124
142
|
{ url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 },
|
|
125
143
|
{ url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 },
|
|
144
|
+
{ url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 },
|
|
145
|
+
{ url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 },
|
|
126
146
|
]
|
|
127
147
|
|
|
128
148
|
[[package]]
|
|
@@ -155,6 +175,7 @@ dependencies = [
|
|
|
155
175
|
]
|
|
156
176
|
sdist = { url = "https://files.pythonhosted.org/packages/fe/c8/a2a376a8711c1e11708b9c9972e0c3223f5fc682552c82d8db844393d6ce/cryptography-45.0.4.tar.gz", hash = "sha256:7405ade85c83c37682c8fe65554759800a4a8c54b2d96e0f8ad114d31b808d57", size = 744890 }
|
|
157
177
|
wheels = [
|
|
178
|
+
{ url = "https://files.pythonhosted.org/packages/cc/1c/92637793de053832523b410dbe016d3f5c11b41d0cf6eef8787aabb51d41/cryptography-45.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:425a9a6ac2823ee6e46a76a21a4e8342d8fa5c01e08b823c1f19a8b74f096069", size = 7055712 },
|
|
158
179
|
{ url = "https://files.pythonhosted.org/packages/ba/14/93b69f2af9ba832ad6618a03f8a034a5851dc9a3314336a3d71c252467e1/cryptography-45.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:680806cf63baa0039b920f4976f5f31b10e772de42f16310a6839d9f21a26b0d", size = 4205335 },
|
|
159
180
|
{ url = "https://files.pythonhosted.org/packages/67/30/fae1000228634bf0b647fca80403db5ca9e3933b91dd060570689f0bd0f7/cryptography-45.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4ca0f52170e821bc8da6fc0cc565b7bb8ff8d90d36b5e9fdd68e8a86bdf72036", size = 4431487 },
|
|
160
181
|
{ url = "https://files.pythonhosted.org/packages/6d/5a/7dffcf8cdf0cb3c2430de7404b327e3db64735747d641fc492539978caeb/cryptography-45.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f3fe7a5ae34d5a414957cc7f457e2b92076e72938423ac64d215722f6cf49a9e", size = 4208922 },
|
|
@@ -164,6 +185,9 @@ wheels = [
|
|
|
164
185
|
{ url = "https://files.pythonhosted.org/packages/db/b7/a84bdcd19d9c02ec5807f2ec2d1456fd8451592c5ee353816c09250e3561/cryptography-45.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2882338b2a6e0bd337052e8b9007ced85c637da19ef9ecaf437744495c8c2999", size = 4463623 },
|
|
165
186
|
{ url = "https://files.pythonhosted.org/packages/d8/84/69707d502d4d905021cac3fb59a316344e9f078b1da7fb43ecde5e10840a/cryptography-45.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:23b9c3ea30c3ed4db59e7b9619272e94891f8a3a5591d0b656a7582631ccf750", size = 4332447 },
|
|
166
187
|
{ url = "https://files.pythonhosted.org/packages/f3/ee/d4f2ab688e057e90ded24384e34838086a9b09963389a5ba6854b5876598/cryptography-45.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0a97c927497e3bc36b33987abb99bf17a9a175a19af38a892dc4bbb844d7ee2", size = 4572830 },
|
|
188
|
+
{ url = "https://files.pythonhosted.org/packages/70/d4/994773a261d7ff98034f72c0e8251fe2755eac45e2265db4c866c1c6829c/cryptography-45.0.4-cp311-abi3-win32.whl", hash = "sha256:e00a6c10a5c53979d6242f123c0a97cff9f3abed7f064fc412c36dc521b5f257", size = 2932769 },
|
|
189
|
+
{ url = "https://files.pythonhosted.org/packages/5a/42/c80bd0b67e9b769b364963b5252b17778a397cefdd36fa9aa4a5f34c599a/cryptography-45.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:817ee05c6c9f7a69a16200f0c90ab26d23a87701e2a284bd15156783e46dbcc8", size = 3410441 },
|
|
190
|
+
{ url = "https://files.pythonhosted.org/packages/ce/0b/2488c89f3a30bc821c9d96eeacfcab6ff3accc08a9601ba03339c0fd05e5/cryptography-45.0.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:964bcc28d867e0f5491a564b7debb3ffdd8717928d315d12e0d7defa9e43b723", size = 7031836 },
|
|
167
191
|
{ url = "https://files.pythonhosted.org/packages/fe/51/8c584ed426093aac257462ae62d26ad61ef1cbf5b58d8b67e6e13c39960e/cryptography-45.0.4-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6a5bf57554e80f75a7db3d4b1dacaa2764611ae166ab42ea9a72bcdb5d577637", size = 4195746 },
|
|
168
192
|
{ url = "https://files.pythonhosted.org/packages/5c/7d/4b0ca4d7af95a704eef2f8f80a8199ed236aaf185d55385ae1d1610c03c2/cryptography-45.0.4-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:46cf7088bf91bdc9b26f9c55636492c1cce3e7aaf8041bbf0243f5e5325cfb2d", size = 4424456 },
|
|
169
193
|
{ url = "https://files.pythonhosted.org/packages/1d/45/5fabacbc6e76ff056f84d9f60eeac18819badf0cefc1b6612ee03d4ab678/cryptography-45.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7bedbe4cc930fa4b100fc845ea1ea5788fcd7ae9562e669989c11618ae8d76ee", size = 4198495 },
|
|
@@ -173,6 +197,8 @@ wheels = [
|
|
|
173
197
|
{ url = "https://files.pythonhosted.org/packages/3a/c0/85fa358ddb063ec588aed4a6ea1df57dc3e3bc1712d87c8fa162d02a65fc/cryptography-45.0.4-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:06509dc70dd71fa56eaa138336244e2fbaf2ac164fc9b5e66828fccfd2b680d6", size = 4451442 },
|
|
174
198
|
{ url = "https://files.pythonhosted.org/packages/33/67/362d6ec1492596e73da24e669a7fbbaeb1c428d6bf49a29f7a12acffd5dc/cryptography-45.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5f31e6b0a5a253f6aa49be67279be4a7e5a4ef259a9f33c69f7d1b1191939872", size = 4325038 },
|
|
175
199
|
{ url = "https://files.pythonhosted.org/packages/53/75/82a14bf047a96a1b13ebb47fb9811c4f73096cfa2e2b17c86879687f9027/cryptography-45.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:944e9ccf67a9594137f942d5b52c8d238b1b4e46c7a0c2891b7ae6e01e7c80a4", size = 4560964 },
|
|
200
|
+
{ url = "https://files.pythonhosted.org/packages/cd/37/1a3cba4c5a468ebf9b95523a5ef5651244693dc712001e276682c278fc00/cryptography-45.0.4-cp37-abi3-win32.whl", hash = "sha256:c22fe01e53dc65edd1945a2e6f0015e887f84ced233acecb64b4daadb32f5c97", size = 2924557 },
|
|
201
|
+
{ url = "https://files.pythonhosted.org/packages/2a/4b/3256759723b7e66380397d958ca07c59cfc3fb5c794fb5516758afd05d41/cryptography-45.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:627ba1bc94f6adf0b0a2e35d87020285ead22d9f648c7e75bb64f367375f3b22", size = 3395508 },
|
|
176
202
|
]
|
|
177
203
|
|
|
178
204
|
[[package]]
|
|
@@ -184,6 +210,37 @@ wheels = [
|
|
|
184
210
|
{ url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 },
|
|
185
211
|
]
|
|
186
212
|
|
|
213
|
+
[[package]]
|
|
214
|
+
name = "exceptiongroup"
|
|
215
|
+
version = "1.3.0"
|
|
216
|
+
source = { registry = "https://pypi.org/simple" }
|
|
217
|
+
dependencies = [
|
|
218
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
219
|
+
]
|
|
220
|
+
sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749 }
|
|
221
|
+
wheels = [
|
|
222
|
+
{ url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674 },
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
[[package]]
|
|
226
|
+
name = "fastmcp"
|
|
227
|
+
version = "2.9.0"
|
|
228
|
+
source = { registry = "https://pypi.org/simple" }
|
|
229
|
+
dependencies = [
|
|
230
|
+
{ name = "authlib" },
|
|
231
|
+
{ name = "exceptiongroup" },
|
|
232
|
+
{ name = "httpx" },
|
|
233
|
+
{ name = "mcp" },
|
|
234
|
+
{ name = "openapi-pydantic" },
|
|
235
|
+
{ name = "python-dotenv" },
|
|
236
|
+
{ name = "rich" },
|
|
237
|
+
{ name = "typer" },
|
|
238
|
+
]
|
|
239
|
+
sdist = { url = "https://files.pythonhosted.org/packages/2d/43/31af92e392c8e28269599fe3228419fe4bbb829b04a61fac17ab8dd2a7a9/fastmcp-2.9.0.tar.gz", hash = "sha256:3f1dc97c409193729b4aa8ad240ad396fe767a982c55c3a3e788f422b1278dd6", size = 2650412 }
|
|
240
|
+
wheels = [
|
|
241
|
+
{ url = "https://files.pythonhosted.org/packages/dc/43/1095c0cbcf9f3b25d048faaf361b81b4dec403c3f75990dc93eeb6f3c3af/fastmcp-2.9.0-py3-none-any.whl", hash = "sha256:e5b00e5fcea2d216d96f7cfb8b67836bd58fc3cd57147e0d89043d905a84334f", size = 159401 },
|
|
242
|
+
]
|
|
243
|
+
|
|
187
244
|
[[package]]
|
|
188
245
|
name = "h11"
|
|
189
246
|
version = "0.16.0"
|
|
@@ -221,6 +278,15 @@ wheels = [
|
|
|
221
278
|
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
|
|
222
279
|
]
|
|
223
280
|
|
|
281
|
+
[[package]]
|
|
282
|
+
name = "httpx-sse"
|
|
283
|
+
version = "0.4.1"
|
|
284
|
+
source = { registry = "https://pypi.org/simple" }
|
|
285
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6e/fa/66bd985dd0b7c109a3bcb89272ee0bfb7e2b4d06309ad7b38ff866734b2a/httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e", size = 12998 }
|
|
286
|
+
wheels = [
|
|
287
|
+
{ url = "https://files.pythonhosted.org/packages/25/0a/6269e3473b09aed2dab8aa1a600c70f31f00ae1349bee30658f7e358a159/httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37", size = 8054 },
|
|
288
|
+
]
|
|
289
|
+
|
|
224
290
|
[[package]]
|
|
225
291
|
name = "idna"
|
|
226
292
|
version = "3.10"
|
|
@@ -358,6 +424,26 @@ wheels = [
|
|
|
358
424
|
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
|
|
359
425
|
]
|
|
360
426
|
|
|
427
|
+
[[package]]
|
|
428
|
+
name = "mcp"
|
|
429
|
+
version = "1.9.4"
|
|
430
|
+
source = { registry = "https://pypi.org/simple" }
|
|
431
|
+
dependencies = [
|
|
432
|
+
{ name = "anyio" },
|
|
433
|
+
{ name = "httpx" },
|
|
434
|
+
{ name = "httpx-sse" },
|
|
435
|
+
{ name = "pydantic" },
|
|
436
|
+
{ name = "pydantic-settings" },
|
|
437
|
+
{ name = "python-multipart" },
|
|
438
|
+
{ name = "sse-starlette" },
|
|
439
|
+
{ name = "starlette" },
|
|
440
|
+
{ name = "uvicorn", marker = "sys_platform != 'emscripten'" },
|
|
441
|
+
]
|
|
442
|
+
sdist = { url = "https://files.pythonhosted.org/packages/06/f2/dc2450e566eeccf92d89a00c3e813234ad58e2ba1e31d11467a09ac4f3b9/mcp-1.9.4.tar.gz", hash = "sha256:cfb0bcd1a9535b42edaef89947b9e18a8feb49362e1cc059d6e7fc636f2cb09f", size = 333294 }
|
|
443
|
+
wheels = [
|
|
444
|
+
{ url = "https://files.pythonhosted.org/packages/97/fc/80e655c955137393c443842ffcc4feccab5b12fa7cb8de9ced90f90e6998/mcp-1.9.4-py3-none-any.whl", hash = "sha256:7fcf36b62936adb8e63f89346bccca1268eeca9bf6dfb562ee10b1dfbda9dac0", size = 130232 },
|
|
445
|
+
]
|
|
446
|
+
|
|
361
447
|
[[package]]
|
|
362
448
|
name = "mdurl"
|
|
363
449
|
version = "0.1.2"
|
|
@@ -417,6 +503,18 @@ wheels = [
|
|
|
417
503
|
{ url = "https://files.pythonhosted.org/packages/d4/ca/af82bf0fad4c3e573c6930ed743b5308492ff19917c7caaf2f9b6f9e2e98/numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244", size = 10260376 },
|
|
418
504
|
]
|
|
419
505
|
|
|
506
|
+
[[package]]
|
|
507
|
+
name = "openapi-pydantic"
|
|
508
|
+
version = "0.5.1"
|
|
509
|
+
source = { registry = "https://pypi.org/simple" }
|
|
510
|
+
dependencies = [
|
|
511
|
+
{ name = "pydantic" },
|
|
512
|
+
]
|
|
513
|
+
sdist = { url = "https://files.pythonhosted.org/packages/02/2e/58d83848dd1a79cb92ed8e63f6ba901ca282c5f09d04af9423ec26c56fd7/openapi_pydantic-0.5.1.tar.gz", hash = "sha256:ff6835af6bde7a459fb93eb93bb92b8749b754fc6e51b2f1590a19dc3005ee0d", size = 60892 }
|
|
514
|
+
wheels = [
|
|
515
|
+
{ url = "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl", hash = "sha256:a3a09ef4586f5bd760a8df7f43028b60cafb6d9f61de2acba9574766255ab146", size = 96381 },
|
|
516
|
+
]
|
|
517
|
+
|
|
420
518
|
[[package]]
|
|
421
519
|
name = "packaging"
|
|
422
520
|
version = "25.0"
|
|
@@ -556,6 +654,20 @@ wheels = [
|
|
|
556
654
|
{ url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777 },
|
|
557
655
|
]
|
|
558
656
|
|
|
657
|
+
[[package]]
|
|
658
|
+
name = "pydantic-settings"
|
|
659
|
+
version = "2.10.1"
|
|
660
|
+
source = { registry = "https://pypi.org/simple" }
|
|
661
|
+
dependencies = [
|
|
662
|
+
{ name = "pydantic" },
|
|
663
|
+
{ name = "python-dotenv" },
|
|
664
|
+
{ name = "typing-inspection" },
|
|
665
|
+
]
|
|
666
|
+
sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583 }
|
|
667
|
+
wheels = [
|
|
668
|
+
{ url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235 },
|
|
669
|
+
]
|
|
670
|
+
|
|
559
671
|
[[package]]
|
|
560
672
|
name = "pygments"
|
|
561
673
|
version = "2.19.1"
|
|
@@ -614,6 +726,24 @@ wheels = [
|
|
|
614
726
|
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
|
615
727
|
]
|
|
616
728
|
|
|
729
|
+
[[package]]
|
|
730
|
+
name = "python-dotenv"
|
|
731
|
+
version = "1.1.1"
|
|
732
|
+
source = { registry = "https://pypi.org/simple" }
|
|
733
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978 }
|
|
734
|
+
wheels = [
|
|
735
|
+
{ url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556 },
|
|
736
|
+
]
|
|
737
|
+
|
|
738
|
+
[[package]]
|
|
739
|
+
name = "python-multipart"
|
|
740
|
+
version = "0.0.20"
|
|
741
|
+
source = { registry = "https://pypi.org/simple" }
|
|
742
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158 }
|
|
743
|
+
wheels = [
|
|
744
|
+
{ url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 },
|
|
745
|
+
]
|
|
746
|
+
|
|
617
747
|
[[package]]
|
|
618
748
|
name = "pytz"
|
|
619
749
|
version = "2025.2"
|
|
@@ -724,13 +854,14 @@ wheels = [
|
|
|
724
854
|
|
|
725
855
|
[[package]]
|
|
726
856
|
name = "sqlsaber"
|
|
727
|
-
version = "0.
|
|
857
|
+
version = "0.4.1"
|
|
728
858
|
source = { editable = "." }
|
|
729
859
|
dependencies = [
|
|
730
860
|
{ name = "aiomysql" },
|
|
731
861
|
{ name = "aiosqlite" },
|
|
732
862
|
{ name = "anthropic" },
|
|
733
863
|
{ name = "asyncpg" },
|
|
864
|
+
{ name = "fastmcp" },
|
|
734
865
|
{ name = "httpx" },
|
|
735
866
|
{ name = "keyring" },
|
|
736
867
|
{ name = "pandas" },
|
|
@@ -753,6 +884,7 @@ requires-dist = [
|
|
|
753
884
|
{ name = "aiosqlite", specifier = ">=0.21.0" },
|
|
754
885
|
{ name = "anthropic", specifier = ">=0.54.0" },
|
|
755
886
|
{ name = "asyncpg", specifier = ">=0.30.0" },
|
|
887
|
+
{ name = "fastmcp", specifier = ">=2.9.0" },
|
|
756
888
|
{ name = "httpx", specifier = ">=0.28.1" },
|
|
757
889
|
{ name = "keyring", specifier = ">=25.6.0" },
|
|
758
890
|
{ name = "pandas", specifier = ">=2.0.0" },
|
|
@@ -769,6 +901,31 @@ dev = [
|
|
|
769
901
|
{ name = "ruff", specifier = ">=0.12.0" },
|
|
770
902
|
]
|
|
771
903
|
|
|
904
|
+
[[package]]
|
|
905
|
+
name = "sse-starlette"
|
|
906
|
+
version = "2.3.6"
|
|
907
|
+
source = { registry = "https://pypi.org/simple" }
|
|
908
|
+
dependencies = [
|
|
909
|
+
{ name = "anyio" },
|
|
910
|
+
]
|
|
911
|
+
sdist = { url = "https://files.pythonhosted.org/packages/8c/f4/989bc70cb8091eda43a9034ef969b25145291f3601703b82766e5172dfed/sse_starlette-2.3.6.tar.gz", hash = "sha256:0382336f7d4ec30160cf9ca0518962905e1b69b72d6c1c995131e0a703b436e3", size = 18284 }
|
|
912
|
+
wheels = [
|
|
913
|
+
{ url = "https://files.pythonhosted.org/packages/81/05/78850ac6e79af5b9508f8841b0f26aa9fd329a1ba00bf65453c2d312bcc8/sse_starlette-2.3.6-py3-none-any.whl", hash = "sha256:d49a8285b182f6e2228e2609c350398b2ca2c36216c2675d875f81e93548f760", size = 10606 },
|
|
914
|
+
]
|
|
915
|
+
|
|
916
|
+
[[package]]
|
|
917
|
+
name = "starlette"
|
|
918
|
+
version = "0.47.1"
|
|
919
|
+
source = { registry = "https://pypi.org/simple" }
|
|
920
|
+
dependencies = [
|
|
921
|
+
{ name = "anyio" },
|
|
922
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
|
923
|
+
]
|
|
924
|
+
sdist = { url = "https://files.pythonhosted.org/packages/0a/69/662169fdb92fb96ec3eaee218cf540a629d629c86d7993d9651226a6789b/starlette-0.47.1.tar.gz", hash = "sha256:aef012dd2b6be325ffa16698f9dc533614fb1cebd593a906b90dc1025529a79b", size = 2583072 }
|
|
925
|
+
wheels = [
|
|
926
|
+
{ url = "https://files.pythonhosted.org/packages/82/95/38ef0cd7fa11eaba6a99b3c4f5ac948d8bc6ff199aabd327a29cc000840c/starlette-0.47.1-py3-none-any.whl", hash = "sha256:5e11c9f5c7c3f24959edbf2dffdc01bba860228acf657129467d8a7468591527", size = 72747 },
|
|
927
|
+
]
|
|
928
|
+
|
|
772
929
|
[[package]]
|
|
773
930
|
name = "typer"
|
|
774
931
|
version = "0.16.0"
|
|
@@ -814,6 +971,19 @@ wheels = [
|
|
|
814
971
|
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 },
|
|
815
972
|
]
|
|
816
973
|
|
|
974
|
+
[[package]]
|
|
975
|
+
name = "uvicorn"
|
|
976
|
+
version = "0.34.3"
|
|
977
|
+
source = { registry = "https://pypi.org/simple" }
|
|
978
|
+
dependencies = [
|
|
979
|
+
{ name = "click" },
|
|
980
|
+
{ name = "h11" },
|
|
981
|
+
]
|
|
982
|
+
sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631 }
|
|
983
|
+
wheels = [
|
|
984
|
+
{ url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431 },
|
|
985
|
+
]
|
|
986
|
+
|
|
817
987
|
[[package]]
|
|
818
988
|
name = "wcwidth"
|
|
819
989
|
version = "0.2.13"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|