awslabs.redshift-mcp-server 0.0.4__tar.gz → 0.0.7__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.
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/PKG-INFO +39 -5
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/README.md +38 -4
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/awslabs/redshift_mcp_server/__init__.py +1 -1
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/awslabs/redshift_mcp_server/consts.py +16 -8
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/awslabs/redshift_mcp_server/redshift.py +42 -50
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/awslabs/redshift_mcp_server/server.py +1 -1
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/pyproject.toml +1 -1
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/tests/test_redshift.py +53 -73
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/tests/test_server.py +1 -0
- awslabs_redshift_mcp_server-0.0.7/uv-requirements.txt +24 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/uv.lock +668 -668
- awslabs_redshift_mcp_server-0.0.4/uv-requirements.txt +0 -26
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/.gitignore +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/.python-version +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/CHANGELOG.md +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/Dockerfile +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/LICENSE +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/NOTICE +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/awslabs/__init__.py +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/awslabs/redshift_mcp_server/models.py +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/docker-healthcheck.sh +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/tests/test_init.py +0 -0
- {awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/tests/test_main.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: awslabs.redshift-mcp-server
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: An AWS Labs Model Context Protocol (MCP) server for Redshift
|
|
5
5
|
Project-URL: homepage, https://awslabs.github.io/mcp/
|
|
6
6
|
Project-URL: docs, https://awslabs.github.io/mcp/servers/redshift-mcp-server/
|
|
@@ -52,7 +52,11 @@ This MCP server provides tools to discover, explore, and query Amazon Redshift c
|
|
|
52
52
|
### AWS Client Requirements
|
|
53
53
|
|
|
54
54
|
1. **Credentials**: Configure AWS credentials via AWS CLI, or environment variables
|
|
55
|
-
2. **
|
|
55
|
+
2. **Region**: Configure AWS region using one of the following (in order of precedence):
|
|
56
|
+
- `AWS_REGION` environment variable (highest priority)
|
|
57
|
+
- `AWS_DEFAULT_REGION` environment variable
|
|
58
|
+
- Region specified in your AWS profile configuration
|
|
59
|
+
3. **Permissions**: Ensure your AWS credentials have the required permissions (see [Permissions](#permissions) section)
|
|
56
60
|
|
|
57
61
|
## Installation
|
|
58
62
|
|
|
@@ -70,7 +74,7 @@ Configure the MCP server in your MCP client configuration (e.g., for Amazon Q De
|
|
|
70
74
|
"args": ["awslabs.redshift-mcp-server@latest"],
|
|
71
75
|
"env": {
|
|
72
76
|
"AWS_PROFILE": "default",
|
|
73
|
-
"
|
|
77
|
+
"AWS_DEFAULT_REGION": "us-east-1",
|
|
74
78
|
"FASTMCP_LOG_LEVEL": "INFO"
|
|
75
79
|
},
|
|
76
80
|
"disabled": false,
|
|
@@ -80,6 +84,35 @@ Configure the MCP server in your MCP client configuration (e.g., for Amazon Q De
|
|
|
80
84
|
}
|
|
81
85
|
```
|
|
82
86
|
|
|
87
|
+
### Windows Installation
|
|
88
|
+
|
|
89
|
+
For Windows users, the MCP server configuration format is slightly different:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"awslabs.redshift-mcp-server": {
|
|
95
|
+
"disabled": false,
|
|
96
|
+
"timeout": 60,
|
|
97
|
+
"type": "stdio",
|
|
98
|
+
"command": "uv",
|
|
99
|
+
"args": [
|
|
100
|
+
"tool",
|
|
101
|
+
"run",
|
|
102
|
+
"--from",
|
|
103
|
+
"awslabs.redshift-mcp-server@latest",
|
|
104
|
+
"awslabs.redshift-mcp-server.exe"
|
|
105
|
+
],
|
|
106
|
+
"env": {
|
|
107
|
+
"AWS_PROFILE": "your-aws-profile",
|
|
108
|
+
"AWS_DEFAULT_REGION": "us-east-1",
|
|
109
|
+
"FASTMCP_LOG_LEVEL": "ERROR"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
83
116
|
or docker after a successful `docker build -t awslabs/redshift-mcp-server:latest .`:
|
|
84
117
|
|
|
85
118
|
```json
|
|
@@ -93,7 +126,7 @@ or docker after a successful `docker build -t awslabs/redshift-mcp-server:latest
|
|
|
93
126
|
"--interactive",
|
|
94
127
|
"--env", "AWS_ACCESS_KEY_ID=[your data]",
|
|
95
128
|
"--env", "AWS_SECRET_ACCESS_KEY=[your data]",
|
|
96
|
-
"--env", "
|
|
129
|
+
"--env", "AWS_DEFAULT_REGION=[your data]",
|
|
97
130
|
"awslabs/redshift-mcp-server:latest"
|
|
98
131
|
]
|
|
99
132
|
}
|
|
@@ -103,7 +136,8 @@ or docker after a successful `docker build -t awslabs/redshift-mcp-server:latest
|
|
|
103
136
|
|
|
104
137
|
### Environment Variables
|
|
105
138
|
|
|
106
|
-
- `AWS_REGION`: AWS region to use (
|
|
139
|
+
- `AWS_REGION`: AWS region to use (overrides all other region settings)
|
|
140
|
+
- `AWS_DEFAULT_REGION`: Default AWS region (used if AWS_REGION not set and no region in profile)
|
|
107
141
|
- `AWS_PROFILE`: AWS profile to use (optional, uses default if not specified)
|
|
108
142
|
- `FASTMCP_LOG_LEVEL`: Logging level (`DEBUG`, `INFO`, `WARNING`, `ERROR`)
|
|
109
143
|
- `LOG_FILE`: Path to log file (optional, logs to stdout if not specified)
|
|
@@ -21,7 +21,11 @@ This MCP server provides tools to discover, explore, and query Amazon Redshift c
|
|
|
21
21
|
### AWS Client Requirements
|
|
22
22
|
|
|
23
23
|
1. **Credentials**: Configure AWS credentials via AWS CLI, or environment variables
|
|
24
|
-
2. **
|
|
24
|
+
2. **Region**: Configure AWS region using one of the following (in order of precedence):
|
|
25
|
+
- `AWS_REGION` environment variable (highest priority)
|
|
26
|
+
- `AWS_DEFAULT_REGION` environment variable
|
|
27
|
+
- Region specified in your AWS profile configuration
|
|
28
|
+
3. **Permissions**: Ensure your AWS credentials have the required permissions (see [Permissions](#permissions) section)
|
|
25
29
|
|
|
26
30
|
## Installation
|
|
27
31
|
|
|
@@ -39,7 +43,7 @@ Configure the MCP server in your MCP client configuration (e.g., for Amazon Q De
|
|
|
39
43
|
"args": ["awslabs.redshift-mcp-server@latest"],
|
|
40
44
|
"env": {
|
|
41
45
|
"AWS_PROFILE": "default",
|
|
42
|
-
"
|
|
46
|
+
"AWS_DEFAULT_REGION": "us-east-1",
|
|
43
47
|
"FASTMCP_LOG_LEVEL": "INFO"
|
|
44
48
|
},
|
|
45
49
|
"disabled": false,
|
|
@@ -49,6 +53,35 @@ Configure the MCP server in your MCP client configuration (e.g., for Amazon Q De
|
|
|
49
53
|
}
|
|
50
54
|
```
|
|
51
55
|
|
|
56
|
+
### Windows Installation
|
|
57
|
+
|
|
58
|
+
For Windows users, the MCP server configuration format is slightly different:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"mcpServers": {
|
|
63
|
+
"awslabs.redshift-mcp-server": {
|
|
64
|
+
"disabled": false,
|
|
65
|
+
"timeout": 60,
|
|
66
|
+
"type": "stdio",
|
|
67
|
+
"command": "uv",
|
|
68
|
+
"args": [
|
|
69
|
+
"tool",
|
|
70
|
+
"run",
|
|
71
|
+
"--from",
|
|
72
|
+
"awslabs.redshift-mcp-server@latest",
|
|
73
|
+
"awslabs.redshift-mcp-server.exe"
|
|
74
|
+
],
|
|
75
|
+
"env": {
|
|
76
|
+
"AWS_PROFILE": "your-aws-profile",
|
|
77
|
+
"AWS_DEFAULT_REGION": "us-east-1",
|
|
78
|
+
"FASTMCP_LOG_LEVEL": "ERROR"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
52
85
|
or docker after a successful `docker build -t awslabs/redshift-mcp-server:latest .`:
|
|
53
86
|
|
|
54
87
|
```json
|
|
@@ -62,7 +95,7 @@ or docker after a successful `docker build -t awslabs/redshift-mcp-server:latest
|
|
|
62
95
|
"--interactive",
|
|
63
96
|
"--env", "AWS_ACCESS_KEY_ID=[your data]",
|
|
64
97
|
"--env", "AWS_SECRET_ACCESS_KEY=[your data]",
|
|
65
|
-
"--env", "
|
|
98
|
+
"--env", "AWS_DEFAULT_REGION=[your data]",
|
|
66
99
|
"awslabs/redshift-mcp-server:latest"
|
|
67
100
|
]
|
|
68
101
|
}
|
|
@@ -72,7 +105,8 @@ or docker after a successful `docker build -t awslabs/redshift-mcp-server:latest
|
|
|
72
105
|
|
|
73
106
|
### Environment Variables
|
|
74
107
|
|
|
75
|
-
- `AWS_REGION`: AWS region to use (
|
|
108
|
+
- `AWS_REGION`: AWS region to use (overrides all other region settings)
|
|
109
|
+
- `AWS_DEFAULT_REGION`: Default AWS region (used if AWS_REGION not set and no region in profile)
|
|
76
110
|
- `AWS_PROFILE`: AWS profile to use (optional, uses default if not specified)
|
|
77
111
|
- `FASTMCP_LOG_LEVEL`: Logging level (`DEBUG`, `INFO`, `WARNING`, `ERROR`)
|
|
78
112
|
- `LOG_FILE`: Path to log file (optional, logs to stdout if not specified)
|
|
@@ -14,13 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
"""Redshift MCP Server constants."""
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
|
|
17
|
+
# System
|
|
18
|
+
CLIENT_CONNECT_TIMEOUT = 60
|
|
19
|
+
CLIENT_READ_TIMEOUT = 600
|
|
20
|
+
CLIENT_RETRIES = {'max_attempts': 5, 'mode': 'adaptive'}
|
|
21
|
+
CLIENT_USER_AGENT_NAME = 'awslabs/mcp/redshift-mcp-server'
|
|
19
22
|
DEFAULT_LOG_LEVEL = 'WARNING'
|
|
20
|
-
|
|
21
|
-
# Timeouts (seconds), etc
|
|
22
|
-
CLIENT_TIMEOUT = 60
|
|
23
|
-
DATA_CLIENT_TIMEOUT = 60
|
|
24
23
|
QUERY_TIMEOUT = 3600
|
|
25
24
|
QUERY_POLL_INTERVAL = 2
|
|
26
25
|
|
|
@@ -29,11 +28,20 @@ QUERY_POLL_INTERVAL = 2
|
|
|
29
28
|
CLIENT_BEST_PRACTICES = """
|
|
30
29
|
## AWS Client Best Practices
|
|
31
30
|
|
|
32
|
-
### Authentication
|
|
31
|
+
### Authentication and Configuration
|
|
33
32
|
|
|
34
33
|
- Default AWS credentials chain (IAM roles, ~/.aws/credentials, etc.).
|
|
35
34
|
- AWS_PROFILE environment variable (if set).
|
|
36
|
-
-
|
|
35
|
+
- Region configuration (in order of precedence):
|
|
36
|
+
- AWS_REGION environment variable (highest priority)
|
|
37
|
+
- AWS_DEFAULT_REGION environment variable
|
|
38
|
+
- Region specified in AWS profile configuration
|
|
39
|
+
|
|
40
|
+
### Error Handling
|
|
41
|
+
|
|
42
|
+
- Always print out AWS client errors in full to help diagnose configuration issues.
|
|
43
|
+
- For region-related errors, suggest checking AWS_REGION, AWS_DEFAULT_REGION, or AWS profile configuration.
|
|
44
|
+
- For credential errors, suggest verifying AWS credentials setup and permissions.
|
|
37
45
|
"""
|
|
38
46
|
|
|
39
47
|
REDSHIFT_BEST_PRACTICES = """
|
|
@@ -20,8 +20,10 @@ import os
|
|
|
20
20
|
import regex
|
|
21
21
|
from awslabs.redshift_mcp_server import __version__
|
|
22
22
|
from awslabs.redshift_mcp_server.consts import (
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
CLIENT_CONNECT_TIMEOUT,
|
|
24
|
+
CLIENT_READ_TIMEOUT,
|
|
25
|
+
CLIENT_RETRIES,
|
|
26
|
+
CLIENT_USER_AGENT_NAME,
|
|
25
27
|
QUERY_POLL_INTERVAL,
|
|
26
28
|
QUERY_TIMEOUT,
|
|
27
29
|
SUSPICIOUS_QUERY_REGEXP,
|
|
@@ -37,7 +39,9 @@ from loguru import logger
|
|
|
37
39
|
class RedshiftClientManager:
|
|
38
40
|
"""Manages AWS clients for Redshift operations."""
|
|
39
41
|
|
|
40
|
-
def __init__(
|
|
42
|
+
def __init__(
|
|
43
|
+
self, config: Config, aws_region: str | None = None, aws_profile: str | None = None
|
|
44
|
+
):
|
|
41
45
|
"""Initialize the client manager."""
|
|
42
46
|
self.aws_region = aws_region
|
|
43
47
|
self.aws_profile = aws_profile
|
|
@@ -50,15 +54,12 @@ class RedshiftClientManager:
|
|
|
50
54
|
"""Get or create the Redshift client for provisioned clusters."""
|
|
51
55
|
if self._redshift_client is None:
|
|
52
56
|
try:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
'redshift', config=self._config, region_name=self.aws_region
|
|
60
|
-
)
|
|
61
|
-
logger.info('Created Redshift client with default credentials')
|
|
57
|
+
# Session works with None values - uses default credentials/region chain
|
|
58
|
+
session = boto3.Session(profile_name=self.aws_profile, region_name=self.aws_region)
|
|
59
|
+
self._redshift_client = session.client('redshift', config=self._config)
|
|
60
|
+
logger.info(
|
|
61
|
+
f'Created Redshift client with profile: {self.aws_profile or "default"}, region: {self.aws_region or "default"}'
|
|
62
|
+
)
|
|
62
63
|
except Exception as e:
|
|
63
64
|
logger.error(f'Error creating Redshift client: {str(e)}')
|
|
64
65
|
raise
|
|
@@ -69,19 +70,14 @@ class RedshiftClientManager:
|
|
|
69
70
|
"""Get or create the Redshift Serverless client."""
|
|
70
71
|
if self._redshift_serverless_client is None:
|
|
71
72
|
try:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
else:
|
|
81
|
-
self._redshift_serverless_client = boto3.client(
|
|
82
|
-
'redshift-serverless', config=self._config, region_name=self.aws_region
|
|
83
|
-
)
|
|
84
|
-
logger.info('Created Redshift Serverless client with default credentials')
|
|
73
|
+
# Session works with None values - uses default credentials/region chain
|
|
74
|
+
session = boto3.Session(profile_name=self.aws_profile, region_name=self.aws_region)
|
|
75
|
+
self._redshift_serverless_client = session.client(
|
|
76
|
+
'redshift-serverless', config=self._config
|
|
77
|
+
)
|
|
78
|
+
logger.info(
|
|
79
|
+
f'Created Redshift Serverless client with profile: {self.aws_profile or "default"}, region: {self.aws_region or "default"}'
|
|
80
|
+
)
|
|
85
81
|
except Exception as e:
|
|
86
82
|
logger.error(f'Error creating Redshift Serverless client: {str(e)}')
|
|
87
83
|
raise
|
|
@@ -92,19 +88,12 @@ class RedshiftClientManager:
|
|
|
92
88
|
"""Get or create the Redshift Data API client."""
|
|
93
89
|
if self._redshift_data_client is None:
|
|
94
90
|
try:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
f'Created Redshift Data API client with profile: {self.aws_profile}'
|
|
102
|
-
)
|
|
103
|
-
else:
|
|
104
|
-
self._redshift_data_client = boto3.client(
|
|
105
|
-
'redshift-data', config=self._config, region_name=self.aws_region
|
|
106
|
-
)
|
|
107
|
-
logger.info('Created Redshift Data API client with default credentials')
|
|
91
|
+
# Session works with None values - uses default credentials/region chain
|
|
92
|
+
session = boto3.Session(profile_name=self.aws_profile, region_name=self.aws_region)
|
|
93
|
+
self._redshift_data_client = session.client('redshift-data', config=self._config)
|
|
94
|
+
logger.info(
|
|
95
|
+
f'Created Redshift Data API client with profile: {self.aws_profile or "default"}, region: {self.aws_region or "default"}'
|
|
96
|
+
)
|
|
108
97
|
except Exception as e:
|
|
109
98
|
logger.error(f'Error creating Redshift Data API client: {str(e)}')
|
|
110
99
|
raise
|
|
@@ -193,19 +182,22 @@ async def execute_statement(
|
|
|
193
182
|
)
|
|
194
183
|
|
|
195
184
|
# Guard from executing read-write statements if not allowed
|
|
196
|
-
|
|
197
|
-
|
|
185
|
+
sqls = protect_sql(sql, allow_read_write)
|
|
186
|
+
# Add application name and version
|
|
187
|
+
sqls = [f"SET application_name TO '{CLIENT_USER_AGENT_NAME}/{__version__}';"] + sqls
|
|
188
|
+
|
|
189
|
+
logger.debug(f'Protected and versioned SQL: {" ".join(sqls)}')
|
|
198
190
|
|
|
199
191
|
# Execute the query using Data API
|
|
200
192
|
if cluster_info['type'] == 'provisioned':
|
|
201
193
|
logger.debug(f'Using ClusterIdentifier for provisioned cluster: {cluster_identifier}')
|
|
202
194
|
response = data_client.batch_execute_statement(
|
|
203
|
-
ClusterIdentifier=cluster_identifier, Database=database_name, Sqls=
|
|
195
|
+
ClusterIdentifier=cluster_identifier, Database=database_name, Sqls=sqls
|
|
204
196
|
)
|
|
205
197
|
elif cluster_info['type'] == 'serverless':
|
|
206
198
|
logger.debug(f'Using WorkgroupName for serverless workgroup: {cluster_identifier}')
|
|
207
199
|
response = data_client.batch_execute_statement(
|
|
208
|
-
WorkgroupName=cluster_identifier, Database=database_name, Sqls=
|
|
200
|
+
WorkgroupName=cluster_identifier, Database=database_name, Sqls=sqls
|
|
209
201
|
)
|
|
210
202
|
else:
|
|
211
203
|
raise Exception(f'Unknown cluster type: {cluster_info["type"]}')
|
|
@@ -237,9 +229,9 @@ async def execute_statement(
|
|
|
237
229
|
raise Exception(f'Query timed out after {QUERY_TIMEOUT} seconds')
|
|
238
230
|
|
|
239
231
|
# Get user query results
|
|
240
|
-
|
|
241
|
-
results_response = data_client.get_statement_result(Id=
|
|
242
|
-
return results_response,
|
|
232
|
+
subquery2_id = status_response['SubStatements'][2]['Id']
|
|
233
|
+
results_response = data_client.get_statement_result(Id=subquery2_id)
|
|
234
|
+
return results_response, subquery2_id
|
|
243
235
|
|
|
244
236
|
|
|
245
237
|
async def discover_clusters() -> list[dict]:
|
|
@@ -620,11 +612,11 @@ async def execute_query(cluster_identifier: str, database_name: str, sql: str) -
|
|
|
620
612
|
# Global client manager instance
|
|
621
613
|
client_manager = RedshiftClientManager(
|
|
622
614
|
config=Config(
|
|
623
|
-
connect_timeout=
|
|
624
|
-
read_timeout=
|
|
625
|
-
retries=
|
|
626
|
-
user_agent_extra=f'
|
|
615
|
+
connect_timeout=CLIENT_CONNECT_TIMEOUT,
|
|
616
|
+
read_timeout=CLIENT_READ_TIMEOUT,
|
|
617
|
+
retries=CLIENT_RETRIES,
|
|
618
|
+
user_agent_extra=f'{CLIENT_USER_AGENT_NAME}/{__version__}',
|
|
627
619
|
),
|
|
628
|
-
aws_region=os.environ.get('AWS_REGION'
|
|
620
|
+
aws_region=os.environ.get('AWS_REGION'),
|
|
629
621
|
aws_profile=os.environ.get('AWS_PROFILE'),
|
|
630
622
|
)
|
|
@@ -85,7 +85,7 @@ This tool uses the Redshift Data API to run queries and return results.
|
|
|
85
85
|
|
|
86
86
|
## Getting Started
|
|
87
87
|
|
|
88
|
-
1. Ensure your AWS credentials are configured (
|
|
88
|
+
1. Ensure your AWS configuration and credentials are configured (environment variables or profile configuration file).
|
|
89
89
|
2. Use the list_clusters tool to discover available Redshift instances.
|
|
90
90
|
3. Note the cluster identifiers for use with other tools (coming in future milestones).
|
|
91
91
|
|
{awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/tests/test_redshift.py
RENAMED
|
@@ -29,21 +29,21 @@ class TestRedshiftClientManagerRedshiftClient:
|
|
|
29
29
|
def test_redshift_client_creation_default_credentials(self, mocker):
|
|
30
30
|
"""Test Redshift client creation with default credentials."""
|
|
31
31
|
mock_client = mocker.Mock()
|
|
32
|
-
|
|
32
|
+
mock_boto3_session = mocker.patch('boto3.Session')
|
|
33
|
+
mock_boto3_session.return_value.client.return_value = mock_client
|
|
33
34
|
|
|
34
35
|
config = Config()
|
|
35
|
-
manager = RedshiftClientManager(config
|
|
36
|
+
manager = RedshiftClientManager(config)
|
|
36
37
|
client = manager.redshift_client()
|
|
37
38
|
|
|
38
39
|
assert client == mock_client
|
|
39
40
|
|
|
40
|
-
# Verify boto3.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
41
|
+
# Verify boto3.Session was called with correct parameters
|
|
42
|
+
mock_boto3_session.assert_called_once_with(profile_name=None, region_name=None)
|
|
43
|
+
mock_boto3_session.return_value.client.assert_called_once_with('redshift', config=config)
|
|
44
44
|
|
|
45
|
-
def
|
|
46
|
-
"""Test Redshift client creation with AWS profile."""
|
|
45
|
+
def test_redshift_client_creation_with_profile_and_region(self, mocker):
|
|
46
|
+
"""Test Redshift client creation with AWS profile and region."""
|
|
47
47
|
mock_session = mocker.Mock()
|
|
48
48
|
mock_client = mocker.Mock()
|
|
49
49
|
mock_session.client.return_value = mock_client
|
|
@@ -55,28 +55,20 @@ class TestRedshiftClientManagerRedshiftClient:
|
|
|
55
55
|
|
|
56
56
|
assert client == mock_client
|
|
57
57
|
|
|
58
|
-
# Verify session was created with profile and
|
|
59
|
-
mock_session_class.assert_called_once_with(
|
|
58
|
+
# Verify session was created with profile and region
|
|
59
|
+
mock_session_class.assert_called_once_with(
|
|
60
|
+
profile_name='test-profile', region_name='us-west-2'
|
|
61
|
+
)
|
|
60
62
|
mock_session.client.assert_called_once_with('redshift', config=config)
|
|
61
63
|
|
|
62
|
-
def
|
|
63
|
-
"""Test error handling when
|
|
64
|
-
mocker.patch('boto3.
|
|
65
|
-
|
|
66
|
-
config = Config()
|
|
67
|
-
manager = RedshiftClientManager(config, 'us-east-1')
|
|
68
|
-
|
|
69
|
-
with pytest.raises(Exception, match='Credentials error'):
|
|
70
|
-
manager.redshift_client()
|
|
71
|
-
|
|
72
|
-
def test_redshift_client_creation_error_with_profile(self, mocker):
|
|
73
|
-
"""Test error handling when session creation fails with profile."""
|
|
74
|
-
mocker.patch('boto3.Session', side_effect=Exception('Profile not found'))
|
|
64
|
+
def test_redshift_client_creation_error(self, mocker):
|
|
65
|
+
"""Test error handling when session creation fails."""
|
|
66
|
+
mocker.patch('boto3.Session', side_effect=Exception('Session error'))
|
|
75
67
|
|
|
76
68
|
config = Config()
|
|
77
|
-
manager = RedshiftClientManager(config
|
|
69
|
+
manager = RedshiftClientManager(config)
|
|
78
70
|
|
|
79
|
-
with pytest.raises(Exception, match='
|
|
71
|
+
with pytest.raises(Exception, match='Session error'):
|
|
80
72
|
manager.redshift_client()
|
|
81
73
|
|
|
82
74
|
|
|
@@ -86,21 +78,23 @@ class TestRedshiftClientManagerServerlessClient:
|
|
|
86
78
|
def test_redshift_serverless_client_creation_default_credentials(self, mocker):
|
|
87
79
|
"""Test Redshift Serverless client creation with default credentials."""
|
|
88
80
|
mock_client = mocker.Mock()
|
|
89
|
-
|
|
81
|
+
mock_boto3_session = mocker.patch('boto3.Session')
|
|
82
|
+
mock_boto3_session.return_value.client.return_value = mock_client
|
|
90
83
|
|
|
91
84
|
config = Config()
|
|
92
|
-
manager = RedshiftClientManager(config
|
|
85
|
+
manager = RedshiftClientManager(config)
|
|
93
86
|
client = manager.redshift_serverless_client()
|
|
94
87
|
|
|
95
88
|
assert client == mock_client
|
|
96
89
|
|
|
97
|
-
# Verify boto3.
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
# Verify boto3.Session was called with correct parameters
|
|
91
|
+
mock_boto3_session.assert_called_once_with(profile_name=None, region_name=None)
|
|
92
|
+
mock_boto3_session.return_value.client.assert_called_once_with(
|
|
93
|
+
'redshift-serverless', config=config
|
|
100
94
|
)
|
|
101
95
|
|
|
102
|
-
def
|
|
103
|
-
"""Test Redshift Serverless client creation with AWS profile."""
|
|
96
|
+
def test_redshift_serverless_client_creation_with_profile_and_region(self, mocker):
|
|
97
|
+
"""Test Redshift Serverless client creation with AWS profile and region."""
|
|
104
98
|
mock_session = mocker.Mock()
|
|
105
99
|
mock_client = mocker.Mock()
|
|
106
100
|
mock_session.client.return_value = mock_client
|
|
@@ -112,28 +106,20 @@ class TestRedshiftClientManagerServerlessClient:
|
|
|
112
106
|
|
|
113
107
|
assert client == mock_client
|
|
114
108
|
|
|
115
|
-
# Verify session was created with profile and
|
|
116
|
-
mock_session_class.assert_called_once_with(
|
|
109
|
+
# Verify session was created with profile and region
|
|
110
|
+
mock_session_class.assert_called_once_with(
|
|
111
|
+
profile_name='test-profile', region_name='us-west-2'
|
|
112
|
+
)
|
|
117
113
|
mock_session.client.assert_called_once_with('redshift-serverless', config=config)
|
|
118
114
|
|
|
119
|
-
def
|
|
120
|
-
"""Test error handling when
|
|
121
|
-
mocker.patch('boto3.
|
|
115
|
+
def test_redshift_serverless_client_creation_error(self, mocker):
|
|
116
|
+
"""Test error handling when session creation fails."""
|
|
117
|
+
mocker.patch('boto3.Session', side_effect=Exception('Session error'))
|
|
122
118
|
|
|
123
119
|
config = Config()
|
|
124
|
-
manager = RedshiftClientManager(config
|
|
120
|
+
manager = RedshiftClientManager(config)
|
|
125
121
|
|
|
126
|
-
with pytest.raises(Exception, match='
|
|
127
|
-
manager.redshift_serverless_client()
|
|
128
|
-
|
|
129
|
-
def test_redshift_serverless_client_creation_error_with_profile(self, mocker):
|
|
130
|
-
"""Test error handling when session creation fails with profile."""
|
|
131
|
-
mocker.patch('boto3.Session', side_effect=Exception('Profile not found'))
|
|
132
|
-
|
|
133
|
-
config = Config()
|
|
134
|
-
manager = RedshiftClientManager(config, 'us-east-1', 'non-existent-profile')
|
|
135
|
-
|
|
136
|
-
with pytest.raises(Exception, match='Profile not found'):
|
|
122
|
+
with pytest.raises(Exception, match='Session error'):
|
|
137
123
|
manager.redshift_serverless_client()
|
|
138
124
|
|
|
139
125
|
|
|
@@ -143,21 +129,23 @@ class TestRedshiftClientManagerDataClient:
|
|
|
143
129
|
def test_redshift_data_client_creation_default_credentials(self, mocker):
|
|
144
130
|
"""Test Redshift Data API client creation with default credentials."""
|
|
145
131
|
mock_client = mocker.Mock()
|
|
146
|
-
|
|
132
|
+
mock_boto3_session = mocker.patch('boto3.Session')
|
|
133
|
+
mock_boto3_session.return_value.client.return_value = mock_client
|
|
147
134
|
|
|
148
135
|
config = Config()
|
|
149
|
-
manager = RedshiftClientManager(config
|
|
136
|
+
manager = RedshiftClientManager(config)
|
|
150
137
|
client = manager.redshift_data_client()
|
|
151
138
|
|
|
152
139
|
assert client == mock_client
|
|
153
140
|
|
|
154
|
-
# Verify boto3.
|
|
155
|
-
|
|
156
|
-
|
|
141
|
+
# Verify boto3.Session was called with correct parameters
|
|
142
|
+
mock_boto3_session.assert_called_once_with(profile_name=None, region_name=None)
|
|
143
|
+
mock_boto3_session.return_value.client.assert_called_once_with(
|
|
144
|
+
'redshift-data', config=config
|
|
157
145
|
)
|
|
158
146
|
|
|
159
|
-
def
|
|
160
|
-
"""Test Redshift Data API client creation with AWS profile."""
|
|
147
|
+
def test_redshift_data_client_creation_with_profile_and_region(self, mocker):
|
|
148
|
+
"""Test Redshift Data API client creation with AWS profile and region."""
|
|
161
149
|
mock_session = mocker.Mock()
|
|
162
150
|
mock_client = mocker.Mock()
|
|
163
151
|
mock_session.client.return_value = mock_client
|
|
@@ -169,28 +157,20 @@ class TestRedshiftClientManagerDataClient:
|
|
|
169
157
|
|
|
170
158
|
assert client == mock_client
|
|
171
159
|
|
|
172
|
-
# Verify session was created with profile and
|
|
173
|
-
mock_session_class.assert_called_once_with(
|
|
160
|
+
# Verify session was created with profile and region
|
|
161
|
+
mock_session_class.assert_called_once_with(
|
|
162
|
+
profile_name='test-profile', region_name='us-west-2'
|
|
163
|
+
)
|
|
174
164
|
mock_session.client.assert_called_once_with('redshift-data', config=config)
|
|
175
165
|
|
|
176
|
-
def
|
|
177
|
-
"""Test error handling when
|
|
178
|
-
mocker.patch('boto3.
|
|
179
|
-
|
|
180
|
-
config = Config()
|
|
181
|
-
manager = RedshiftClientManager(config, 'us-east-1')
|
|
182
|
-
|
|
183
|
-
with pytest.raises(Exception, match='Credentials error'):
|
|
184
|
-
manager.redshift_data_client()
|
|
185
|
-
|
|
186
|
-
def test_redshift_data_client_creation_error_with_profile(self, mocker):
|
|
187
|
-
"""Test error handling when session creation fails with profile."""
|
|
188
|
-
mocker.patch('boto3.Session', side_effect=Exception('Profile not found'))
|
|
166
|
+
def test_redshift_data_client_creation_error(self, mocker):
|
|
167
|
+
"""Test error handling when session creation fails."""
|
|
168
|
+
mocker.patch('boto3.Session', side_effect=Exception('Session error'))
|
|
189
169
|
|
|
190
170
|
config = Config()
|
|
191
|
-
manager = RedshiftClientManager(config
|
|
171
|
+
manager = RedshiftClientManager(config)
|
|
192
172
|
|
|
193
|
-
with pytest.raises(Exception, match='
|
|
173
|
+
with pytest.raises(Exception, match='Session error'):
|
|
194
174
|
manager.redshift_data_client()
|
|
195
175
|
|
|
196
176
|
|
{awslabs_redshift_mcp_server-0.0.4 → awslabs_redshift_mcp_server-0.0.7}/tests/test_server.py
RENAMED
|
@@ -815,6 +815,7 @@ class TestExecuteQueryTool:
|
|
|
815
815
|
mock_data_client.describe_statement.return_value = {
|
|
816
816
|
'Status': 'FINISHED',
|
|
817
817
|
'SubStatements': [
|
|
818
|
+
{'Id': 'set-app-name'}, # SET application_name
|
|
818
819
|
{'Id': 'sub-query-0'}, # BEGIN READ ONLY
|
|
819
820
|
{'Id': 'query-123'}, # Our actual SQL query
|
|
820
821
|
{'Id': 'sub-query-2'}, # END
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# This file was autogenerated by uv via the following command:
|
|
2
|
+
# echo "uv==0.8.10" > uv-requirements.in
|
|
3
|
+
# uv pip compile --generate-hashes --output-file=uv-requirements.txt --strip-extras --python=3.10 uv-requirements.in
|
|
4
|
+
uv==0.8.10 \
|
|
5
|
+
--hash=sha256:31e4fc37ee94b94c032384a0957ad32ba7dce4ce6c04b4880fd3e31e25e51a82 \
|
|
6
|
+
--hash=sha256:36a5ce708d52388c37043e7335f9eb3fea5a19a56166a2cc6adb365179a1cd77 \
|
|
7
|
+
--hash=sha256:38286d230daad82388469c8dc7a1d2f5dc279c11178319c886d1a88d7938e513 \
|
|
8
|
+
--hash=sha256:3e190cee3bb2b4f574a419eef87ae8e33f713e9cd6f856b83277ece70ad9ca9b \
|
|
9
|
+
--hash=sha256:3fdf89fc40af9902141c39ed943bcfca15664623363335eb032a44f22001e2b4 \
|
|
10
|
+
--hash=sha256:4cc190d403a89e46d13cec83b6f8e8d7d07aaf1e5a996eac9a3f0c2a8cd92537 \
|
|
11
|
+
--hash=sha256:57b71dc79eff25a5419d3fe4a563d3b9397f55d789f685ef27f43f033b31f482 \
|
|
12
|
+
--hash=sha256:86fe044c2be43977566a0d184a487edd7aace2febb757fd95927684b629ef50b \
|
|
13
|
+
--hash=sha256:88df34c32555064fae459cce665757619fd1af7deb2dc393352b15d909d2d131 \
|
|
14
|
+
--hash=sha256:9ad21eeaa4156a1bf5ed85903f80db06e2c02badd3a587ba98d3171517960555 \
|
|
15
|
+
--hash=sha256:a5495b5a6e3111c03cf5e4dbdd598bc8fd1da887e3920d58cd5a2d4c8bc9a473 \
|
|
16
|
+
--hash=sha256:ab072cd3bf2f9dc264659a1ff48ad91a910ac4830bcfe965e2d3f89c86646f46 \
|
|
17
|
+
--hash=sha256:af8a5526b0e331775a264fa0dbccfd53c183cb974f269a208af136d7561f9eb2 \
|
|
18
|
+
--hash=sha256:b00637c63d5dfc9f879281c5c91db2bb909ab1f9ab275dab015e7fb6cac6be5b \
|
|
19
|
+
--hash=sha256:b3ff3c451fcd23ea78356d8c18e802d0e423cbe655273601e3ec039a51b33286 \
|
|
20
|
+
--hash=sha256:c4a493cd4b15b3aef11523531aff96a77a586666a63e842fa437966b7b7ee62d \
|
|
21
|
+
--hash=sha256:defc50bb319be2d58be74a680710cd4b7697e88d5f79974eacd354df95f0b6b0 \
|
|
22
|
+
--hash=sha256:e0a02bcec766eb0862b7082ab746b204add7d9fcaa62322502d159b5a7ccc54a \
|
|
23
|
+
--hash=sha256:eb79a46d8099f563ef58237bf4e9009f876a40145e757ea883a92b24b724d01e
|
|
24
|
+
# via -r uv-requirements.in
|