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.
@@ -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,2 @@
1
+ [console_scripts]
2
+ langprotect-gateway = langprotect_mcp_gateway:main
@@ -0,0 +1,6 @@
1
+ requests>=2.31.0
2
+
3
+ [dev]
4
+ pytest>=7.0.0
5
+ black>=23.0.0
6
+ mypy>=1.0.0
@@ -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"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+