@naganpm/snowflake-mcp-server 1.0.2 โ 1.0.6
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.
- package/README.md +20 -0
- package/package.json +7 -2
- package/.continue/prompts/new-prompt.md +0 -14
- package/.env.example +0 -7
- package/Dockerfile +0 -21
- package/QUICKSTART.md +0 -174
- package/SETUP_COMPLETE.md +0 -226
- package/docker-compose.yml +0 -16
- package/examples/usage.ts +0 -84
- package/postman_collection.json +0 -148
- package/src/index.ts +0 -51
- package/src/mcp-server.ts +0 -137
- package/src/middleware/error.middleware.ts +0 -22
- package/src/routes/snowflake.routes.ts +0 -123
- package/src/services/snowflake.service.ts +0 -149
- package/test-api.sh +0 -39
- package/tsconfig.json +0 -28
package/README.md
CHANGED
|
@@ -22,6 +22,26 @@ npm install
|
|
|
22
22
|
|
|
23
23
|
## Configuration
|
|
24
24
|
|
|
25
|
+
#### Approach1
|
|
26
|
+
|
|
27
|
+
Note: If you are trying to configure MCP using continue.dev
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
mcpServers:
|
|
31
|
+
- name: snowflake MCP
|
|
32
|
+
command: npx
|
|
33
|
+
args:
|
|
34
|
+
- -y
|
|
35
|
+
- "@naganpm/snowflake-mcp-server@latest"
|
|
36
|
+
env:
|
|
37
|
+
SNOWFLAKE_ACCOUNT: <account-id>.us-east-2.aws
|
|
38
|
+
SNOWFLAKE_USERNAME: <your-username>
|
|
39
|
+
SNOWFLAKE_PASSWORD: <your-password>
|
|
40
|
+
SNOWFLAKE_WAREHOUSE: <warehouse-name>
|
|
41
|
+
SNOWFLAKE_DATABASE: <database-name>
|
|
42
|
+
SNOWFLAKE_SCHEMA: <schema-name>
|
|
43
|
+
```
|
|
44
|
+
#### Approach2
|
|
25
45
|
1. Copy `.env.example` to `.env`:
|
|
26
46
|
```bash
|
|
27
47
|
cp .env.example .env
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naganpm/snowflake-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "MCP server for Snowflake database integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"express",
|
|
24
24
|
"typescript"
|
|
25
25
|
],
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
26
31
|
"author": "",
|
|
27
32
|
"license": "MIT",
|
|
28
33
|
"dependencies": {
|
|
@@ -42,4 +47,4 @@
|
|
|
42
47
|
"engines": {
|
|
43
48
|
"node": ">=18.0.0"
|
|
44
49
|
}
|
|
45
|
-
}
|
|
50
|
+
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Snowflake MCP
|
|
3
|
-
description: Create a snowflake MCP
|
|
4
|
-
invokable: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
URL: https://bd50859.us-east-2.aws.snowflakecomputing.com/
|
|
8
|
-
USERNAME: DEP_QA2
|
|
9
|
-
PASSWORD: Depqa2222$
|
|
10
|
-
|
|
11
|
-
### Instructions
|
|
12
|
-
- Create a snowflake mcp server in current folder and I want to configure this MCP as npm package.
|
|
13
|
-
- Use express.js and typescript preferrably.
|
|
14
|
-
- You can refer to @naganpm/mysql-mcp-server npm package for reference.
|
package/.env.example
DELETED
package/Dockerfile
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
FROM node:18-alpine
|
|
2
|
-
|
|
3
|
-
WORKDIR /app
|
|
4
|
-
|
|
5
|
-
# Copy package files
|
|
6
|
-
COPY package*.json ./
|
|
7
|
-
|
|
8
|
-
# Install dependencies
|
|
9
|
-
RUN npm ci --only=production
|
|
10
|
-
|
|
11
|
-
# Copy built files
|
|
12
|
-
COPY dist ./dist
|
|
13
|
-
|
|
14
|
-
# Expose port
|
|
15
|
-
EXPOSE 3000
|
|
16
|
-
|
|
17
|
-
# Set environment variable
|
|
18
|
-
ENV NODE_ENV=production
|
|
19
|
-
|
|
20
|
-
# Start the server
|
|
21
|
-
CMD ["node", "dist/index.js"]
|
package/QUICKSTART.md
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
# Snowflake MCP Server - Quick Start Guide
|
|
2
|
-
|
|
3
|
-
## ๐ Getting Started
|
|
4
|
-
|
|
5
|
-
### 1. Install Dependencies
|
|
6
|
-
```bash
|
|
7
|
-
npm install
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
### 2. Configure Environment
|
|
11
|
-
Edit `.env` file with your Snowflake credentials:
|
|
12
|
-
```env
|
|
13
|
-
SNOWFLAKE_ACCOUNT=your-account.region.cloud
|
|
14
|
-
SNOWFLAKE_USERNAME=your-username
|
|
15
|
-
SNOWFLAKE_PASSWORD=your-password
|
|
16
|
-
SNOWFLAKE_WAREHOUSE=YOUR_WAREHOUSE # Optional
|
|
17
|
-
SNOWFLAKE_DATABASE=YOUR_DATABASE # Optional
|
|
18
|
-
SNOWFLAKE_SCHEMA=YOUR_SCHEMA # Optional
|
|
19
|
-
PORT=3000
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### 3. Run the Server
|
|
23
|
-
|
|
24
|
-
**Development Mode:**
|
|
25
|
-
```bash
|
|
26
|
-
npm run dev
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**Production Mode:**
|
|
30
|
-
```bash
|
|
31
|
-
npm run build
|
|
32
|
-
npm start
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## ๐ก API Endpoints
|
|
36
|
-
|
|
37
|
-
| Method | Endpoint | Description |
|
|
38
|
-
|--------|----------|-------------|
|
|
39
|
-
| GET | `/health` | Health check |
|
|
40
|
-
| GET | `/api/snowflake/status` | Connection status |
|
|
41
|
-
| POST | `/api/snowflake/query` | Execute SQL query |
|
|
42
|
-
| GET | `/api/snowflake/databases` | List databases |
|
|
43
|
-
| GET | `/api/snowflake/schemas` | List schemas |
|
|
44
|
-
| GET | `/api/snowflake/tables` | List tables |
|
|
45
|
-
| GET | `/api/snowflake/tables/:name/describe` | Describe table |
|
|
46
|
-
| GET | `/api/snowflake/warehouses` | List warehouses |
|
|
47
|
-
| GET | `/api/snowflake/session` | Current session info |
|
|
48
|
-
|
|
49
|
-
## ๐งช Testing
|
|
50
|
-
|
|
51
|
-
### Using cURL
|
|
52
|
-
```bash
|
|
53
|
-
# Health check
|
|
54
|
-
curl http://localhost:3000/health
|
|
55
|
-
|
|
56
|
-
# Execute query
|
|
57
|
-
curl -X POST http://localhost:3000/api/snowflake/query \
|
|
58
|
-
-H "Content-Type: application/json" \
|
|
59
|
-
-d '{"query": "SELECT CURRENT_DATE()"}'
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Using the test script
|
|
63
|
-
```bash
|
|
64
|
-
./test-api.sh
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Import Postman Collection
|
|
68
|
-
Import `postman_collection.json` into Postman for easy testing.
|
|
69
|
-
|
|
70
|
-
## ๐ฆ NPM Package Usage
|
|
71
|
-
|
|
72
|
-
After publishing to NPM, users can install:
|
|
73
|
-
```bash
|
|
74
|
-
npm install @naganpm/snowflake-mcp-server
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Then use programmatically:
|
|
78
|
-
```typescript
|
|
79
|
-
import { SnowflakeService } from '@naganpm/snowflake-mcp-server';
|
|
80
|
-
|
|
81
|
-
const service = SnowflakeService.getInstance();
|
|
82
|
-
const result = await service.executeQuery('SELECT 1');
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## ๐ณ Docker Deployment
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
# Build and run with Docker Compose
|
|
89
|
-
docker-compose up -d
|
|
90
|
-
|
|
91
|
-
# Or build manually
|
|
92
|
-
docker build -t snowflake-mcp .
|
|
93
|
-
docker run -p 3000:3000 --env-file .env snowflake-mcp
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## ๐ Project Structure
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
snowflake-mcp-server/
|
|
100
|
-
โโโ src/
|
|
101
|
-
โ โโโ index.ts # Main server entry
|
|
102
|
-
โ โโโ services/
|
|
103
|
-
โ โ โโโ snowflake.service.ts # Snowflake SDK wrapper
|
|
104
|
-
โ โโโ routes/
|
|
105
|
-
โ โ โโโ snowflake.routes.ts # API routes
|
|
106
|
-
โ โโโ middleware/
|
|
107
|
-
โ โโโ error.middleware.ts # Error handling
|
|
108
|
-
โโโ dist/ # Compiled JavaScript
|
|
109
|
-
โโโ examples/ # Usage examples
|
|
110
|
-
โโโ package.json
|
|
111
|
-
โโโ tsconfig.json
|
|
112
|
-
โโโ .env # Environment config
|
|
113
|
-
โโโ Dockerfile
|
|
114
|
-
โโโ docker-compose.yml
|
|
115
|
-
โโโ README.md
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## ๐ Security Notes
|
|
119
|
-
|
|
120
|
-
- Never commit `.env` file to version control
|
|
121
|
-
- Use environment variables for sensitive data
|
|
122
|
-
- Consider using Snowflake key-pair authentication for production
|
|
123
|
-
- Implement rate limiting for production use
|
|
124
|
-
- Add authentication/authorization middleware
|
|
125
|
-
|
|
126
|
-
## ๐ ๏ธ Development Commands
|
|
127
|
-
|
|
128
|
-
| Command | Description |
|
|
129
|
-
|---------|-------------|
|
|
130
|
-
| `npm run dev` | Run in development mode |
|
|
131
|
-
| `npm run build` | Build TypeScript to JavaScript |
|
|
132
|
-
| `npm start` | Run production build |
|
|
133
|
-
| `npm run watch` | Watch mode for development |
|
|
134
|
-
| `npm run clean` | Clean dist folder |
|
|
135
|
-
|
|
136
|
-
## ๐ Publishing to NPM
|
|
137
|
-
|
|
138
|
-
1. Update version in `package.json`
|
|
139
|
-
2. Build the project: `npm run build`
|
|
140
|
-
3. Login to NPM: `npm login`
|
|
141
|
-
4. Publish: `npm publish --access public`
|
|
142
|
-
|
|
143
|
-
## ๐ค Contributing
|
|
144
|
-
|
|
145
|
-
1. Fork the repository
|
|
146
|
-
2. Create a feature branch
|
|
147
|
-
3. Make your changes
|
|
148
|
-
4. Submit a pull request
|
|
149
|
-
|
|
150
|
-
## ๐ License
|
|
151
|
-
|
|
152
|
-
MIT License - see LICENSE file for details
|
|
153
|
-
|
|
154
|
-
## ๐ Troubleshooting
|
|
155
|
-
|
|
156
|
-
### Connection Issues
|
|
157
|
-
- Verify Snowflake credentials in `.env`
|
|
158
|
-
- Check network connectivity to Snowflake
|
|
159
|
-
- Ensure account format is correct (account.region.cloud)
|
|
160
|
-
|
|
161
|
-
### Build Issues
|
|
162
|
-
- Clear node_modules: `rm -rf node_modules && npm install`
|
|
163
|
-
- Clear dist: `npm run clean && npm run build`
|
|
164
|
-
|
|
165
|
-
### Runtime Issues
|
|
166
|
-
- Check logs for error messages
|
|
167
|
-
- Verify environment variables are loaded
|
|
168
|
-
- Test with simple queries first
|
|
169
|
-
|
|
170
|
-
## ๐ Additional Resources
|
|
171
|
-
|
|
172
|
-
- [Snowflake SDK Documentation](https://docs.snowflake.com/en/user-guide/nodejs-driver)
|
|
173
|
-
- [Express.js Documentation](https://expressjs.com/)
|
|
174
|
-
- [TypeScript Documentation](https://www.typescriptlang.org/)
|
package/SETUP_COMPLETE.md
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
# Snowflake MCP Server - Complete Setup โ
|
|
2
|
-
|
|
3
|
-
## โจ What Has Been Created
|
|
4
|
-
|
|
5
|
-
A production-ready Snowflake MCP (Model Context Protocol) server configured as an NPM package with the following features:
|
|
6
|
-
|
|
7
|
-
### ๐ฏ Core Features
|
|
8
|
-
- **Express.js REST API** with TypeScript
|
|
9
|
-
- **Snowflake SDK Integration** for database operations
|
|
10
|
-
- **Singleton Pattern** for connection management
|
|
11
|
-
- **Error Handling Middleware**
|
|
12
|
-
- **CORS Support**
|
|
13
|
-
- **Environment Configuration**
|
|
14
|
-
- **Health Monitoring**
|
|
15
|
-
|
|
16
|
-
### ๐ Project Structure
|
|
17
|
-
```
|
|
18
|
-
snowflake-mcp-server/
|
|
19
|
-
โโโ src/
|
|
20
|
-
โ โโโ index.ts # Main server (Express app)
|
|
21
|
-
โ โโโ services/
|
|
22
|
-
โ โ โโโ snowflake.service.ts # Snowflake connection & queries
|
|
23
|
-
โ โโโ routes/
|
|
24
|
-
โ โ โโโ snowflake.routes.ts # API endpoints
|
|
25
|
-
โ โโโ middleware/
|
|
26
|
-
โ โโโ error.middleware.ts # Error handling
|
|
27
|
-
โโโ dist/ # Compiled JavaScript
|
|
28
|
-
โโโ examples/
|
|
29
|
-
โ โโโ usage.ts # Usage examples
|
|
30
|
-
โโโ node_modules/ # Dependencies
|
|
31
|
-
โโโ .env # Your Snowflake credentials
|
|
32
|
-
โโโ .env.example # Template
|
|
33
|
-
โโโ package.json # NPM configuration
|
|
34
|
-
โโโ tsconfig.json # TypeScript config
|
|
35
|
-
โโโ Dockerfile # Docker image
|
|
36
|
-
โโโ docker-compose.yml # Docker compose
|
|
37
|
-
โโโ postman_collection.json # API testing
|
|
38
|
-
โโโ test-api.sh # Bash test script
|
|
39
|
-
โโโ README.md # Full documentation
|
|
40
|
-
โโโ QUICKSTART.md # Quick start guide
|
|
41
|
-
โโโ LICENSE # MIT license
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### ๐ Available API Endpoints
|
|
45
|
-
|
|
46
|
-
| Endpoint | Method | Description |
|
|
47
|
-
|----------|--------|-------------|
|
|
48
|
-
| `/health` | GET | Health check |
|
|
49
|
-
| `/api/snowflake/status` | GET | Connection status |
|
|
50
|
-
| `/api/snowflake/query` | POST | Execute SQL query |
|
|
51
|
-
| `/api/snowflake/databases` | GET | List all databases |
|
|
52
|
-
| `/api/snowflake/schemas` | GET | List schemas |
|
|
53
|
-
| `/api/snowflake/tables` | GET | List tables |
|
|
54
|
-
| `/api/snowflake/tables/:name/describe` | GET | Describe table structure |
|
|
55
|
-
| `/api/snowflake/warehouses` | GET | List warehouses |
|
|
56
|
-
| `/api/snowflake/session` | GET | Current session info |
|
|
57
|
-
|
|
58
|
-
### ๐ง Configuration
|
|
59
|
-
|
|
60
|
-
**Port:** 3000
|
|
61
|
-
|
|
62
|
-
All credentials should be stored in `.env` file (not committed to git).
|
|
63
|
-
|
|
64
|
-
See `.env.example` for configuration template.
|
|
65
|
-
|
|
66
|
-
## ๐ Quick Start Commands
|
|
67
|
-
|
|
68
|
-
### 1. Development Mode
|
|
69
|
-
```bash
|
|
70
|
-
npm run dev
|
|
71
|
-
# Server runs at: http://localhost:3000
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### 2. Build for Production
|
|
75
|
-
```bash
|
|
76
|
-
npm run build
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 3. Run Production Build
|
|
80
|
-
```bash
|
|
81
|
-
npm start
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### 4. Test the API
|
|
85
|
-
```bash
|
|
86
|
-
# Using curl
|
|
87
|
-
curl http://localhost:3000/health
|
|
88
|
-
|
|
89
|
-
# Using the test script
|
|
90
|
-
./test-api.sh
|
|
91
|
-
|
|
92
|
-
# Using Postman
|
|
93
|
-
# Import postman_collection.json into Postman
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## ๐ฆ NPM Package Details
|
|
97
|
-
|
|
98
|
-
- **Package Name:** `@naganpm/snowflake-mcp-server`
|
|
99
|
-
- **Version:** 1.0.0
|
|
100
|
-
- **Main Entry:** `dist/index.js`
|
|
101
|
-
- **TypeScript Definitions:** `dist/index.d.ts`
|
|
102
|
-
- **Binary:** `snowflake-mcp-server`
|
|
103
|
-
|
|
104
|
-
### To Publish to NPM:
|
|
105
|
-
```bash
|
|
106
|
-
npm login
|
|
107
|
-
npm publish --access public
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## ๐งช Testing Examples
|
|
111
|
-
|
|
112
|
-
### Test Health Check
|
|
113
|
-
```bash
|
|
114
|
-
curl http://localhost:3000/health
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Execute a Query
|
|
118
|
-
```bash
|
|
119
|
-
curl -X POST http://localhost:3000/api/snowflake/query \
|
|
120
|
-
-H "Content-Type: application/json" \
|
|
121
|
-
-d '{
|
|
122
|
-
"query": "SELECT CURRENT_DATE(), CURRENT_USER(), CURRENT_ROLE()"
|
|
123
|
-
}'
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### List Databases
|
|
127
|
-
```bash
|
|
128
|
-
curl http://localhost:3000/api/snowflake/databases
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### Get Session Info
|
|
132
|
-
```bash
|
|
133
|
-
curl http://localhost:3000/api/snowflake/session
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## ๐ณ Docker Deployment
|
|
137
|
-
|
|
138
|
-
### Build and Run
|
|
139
|
-
```bash
|
|
140
|
-
docker-compose up -d
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Manual Docker Build
|
|
144
|
-
```bash
|
|
145
|
-
docker build -t snowflake-mcp .
|
|
146
|
-
docker run -p 3000:3000 --env-file .env snowflake-mcp
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## ๐ Key Dependencies
|
|
150
|
-
|
|
151
|
-
- **express** ^4.18.2 - Web framework
|
|
152
|
-
- **snowflake-sdk** ^1.11.0 - Snowflake database driver
|
|
153
|
-
- **typescript** ^5.3.3 - Type safety
|
|
154
|
-
- **dotenv** ^16.4.1 - Environment configuration
|
|
155
|
-
- **cors** ^2.8.5 - CORS support
|
|
156
|
-
|
|
157
|
-
## ๐ Usage as NPM Package
|
|
158
|
-
|
|
159
|
-
After installation:
|
|
160
|
-
```typescript
|
|
161
|
-
import { SnowflakeService } from '@naganpm/snowflake-mcp-server';
|
|
162
|
-
|
|
163
|
-
// Get singleton instance
|
|
164
|
-
const service = SnowflakeService.getInstance();
|
|
165
|
-
|
|
166
|
-
// Execute queries
|
|
167
|
-
const result = await service.executeQuery('SELECT * FROM my_table LIMIT 10');
|
|
168
|
-
console.log(result.rows);
|
|
169
|
-
|
|
170
|
-
// List databases
|
|
171
|
-
const databases = await service.listDatabases();
|
|
172
|
-
|
|
173
|
-
// Describe table
|
|
174
|
-
const tableInfo = await service.describeTable('my_table');
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## โ
Verified Working
|
|
178
|
-
|
|
179
|
-
- โ
Server starts successfully
|
|
180
|
-
- โ
Health endpoint responds
|
|
181
|
-
- โ
Status endpoint works
|
|
182
|
-
- โ
TypeScript compiles without errors
|
|
183
|
-
- โ
All dependencies installed
|
|
184
|
-
- โ
Environment configuration loaded
|
|
185
|
-
|
|
186
|
-
## ๐ Documentation Files
|
|
187
|
-
|
|
188
|
-
- **README.md** - Comprehensive documentation
|
|
189
|
-
- **QUICKSTART.md** - Quick start guide
|
|
190
|
-
- **postman_collection.json** - Postman API collection
|
|
191
|
-
- **examples/usage.ts** - Code examples
|
|
192
|
-
- **test-api.sh** - Automated testing script
|
|
193
|
-
|
|
194
|
-
## ๐ Security Notes
|
|
195
|
-
|
|
196
|
-
- `.env` file is in `.gitignore` (not committed)
|
|
197
|
-
- Password stored only locally
|
|
198
|
-
- Add authentication middleware for production
|
|
199
|
-
- Consider using Snowflake key-pair auth for production
|
|
200
|
-
- Implement rate limiting
|
|
201
|
-
|
|
202
|
-
## ๐ ๏ธ Development Workflow
|
|
203
|
-
|
|
204
|
-
1. **Make changes** in `src/` directory
|
|
205
|
-
2. **Test** with `npm run dev`
|
|
206
|
-
3. **Build** with `npm run build`
|
|
207
|
-
4. **Deploy** with `npm start` or Docker
|
|
208
|
-
|
|
209
|
-
## ๐ Next Steps
|
|
210
|
-
|
|
211
|
-
1. Add your Snowflake warehouse, database, and schema to `.env` (optional)
|
|
212
|
-
2. Start the server: `npm run dev`
|
|
213
|
-
3. Test with Postman or curl
|
|
214
|
-
4. Deploy to production or publish to NPM
|
|
215
|
-
5. Add authentication/authorization if needed
|
|
216
|
-
6. Set up CI/CD pipeline
|
|
217
|
-
|
|
218
|
-
## ๐ Success!
|
|
219
|
-
|
|
220
|
-
Your Snowflake MCP server is ready to use! It's configured as a proper NPM package following the structure of `@naganpm/mysql-mcp-server`.
|
|
221
|
-
|
|
222
|
-
Start the server with `npm run dev` and visit:
|
|
223
|
-
- Health: http://localhost:3000/health
|
|
224
|
-
- API Docs: See README.md for all endpoints
|
|
225
|
-
|
|
226
|
-
Happy coding! ๐
|
package/docker-compose.yml
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
version: '3.8'
|
|
2
|
-
|
|
3
|
-
services:
|
|
4
|
-
snowflake-mcp:
|
|
5
|
-
build: .
|
|
6
|
-
ports:
|
|
7
|
-
- "3000:3000"
|
|
8
|
-
environment:
|
|
9
|
-
- SNOWFLAKE_ACCOUNT=${SNOWFLAKE_ACCOUNT}
|
|
10
|
-
- SNOWFLAKE_USERNAME=${SNOWFLAKE_USERNAME}
|
|
11
|
-
- SNOWFLAKE_PASSWORD=${SNOWFLAKE_PASSWORD}
|
|
12
|
-
- SNOWFLAKE_WAREHOUSE=${SNOWFLAKE_WAREHOUSE}
|
|
13
|
-
- SNOWFLAKE_DATABASE=${SNOWFLAKE_DATABASE}
|
|
14
|
-
- SNOWFLAKE_SCHEMA=${SNOWFLAKE_SCHEMA}
|
|
15
|
-
- PORT=3000
|
|
16
|
-
restart: unless-stopped
|
package/examples/usage.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example usage of Snowflake MCP Server
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const BASE_URL = 'http://localhost:3000';
|
|
6
|
-
|
|
7
|
-
// Example 1: Execute a simple query
|
|
8
|
-
async function executeQuery() {
|
|
9
|
-
const response = await fetch(`${BASE_URL}/api/snowflake/query`, {
|
|
10
|
-
method: 'POST',
|
|
11
|
-
headers: {
|
|
12
|
-
'Content-Type': 'application/json',
|
|
13
|
-
},
|
|
14
|
-
body: JSON.stringify({
|
|
15
|
-
query: 'SELECT CURRENT_DATE() as today, CURRENT_USER() as user',
|
|
16
|
-
}),
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const result = await response.json();
|
|
20
|
-
console.log('Query Result:', result);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Example 2: List all databases
|
|
24
|
-
async function listDatabases() {
|
|
25
|
-
const response = await fetch(`${BASE_URL}/api/snowflake/databases`);
|
|
26
|
-
const result = await response.json();
|
|
27
|
-
console.log('Databases:', result);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Example 3: List tables in a specific database and schema
|
|
31
|
-
async function listTables(database: string, schema: string) {
|
|
32
|
-
const response = await fetch(
|
|
33
|
-
`${BASE_URL}/api/snowflake/tables?database=${database}&schema=${schema}`
|
|
34
|
-
);
|
|
35
|
-
const result = await response.json();
|
|
36
|
-
console.log('Tables:', result);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Example 4: Describe a table
|
|
40
|
-
async function describeTable(tableName: string) {
|
|
41
|
-
const response = await fetch(
|
|
42
|
-
`${BASE_URL}/api/snowflake/tables/${tableName}/describe`
|
|
43
|
-
);
|
|
44
|
-
const result = await response.json();
|
|
45
|
-
console.log('Table Description:', result);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Example 5: Get current session info
|
|
49
|
-
async function getSessionInfo() {
|
|
50
|
-
const response = await fetch(`${BASE_URL}/api/snowflake/session`);
|
|
51
|
-
const result = await response.json();
|
|
52
|
-
console.log('Session Info:', result);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Example 6: Execute query with parameters
|
|
56
|
-
async function executeQueryWithBinds() {
|
|
57
|
-
const response = await fetch(`${BASE_URL}/api/snowflake/query`, {
|
|
58
|
-
method: 'POST',
|
|
59
|
-
headers: {
|
|
60
|
-
'Content-Type': 'application/json',
|
|
61
|
-
},
|
|
62
|
-
body: JSON.stringify({
|
|
63
|
-
query: 'SELECT * FROM table_name WHERE id = ? AND status = ?',
|
|
64
|
-
binds: [123, 'active'],
|
|
65
|
-
}),
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const result = await response.json();
|
|
69
|
-
console.log('Query Result with Binds:', result);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Run examples
|
|
73
|
-
async function main() {
|
|
74
|
-
try {
|
|
75
|
-
await executeQuery();
|
|
76
|
-
await listDatabases();
|
|
77
|
-
await getSessionInfo();
|
|
78
|
-
} catch (error) {
|
|
79
|
-
console.error('Error:', error);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Uncomment to run
|
|
84
|
-
// main();
|
package/postman_collection.json
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"info": {
|
|
3
|
-
"name": "Snowflake MCP Server",
|
|
4
|
-
"description": "API collection for Snowflake MCP Server",
|
|
5
|
-
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
|
6
|
-
},
|
|
7
|
-
"item": [
|
|
8
|
-
{
|
|
9
|
-
"name": "Health Check",
|
|
10
|
-
"request": {
|
|
11
|
-
"method": "GET",
|
|
12
|
-
"header": [],
|
|
13
|
-
"url": {
|
|
14
|
-
"raw": "{{base_url}}/health",
|
|
15
|
-
"host": ["{{base_url}}"],
|
|
16
|
-
"path": ["health"]
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"name": "Connection Status",
|
|
22
|
-
"request": {
|
|
23
|
-
"method": "GET",
|
|
24
|
-
"header": [],
|
|
25
|
-
"url": {
|
|
26
|
-
"raw": "{{base_url}}/api/snowflake/status",
|
|
27
|
-
"host": ["{{base_url}}"],
|
|
28
|
-
"path": ["api", "snowflake", "status"]
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"name": "Execute Query",
|
|
34
|
-
"request": {
|
|
35
|
-
"method": "POST",
|
|
36
|
-
"header": [
|
|
37
|
-
{
|
|
38
|
-
"key": "Content-Type",
|
|
39
|
-
"value": "application/json"
|
|
40
|
-
}
|
|
41
|
-
],
|
|
42
|
-
"body": {
|
|
43
|
-
"mode": "raw",
|
|
44
|
-
"raw": "{\n \"query\": \"SELECT CURRENT_DATE(), CURRENT_USER(), CURRENT_ROLE()\"\n}"
|
|
45
|
-
},
|
|
46
|
-
"url": {
|
|
47
|
-
"raw": "{{base_url}}/api/snowflake/query",
|
|
48
|
-
"host": ["{{base_url}}"],
|
|
49
|
-
"path": ["api", "snowflake", "query"]
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"name": "List Databases",
|
|
55
|
-
"request": {
|
|
56
|
-
"method": "GET",
|
|
57
|
-
"header": [],
|
|
58
|
-
"url": {
|
|
59
|
-
"raw": "{{base_url}}/api/snowflake/databases",
|
|
60
|
-
"host": ["{{base_url}}"],
|
|
61
|
-
"path": ["api", "snowflake", "databases"]
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"name": "List Schemas",
|
|
67
|
-
"request": {
|
|
68
|
-
"method": "GET",
|
|
69
|
-
"header": [],
|
|
70
|
-
"url": {
|
|
71
|
-
"raw": "{{base_url}}/api/snowflake/schemas?database=YOUR_DATABASE",
|
|
72
|
-
"host": ["{{base_url}}"],
|
|
73
|
-
"path": ["api", "snowflake", "schemas"],
|
|
74
|
-
"query": [
|
|
75
|
-
{
|
|
76
|
-
"key": "database",
|
|
77
|
-
"value": "YOUR_DATABASE"
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"name": "List Tables",
|
|
85
|
-
"request": {
|
|
86
|
-
"method": "GET",
|
|
87
|
-
"header": [],
|
|
88
|
-
"url": {
|
|
89
|
-
"raw": "{{base_url}}/api/snowflake/tables?database=YOUR_DATABASE&schema=PUBLIC",
|
|
90
|
-
"host": ["{{base_url}}"],
|
|
91
|
-
"path": ["api", "snowflake", "tables"],
|
|
92
|
-
"query": [
|
|
93
|
-
{
|
|
94
|
-
"key": "database",
|
|
95
|
-
"value": "YOUR_DATABASE"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"key": "schema",
|
|
99
|
-
"value": "PUBLIC"
|
|
100
|
-
}
|
|
101
|
-
]
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
"name": "Describe Table",
|
|
107
|
-
"request": {
|
|
108
|
-
"method": "GET",
|
|
109
|
-
"header": [],
|
|
110
|
-
"url": {
|
|
111
|
-
"raw": "{{base_url}}/api/snowflake/tables/YOUR_TABLE/describe",
|
|
112
|
-
"host": ["{{base_url}}"],
|
|
113
|
-
"path": ["api", "snowflake", "tables", "YOUR_TABLE", "describe"]
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
"name": "List Warehouses",
|
|
119
|
-
"request": {
|
|
120
|
-
"method": "GET",
|
|
121
|
-
"header": [],
|
|
122
|
-
"url": {
|
|
123
|
-
"raw": "{{base_url}}/api/snowflake/warehouses",
|
|
124
|
-
"host": ["{{base_url}}"],
|
|
125
|
-
"path": ["api", "snowflake", "warehouses"]
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
"name": "Get Current Session",
|
|
131
|
-
"request": {
|
|
132
|
-
"method": "GET",
|
|
133
|
-
"header": [],
|
|
134
|
-
"url": {
|
|
135
|
-
"raw": "{{base_url}}/api/snowflake/session",
|
|
136
|
-
"host": ["{{base_url}}"],
|
|
137
|
-
"path": ["api", "snowflake", "session"]
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
],
|
|
142
|
-
"variable": [
|
|
143
|
-
{
|
|
144
|
-
"key": "base_url",
|
|
145
|
-
"value": "http://localhost:3000"
|
|
146
|
-
}
|
|
147
|
-
]
|
|
148
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import express, { Express, Request, Response } from 'express';
|
|
3
|
-
import cors from 'cors';
|
|
4
|
-
import dotenv from 'dotenv';
|
|
5
|
-
import { SnowflakeService } from './services/snowflake.service';
|
|
6
|
-
import { errorHandler } from './middleware/error.middleware';
|
|
7
|
-
import { snowflakeRoutes } from './routes/snowflake.routes';
|
|
8
|
-
|
|
9
|
-
dotenv.config();
|
|
10
|
-
|
|
11
|
-
const app: Express = express();
|
|
12
|
-
const port = process.env.PORT || 3000;
|
|
13
|
-
|
|
14
|
-
// Middleware
|
|
15
|
-
app.use(cors());
|
|
16
|
-
app.use(express.json());
|
|
17
|
-
app.use(express.urlencoded({ extended: true }));
|
|
18
|
-
|
|
19
|
-
// Health check
|
|
20
|
-
app.get('/health', (req: Request, res: Response) => {
|
|
21
|
-
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
// Snowflake routes
|
|
25
|
-
app.use('/api/snowflake', snowflakeRoutes);
|
|
26
|
-
|
|
27
|
-
// Error handler
|
|
28
|
-
app.use(errorHandler);
|
|
29
|
-
|
|
30
|
-
// Initialize Snowflake connection
|
|
31
|
-
const snowflakeService = SnowflakeService.getInstance();
|
|
32
|
-
|
|
33
|
-
app.listen(port, () => {
|
|
34
|
-
console.log(`๐ Snowflake MCP Server running on port ${port}`);
|
|
35
|
-
console.log(`๐ Health check: http://localhost:${port}/health`);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Graceful shutdown
|
|
39
|
-
process.on('SIGINT', async () => {
|
|
40
|
-
console.log('\n๐ Shutting down gracefully...');
|
|
41
|
-
await snowflakeService.disconnect();
|
|
42
|
-
process.exit(0);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
process.on('SIGTERM', async () => {
|
|
46
|
-
console.log('\n๐ Shutting down gracefully...');
|
|
47
|
-
await snowflakeService.disconnect();
|
|
48
|
-
process.exit(0);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
export default app;
|
package/src/mcp-server.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
-
import {
|
|
5
|
-
CallToolRequestSchema,
|
|
6
|
-
ListToolsRequestSchema,
|
|
7
|
-
} from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
-
import { SnowflakeService } from './services/snowflake.service';
|
|
9
|
-
import dotenv from 'dotenv';
|
|
10
|
-
|
|
11
|
-
dotenv.config();
|
|
12
|
-
|
|
13
|
-
const snowflakeService = SnowflakeService.getInstance();
|
|
14
|
-
|
|
15
|
-
const server = new Server(
|
|
16
|
-
{
|
|
17
|
-
name: 'snowflake-mcp-server',
|
|
18
|
-
version: '1.0.0',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
capabilities: {
|
|
22
|
-
tools: {},
|
|
23
|
-
},
|
|
24
|
-
}
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
28
|
-
return {
|
|
29
|
-
tools: [
|
|
30
|
-
{
|
|
31
|
-
name: 'execute_query',
|
|
32
|
-
description: 'Execute a SQL query on Snowflake database',
|
|
33
|
-
inputSchema: {
|
|
34
|
-
type: 'object',
|
|
35
|
-
properties: {
|
|
36
|
-
query: { type: 'string', description: 'SQL query to execute' },
|
|
37
|
-
binds: { type: 'array', description: 'Optional bind parameters' },
|
|
38
|
-
},
|
|
39
|
-
required: ['query'],
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
name: 'list_databases',
|
|
44
|
-
description: 'List all databases',
|
|
45
|
-
inputSchema: { type: 'object', properties: {} },
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: 'list_schemas',
|
|
49
|
-
description: 'List schemas',
|
|
50
|
-
inputSchema: {
|
|
51
|
-
type: 'object',
|
|
52
|
-
properties: { database: { type: 'string' } },
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: 'list_tables',
|
|
57
|
-
description: 'List tables',
|
|
58
|
-
inputSchema: {
|
|
59
|
-
type: 'object',
|
|
60
|
-
properties: { database: { type: 'string' }, schema: { type: 'string' } },
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: 'describe_table',
|
|
65
|
-
description: 'Describe table structure',
|
|
66
|
-
inputSchema: {
|
|
67
|
-
type: 'object',
|
|
68
|
-
properties: { tableName: { type: 'string' } },
|
|
69
|
-
required: ['tableName'],
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name: 'list_warehouses',
|
|
74
|
-
description: 'List warehouses',
|
|
75
|
-
inputSchema: { type: 'object', properties: {} },
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: 'get_session_info',
|
|
79
|
-
description: 'Get session info',
|
|
80
|
-
inputSchema: { type: 'object', properties: {} },
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
};
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
87
|
-
try {
|
|
88
|
-
const { name, arguments: args } = request.params;
|
|
89
|
-
let result;
|
|
90
|
-
|
|
91
|
-
switch (name) {
|
|
92
|
-
case 'execute_query':
|
|
93
|
-
result = await snowflakeService.executeQuery((args?.query as string) || '', args?.binds as any);
|
|
94
|
-
break;
|
|
95
|
-
case 'list_databases':
|
|
96
|
-
result = await snowflakeService.listDatabases();
|
|
97
|
-
break;
|
|
98
|
-
case 'list_schemas':
|
|
99
|
-
result = await snowflakeService.listSchemas(args?.database as string);
|
|
100
|
-
break;
|
|
101
|
-
case 'list_tables':
|
|
102
|
-
result = await snowflakeService.listTables(args?.database as string, args?.schema as string);
|
|
103
|
-
break;
|
|
104
|
-
case 'describe_table':
|
|
105
|
-
result = await snowflakeService.describeTable((args?.tableName as string) || '');
|
|
106
|
-
break;
|
|
107
|
-
case 'list_warehouses':
|
|
108
|
-
result = await snowflakeService.listWarehouses();
|
|
109
|
-
break;
|
|
110
|
-
case 'get_session_info':
|
|
111
|
-
result = await snowflakeService.getCurrentSession();
|
|
112
|
-
break;
|
|
113
|
-
default:
|
|
114
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
119
|
-
};
|
|
120
|
-
} catch (error: any) {
|
|
121
|
-
return {
|
|
122
|
-
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
123
|
-
isError: true,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
async function main() {
|
|
129
|
-
const transport = new StdioServerTransport();
|
|
130
|
-
await server.connect(transport);
|
|
131
|
-
console.error('Snowflake MCP server running on stdio');
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
main().catch((error) => {
|
|
135
|
-
console.error('Failed to start MCP server:', error);
|
|
136
|
-
process.exit(1);
|
|
137
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
|
|
3
|
-
export const errorHandler = (
|
|
4
|
-
err: any,
|
|
5
|
-
req: Request,
|
|
6
|
-
res: Response,
|
|
7
|
-
next: NextFunction
|
|
8
|
-
) => {
|
|
9
|
-
console.error('โ Error:', err);
|
|
10
|
-
|
|
11
|
-
const statusCode = err.statusCode || 500;
|
|
12
|
-
const message = err.message || 'Internal Server Error';
|
|
13
|
-
|
|
14
|
-
res.status(statusCode).json({
|
|
15
|
-
success: false,
|
|
16
|
-
error: {
|
|
17
|
-
message,
|
|
18
|
-
code: err.code || 'INTERNAL_ERROR',
|
|
19
|
-
...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
};
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { Router, Request, Response, NextFunction } from 'express';
|
|
2
|
-
import { SnowflakeService } from '../services/snowflake.service';
|
|
3
|
-
|
|
4
|
-
const router = Router();
|
|
5
|
-
const snowflakeService = SnowflakeService.getInstance();
|
|
6
|
-
|
|
7
|
-
// Execute query
|
|
8
|
-
router.post('/query', async (req: Request, res: Response, next: NextFunction) => {
|
|
9
|
-
try {
|
|
10
|
-
const { query, binds } = req.body;
|
|
11
|
-
|
|
12
|
-
if (!query) {
|
|
13
|
-
return res.status(400).json({ error: 'Query is required' });
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const result = await snowflakeService.executeQuery(query, binds);
|
|
17
|
-
res.json({
|
|
18
|
-
success: true,
|
|
19
|
-
data: result,
|
|
20
|
-
});
|
|
21
|
-
} catch (error: any) {
|
|
22
|
-
next(error);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
// List databases
|
|
27
|
-
router.get('/databases', async (req: Request, res: Response, next: NextFunction) => {
|
|
28
|
-
try {
|
|
29
|
-
const result = await snowflakeService.listDatabases();
|
|
30
|
-
res.json({
|
|
31
|
-
success: true,
|
|
32
|
-
data: result,
|
|
33
|
-
});
|
|
34
|
-
} catch (error: any) {
|
|
35
|
-
next(error);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// List schemas
|
|
40
|
-
router.get('/schemas', async (req: Request, res: Response, next: NextFunction) => {
|
|
41
|
-
try {
|
|
42
|
-
const { database } = req.query;
|
|
43
|
-
const result = await snowflakeService.listSchemas(database as string);
|
|
44
|
-
res.json({
|
|
45
|
-
success: true,
|
|
46
|
-
data: result,
|
|
47
|
-
});
|
|
48
|
-
} catch (error: any) {
|
|
49
|
-
next(error);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// List tables
|
|
54
|
-
router.get('/tables', async (req: Request, res: Response, next: NextFunction) => {
|
|
55
|
-
try {
|
|
56
|
-
const { database, schema } = req.query;
|
|
57
|
-
const result = await snowflakeService.listTables(
|
|
58
|
-
database as string,
|
|
59
|
-
schema as string
|
|
60
|
-
);
|
|
61
|
-
res.json({
|
|
62
|
-
success: true,
|
|
63
|
-
data: result,
|
|
64
|
-
});
|
|
65
|
-
} catch (error: any) {
|
|
66
|
-
next(error);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Describe table
|
|
71
|
-
router.get('/tables/:tableName/describe', async (req: Request, res: Response, next: NextFunction) => {
|
|
72
|
-
try {
|
|
73
|
-
const { tableName } = req.params;
|
|
74
|
-
const result = await snowflakeService.describeTable(tableName);
|
|
75
|
-
res.json({
|
|
76
|
-
success: true,
|
|
77
|
-
data: result,
|
|
78
|
-
});
|
|
79
|
-
} catch (error: any) {
|
|
80
|
-
next(error);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
// List warehouses
|
|
85
|
-
router.get('/warehouses', async (req: Request, res: Response, next: NextFunction) => {
|
|
86
|
-
try {
|
|
87
|
-
const result = await snowflakeService.listWarehouses();
|
|
88
|
-
res.json({
|
|
89
|
-
success: true,
|
|
90
|
-
data: result,
|
|
91
|
-
});
|
|
92
|
-
} catch (error: any) {
|
|
93
|
-
next(error);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Get current session
|
|
98
|
-
router.get('/session', async (req: Request, res: Response, next: NextFunction) => {
|
|
99
|
-
try {
|
|
100
|
-
const result = await snowflakeService.getCurrentSession();
|
|
101
|
-
res.json({
|
|
102
|
-
success: true,
|
|
103
|
-
data: result,
|
|
104
|
-
});
|
|
105
|
-
} catch (error: any) {
|
|
106
|
-
next(error);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// Connection status
|
|
111
|
-
router.get('/status', async (req: Request, res: Response, next: NextFunction) => {
|
|
112
|
-
try {
|
|
113
|
-
const isConnected = snowflakeService.isConnected();
|
|
114
|
-
res.json({
|
|
115
|
-
success: true,
|
|
116
|
-
connected: isConnected,
|
|
117
|
-
});
|
|
118
|
-
} catch (error: any) {
|
|
119
|
-
next(error);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
export { router as snowflakeRoutes };
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import snowflake from 'snowflake-sdk';
|
|
2
|
-
|
|
3
|
-
export interface SnowflakeConfig {
|
|
4
|
-
account: string;
|
|
5
|
-
username: string;
|
|
6
|
-
password: string;
|
|
7
|
-
warehouse?: string;
|
|
8
|
-
database?: string;
|
|
9
|
-
schema?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface QueryResult {
|
|
13
|
-
columns: string[];
|
|
14
|
-
rows: any[];
|
|
15
|
-
rowCount: number;
|
|
16
|
-
executionTime: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class SnowflakeService {
|
|
20
|
-
private static instance: SnowflakeService;
|
|
21
|
-
private connection: snowflake.Connection | null = null;
|
|
22
|
-
private config: SnowflakeConfig;
|
|
23
|
-
|
|
24
|
-
private constructor() {
|
|
25
|
-
this.config = {
|
|
26
|
-
account: process.env.SNOWFLAKE_ACCOUNT || '',
|
|
27
|
-
username: process.env.SNOWFLAKE_USERNAME || '',
|
|
28
|
-
password: process.env.SNOWFLAKE_PASSWORD || '',
|
|
29
|
-
warehouse: process.env.SNOWFLAKE_WAREHOUSE,
|
|
30
|
-
database: process.env.SNOWFLAKE_DATABASE,
|
|
31
|
-
schema: process.env.SNOWFLAKE_SCHEMA,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
public static getInstance(): SnowflakeService {
|
|
36
|
-
if (!SnowflakeService.instance) {
|
|
37
|
-
SnowflakeService.instance = new SnowflakeService();
|
|
38
|
-
}
|
|
39
|
-
return SnowflakeService.instance;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
private async connect(): Promise<snowflake.Connection> {
|
|
43
|
-
if (this.connection) {
|
|
44
|
-
return this.connection;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return new Promise((resolve, reject) => {
|
|
48
|
-
const connectionOptions: any = {
|
|
49
|
-
account: this.config.account,
|
|
50
|
-
username: this.config.username,
|
|
51
|
-
password: this.config.password,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
if (this.config.warehouse) connectionOptions.warehouse = this.config.warehouse;
|
|
55
|
-
if (this.config.database) connectionOptions.database = this.config.database;
|
|
56
|
-
if (this.config.schema) connectionOptions.schema = this.config.schema;
|
|
57
|
-
|
|
58
|
-
this.connection = snowflake.createConnection(connectionOptions);
|
|
59
|
-
|
|
60
|
-
this.connection.connect((err, conn) => {
|
|
61
|
-
if (err) {
|
|
62
|
-
console.error('โ Failed to connect to Snowflake:', err.message);
|
|
63
|
-
reject(err);
|
|
64
|
-
} else {
|
|
65
|
-
console.log('โ
Successfully connected to Snowflake');
|
|
66
|
-
resolve(conn);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public async executeQuery(sqlText: string, binds?: any[]): Promise<QueryResult> {
|
|
73
|
-
const startTime = Date.now();
|
|
74
|
-
const conn = await this.connect();
|
|
75
|
-
|
|
76
|
-
return new Promise((resolve, reject) => {
|
|
77
|
-
conn.execute({
|
|
78
|
-
sqlText,
|
|
79
|
-
binds,
|
|
80
|
-
complete: (err, stmt, rows) => {
|
|
81
|
-
const executionTime = Date.now() - startTime;
|
|
82
|
-
|
|
83
|
-
if (err) {
|
|
84
|
-
reject(err);
|
|
85
|
-
} else {
|
|
86
|
-
const columns = stmt.getColumns().map(col => col.getName());
|
|
87
|
-
resolve({
|
|
88
|
-
columns,
|
|
89
|
-
rows: rows || [],
|
|
90
|
-
rowCount: rows?.length || 0,
|
|
91
|
-
executionTime,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
public async listDatabases(): Promise<QueryResult> {
|
|
100
|
-
return this.executeQuery('SHOW DATABASES');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
public async listSchemas(database?: string): Promise<QueryResult> {
|
|
104
|
-
if (database) {
|
|
105
|
-
return this.executeQuery(`SHOW SCHEMAS IN DATABASE ${database}`);
|
|
106
|
-
}
|
|
107
|
-
return this.executeQuery('SHOW SCHEMAS');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
public async listTables(database?: string, schema?: string): Promise<QueryResult> {
|
|
111
|
-
if (database && schema) {
|
|
112
|
-
return this.executeQuery(`SHOW TABLES IN ${database}.${schema}`);
|
|
113
|
-
}
|
|
114
|
-
return this.executeQuery('SHOW TABLES');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
public async describeTable(tableName: string): Promise<QueryResult> {
|
|
118
|
-
return this.executeQuery(`DESCRIBE TABLE ${tableName}`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
public async listWarehouses(): Promise<QueryResult> {
|
|
122
|
-
return this.executeQuery('SHOW WAREHOUSES');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public async getCurrentSession(): Promise<QueryResult> {
|
|
126
|
-
return this.executeQuery('SELECT CURRENT_USER(), CURRENT_ROLE(), CURRENT_DATABASE(), CURRENT_SCHEMA(), CURRENT_WAREHOUSE()');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
public async disconnect(): Promise<void> {
|
|
130
|
-
if (this.connection) {
|
|
131
|
-
return new Promise((resolve, reject) => {
|
|
132
|
-
this.connection!.destroy((err) => {
|
|
133
|
-
if (err) {
|
|
134
|
-
console.error('โ Error disconnecting from Snowflake:', err.message);
|
|
135
|
-
reject(err);
|
|
136
|
-
} else {
|
|
137
|
-
console.log('โ
Disconnected from Snowflake');
|
|
138
|
-
this.connection = null;
|
|
139
|
-
resolve();
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
public isConnected(): boolean {
|
|
147
|
-
return this.connection !== null;
|
|
148
|
-
}
|
|
149
|
-
}
|
package/test-api.sh
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
echo "๐งช Testing Snowflake MCP Server..."
|
|
4
|
-
|
|
5
|
-
# Base URL
|
|
6
|
-
BASE_URL="http://localhost:3000"
|
|
7
|
-
|
|
8
|
-
# Colors
|
|
9
|
-
GREEN='\033[0;32m'
|
|
10
|
-
RED='\033[0;31m'
|
|
11
|
-
NC='\033[0m' # No Color
|
|
12
|
-
|
|
13
|
-
# Health check
|
|
14
|
-
echo -e "\n๐ Testing Health Check..."
|
|
15
|
-
curl -s ${BASE_URL}/health | jq .
|
|
16
|
-
|
|
17
|
-
# Connection status
|
|
18
|
-
echo -e "\n๐ Testing Connection Status..."
|
|
19
|
-
curl -s ${BASE_URL}/api/snowflake/status | jq .
|
|
20
|
-
|
|
21
|
-
# Current session
|
|
22
|
-
echo -e "\n๐ค Testing Current Session..."
|
|
23
|
-
curl -s ${BASE_URL}/api/snowflake/session | jq .
|
|
24
|
-
|
|
25
|
-
# List databases
|
|
26
|
-
echo -e "\n๐๏ธ Testing List Databases..."
|
|
27
|
-
curl -s ${BASE_URL}/api/snowflake/databases | jq .
|
|
28
|
-
|
|
29
|
-
# List warehouses
|
|
30
|
-
echo -e "\n๐ญ Testing List Warehouses..."
|
|
31
|
-
curl -s ${BASE_URL}/api/snowflake/warehouses | jq .
|
|
32
|
-
|
|
33
|
-
# Execute query
|
|
34
|
-
echo -e "\nโก Testing Execute Query..."
|
|
35
|
-
curl -s -X POST ${BASE_URL}/api/snowflake/query \
|
|
36
|
-
-H "Content-Type: application/json" \
|
|
37
|
-
-d '{"query": "SELECT CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP()"}' | jq .
|
|
38
|
-
|
|
39
|
-
echo -e "\n${GREEN}โ
Tests completed!${NC}"
|
package/tsconfig.json
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"lib": [
|
|
6
|
-
"ES2020"
|
|
7
|
-
],
|
|
8
|
-
"outDir": "./dist",
|
|
9
|
-
"rootDir": "./src",
|
|
10
|
-
"strict": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
"forceConsistentCasingInFileNames": true,
|
|
14
|
-
"resolveJsonModule": true,
|
|
15
|
-
"declaration": true,
|
|
16
|
-
"declarationMap": true,
|
|
17
|
-
"sourceMap": true,
|
|
18
|
-
"moduleResolution": "node"
|
|
19
|
-
},
|
|
20
|
-
"include": [
|
|
21
|
-
"src/**/*",
|
|
22
|
-
"src/mcp-server.ts"
|
|
23
|
-
],
|
|
24
|
-
"exclude": [
|
|
25
|
-
"node_modules",
|
|
26
|
-
"dist"
|
|
27
|
-
]
|
|
28
|
-
}
|