Skip to content

Commit 9a58230

Browse files
AIP-308: Add user/password authentication support for Redshift MCP
- Added RedshiftAuthConfig model for authentication configuration - Added support for user/password authentication in execute_statement function - Updated tool definitions to include authentication parameters - Updated documentation to reflect new authentication options Co-authored-by: Daniel Foguelman <>
1 parent 71b328c commit 9a58230

File tree

5 files changed

+94
-7
lines changed

5 files changed

+94
-7
lines changed

src/redshift-mcp-server/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This MCP server provides tools to discover, explore, and query Amazon Redshift c
99
- **Cluster Discovery**: Automatically discover both provisioned Redshift clusters and serverless workgroups
1010
- **Metadata Exploration**: Browse databases, schemas, tables, and columns
1111
- **Safe Query Execution**: Execute SQL queries in a READ ONLY mode (a safe READ WRITE support is planned to be implemnted in the future versions)
12+
- **Multiple Authentication Methods**: Support for both IAM authentication and username/password authentication
1213
- **Multi-Cluster Support**: Work with multiple clusters and workgroups simultaneously
1314

1415
## Prerequisites
@@ -27,6 +28,19 @@ This MCP server provides tools to discover, explore, and query Amazon Redshift c
2728
- Region specified in your AWS profile configuration
2829
3. **Permissions**: Ensure your AWS credentials have the required permissions (see [Permissions](#permissions) section)
2930

31+
### Authentication Methods
32+
33+
1. **IAM Authentication** (Default): Uses AWS IAM credentials to authenticate with Redshift
34+
- Requires appropriate IAM permissions for Redshift Data API
35+
- No additional configuration needed beyond AWS credentials
36+
37+
2. **Username/Password Authentication**: Uses database credentials to authenticate
38+
- Set the following environment variables:
39+
- `REDSHIFT_AUTH_TYPE=user_password`
40+
- `REDSHIFT_USERNAME=<your-username>`
41+
- `REDSHIFT_PASSWORD=<your-password>`
42+
- Or provide these parameters directly to the MCP tools
43+
3044
## Installation
3145

3246
| Cursor | VS Code |

src/redshift-mcp-server/awslabs/redshift_mcp_server/consts.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414

1515
"""Redshift MCP Server constants."""
1616

17+
# Authentication
18+
AUTH_TYPE_IAM = "iam"
19+
AUTH_TYPE_USER_PASSWORD = "user_password"
20+
DEFAULT_AUTH_TYPE = AUTH_TYPE_IAM
21+
1722
# System
1823
CLIENT_CONNECT_TIMEOUT = 60
1924
CLIENT_READ_TIMEOUT = 600
@@ -59,6 +64,7 @@
5964
6065
- We are use the Redshift API and Redshift Data API.
6166
- Leverage IAM authentication when possible instead of secrets (database passwords).
67+
- When IAM authentication is not available, user/password authentication can be used as an alternative.
6268
"""
6369

6470
# SQL queries

src/redshift-mcp-server/awslabs/redshift_mcp_server/models.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,23 @@ class RedshiftCluster(BaseModel):
3838
tags: Optional[Dict[str, str]] = Field(
3939
default_factory=dict, description='Tags associated with the cluster'
4040
)
41+
auth_type: Optional[str] = Field(
42+
None, description='Authentication type (iam or user_password)'
43+
)
44+
45+
46+
class RedshiftAuthConfig(BaseModel):
47+
"""Authentication configuration for Redshift connections."""
48+
49+
auth_type: str = Field(
50+
'iam', description='Authentication type (iam or user_password)'
51+
)
52+
username: Optional[str] = Field(
53+
None, description='Username for user/password authentication'
54+
)
55+
password: Optional[str] = Field(
56+
None, description='Password for user/password authentication'
57+
)
4158

4259

4360
class RedshiftDatabase(BaseModel):

src/redshift-mcp-server/awslabs/redshift_mcp_server/redshift.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import regex
2121
from awslabs.redshift_mcp_server import __version__
2222
from awslabs.redshift_mcp_server.consts import (
23+
AUTH_TYPE_IAM,
24+
AUTH_TYPE_USER_PASSWORD,
25+
DEFAULT_AUTH_TYPE,
2326
CLIENT_CONNECT_TIMEOUT,
2427
CLIENT_READ_TIMEOUT,
2528
CLIENT_RETRIES,
@@ -40,11 +43,15 @@ class RedshiftClientManager:
4043
"""Manages AWS clients for Redshift operations."""
4144

4245
def __init__(
43-
self, config: Config, aws_region: str | None = None, aws_profile: str | None = None
46+
self, config: Config, aws_region: str | None = None, aws_profile: str | None = None,
47+
auth_type: str | None = None, username: str | None = None, password: str | None = None
4448
):
4549
"""Initialize the client manager."""
4650
self.aws_region = aws_region
4751
self.aws_profile = aws_profile
52+
self.auth_type = auth_type
53+
self.username = username
54+
self.password = password
4855
self._redshift_client = None
4956
self._redshift_serverless_client = None
5057
self._redshift_data_client = None
@@ -189,18 +196,34 @@ async def execute_statement(
189196
logger.debug(f'Protected and versioned SQL: {" ".join(sqls)}')
190197

191198
# Execute the query using Data API
199+
auth_type = os.environ.get("REDSHIFT_AUTH_TYPE", "iam")
200+
username = os.environ.get("REDSHIFT_USERNAME")
201+
password = os.environ.get("REDSHIFT_PASSWORD")
202+
203+
# Prepare common parameters
204+
params = {
205+
"Database": database_name,
206+
"Sqls": sqls
207+
}
208+
209+
# Add authentication parameters based on auth type
210+
if auth_type == "user_password" and username and password:
211+
logger.debug(f"Using user/password authentication with username: {username}")
212+
params["DbUser"] = username
213+
params["SecretArn"] = None # Not using a secret
214+
215+
# Add cluster identifier based on cluster type
192216
if cluster_info['type'] == 'provisioned':
193217
logger.debug(f'Using ClusterIdentifier for provisioned cluster: {cluster_identifier}')
194-
response = data_client.batch_execute_statement(
195-
ClusterIdentifier=cluster_identifier, Database=database_name, Sqls=sqls
196-
)
218+
params["ClusterIdentifier"] = cluster_identifier
197219
elif cluster_info['type'] == 'serverless':
198220
logger.debug(f'Using WorkgroupName for serverless workgroup: {cluster_identifier}')
199-
response = data_client.batch_execute_statement(
200-
WorkgroupName=cluster_identifier, Database=database_name, Sqls=sqls
201-
)
221+
params["WorkgroupName"] = cluster_identifier
202222
else:
203223
raise Exception(f'Unknown cluster type: {cluster_info["type"]}')
224+
225+
# Execute the statement
226+
response = data_client.batch_execute_statement(**params)
204227

205228
query_id = response['Id']
206229
logger.debug(f'Started query execution: {query_id}')
@@ -619,4 +642,7 @@ async def execute_query(cluster_identifier: str, database_name: str, sql: str) -
619642
),
620643
aws_region=os.environ.get('AWS_REGION'),
621644
aws_profile=os.environ.get('AWS_PROFILE'),
645+
auth_type=os.environ.get('REDSHIFT_AUTH_TYPE'),
646+
username=os.environ.get('REDSHIFT_USERNAME'),
647+
password=os.environ.get('REDSHIFT_PASSWORD'),
622648
)

src/redshift-mcp-server/awslabs/redshift_mcp_server/server.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717
import os
1818
import sys
1919
from awslabs.redshift_mcp_server.consts import (
20+
AUTH_TYPE_IAM,
21+
AUTH_TYPE_USER_PASSWORD,
2022
CLIENT_BEST_PRACTICES,
23+
DEFAULT_AUTH_TYPE,
2124
DEFAULT_LOG_LEVEL,
2225
REDSHIFT_BEST_PRACTICES,
2326
)
2427
from awslabs.redshift_mcp_server.models import (
2528
QueryResult,
29+
RedshiftAuthConfig,
2630
RedshiftCluster,
2731
RedshiftColumn,
2832
RedshiftDatabase,
@@ -57,6 +61,8 @@
5761
5862
This MCP server provides comprehensive access to Amazon Redshift clusters and serverless workgroups.
5963
64+
It supports both IAM authentication and username/password authentication for connecting to Redshift clusters.
65+
6066
## Available Tools
6167
6268
### list_clusters
@@ -536,9 +542,23 @@ async def execute_query_tool(
536542
sql: str = Field(
537543
..., description='The SQL statement to execute. Should be a single SQL statement.'
538544
),
545+
auth_type: str = Field(
546+
DEFAULT_AUTH_TYPE,
547+
description='Authentication type to use (iam or user_password). Default is iam.',
548+
),
549+
username: str = Field(
550+
None,
551+
description='Username for user/password authentication. Required if auth_type is user_password.',
552+
),
553+
password: str = Field(
554+
None,
555+
description='Password for user/password authentication. Required if auth_type is user_password.',
556+
),
539557
) -> QueryResult:
540558
"""Execute a SQL query against a Redshift cluster or serverless workgroup.
541559
560+
This tool supports both IAM authentication and username/password authentication.
561+
542562
This tool uses the Redshift Data API to execute SQL queries and return results.
543563
It supports both provisioned clusters and serverless workgroups, and handles
544564
various data types in the result set.
@@ -549,6 +569,7 @@ async def execute_query_tool(
549569
- The cluster must be available and accessible.
550570
- Required IAM permissions: redshift-data:ExecuteStatement, redshift-data:DescribeStatement, redshift-data:GetStatementResult.
551571
- The user must have appropriate permissions to execute queries in the specified database.
572+
- For user/password authentication, provide the username and password parameters and set auth_type to "user_password".
552573
553574
## Parameters
554575
@@ -557,6 +578,9 @@ async def execute_query_tool(
557578
- database_name: The database name to execute the query against.
558579
IMPORTANT: Use a valid database name from the list_databases tool.
559580
- sql: The SQL statement to execute. Should be a single SQL statement.
581+
- auth_type: Authentication type to use (iam or user_password). Default is iam.
582+
- username: Username for user/password authentication. Required if auth_type is user_password.
583+
- password: Password for user/password authentication. Required if auth_type is user_password.
560584
561585
## Response Structure
562586

0 commit comments

Comments
 (0)