agent-airlock 0.1.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.
- agent_airlock-0.1.0/.gitignore +64 -0
- agent_airlock-0.1.0/LICENSE +21 -0
- agent_airlock-0.1.0/PKG-INFO +332 -0
- agent_airlock-0.1.0/README.md +286 -0
- agent_airlock-0.1.0/pyproject.toml +143 -0
- agent_airlock-0.1.0/src/agent_airlock/__init__.py +150 -0
- agent_airlock-0.1.0/src/agent_airlock/config.py +142 -0
- agent_airlock-0.1.0/src/agent_airlock/core.py +347 -0
- agent_airlock-0.1.0/src/agent_airlock/mcp.py +334 -0
- agent_airlock-0.1.0/src/agent_airlock/policy.py +475 -0
- agent_airlock-0.1.0/src/agent_airlock/py.typed +0 -0
- agent_airlock-0.1.0/src/agent_airlock/sandbox.py +493 -0
- agent_airlock-0.1.0/src/agent_airlock/sanitizer.py +429 -0
- agent_airlock-0.1.0/src/agent_airlock/self_heal.py +222 -0
- agent_airlock-0.1.0/src/agent_airlock/validator.py +187 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Claude Code auto-memory
|
|
2
|
+
.claude/auto-memory/dirty-files
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
*.so
|
|
9
|
+
.Python
|
|
10
|
+
build/
|
|
11
|
+
develop-eggs/
|
|
12
|
+
dist/
|
|
13
|
+
downloads/
|
|
14
|
+
eggs/
|
|
15
|
+
.eggs/
|
|
16
|
+
lib/
|
|
17
|
+
lib64/
|
|
18
|
+
parts/
|
|
19
|
+
sdist/
|
|
20
|
+
var/
|
|
21
|
+
wheels/
|
|
22
|
+
*.egg-info/
|
|
23
|
+
.installed.cfg
|
|
24
|
+
*.egg
|
|
25
|
+
|
|
26
|
+
# Virtual environments
|
|
27
|
+
.env
|
|
28
|
+
.venv
|
|
29
|
+
env/
|
|
30
|
+
venv/
|
|
31
|
+
ENV/
|
|
32
|
+
|
|
33
|
+
# IDE
|
|
34
|
+
.idea/
|
|
35
|
+
.vscode/
|
|
36
|
+
*.swp
|
|
37
|
+
*.swo
|
|
38
|
+
*~
|
|
39
|
+
|
|
40
|
+
# Testing
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
htmlcov/
|
|
46
|
+
.pytest_cache/
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
|
|
50
|
+
# mypy
|
|
51
|
+
.mypy_cache/
|
|
52
|
+
.dmypy.json
|
|
53
|
+
dmypy.json
|
|
54
|
+
|
|
55
|
+
# ruff
|
|
56
|
+
.ruff_cache/
|
|
57
|
+
|
|
58
|
+
# Logs
|
|
59
|
+
*.log
|
|
60
|
+
airlock_audit.json
|
|
61
|
+
|
|
62
|
+
# OS
|
|
63
|
+
.DS_Store
|
|
64
|
+
Thumbs.db
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sattyam Jain
|
|
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,332 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-airlock
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The Pydantic-based Firewall for MCP Servers. Stops hallucinated tool calls, validates schemas, and sandboxes dangerous operations.
|
|
5
|
+
Project-URL: Homepage, https://github.com/sattyamjain/agent-airlock
|
|
6
|
+
Project-URL: Documentation, https://github.com/sattyamjain/agent-airlock#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/sattyamjain/agent-airlock
|
|
8
|
+
Project-URL: Issues, https://github.com/sattyamjain/agent-airlock/issues
|
|
9
|
+
Author-email: Sattyam Jain <sattyamjain@example.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agent-safety,ai-security,e2b,llm,mcp,model-context-protocol,pydantic,sandbox,validation
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Security
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: pydantic<3.0,>=2.0
|
|
26
|
+
Requires-Dist: structlog>=24.0
|
|
27
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: cloudpickle>=3.0; extra == 'all'
|
|
30
|
+
Requires-Dist: e2b<2.0,>=1.0; extra == 'all'
|
|
31
|
+
Requires-Dist: fastmcp<3.0,>=2.0; extra == 'all'
|
|
32
|
+
Requires-Dist: mcp>=1.0; extra == 'all'
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: ruff>=0.2; extra == 'dev'
|
|
39
|
+
Provides-Extra: mcp
|
|
40
|
+
Requires-Dist: fastmcp<3.0,>=2.0; extra == 'mcp'
|
|
41
|
+
Requires-Dist: mcp>=1.0; extra == 'mcp'
|
|
42
|
+
Provides-Extra: sandbox
|
|
43
|
+
Requires-Dist: cloudpickle>=3.0; extra == 'sandbox'
|
|
44
|
+
Requires-Dist: e2b<2.0,>=1.0; extra == 'sandbox'
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
|
|
47
|
+
# Agent-Airlock
|
|
48
|
+
|
|
49
|
+
### Your AI Agent Just Tried to `rm -rf /`. We Stopped It.
|
|
50
|
+
|
|
51
|
+
[](https://github.com/sattyamjjain/agent-airlock/actions/workflows/ci.yml)
|
|
52
|
+
[](https://codecov.io/gh/sattyamjjain/agent-airlock)
|
|
53
|
+
[](https://www.python.org/downloads/)
|
|
54
|
+
[](https://opensource.org/licenses/MIT)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
Agent: "I'll help you clean up disk space..."
|
|
60
|
+
↓
|
|
61
|
+
rm -rf / --no-preserve-root
|
|
62
|
+
↓
|
|
63
|
+
┌─────────────────────────────────────────┐
|
|
64
|
+
│ 🛡️ AIRLOCK_BLOCK: Operation Denied │
|
|
65
|
+
│ │
|
|
66
|
+
│ Reason: Matches denied pattern 'rm_*' │
|
|
67
|
+
│ Policy: PRODUCTION_POLICY │
|
|
68
|
+
│ Fix: Use approved cleanup tools only │
|
|
69
|
+
└─────────────────────────────────────────┘
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Agent-Airlock is the open-source firewall for MCP servers.**
|
|
73
|
+
One decorator. Zero trust. Full control.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install agent-airlock
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## The Reality No One Talks About
|
|
82
|
+
|
|
83
|
+
In January 2026, MCP has 16,000+ servers on GitHub. OpenAI adopted it. The Linux Foundation hosts it.
|
|
84
|
+
|
|
85
|
+
But here's what the hype cycle ignores:
|
|
86
|
+
|
|
87
|
+
**LLMs hallucinate tool calls.** Every. Single. Day.
|
|
88
|
+
|
|
89
|
+
- Claude invents arguments that don't exist in your function signature
|
|
90
|
+
- GPT-4 sends `"100"` when your code expects `100`
|
|
91
|
+
- Agents chain 47 tool calls before you notice one deleted production data
|
|
92
|
+
|
|
93
|
+
The enterprise vendors saw this coming. Prompt Security charges $50K/year. Pangea wants your data flowing through their proxy. Cisco is "coming soon."
|
|
94
|
+
|
|
95
|
+
**We built the alternative.**
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## What This Actually Does
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from agent_airlock import Airlock
|
|
103
|
+
|
|
104
|
+
@Airlock()
|
|
105
|
+
def transfer_funds(from_account: str, to_account: str, amount: int) -> dict:
|
|
106
|
+
# Your banking logic here
|
|
107
|
+
return {"status": "transferred", "amount": amount}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
That's it. One line. Now your function has:
|
|
111
|
+
|
|
112
|
+
| Protection | What It Stops |
|
|
113
|
+
|------------|---------------|
|
|
114
|
+
| **Ghost Argument Stripping** | LLM sends `force=True` that doesn't exist → stripped silently |
|
|
115
|
+
| **Strict Type Validation** | LLM sends `amount="500"` → blocked, not silently coerced to 500 |
|
|
116
|
+
| **Self-Healing Errors** | Instead of crashing, returns `{"fix_hint": "amount must be int"}` |
|
|
117
|
+
|
|
118
|
+
The LLM gets a structured error. It retries correctly. Your system stays alive.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## When You Need the Big Guns
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from agent_airlock import Airlock, STRICT_POLICY
|
|
126
|
+
|
|
127
|
+
@Airlock(sandbox=True, policy=STRICT_POLICY)
|
|
128
|
+
def execute_code(code: str) -> str:
|
|
129
|
+
"""This runs in an E2B Firecracker MicroVM. Not on your machine."""
|
|
130
|
+
exec(code)
|
|
131
|
+
return "executed"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**sandbox=True** means:
|
|
135
|
+
- Code executes in an isolated VM (125ms boot time)
|
|
136
|
+
- No access to your filesystem, network, or secrets
|
|
137
|
+
- Warm pool keeps latency under 200ms after first call
|
|
138
|
+
|
|
139
|
+
**policy=STRICT_POLICY** means:
|
|
140
|
+
- Rate limited to 100 calls/hour
|
|
141
|
+
- Requires agent identity tracking
|
|
142
|
+
- Every call logged for audit
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## The Policies You'll Actually Use
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from agent_airlock import (
|
|
150
|
+
PERMISSIVE_POLICY, # Development - no restrictions
|
|
151
|
+
STRICT_POLICY, # Production - rate limited, requires agent ID
|
|
152
|
+
READ_ONLY_POLICY, # Analytics agents - can query, can't mutate
|
|
153
|
+
BUSINESS_HOURS_POLICY, # Dangerous ops only during 9-5
|
|
154
|
+
)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Or build your own:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from agent_airlock import SecurityPolicy
|
|
161
|
+
|
|
162
|
+
MY_POLICY = SecurityPolicy(
|
|
163
|
+
allowed_tools=["read_*", "query_*", "search_*"],
|
|
164
|
+
denied_tools=["delete_*", "drop_*", "rm_*"],
|
|
165
|
+
rate_limits={"*": "1000/hour", "write_*": "100/hour"},
|
|
166
|
+
time_restrictions={"deploy_*": "09:00-17:00"},
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## The Cost Problem (And How We Solve It)
|
|
173
|
+
|
|
174
|
+
A single runaway agent can burn $500 in API costs before you notice.
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from agent_airlock import Airlock, AirlockConfig
|
|
178
|
+
|
|
179
|
+
config = AirlockConfig(
|
|
180
|
+
max_output_chars=5000, # Truncate before token explosion
|
|
181
|
+
max_output_tokens=2000, # Hard limit on response size
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
@Airlock(config=config)
|
|
185
|
+
def query_logs(query: str) -> str:
|
|
186
|
+
# Even if this returns 10MB of logs,
|
|
187
|
+
# Airlock truncates to 5000 chars before the LLM sees it
|
|
188
|
+
return massive_log_query(query)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Result:** Agents that cost 70% less to run. Not a marketing number—it's what happens when you stop feeding 10MB responses to a tokenizer.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## The Security You Forgot You Needed
|
|
196
|
+
|
|
197
|
+
Your agent just queried a user's profile. The LLM is about to see their SSN.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
config = AirlockConfig(
|
|
201
|
+
mask_pii=True, # SSN, credit cards, phone numbers
|
|
202
|
+
mask_secrets=True, # API keys, passwords, connection strings
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
@Airlock(config=config)
|
|
206
|
+
def get_user(user_id: str) -> dict:
|
|
207
|
+
return db.users.find_one({"id": user_id})
|
|
208
|
+
|
|
209
|
+
# What the LLM sees:
|
|
210
|
+
# {"name": "John", "ssn": "[REDACTED]", "api_key": "sk-...XXXX"}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The data exists in your database. The LLM never sees it. The audit log has the masked version.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## FastMCP Integration (The Clean Way)
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from fastmcp import FastMCP
|
|
221
|
+
from agent_airlock.mcp import secure_tool, STRICT_POLICY
|
|
222
|
+
|
|
223
|
+
mcp = FastMCP("production-server")
|
|
224
|
+
|
|
225
|
+
@secure_tool(mcp, policy=STRICT_POLICY)
|
|
226
|
+
def delete_user(user_id: str) -> dict:
|
|
227
|
+
"""One decorator. MCP registration + Airlock protection."""
|
|
228
|
+
return db.users.delete(user_id)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
No ceremony. No boilerplate. The `@secure_tool` decorator handles:
|
|
232
|
+
1. MCP tool registration
|
|
233
|
+
2. Ghost argument stripping
|
|
234
|
+
3. Type validation
|
|
235
|
+
4. Policy enforcement
|
|
236
|
+
5. Output sanitization
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Why Not Just Use [Insert Enterprise Vendor]?
|
|
241
|
+
|
|
242
|
+
| | Prompt Security | Pangea | **Agent-Airlock** |
|
|
243
|
+
|---|---|---|---|
|
|
244
|
+
| **Pricing** | $50K+/year | Enterprise | **Free forever** |
|
|
245
|
+
| **Integration** | Proxy gateway | Proxy gateway | **One decorator** |
|
|
246
|
+
| **Self-Healing** | No | No | **Yes** |
|
|
247
|
+
| **E2B Sandboxing** | No | No | **Native** |
|
|
248
|
+
| **Your Data** | Through their servers | Through their servers | **Never leaves your infra** |
|
|
249
|
+
| **Source Code** | Closed | Closed | **MIT Licensed** |
|
|
250
|
+
|
|
251
|
+
We're not anti-enterprise. We're anti-gatekeeping.
|
|
252
|
+
|
|
253
|
+
Security for AI agents shouldn't require a procurement process.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Install
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Core (validation + policies + sanitization)
|
|
261
|
+
pip install agent-airlock
|
|
262
|
+
|
|
263
|
+
# With E2B sandbox support
|
|
264
|
+
pip install agent-airlock[sandbox]
|
|
265
|
+
|
|
266
|
+
# With FastMCP integration
|
|
267
|
+
pip install agent-airlock[mcp]
|
|
268
|
+
|
|
269
|
+
# Everything
|
|
270
|
+
pip install agent-airlock[all]
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Set your E2B key (if using sandbox):
|
|
274
|
+
```bash
|
|
275
|
+
export E2B_API_KEY="your-key-here"
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## The Numbers
|
|
281
|
+
|
|
282
|
+
- **182 tests** passing
|
|
283
|
+
- **84% coverage**
|
|
284
|
+
- **<50ms** validation overhead
|
|
285
|
+
- **<200ms** sandbox execution (warm pool)
|
|
286
|
+
- **0** external dependencies for core functionality
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Documentation
|
|
291
|
+
|
|
292
|
+
- **[Examples](./examples/)** — Copy-paste patterns for common use cases
|
|
293
|
+
- **[Security Guide](./docs/SECURITY.md)** — Production deployment checklist
|
|
294
|
+
- **[API Reference](#api-reference)** — Every function, every parameter
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Who Built This
|
|
299
|
+
|
|
300
|
+
[Sattyam Jain](https://github.com/sattyamjjain) — Building AI infrastructure at scale.
|
|
301
|
+
|
|
302
|
+
This started as an internal tool after watching an agent hallucinate its way through a production database. Now it's yours.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Contributing
|
|
307
|
+
|
|
308
|
+
We review every PR within 48 hours.
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
git clone https://github.com/sattyamjjain/agent-airlock
|
|
312
|
+
cd agent-airlock
|
|
313
|
+
pip install -e ".[dev]"
|
|
314
|
+
pytest tests/ -v
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Found a bug? [Open an issue](https://github.com/sattyamjjain/agent-airlock/issues).
|
|
318
|
+
Have a feature idea? [Start a discussion](https://github.com/sattyamjjain/agent-airlock/discussions).
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
MIT. Use it. Fork it. Ship it. No strings.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
<p align="center">
|
|
329
|
+
<strong>If this saved your production database from an LLM hallucination, consider a ⭐</strong>
|
|
330
|
+
<br><br>
|
|
331
|
+
<a href="https://github.com/sattyamjjain/agent-airlock">github.com/sattyamjjain/agent-airlock</a>
|
|
332
|
+
</p>
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# Agent-Airlock
|
|
2
|
+
|
|
3
|
+
### Your AI Agent Just Tried to `rm -rf /`. We Stopped It.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/sattyamjjain/agent-airlock/actions/workflows/ci.yml)
|
|
6
|
+
[](https://codecov.io/gh/sattyamjjain/agent-airlock)
|
|
7
|
+
[](https://www.python.org/downloads/)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Agent: "I'll help you clean up disk space..."
|
|
14
|
+
↓
|
|
15
|
+
rm -rf / --no-preserve-root
|
|
16
|
+
↓
|
|
17
|
+
┌─────────────────────────────────────────┐
|
|
18
|
+
│ 🛡️ AIRLOCK_BLOCK: Operation Denied │
|
|
19
|
+
│ │
|
|
20
|
+
│ Reason: Matches denied pattern 'rm_*' │
|
|
21
|
+
│ Policy: PRODUCTION_POLICY │
|
|
22
|
+
│ Fix: Use approved cleanup tools only │
|
|
23
|
+
└─────────────────────────────────────────┘
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Agent-Airlock is the open-source firewall for MCP servers.**
|
|
27
|
+
One decorator. Zero trust. Full control.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install agent-airlock
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## The Reality No One Talks About
|
|
36
|
+
|
|
37
|
+
In January 2026, MCP has 16,000+ servers on GitHub. OpenAI adopted it. The Linux Foundation hosts it.
|
|
38
|
+
|
|
39
|
+
But here's what the hype cycle ignores:
|
|
40
|
+
|
|
41
|
+
**LLMs hallucinate tool calls.** Every. Single. Day.
|
|
42
|
+
|
|
43
|
+
- Claude invents arguments that don't exist in your function signature
|
|
44
|
+
- GPT-4 sends `"100"` when your code expects `100`
|
|
45
|
+
- Agents chain 47 tool calls before you notice one deleted production data
|
|
46
|
+
|
|
47
|
+
The enterprise vendors saw this coming. Prompt Security charges $50K/year. Pangea wants your data flowing through their proxy. Cisco is "coming soon."
|
|
48
|
+
|
|
49
|
+
**We built the alternative.**
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## What This Actually Does
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from agent_airlock import Airlock
|
|
57
|
+
|
|
58
|
+
@Airlock()
|
|
59
|
+
def transfer_funds(from_account: str, to_account: str, amount: int) -> dict:
|
|
60
|
+
# Your banking logic here
|
|
61
|
+
return {"status": "transferred", "amount": amount}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
That's it. One line. Now your function has:
|
|
65
|
+
|
|
66
|
+
| Protection | What It Stops |
|
|
67
|
+
|------------|---------------|
|
|
68
|
+
| **Ghost Argument Stripping** | LLM sends `force=True` that doesn't exist → stripped silently |
|
|
69
|
+
| **Strict Type Validation** | LLM sends `amount="500"` → blocked, not silently coerced to 500 |
|
|
70
|
+
| **Self-Healing Errors** | Instead of crashing, returns `{"fix_hint": "amount must be int"}` |
|
|
71
|
+
|
|
72
|
+
The LLM gets a structured error. It retries correctly. Your system stays alive.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## When You Need the Big Guns
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from agent_airlock import Airlock, STRICT_POLICY
|
|
80
|
+
|
|
81
|
+
@Airlock(sandbox=True, policy=STRICT_POLICY)
|
|
82
|
+
def execute_code(code: str) -> str:
|
|
83
|
+
"""This runs in an E2B Firecracker MicroVM. Not on your machine."""
|
|
84
|
+
exec(code)
|
|
85
|
+
return "executed"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**sandbox=True** means:
|
|
89
|
+
- Code executes in an isolated VM (125ms boot time)
|
|
90
|
+
- No access to your filesystem, network, or secrets
|
|
91
|
+
- Warm pool keeps latency under 200ms after first call
|
|
92
|
+
|
|
93
|
+
**policy=STRICT_POLICY** means:
|
|
94
|
+
- Rate limited to 100 calls/hour
|
|
95
|
+
- Requires agent identity tracking
|
|
96
|
+
- Every call logged for audit
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## The Policies You'll Actually Use
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from agent_airlock import (
|
|
104
|
+
PERMISSIVE_POLICY, # Development - no restrictions
|
|
105
|
+
STRICT_POLICY, # Production - rate limited, requires agent ID
|
|
106
|
+
READ_ONLY_POLICY, # Analytics agents - can query, can't mutate
|
|
107
|
+
BUSINESS_HOURS_POLICY, # Dangerous ops only during 9-5
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Or build your own:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from agent_airlock import SecurityPolicy
|
|
115
|
+
|
|
116
|
+
MY_POLICY = SecurityPolicy(
|
|
117
|
+
allowed_tools=["read_*", "query_*", "search_*"],
|
|
118
|
+
denied_tools=["delete_*", "drop_*", "rm_*"],
|
|
119
|
+
rate_limits={"*": "1000/hour", "write_*": "100/hour"},
|
|
120
|
+
time_restrictions={"deploy_*": "09:00-17:00"},
|
|
121
|
+
)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## The Cost Problem (And How We Solve It)
|
|
127
|
+
|
|
128
|
+
A single runaway agent can burn $500 in API costs before you notice.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from agent_airlock import Airlock, AirlockConfig
|
|
132
|
+
|
|
133
|
+
config = AirlockConfig(
|
|
134
|
+
max_output_chars=5000, # Truncate before token explosion
|
|
135
|
+
max_output_tokens=2000, # Hard limit on response size
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
@Airlock(config=config)
|
|
139
|
+
def query_logs(query: str) -> str:
|
|
140
|
+
# Even if this returns 10MB of logs,
|
|
141
|
+
# Airlock truncates to 5000 chars before the LLM sees it
|
|
142
|
+
return massive_log_query(query)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Result:** Agents that cost 70% less to run. Not a marketing number—it's what happens when you stop feeding 10MB responses to a tokenizer.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## The Security You Forgot You Needed
|
|
150
|
+
|
|
151
|
+
Your agent just queried a user's profile. The LLM is about to see their SSN.
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
config = AirlockConfig(
|
|
155
|
+
mask_pii=True, # SSN, credit cards, phone numbers
|
|
156
|
+
mask_secrets=True, # API keys, passwords, connection strings
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
@Airlock(config=config)
|
|
160
|
+
def get_user(user_id: str) -> dict:
|
|
161
|
+
return db.users.find_one({"id": user_id})
|
|
162
|
+
|
|
163
|
+
# What the LLM sees:
|
|
164
|
+
# {"name": "John", "ssn": "[REDACTED]", "api_key": "sk-...XXXX"}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The data exists in your database. The LLM never sees it. The audit log has the masked version.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## FastMCP Integration (The Clean Way)
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from fastmcp import FastMCP
|
|
175
|
+
from agent_airlock.mcp import secure_tool, STRICT_POLICY
|
|
176
|
+
|
|
177
|
+
mcp = FastMCP("production-server")
|
|
178
|
+
|
|
179
|
+
@secure_tool(mcp, policy=STRICT_POLICY)
|
|
180
|
+
def delete_user(user_id: str) -> dict:
|
|
181
|
+
"""One decorator. MCP registration + Airlock protection."""
|
|
182
|
+
return db.users.delete(user_id)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
No ceremony. No boilerplate. The `@secure_tool` decorator handles:
|
|
186
|
+
1. MCP tool registration
|
|
187
|
+
2. Ghost argument stripping
|
|
188
|
+
3. Type validation
|
|
189
|
+
4. Policy enforcement
|
|
190
|
+
5. Output sanitization
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Why Not Just Use [Insert Enterprise Vendor]?
|
|
195
|
+
|
|
196
|
+
| | Prompt Security | Pangea | **Agent-Airlock** |
|
|
197
|
+
|---|---|---|---|
|
|
198
|
+
| **Pricing** | $50K+/year | Enterprise | **Free forever** |
|
|
199
|
+
| **Integration** | Proxy gateway | Proxy gateway | **One decorator** |
|
|
200
|
+
| **Self-Healing** | No | No | **Yes** |
|
|
201
|
+
| **E2B Sandboxing** | No | No | **Native** |
|
|
202
|
+
| **Your Data** | Through their servers | Through their servers | **Never leaves your infra** |
|
|
203
|
+
| **Source Code** | Closed | Closed | **MIT Licensed** |
|
|
204
|
+
|
|
205
|
+
We're not anti-enterprise. We're anti-gatekeeping.
|
|
206
|
+
|
|
207
|
+
Security for AI agents shouldn't require a procurement process.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Install
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Core (validation + policies + sanitization)
|
|
215
|
+
pip install agent-airlock
|
|
216
|
+
|
|
217
|
+
# With E2B sandbox support
|
|
218
|
+
pip install agent-airlock[sandbox]
|
|
219
|
+
|
|
220
|
+
# With FastMCP integration
|
|
221
|
+
pip install agent-airlock[mcp]
|
|
222
|
+
|
|
223
|
+
# Everything
|
|
224
|
+
pip install agent-airlock[all]
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Set your E2B key (if using sandbox):
|
|
228
|
+
```bash
|
|
229
|
+
export E2B_API_KEY="your-key-here"
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## The Numbers
|
|
235
|
+
|
|
236
|
+
- **182 tests** passing
|
|
237
|
+
- **84% coverage**
|
|
238
|
+
- **<50ms** validation overhead
|
|
239
|
+
- **<200ms** sandbox execution (warm pool)
|
|
240
|
+
- **0** external dependencies for core functionality
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Documentation
|
|
245
|
+
|
|
246
|
+
- **[Examples](./examples/)** — Copy-paste patterns for common use cases
|
|
247
|
+
- **[Security Guide](./docs/SECURITY.md)** — Production deployment checklist
|
|
248
|
+
- **[API Reference](#api-reference)** — Every function, every parameter
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Who Built This
|
|
253
|
+
|
|
254
|
+
[Sattyam Jain](https://github.com/sattyamjjain) — Building AI infrastructure at scale.
|
|
255
|
+
|
|
256
|
+
This started as an internal tool after watching an agent hallucinate its way through a production database. Now it's yours.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Contributing
|
|
261
|
+
|
|
262
|
+
We review every PR within 48 hours.
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
git clone https://github.com/sattyamjjain/agent-airlock
|
|
266
|
+
cd agent-airlock
|
|
267
|
+
pip install -e ".[dev]"
|
|
268
|
+
pytest tests/ -v
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Found a bug? [Open an issue](https://github.com/sattyamjjain/agent-airlock/issues).
|
|
272
|
+
Have a feature idea? [Start a discussion](https://github.com/sattyamjjain/agent-airlock/discussions).
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## License
|
|
277
|
+
|
|
278
|
+
MIT. Use it. Fork it. Ship it. No strings.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
<p align="center">
|
|
283
|
+
<strong>If this saved your production database from an LLM hallucination, consider a ⭐</strong>
|
|
284
|
+
<br><br>
|
|
285
|
+
<a href="https://github.com/sattyamjjain/agent-airlock">github.com/sattyamjjain/agent-airlock</a>
|
|
286
|
+
</p>
|