langprotect-mcp-gateway 1.0.0__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.
- langprotect_mcp_gateway-1.0.0/LICENSE +21 -0
- langprotect_mcp_gateway-1.0.0/PKG-INFO +215 -0
- langprotect_mcp_gateway-1.0.0/README.md +187 -0
- langprotect_mcp_gateway-1.0.0/langprotect_mcp_gateway/__init__.py +23 -0
- langprotect_mcp_gateway-1.0.0/langprotect_mcp_gateway/gateway.py +528 -0
- langprotect_mcp_gateway-1.0.0/langprotect_mcp_gateway.egg-info/PKG-INFO +215 -0
- langprotect_mcp_gateway-1.0.0/langprotect_mcp_gateway.egg-info/SOURCES.txt +11 -0
- langprotect_mcp_gateway-1.0.0/langprotect_mcp_gateway.egg-info/dependency_links.txt +1 -0
- langprotect_mcp_gateway-1.0.0/langprotect_mcp_gateway.egg-info/entry_points.txt +2 -0
- langprotect_mcp_gateway-1.0.0/langprotect_mcp_gateway.egg-info/requires.txt +6 -0
- langprotect_mcp_gateway-1.0.0/langprotect_mcp_gateway.egg-info/top_level.txt +1 -0
- langprotect_mcp_gateway-1.0.0/pyproject.toml +50 -0
- langprotect_mcp_gateway-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LangProtect Security Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langprotect-mcp-gateway
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Security gateway for Model Context Protocol (MCP) to protect AI tool interactions
|
|
5
|
+
Author-email: LangProtect Security Team <security@langprotect.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://langprotect.com
|
|
8
|
+
Project-URL: Documentation, https://docs.langprotect.com
|
|
9
|
+
Project-URL: Repository, https://github.com/langprotect/mcp-gateway
|
|
10
|
+
Project-URL: Issues, https://github.com/langprotect/mcp-gateway/issues
|
|
11
|
+
Keywords: mcp,security,ai-security,langprotect,model-context-protocol
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: requests>=2.31.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# LangProtect MCP Gateway
|
|
30
|
+
|
|
31
|
+
🛡️ **Security gateway for Model Context Protocol (MCP)** - Protect your AI tool interactions from security threats.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
✅ **Automatic Threat Detection** - Scans all MCP requests for security risks
|
|
36
|
+
✅ **Access Control** - Whitelist/blacklist MCP servers and tools
|
|
37
|
+
✅ **Full Audit Trail** - Logs all AI interactions for compliance
|
|
38
|
+
✅ **IDE Support** - Works with VS Code, Cursor, and all MCP-compatible IDEs
|
|
39
|
+
✅ **Easy Setup** - 30-second installation
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install langprotect-mcp-gateway
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Configuration
|
|
50
|
+
|
|
51
|
+
Create your MCP config file:
|
|
52
|
+
|
|
53
|
+
**VS Code:** `~/.config/Code/User/mcp.json`
|
|
54
|
+
**Cursor:** `~/.cursor/mcp.json`
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"langprotect-gateway": {
|
|
60
|
+
"command": "langprotect-gateway",
|
|
61
|
+
"env": {
|
|
62
|
+
"LANGPROTECT_URL": "https://your-langprotect-server.com",
|
|
63
|
+
"LANGPROTECT_EMAIL": "your.email@company.com",
|
|
64
|
+
"LANGPROTECT_PASSWORD": "your-password"
|
|
65
|
+
},
|
|
66
|
+
"servers": {
|
|
67
|
+
"filesystem": {
|
|
68
|
+
"command": "npx",
|
|
69
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
📝 **Note:** Replace `LANGPROTECT_URL` with your actual server URL (e.g., `https://langprotect.yourcompany.com` or `http://localhost:8000` for local testing).
|
|
78
|
+
|
|
79
|
+
### Restart Your IDE
|
|
80
|
+
|
|
81
|
+
**VS Code:** `Ctrl+Shift+P` → "Reload Window"
|
|
82
|
+
**Cursor:** Close and reopen
|
|
83
|
+
|
|
84
|
+
Done! 🎉 All your AI tool interactions are now protected.
|
|
85
|
+
|
|
86
|
+
## What It Does
|
|
87
|
+
|
|
88
|
+
The LangProtect MCP Gateway intercepts all AI tool interactions and:
|
|
89
|
+
|
|
90
|
+
1. **Scans for threats** - Detects malicious commands, data exfiltration attempts
|
|
91
|
+
2. **Enforces policies** - Blocks access to sensitive files and dangerous operations
|
|
92
|
+
3. **Logs everything** - Complete audit trail for compliance
|
|
93
|
+
4. **Auto-detects IDE** - Tracks which IDE/tool made each request
|
|
94
|
+
|
|
95
|
+
## Supported IDEs
|
|
96
|
+
|
|
97
|
+
- ✅ VS Code (with GitHub Copilot, Codeium, etc.)
|
|
98
|
+
- ✅ Cursor IDE
|
|
99
|
+
- ✅ Windsurf
|
|
100
|
+
- ✅ Zed Editor
|
|
101
|
+
- ✅ Any MCP-compatible IDE
|
|
102
|
+
|
|
103
|
+
## Environment Variables
|
|
104
|
+
|
|
105
|
+
| Variable | Required | Default | Description |
|
|
106
|
+
|----------|----------|---------|-------------|
|
|
107
|
+
| `LANGPROTECT_URL` | No | `http://localhost:8000` | Your LangProtect server URL |
|
|
108
|
+
| `LANGPROTECT_EMAIL` | **Yes** | - | Your email address |
|
|
109
|
+
| `LANGPROTECT_PASSWORD` | **Yes** | - | Your password |
|
|
110
|
+
| `DEBUG` | No | `false` | Enable debug logging (true/false) |
|
|
111
|
+
| `MCP_CONFIG_PATH` | No | Auto-detected | Path to servers config (Cursor only) |
|
|
112
|
+
|
|
113
|
+
⚠️ **Production Setup:** For production deployments, always set `LANGPROTECT_URL` to your actual server:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
"env": {
|
|
117
|
+
"LANGPROTECT_URL": "https://langprotect.yourcompany.com",
|
|
118
|
+
"LANGPROTECT_EMAIL": "your.email@company.com",
|
|
119
|
+
"LANGPROTECT_PASSWORD": "your-password"
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The default `http://localhost:8000` is only for local development/testing.
|
|
124
|
+
|
|
125
|
+
## Architecture
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
AI Assistant (Copilot, etc.)
|
|
129
|
+
↓
|
|
130
|
+
LangProtect Gateway (this package)
|
|
131
|
+
↓
|
|
132
|
+
[Security Scan]
|
|
133
|
+
↓
|
|
134
|
+
MCP Servers (filesystem, github, etc.)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Every request is:
|
|
138
|
+
1. Intercepted by the gateway
|
|
139
|
+
2. Scanned for security threats
|
|
140
|
+
3. Logged to LangProtect backend
|
|
141
|
+
4. Forwarded to actual MCP server (if safe)
|
|
142
|
+
5. Response returned to AI
|
|
143
|
+
|
|
144
|
+
## Dashboard
|
|
145
|
+
|
|
146
|
+
Monitor all activity at your LangProtect dashboard:
|
|
147
|
+
- View all AI interactions
|
|
148
|
+
- See security threats blocked
|
|
149
|
+
- Track IDE usage
|
|
150
|
+
- Generate compliance reports
|
|
151
|
+
|
|
152
|
+
## Security
|
|
153
|
+
|
|
154
|
+
The gateway protects against:
|
|
155
|
+
- 🚫 Sensitive file access (`.env`, SSH keys, etc.)
|
|
156
|
+
- 🚫 Dangerous commands (`rm -rf`, data exfiltration)
|
|
157
|
+
- 🚫 SQL injection patterns
|
|
158
|
+
- 🚫 Hardcoded credentials in suggestions
|
|
159
|
+
- 🚫 Prompt injection attacks
|
|
160
|
+
|
|
161
|
+
## Troubleshooting
|
|
162
|
+
|
|
163
|
+
**Authentication failed:**
|
|
164
|
+
- Check `LANGPROTECT_URL`, `LANGPROTECT_EMAIL`, `LANGPROTECT_PASSWORD` are correct
|
|
165
|
+
- Ensure LangProtect backend is accessible
|
|
166
|
+
|
|
167
|
+
**Gateway not starting:**
|
|
168
|
+
- Check Python version: `python3 --version` (need 3.11+)
|
|
169
|
+
- Check package installed: `pip show langprotect-mcp-gateway`
|
|
170
|
+
|
|
171
|
+
**Tools not working:**
|
|
172
|
+
- Check MCP servers are configured under `"servers"` section
|
|
173
|
+
- Restart IDE completely
|
|
174
|
+
|
|
175
|
+
## For Team Leads
|
|
176
|
+
|
|
177
|
+
### Quick Team Rollout:
|
|
178
|
+
|
|
179
|
+
1. **Share credentials** with each team member:
|
|
180
|
+
```
|
|
181
|
+
Email: user@company.com
|
|
182
|
+
Password: secure-password
|
|
183
|
+
Server: http://langprotect.company.com:8000
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
2. **Team members install:**
|
|
187
|
+
```bash
|
|
188
|
+
pip install langprotect-mcp-gateway
|
|
189
|
+
# Configure mcp.json with credentials
|
|
190
|
+
# Restart IDE
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
3. **Monitor dashboard:** See all team activity in real-time
|
|
194
|
+
|
|
195
|
+
## Updates
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install --upgrade langprotect-mcp-gateway
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Support
|
|
202
|
+
|
|
203
|
+
- **Documentation:** https://docs.langprotect.com
|
|
204
|
+
- **Issues:** https://github.com/langprotect/mcp-gateway/issues
|
|
205
|
+
- **Security:** security@langprotect.com
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT License - see LICENSE file for details
|
|
210
|
+
|
|
211
|
+
## Links
|
|
212
|
+
|
|
213
|
+
- **Homepage:** https://langprotect.com
|
|
214
|
+
- **GitHub:** https://github.com/langprotect/mcp-gateway
|
|
215
|
+
- **Documentation:** https://docs.langprotect.com
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# LangProtect MCP Gateway
|
|
2
|
+
|
|
3
|
+
🛡️ **Security gateway for Model Context Protocol (MCP)** - Protect your AI tool interactions from security threats.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ **Automatic Threat Detection** - Scans all MCP requests for security risks
|
|
8
|
+
✅ **Access Control** - Whitelist/blacklist MCP servers and tools
|
|
9
|
+
✅ **Full Audit Trail** - Logs all AI interactions for compliance
|
|
10
|
+
✅ **IDE Support** - Works with VS Code, Cursor, and all MCP-compatible IDEs
|
|
11
|
+
✅ **Easy Setup** - 30-second installation
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install langprotect-mcp-gateway
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Configuration
|
|
22
|
+
|
|
23
|
+
Create your MCP config file:
|
|
24
|
+
|
|
25
|
+
**VS Code:** `~/.config/Code/User/mcp.json`
|
|
26
|
+
**Cursor:** `~/.cursor/mcp.json`
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"langprotect-gateway": {
|
|
32
|
+
"command": "langprotect-gateway",
|
|
33
|
+
"env": {
|
|
34
|
+
"LANGPROTECT_URL": "https://your-langprotect-server.com",
|
|
35
|
+
"LANGPROTECT_EMAIL": "your.email@company.com",
|
|
36
|
+
"LANGPROTECT_PASSWORD": "your-password"
|
|
37
|
+
},
|
|
38
|
+
"servers": {
|
|
39
|
+
"filesystem": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
📝 **Note:** Replace `LANGPROTECT_URL` with your actual server URL (e.g., `https://langprotect.yourcompany.com` or `http://localhost:8000` for local testing).
|
|
50
|
+
|
|
51
|
+
### Restart Your IDE
|
|
52
|
+
|
|
53
|
+
**VS Code:** `Ctrl+Shift+P` → "Reload Window"
|
|
54
|
+
**Cursor:** Close and reopen
|
|
55
|
+
|
|
56
|
+
Done! 🎉 All your AI tool interactions are now protected.
|
|
57
|
+
|
|
58
|
+
## What It Does
|
|
59
|
+
|
|
60
|
+
The LangProtect MCP Gateway intercepts all AI tool interactions and:
|
|
61
|
+
|
|
62
|
+
1. **Scans for threats** - Detects malicious commands, data exfiltration attempts
|
|
63
|
+
2. **Enforces policies** - Blocks access to sensitive files and dangerous operations
|
|
64
|
+
3. **Logs everything** - Complete audit trail for compliance
|
|
65
|
+
4. **Auto-detects IDE** - Tracks which IDE/tool made each request
|
|
66
|
+
|
|
67
|
+
## Supported IDEs
|
|
68
|
+
|
|
69
|
+
- ✅ VS Code (with GitHub Copilot, Codeium, etc.)
|
|
70
|
+
- ✅ Cursor IDE
|
|
71
|
+
- ✅ Windsurf
|
|
72
|
+
- ✅ Zed Editor
|
|
73
|
+
- ✅ Any MCP-compatible IDE
|
|
74
|
+
|
|
75
|
+
## Environment Variables
|
|
76
|
+
|
|
77
|
+
| Variable | Required | Default | Description |
|
|
78
|
+
|----------|----------|---------|-------------|
|
|
79
|
+
| `LANGPROTECT_URL` | No | `http://localhost:8000` | Your LangProtect server URL |
|
|
80
|
+
| `LANGPROTECT_EMAIL` | **Yes** | - | Your email address |
|
|
81
|
+
| `LANGPROTECT_PASSWORD` | **Yes** | - | Your password |
|
|
82
|
+
| `DEBUG` | No | `false` | Enable debug logging (true/false) |
|
|
83
|
+
| `MCP_CONFIG_PATH` | No | Auto-detected | Path to servers config (Cursor only) |
|
|
84
|
+
|
|
85
|
+
⚠️ **Production Setup:** For production deployments, always set `LANGPROTECT_URL` to your actual server:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
"env": {
|
|
89
|
+
"LANGPROTECT_URL": "https://langprotect.yourcompany.com",
|
|
90
|
+
"LANGPROTECT_EMAIL": "your.email@company.com",
|
|
91
|
+
"LANGPROTECT_PASSWORD": "your-password"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The default `http://localhost:8000` is only for local development/testing.
|
|
96
|
+
|
|
97
|
+
## Architecture
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
AI Assistant (Copilot, etc.)
|
|
101
|
+
↓
|
|
102
|
+
LangProtect Gateway (this package)
|
|
103
|
+
↓
|
|
104
|
+
[Security Scan]
|
|
105
|
+
↓
|
|
106
|
+
MCP Servers (filesystem, github, etc.)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Every request is:
|
|
110
|
+
1. Intercepted by the gateway
|
|
111
|
+
2. Scanned for security threats
|
|
112
|
+
3. Logged to LangProtect backend
|
|
113
|
+
4. Forwarded to actual MCP server (if safe)
|
|
114
|
+
5. Response returned to AI
|
|
115
|
+
|
|
116
|
+
## Dashboard
|
|
117
|
+
|
|
118
|
+
Monitor all activity at your LangProtect dashboard:
|
|
119
|
+
- View all AI interactions
|
|
120
|
+
- See security threats blocked
|
|
121
|
+
- Track IDE usage
|
|
122
|
+
- Generate compliance reports
|
|
123
|
+
|
|
124
|
+
## Security
|
|
125
|
+
|
|
126
|
+
The gateway protects against:
|
|
127
|
+
- 🚫 Sensitive file access (`.env`, SSH keys, etc.)
|
|
128
|
+
- 🚫 Dangerous commands (`rm -rf`, data exfiltration)
|
|
129
|
+
- 🚫 SQL injection patterns
|
|
130
|
+
- 🚫 Hardcoded credentials in suggestions
|
|
131
|
+
- 🚫 Prompt injection attacks
|
|
132
|
+
|
|
133
|
+
## Troubleshooting
|
|
134
|
+
|
|
135
|
+
**Authentication failed:**
|
|
136
|
+
- Check `LANGPROTECT_URL`, `LANGPROTECT_EMAIL`, `LANGPROTECT_PASSWORD` are correct
|
|
137
|
+
- Ensure LangProtect backend is accessible
|
|
138
|
+
|
|
139
|
+
**Gateway not starting:**
|
|
140
|
+
- Check Python version: `python3 --version` (need 3.11+)
|
|
141
|
+
- Check package installed: `pip show langprotect-mcp-gateway`
|
|
142
|
+
|
|
143
|
+
**Tools not working:**
|
|
144
|
+
- Check MCP servers are configured under `"servers"` section
|
|
145
|
+
- Restart IDE completely
|
|
146
|
+
|
|
147
|
+
## For Team Leads
|
|
148
|
+
|
|
149
|
+
### Quick Team Rollout:
|
|
150
|
+
|
|
151
|
+
1. **Share credentials** with each team member:
|
|
152
|
+
```
|
|
153
|
+
Email: user@company.com
|
|
154
|
+
Password: secure-password
|
|
155
|
+
Server: http://langprotect.company.com:8000
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
2. **Team members install:**
|
|
159
|
+
```bash
|
|
160
|
+
pip install langprotect-mcp-gateway
|
|
161
|
+
# Configure mcp.json with credentials
|
|
162
|
+
# Restart IDE
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
3. **Monitor dashboard:** See all team activity in real-time
|
|
166
|
+
|
|
167
|
+
## Updates
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
pip install --upgrade langprotect-mcp-gateway
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Support
|
|
174
|
+
|
|
175
|
+
- **Documentation:** https://docs.langprotect.com
|
|
176
|
+
- **Issues:** https://github.com/langprotect/mcp-gateway/issues
|
|
177
|
+
- **Security:** security@langprotect.com
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT License - see LICENSE file for details
|
|
182
|
+
|
|
183
|
+
## Links
|
|
184
|
+
|
|
185
|
+
- **Homepage:** https://langprotect.com
|
|
186
|
+
- **GitHub:** https://github.com/langprotect/mcp-gateway
|
|
187
|
+
- **Documentation:** https://docs.langprotect.com
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LangProtect MCP Gateway
|
|
3
|
+
~~~~~~~~~~~~~~~~~~~~~~~
|
|
4
|
+
|
|
5
|
+
A security gateway for Model Context Protocol (MCP) that protects AI tool interactions.
|
|
6
|
+
|
|
7
|
+
Basic usage:
|
|
8
|
+
from langprotect_mcp_gateway import LangProtectGateway
|
|
9
|
+
|
|
10
|
+
gateway = LangProtectGateway()
|
|
11
|
+
gateway.run()
|
|
12
|
+
|
|
13
|
+
Or via command line:
|
|
14
|
+
langprotect-gateway
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__version__ = '1.0.0'
|
|
18
|
+
__author__ = 'LangProtect Security Team'
|
|
19
|
+
__license__ = 'MIT'
|
|
20
|
+
|
|
21
|
+
from .gateway import LangProtectGateway, main
|
|
22
|
+
|
|
23
|
+
__all__ = ['LangProtectGateway', 'main', '__version__']
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
LangProtect MCP Gateway - Universal MCP Logging & Security
|
|
4
|
+
|
|
5
|
+
This gateway intercepts ALL MCP tool calls from any client (Claude, VS Code, etc.)
|
|
6
|
+
and logs them to LangProtect backend for security scanning and auditing.
|
|
7
|
+
|
|
8
|
+
Architecture:
|
|
9
|
+
1. Reads user's MCP config to discover other MCP servers
|
|
10
|
+
2. Implements MCP protocol (initialize, list_tools, call_tool)
|
|
11
|
+
3. Logs every tool call to LangProtect backend
|
|
12
|
+
4. Forwards requests to actual MCP servers
|
|
13
|
+
5. Returns responses to AI client
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
python3 langprotect_gateway.py
|
|
17
|
+
|
|
18
|
+
Configuration (via environment variables):
|
|
19
|
+
LANGPROTECT_URL - Backend API URL (default: http://localhost:8000)
|
|
20
|
+
LANGPROTECT_EMAIL - User email for authentication
|
|
21
|
+
LANGPROTECT_PASSWORD - User password
|
|
22
|
+
MCP_CONFIG_PATH - Path to mcp.json (auto-detected if not set)
|
|
23
|
+
DEBUG - Enable debug logging (true/false)
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import sys
|
|
27
|
+
import json
|
|
28
|
+
import os
|
|
29
|
+
import subprocess
|
|
30
|
+
import requests
|
|
31
|
+
import threading
|
|
32
|
+
import time
|
|
33
|
+
from datetime import datetime, timedelta
|
|
34
|
+
from pathlib import Path
|
|
35
|
+
from typing import Dict, List, Any, Optional
|
|
36
|
+
import logging
|
|
37
|
+
|
|
38
|
+
# Configure logging
|
|
39
|
+
logging.basicConfig(
|
|
40
|
+
level=logging.DEBUG if os.getenv('DEBUG', 'false').lower() == 'true' else logging.INFO,
|
|
41
|
+
format='[%(asctime)s] %(levelname)s: %(message)s',
|
|
42
|
+
handlers=[logging.StreamHandler(sys.stderr)]
|
|
43
|
+
)
|
|
44
|
+
logger = logging.getLogger('langprotect-gateway')
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class MCPServer:
|
|
48
|
+
"""Represents a single MCP server that can be called"""
|
|
49
|
+
|
|
50
|
+
def __init__(self, name: str, config: Dict[str, Any]):
|
|
51
|
+
self.name = name
|
|
52
|
+
self.command = config.get('command')
|
|
53
|
+
self.args = config.get('args', [])
|
|
54
|
+
self.env = config.get('env', {})
|
|
55
|
+
self.tools = [] # Will be populated by discovery
|
|
56
|
+
self.process = None
|
|
57
|
+
logger.info(f"Initialized MCP server: {name}")
|
|
58
|
+
|
|
59
|
+
def call(self, method: str, params: Dict) -> Dict:
|
|
60
|
+
"""Call this MCP server with a method and params"""
|
|
61
|
+
try:
|
|
62
|
+
# Start process for this call
|
|
63
|
+
env = {**os.environ, **self.env}
|
|
64
|
+
|
|
65
|
+
self.process = subprocess.Popen(
|
|
66
|
+
[self.command] + self.args,
|
|
67
|
+
stdin=subprocess.PIPE,
|
|
68
|
+
stdout=subprocess.PIPE,
|
|
69
|
+
stderr=subprocess.PIPE,
|
|
70
|
+
text=True,
|
|
71
|
+
env=env
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Send request
|
|
75
|
+
request = {
|
|
76
|
+
"jsonrpc": "2.0",
|
|
77
|
+
"id": 1,
|
|
78
|
+
"method": method,
|
|
79
|
+
"params": params
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
logger.debug(f"Calling {self.name}.{method}: {json.dumps(request)}")
|
|
83
|
+
|
|
84
|
+
self.process.stdin.write(json.dumps(request) + "\n")
|
|
85
|
+
self.process.stdin.flush()
|
|
86
|
+
|
|
87
|
+
# Read response
|
|
88
|
+
response_line = self.process.stdout.readline()
|
|
89
|
+
if not response_line:
|
|
90
|
+
error_output = self.process.stderr.read()
|
|
91
|
+
raise Exception(f"No response from {self.name}: {error_output}")
|
|
92
|
+
|
|
93
|
+
response = json.loads(response_line)
|
|
94
|
+
|
|
95
|
+
# Cleanup
|
|
96
|
+
self.process.terminate()
|
|
97
|
+
self.process.wait(timeout=1)
|
|
98
|
+
|
|
99
|
+
logger.debug(f"Response from {self.name}: {json.dumps(response)[:200]}")
|
|
100
|
+
|
|
101
|
+
return response
|
|
102
|
+
|
|
103
|
+
except Exception as e:
|
|
104
|
+
logger.error(f"Error calling {self.name}: {e}")
|
|
105
|
+
if self.process:
|
|
106
|
+
self.process.terminate()
|
|
107
|
+
raise
|
|
108
|
+
|
|
109
|
+
def discover_tools(self) -> List[Dict]:
|
|
110
|
+
"""Discover what tools this MCP server provides"""
|
|
111
|
+
try:
|
|
112
|
+
response = self.call("tools/list", {})
|
|
113
|
+
if "result" in response:
|
|
114
|
+
self.tools = response["result"].get("tools", [])
|
|
115
|
+
logger.info(f"Discovered {len(self.tools)} tools from {self.name}")
|
|
116
|
+
return self.tools
|
|
117
|
+
return []
|
|
118
|
+
except Exception as e:
|
|
119
|
+
logger.warning(f"Could not discover tools from {self.name}: {e}")
|
|
120
|
+
return []
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class LangProtectGateway:
|
|
124
|
+
"""Main gateway that intercepts and logs all MCP traffic"""
|
|
125
|
+
|
|
126
|
+
def __init__(self):
|
|
127
|
+
self.langprotect_url = os.getenv('LANGPROTECT_URL', 'http://localhost:8000')
|
|
128
|
+
self.email = os.getenv('LANGPROTECT_EMAIL')
|
|
129
|
+
self.password = os.getenv('LANGPROTECT_PASSWORD')
|
|
130
|
+
self.jwt_token = None
|
|
131
|
+
self.token_expiry = None
|
|
132
|
+
self.mcp_servers = {} # name -> MCPServer
|
|
133
|
+
self.tool_to_server = {} # tool_name -> server_name
|
|
134
|
+
|
|
135
|
+
# Debug: Log what we received
|
|
136
|
+
logger.debug(f"Environment variables received:")
|
|
137
|
+
logger.debug(f" LANGPROTECT_URL: {self.langprotect_url}")
|
|
138
|
+
logger.debug(f" LANGPROTECT_EMAIL: {self.email}")
|
|
139
|
+
logger.debug(f" LANGPROTECT_PASSWORD: {'***' + self.password[-4:] if self.password else 'NOT SET'}")
|
|
140
|
+
|
|
141
|
+
# Validate credentials
|
|
142
|
+
if not self.email or not self.password:
|
|
143
|
+
logger.error("LANGPROTECT_EMAIL and LANGPROTECT_PASSWORD must be set")
|
|
144
|
+
sys.exit(1)
|
|
145
|
+
|
|
146
|
+
# Authenticate
|
|
147
|
+
self.login()
|
|
148
|
+
|
|
149
|
+
# Discover MCP servers
|
|
150
|
+
self.discover_mcp_servers()
|
|
151
|
+
|
|
152
|
+
# Start token refresh thread
|
|
153
|
+
self.start_token_refresh()
|
|
154
|
+
|
|
155
|
+
logger.info("LangProtect Gateway initialized successfully")
|
|
156
|
+
|
|
157
|
+
def login(self):
|
|
158
|
+
"""Authenticate with LangProtect backend and get JWT token"""
|
|
159
|
+
try:
|
|
160
|
+
logger.info(f"Logging in to {self.langprotect_url}...")
|
|
161
|
+
|
|
162
|
+
response = requests.post(
|
|
163
|
+
f"{self.langprotect_url}/v1/group-users/signin",
|
|
164
|
+
json={
|
|
165
|
+
'email': self.email,
|
|
166
|
+
'password': self.password
|
|
167
|
+
},
|
|
168
|
+
timeout=10
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if response.status_code == 200:
|
|
172
|
+
data = response.json()
|
|
173
|
+
self.jwt_token = data.get('access_token')
|
|
174
|
+
self.token_expiry = datetime.now() + timedelta(days=6)
|
|
175
|
+
logger.info("✅ Authentication successful")
|
|
176
|
+
return True
|
|
177
|
+
else:
|
|
178
|
+
logger.error(f"❌ Login failed: {response.status_code} - {response.text}")
|
|
179
|
+
sys.exit(1)
|
|
180
|
+
|
|
181
|
+
except Exception as e:
|
|
182
|
+
logger.error(f"❌ Login error: {e}")
|
|
183
|
+
sys.exit(1)
|
|
184
|
+
|
|
185
|
+
def ensure_token(self):
|
|
186
|
+
"""Ensure we have a valid JWT token"""
|
|
187
|
+
if not self.jwt_token or (self.token_expiry and datetime.now() > self.token_expiry):
|
|
188
|
+
logger.info("Token expired, re-authenticating...")
|
|
189
|
+
return self.login()
|
|
190
|
+
return True
|
|
191
|
+
|
|
192
|
+
def start_token_refresh(self):
|
|
193
|
+
"""Start background thread to refresh JWT token"""
|
|
194
|
+
def refresh_loop():
|
|
195
|
+
while True:
|
|
196
|
+
time.sleep(86400) # Check daily
|
|
197
|
+
if self.token_expiry and datetime.now() > self.token_expiry:
|
|
198
|
+
logger.info("Auto-refreshing token...")
|
|
199
|
+
self.login()
|
|
200
|
+
|
|
201
|
+
refresh_thread = threading.Thread(target=refresh_loop, daemon=True)
|
|
202
|
+
refresh_thread.start()
|
|
203
|
+
logger.debug("Token refresh thread started")
|
|
204
|
+
|
|
205
|
+
def discover_mcp_servers(self):
|
|
206
|
+
"""Find and load MCP servers from user's config"""
|
|
207
|
+
config_paths = [
|
|
208
|
+
os.getenv('MCP_CONFIG_PATH'),
|
|
209
|
+
os.path.expanduser('~/.cursor/mcp.json'),
|
|
210
|
+
os.path.expanduser('~/.config/Claude/claude_desktop_config.json'),
|
|
211
|
+
os.path.expanduser('~/Library/Application Support/Claude/claude_desktop_config.json')
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
for path in config_paths:
|
|
215
|
+
if not path:
|
|
216
|
+
continue
|
|
217
|
+
|
|
218
|
+
path = os.path.expanduser(path)
|
|
219
|
+
if os.path.exists(path):
|
|
220
|
+
logger.info(f"Found MCP config: {path}")
|
|
221
|
+
try:
|
|
222
|
+
with open(path, 'r') as f:
|
|
223
|
+
config = json.load(f)
|
|
224
|
+
|
|
225
|
+
servers = config.get('mcpServers', {})
|
|
226
|
+
|
|
227
|
+
# Load all servers except ourselves
|
|
228
|
+
for name, cfg in servers.items():
|
|
229
|
+
if name == 'langprotect-gateway' or name == 'langprotect':
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
server = MCPServer(name, cfg)
|
|
234
|
+
self.mcp_servers[name] = server
|
|
235
|
+
|
|
236
|
+
# Discover tools from this server
|
|
237
|
+
tools = server.discover_tools()
|
|
238
|
+
for tool in tools:
|
|
239
|
+
tool_name = tool.get('name')
|
|
240
|
+
if tool_name:
|
|
241
|
+
self.tool_to_server[tool_name] = name
|
|
242
|
+
logger.debug(f" Tool: {tool_name} -> {name}")
|
|
243
|
+
|
|
244
|
+
except Exception as e:
|
|
245
|
+
logger.warning(f"Failed to load MCP server {name}: {e}")
|
|
246
|
+
|
|
247
|
+
logger.info(f"✅ Loaded {len(self.mcp_servers)} MCP servers")
|
|
248
|
+
logger.info(f"✅ Discovered {len(self.tool_to_server)} tools")
|
|
249
|
+
return
|
|
250
|
+
|
|
251
|
+
except Exception as e:
|
|
252
|
+
logger.error(f"Error reading config {path}: {e}")
|
|
253
|
+
|
|
254
|
+
logger.warning("⚠️ No MCP config found - gateway will not proxy any servers")
|
|
255
|
+
|
|
256
|
+
def log_to_backend(self, method: str, params: Dict, server_name: str = "unknown") -> Dict:
|
|
257
|
+
"""Log MCP request to LangProtect backend for scanning"""
|
|
258
|
+
self.ensure_token()
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
# Build content for scanning - convert MCP request to scannable format
|
|
262
|
+
if method == 'tools/call':
|
|
263
|
+
tool_name = params.get('name', 'unknown_tool')
|
|
264
|
+
arguments = params.get('arguments', {})
|
|
265
|
+
scan_content = json.dumps({
|
|
266
|
+
'tool': tool_name,
|
|
267
|
+
'arguments': arguments,
|
|
268
|
+
'server_url': server_name,
|
|
269
|
+
'method': method
|
|
270
|
+
})
|
|
271
|
+
else:
|
|
272
|
+
scan_content = json.dumps({
|
|
273
|
+
'method': method,
|
|
274
|
+
'params': params,
|
|
275
|
+
'server_url': server_name
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
# Use standard group scan endpoint (works with existing scanners + policies)
|
|
279
|
+
payload = {
|
|
280
|
+
'prompt': scan_content, # MCP request as prompt
|
|
281
|
+
'client_ip': '127.0.0.1',
|
|
282
|
+
'user_agent': f'LangProtect-MCP-Gateway/1.0 (server={server_name})',
|
|
283
|
+
'source': 'mcp-gateway'
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
logger.debug(f"Logging to backend: {method} on {server_name}")
|
|
287
|
+
|
|
288
|
+
response = requests.post(
|
|
289
|
+
f"{self.langprotect_url}/v1/group-logs/scan",
|
|
290
|
+
json=payload,
|
|
291
|
+
headers={
|
|
292
|
+
'Authorization': f'Bearer {self.jwt_token}',
|
|
293
|
+
'Content-Type': 'application/json'
|
|
294
|
+
},
|
|
295
|
+
timeout=30
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
if response.status_code != 200:
|
|
299
|
+
logger.error(f"Backend scan failed: {response.status_code} - {response.text}")
|
|
300
|
+
# Fail-open: allow request if backend error
|
|
301
|
+
return {'status': 'allowed', 'error': f'Backend error: {response.status_code}'}
|
|
302
|
+
|
|
303
|
+
result = response.json()
|
|
304
|
+
status = result.get('status', '').lower()
|
|
305
|
+
|
|
306
|
+
logger.debug(f"Backend response: status={status}, log_id={result.get('id')}")
|
|
307
|
+
|
|
308
|
+
return result
|
|
309
|
+
|
|
310
|
+
except Exception as e:
|
|
311
|
+
logger.error(f"Error logging to backend: {e}")
|
|
312
|
+
# Fail-open for now (TODO: make configurable)
|
|
313
|
+
return {'status': 'allowed', 'error': str(e)}
|
|
314
|
+
|
|
315
|
+
def handle_mcp_request(self, request: Dict) -> Dict:
|
|
316
|
+
"""Main MCP protocol handler"""
|
|
317
|
+
method = request.get('method')
|
|
318
|
+
request_id = request.get('id')
|
|
319
|
+
|
|
320
|
+
logger.info(f"📥 MCP Request: {method} (id={request_id})")
|
|
321
|
+
|
|
322
|
+
try:
|
|
323
|
+
if method == 'initialize':
|
|
324
|
+
return self.handle_initialize(request)
|
|
325
|
+
elif method == 'tools/list':
|
|
326
|
+
return self.handle_list_tools(request)
|
|
327
|
+
elif method == 'tools/call':
|
|
328
|
+
return self.handle_call_tool(request)
|
|
329
|
+
else:
|
|
330
|
+
logger.warning(f"Unknown method: {method}")
|
|
331
|
+
return {
|
|
332
|
+
'jsonrpc': '2.0',
|
|
333
|
+
'id': request_id,
|
|
334
|
+
'error': {
|
|
335
|
+
'code': -32601,
|
|
336
|
+
'message': f'Method not found: {method}'
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
except Exception as e:
|
|
341
|
+
logger.error(f"Error handling {method}: {e}", exc_info=True)
|
|
342
|
+
return {
|
|
343
|
+
'jsonrpc': '2.0',
|
|
344
|
+
'id': request_id,
|
|
345
|
+
'error': {
|
|
346
|
+
'code': -32603,
|
|
347
|
+
'message': f'Internal error: {str(e)}'
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
def handle_initialize(self, request: Dict) -> Dict:
|
|
352
|
+
"""Handle MCP initialize handshake"""
|
|
353
|
+
logger.info("Handling initialize request")
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
'jsonrpc': '2.0',
|
|
357
|
+
'id': request.get('id'),
|
|
358
|
+
'result': {
|
|
359
|
+
'protocolVersion': '2024-11-05',
|
|
360
|
+
'capabilities': {
|
|
361
|
+
'tools': {}
|
|
362
|
+
},
|
|
363
|
+
'serverInfo': {
|
|
364
|
+
'name': 'langprotect-gateway',
|
|
365
|
+
'version': '1.0.0'
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
def handle_list_tools(self, request: Dict) -> Dict:
|
|
371
|
+
"""Return all tools from all MCP servers"""
|
|
372
|
+
logger.info(f"Listing tools from {len(self.mcp_servers)} servers")
|
|
373
|
+
|
|
374
|
+
all_tools = []
|
|
375
|
+
|
|
376
|
+
for server_name, server in self.mcp_servers.items():
|
|
377
|
+
# Use cached tools from discovery
|
|
378
|
+
for tool in server.tools:
|
|
379
|
+
# Add server name to tool description for clarity
|
|
380
|
+
tool_copy = tool.copy()
|
|
381
|
+
original_desc = tool_copy.get('description', '')
|
|
382
|
+
tool_copy['description'] = f"[{server_name}] {original_desc}"
|
|
383
|
+
all_tools.append(tool_copy)
|
|
384
|
+
|
|
385
|
+
logger.info(f"✅ Returning {len(all_tools)} tools")
|
|
386
|
+
|
|
387
|
+
return {
|
|
388
|
+
'jsonrpc': '2.0',
|
|
389
|
+
'id': request.get('id'),
|
|
390
|
+
'result': {
|
|
391
|
+
'tools': all_tools
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
def handle_call_tool(self, request: Dict) -> Dict:
|
|
396
|
+
"""Intercept tool call, log it, check policy, forward to server"""
|
|
397
|
+
params = request.get('params', {})
|
|
398
|
+
tool_name = params.get('name')
|
|
399
|
+
arguments = params.get('arguments', {})
|
|
400
|
+
|
|
401
|
+
logger.info(f"🔧 Tool call: {tool_name}")
|
|
402
|
+
logger.debug(f" Arguments: {json.dumps(arguments)[:200]}")
|
|
403
|
+
|
|
404
|
+
# Find which server owns this tool
|
|
405
|
+
server_name = self.tool_to_server.get(tool_name)
|
|
406
|
+
if not server_name:
|
|
407
|
+
logger.error(f"Unknown tool: {tool_name}")
|
|
408
|
+
return {
|
|
409
|
+
'jsonrpc': '2.0',
|
|
410
|
+
'id': request.get('id'),
|
|
411
|
+
'error': {
|
|
412
|
+
'code': -32602,
|
|
413
|
+
'message': f'Unknown tool: {tool_name}'
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
# 1. Log to LangProtect backend (security scan)
|
|
418
|
+
log_result = self.log_to_backend('tools/call', params, server_name)
|
|
419
|
+
|
|
420
|
+
# 2. Check if blocked by policy
|
|
421
|
+
status = log_result.get('status', '').lower()
|
|
422
|
+
if status == 'blocked':
|
|
423
|
+
reason = 'Policy violation'
|
|
424
|
+
detections = log_result.get('detections', {})
|
|
425
|
+
if 'MCPActionControl' in detections:
|
|
426
|
+
reason = detections['MCPActionControl'].get('reason', reason)
|
|
427
|
+
|
|
428
|
+
logger.warning(f"🛡️ BLOCKED: {tool_name} - {reason}")
|
|
429
|
+
|
|
430
|
+
return {
|
|
431
|
+
'jsonrpc': '2.0',
|
|
432
|
+
'id': request.get('id'),
|
|
433
|
+
'error': {
|
|
434
|
+
'code': -32000,
|
|
435
|
+
'message': f'🛡️ LangProtect: {reason}',
|
|
436
|
+
'data': {
|
|
437
|
+
'log_id': log_result.get('id'),
|
|
438
|
+
'risk_score': log_result.get('risk_score'),
|
|
439
|
+
'detections': detections
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
# 3. Forward to actual MCP server
|
|
445
|
+
logger.info(f"✅ ALLOWED: Forwarding to {server_name}")
|
|
446
|
+
|
|
447
|
+
try:
|
|
448
|
+
server = self.mcp_servers[server_name]
|
|
449
|
+
response = server.call('tools/call', params)
|
|
450
|
+
|
|
451
|
+
# Log successful response
|
|
452
|
+
if 'result' in response:
|
|
453
|
+
logger.info(f"✅ Tool {tool_name} completed successfully")
|
|
454
|
+
elif 'error' in response:
|
|
455
|
+
logger.warning(f"⚠️ Tool {tool_name} returned error: {response['error'].get('message')}")
|
|
456
|
+
|
|
457
|
+
# Return response with original request ID
|
|
458
|
+
response['id'] = request.get('id')
|
|
459
|
+
return response
|
|
460
|
+
|
|
461
|
+
except Exception as e:
|
|
462
|
+
logger.error(f"Error executing {tool_name} on {server_name}: {e}")
|
|
463
|
+
return {
|
|
464
|
+
'jsonrpc': '2.0',
|
|
465
|
+
'id': request.get('id'),
|
|
466
|
+
'error': {
|
|
467
|
+
'code': -32603,
|
|
468
|
+
'message': f'Error executing tool: {str(e)}'
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
def run(self):
|
|
473
|
+
"""Main loop: read MCP requests from stdin, write responses to stdout"""
|
|
474
|
+
logger.info("🚀 LangProtect Gateway started")
|
|
475
|
+
logger.info(f"📡 Connected to: {self.langprotect_url}")
|
|
476
|
+
logger.info(f"👤 User: {self.email}")
|
|
477
|
+
logger.info(f"🔧 Proxying {len(self.mcp_servers)} MCP servers")
|
|
478
|
+
logger.info("=" * 60)
|
|
479
|
+
|
|
480
|
+
try:
|
|
481
|
+
for line in sys.stdin:
|
|
482
|
+
line = line.strip()
|
|
483
|
+
if not line:
|
|
484
|
+
continue
|
|
485
|
+
|
|
486
|
+
try:
|
|
487
|
+
request = json.loads(line)
|
|
488
|
+
response = self.handle_mcp_request(request)
|
|
489
|
+
|
|
490
|
+
# Write response to stdout (MCP protocol)
|
|
491
|
+
print(json.dumps(response), flush=True)
|
|
492
|
+
|
|
493
|
+
except json.JSONDecodeError as e:
|
|
494
|
+
logger.error(f"Invalid JSON: {e}")
|
|
495
|
+
error_response = {
|
|
496
|
+
'jsonrpc': '2.0',
|
|
497
|
+
'error': {
|
|
498
|
+
'code': -32700,
|
|
499
|
+
'message': f'Parse error: {str(e)}'
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
print(json.dumps(error_response), flush=True)
|
|
503
|
+
|
|
504
|
+
except KeyboardInterrupt:
|
|
505
|
+
logger.info("\n👋 Gateway shutting down...")
|
|
506
|
+
except Exception as e:
|
|
507
|
+
logger.error(f"Fatal error: {e}", exc_info=True)
|
|
508
|
+
sys.exit(1)
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def main():
|
|
512
|
+
"""Entry point"""
|
|
513
|
+
# Check for setup mode
|
|
514
|
+
if len(sys.argv) > 1 and sys.argv[1] == 'setup':
|
|
515
|
+
logger.info("⚠️ Setup mode not yet implemented")
|
|
516
|
+
logger.info("Please set environment variables:")
|
|
517
|
+
logger.info(" LANGPROTECT_URL=https://api.langprotect.com")
|
|
518
|
+
logger.info(" LANGPROTECT_EMAIL=your@email.com")
|
|
519
|
+
logger.info(" LANGPROTECT_PASSWORD=yourpassword")
|
|
520
|
+
sys.exit(1)
|
|
521
|
+
|
|
522
|
+
# Start gateway
|
|
523
|
+
gateway = LangProtectGateway()
|
|
524
|
+
gateway.run()
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
if __name__ == '__main__':
|
|
528
|
+
main()
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langprotect-mcp-gateway
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Security gateway for Model Context Protocol (MCP) to protect AI tool interactions
|
|
5
|
+
Author-email: LangProtect Security Team <security@langprotect.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://langprotect.com
|
|
8
|
+
Project-URL: Documentation, https://docs.langprotect.com
|
|
9
|
+
Project-URL: Repository, https://github.com/langprotect/mcp-gateway
|
|
10
|
+
Project-URL: Issues, https://github.com/langprotect/mcp-gateway/issues
|
|
11
|
+
Keywords: mcp,security,ai-security,langprotect,model-context-protocol
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: requests>=2.31.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# LangProtect MCP Gateway
|
|
30
|
+
|
|
31
|
+
🛡️ **Security gateway for Model Context Protocol (MCP)** - Protect your AI tool interactions from security threats.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
✅ **Automatic Threat Detection** - Scans all MCP requests for security risks
|
|
36
|
+
✅ **Access Control** - Whitelist/blacklist MCP servers and tools
|
|
37
|
+
✅ **Full Audit Trail** - Logs all AI interactions for compliance
|
|
38
|
+
✅ **IDE Support** - Works with VS Code, Cursor, and all MCP-compatible IDEs
|
|
39
|
+
✅ **Easy Setup** - 30-second installation
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install langprotect-mcp-gateway
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Configuration
|
|
50
|
+
|
|
51
|
+
Create your MCP config file:
|
|
52
|
+
|
|
53
|
+
**VS Code:** `~/.config/Code/User/mcp.json`
|
|
54
|
+
**Cursor:** `~/.cursor/mcp.json`
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"langprotect-gateway": {
|
|
60
|
+
"command": "langprotect-gateway",
|
|
61
|
+
"env": {
|
|
62
|
+
"LANGPROTECT_URL": "https://your-langprotect-server.com",
|
|
63
|
+
"LANGPROTECT_EMAIL": "your.email@company.com",
|
|
64
|
+
"LANGPROTECT_PASSWORD": "your-password"
|
|
65
|
+
},
|
|
66
|
+
"servers": {
|
|
67
|
+
"filesystem": {
|
|
68
|
+
"command": "npx",
|
|
69
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
📝 **Note:** Replace `LANGPROTECT_URL` with your actual server URL (e.g., `https://langprotect.yourcompany.com` or `http://localhost:8000` for local testing).
|
|
78
|
+
|
|
79
|
+
### Restart Your IDE
|
|
80
|
+
|
|
81
|
+
**VS Code:** `Ctrl+Shift+P` → "Reload Window"
|
|
82
|
+
**Cursor:** Close and reopen
|
|
83
|
+
|
|
84
|
+
Done! 🎉 All your AI tool interactions are now protected.
|
|
85
|
+
|
|
86
|
+
## What It Does
|
|
87
|
+
|
|
88
|
+
The LangProtect MCP Gateway intercepts all AI tool interactions and:
|
|
89
|
+
|
|
90
|
+
1. **Scans for threats** - Detects malicious commands, data exfiltration attempts
|
|
91
|
+
2. **Enforces policies** - Blocks access to sensitive files and dangerous operations
|
|
92
|
+
3. **Logs everything** - Complete audit trail for compliance
|
|
93
|
+
4. **Auto-detects IDE** - Tracks which IDE/tool made each request
|
|
94
|
+
|
|
95
|
+
## Supported IDEs
|
|
96
|
+
|
|
97
|
+
- ✅ VS Code (with GitHub Copilot, Codeium, etc.)
|
|
98
|
+
- ✅ Cursor IDE
|
|
99
|
+
- ✅ Windsurf
|
|
100
|
+
- ✅ Zed Editor
|
|
101
|
+
- ✅ Any MCP-compatible IDE
|
|
102
|
+
|
|
103
|
+
## Environment Variables
|
|
104
|
+
|
|
105
|
+
| Variable | Required | Default | Description |
|
|
106
|
+
|----------|----------|---------|-------------|
|
|
107
|
+
| `LANGPROTECT_URL` | No | `http://localhost:8000` | Your LangProtect server URL |
|
|
108
|
+
| `LANGPROTECT_EMAIL` | **Yes** | - | Your email address |
|
|
109
|
+
| `LANGPROTECT_PASSWORD` | **Yes** | - | Your password |
|
|
110
|
+
| `DEBUG` | No | `false` | Enable debug logging (true/false) |
|
|
111
|
+
| `MCP_CONFIG_PATH` | No | Auto-detected | Path to servers config (Cursor only) |
|
|
112
|
+
|
|
113
|
+
⚠️ **Production Setup:** For production deployments, always set `LANGPROTECT_URL` to your actual server:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
"env": {
|
|
117
|
+
"LANGPROTECT_URL": "https://langprotect.yourcompany.com",
|
|
118
|
+
"LANGPROTECT_EMAIL": "your.email@company.com",
|
|
119
|
+
"LANGPROTECT_PASSWORD": "your-password"
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The default `http://localhost:8000` is only for local development/testing.
|
|
124
|
+
|
|
125
|
+
## Architecture
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
AI Assistant (Copilot, etc.)
|
|
129
|
+
↓
|
|
130
|
+
LangProtect Gateway (this package)
|
|
131
|
+
↓
|
|
132
|
+
[Security Scan]
|
|
133
|
+
↓
|
|
134
|
+
MCP Servers (filesystem, github, etc.)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Every request is:
|
|
138
|
+
1. Intercepted by the gateway
|
|
139
|
+
2. Scanned for security threats
|
|
140
|
+
3. Logged to LangProtect backend
|
|
141
|
+
4. Forwarded to actual MCP server (if safe)
|
|
142
|
+
5. Response returned to AI
|
|
143
|
+
|
|
144
|
+
## Dashboard
|
|
145
|
+
|
|
146
|
+
Monitor all activity at your LangProtect dashboard:
|
|
147
|
+
- View all AI interactions
|
|
148
|
+
- See security threats blocked
|
|
149
|
+
- Track IDE usage
|
|
150
|
+
- Generate compliance reports
|
|
151
|
+
|
|
152
|
+
## Security
|
|
153
|
+
|
|
154
|
+
The gateway protects against:
|
|
155
|
+
- 🚫 Sensitive file access (`.env`, SSH keys, etc.)
|
|
156
|
+
- 🚫 Dangerous commands (`rm -rf`, data exfiltration)
|
|
157
|
+
- 🚫 SQL injection patterns
|
|
158
|
+
- 🚫 Hardcoded credentials in suggestions
|
|
159
|
+
- 🚫 Prompt injection attacks
|
|
160
|
+
|
|
161
|
+
## Troubleshooting
|
|
162
|
+
|
|
163
|
+
**Authentication failed:**
|
|
164
|
+
- Check `LANGPROTECT_URL`, `LANGPROTECT_EMAIL`, `LANGPROTECT_PASSWORD` are correct
|
|
165
|
+
- Ensure LangProtect backend is accessible
|
|
166
|
+
|
|
167
|
+
**Gateway not starting:**
|
|
168
|
+
- Check Python version: `python3 --version` (need 3.11+)
|
|
169
|
+
- Check package installed: `pip show langprotect-mcp-gateway`
|
|
170
|
+
|
|
171
|
+
**Tools not working:**
|
|
172
|
+
- Check MCP servers are configured under `"servers"` section
|
|
173
|
+
- Restart IDE completely
|
|
174
|
+
|
|
175
|
+
## For Team Leads
|
|
176
|
+
|
|
177
|
+
### Quick Team Rollout:
|
|
178
|
+
|
|
179
|
+
1. **Share credentials** with each team member:
|
|
180
|
+
```
|
|
181
|
+
Email: user@company.com
|
|
182
|
+
Password: secure-password
|
|
183
|
+
Server: http://langprotect.company.com:8000
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
2. **Team members install:**
|
|
187
|
+
```bash
|
|
188
|
+
pip install langprotect-mcp-gateway
|
|
189
|
+
# Configure mcp.json with credentials
|
|
190
|
+
# Restart IDE
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
3. **Monitor dashboard:** See all team activity in real-time
|
|
194
|
+
|
|
195
|
+
## Updates
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install --upgrade langprotect-mcp-gateway
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Support
|
|
202
|
+
|
|
203
|
+
- **Documentation:** https://docs.langprotect.com
|
|
204
|
+
- **Issues:** https://github.com/langprotect/mcp-gateway/issues
|
|
205
|
+
- **Security:** security@langprotect.com
|
|
206
|
+
|
|
207
|
+
## License
|
|
208
|
+
|
|
209
|
+
MIT License - see LICENSE file for details
|
|
210
|
+
|
|
211
|
+
## Links
|
|
212
|
+
|
|
213
|
+
- **Homepage:** https://langprotect.com
|
|
214
|
+
- **GitHub:** https://github.com/langprotect/mcp-gateway
|
|
215
|
+
- **Documentation:** https://docs.langprotect.com
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
langprotect_mcp_gateway/__init__.py
|
|
5
|
+
langprotect_mcp_gateway/gateway.py
|
|
6
|
+
langprotect_mcp_gateway.egg-info/PKG-INFO
|
|
7
|
+
langprotect_mcp_gateway.egg-info/SOURCES.txt
|
|
8
|
+
langprotect_mcp_gateway.egg-info/dependency_links.txt
|
|
9
|
+
langprotect_mcp_gateway.egg-info/entry_points.txt
|
|
10
|
+
langprotect_mcp_gateway.egg-info/requires.txt
|
|
11
|
+
langprotect_mcp_gateway.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
langprotect_mcp_gateway
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=65.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "langprotect-mcp-gateway"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Security gateway for Model Context Protocol (MCP) to protect AI tool interactions"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "LangProtect Security Team", email = "security@langprotect.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["mcp", "security", "ai-security", "langprotect", "model-context-protocol"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Topic :: Security",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
dependencies = [
|
|
27
|
+
"requests>=2.31.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"pytest>=7.0.0",
|
|
33
|
+
"black>=23.0.0",
|
|
34
|
+
"mypy>=1.0.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://langprotect.com"
|
|
39
|
+
Documentation = "https://docs.langprotect.com"
|
|
40
|
+
Repository = "https://github.com/langprotect/mcp-gateway"
|
|
41
|
+
Issues = "https://github.com/langprotect/mcp-gateway/issues"
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
langprotect-gateway = "langprotect_mcp_gateway:main"
|
|
45
|
+
|
|
46
|
+
[tool.setuptools]
|
|
47
|
+
packages = ["langprotect_mcp_gateway"]
|
|
48
|
+
|
|
49
|
+
[tool.setuptools.package-data]
|
|
50
|
+
langprotect_mcp_gateway = ["*.json"]
|