agent-mcp-gateway 0.1.5__py3-none-any.whl

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.

Potentially problematic release.


This version of agent-mcp-gateway might be problematic. Click here for more details.

@@ -0,0 +1,1418 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-mcp-gateway
3
+ Version: 0.1.5
4
+ Summary: An MCP gateway that aggregates your existing MCP servers and lets you define which servers and individual tools each agent or subagent can access. Solves Claude Code's MCP context window waste where all tool definitions load upfront instead of being discovered when actually needed.
5
+ Project-URL: Homepage, https://github.com/roddutra/agent-mcp-gateway
6
+ Project-URL: Documentation, https://github.com/roddutra/agent-mcp-gateway#readme
7
+ Project-URL: Repository, https://github.com/roddutra/agent-mcp-gateway
8
+ Project-URL: Issues, https://github.com/roddutra/agent-mcp-gateway/issues
9
+ Author: Rodrigo Franken Dutra
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: agent,fastmcp,gateway,mcp,model-context-protocol,proxy
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.12
20
+ Requires-Dist: fastmcp<3.0,>=2.13.0.1
21
+ Requires-Dist: watchdog<7.0,>=6.0.0
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Agent MCP Gateway
25
+
26
+ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) gateway that aggregates multiple MCP servers and provides policy-based access control for agents and subagents. Solves Claude Code's MCP context window waste by enabling on-demand tool discovery instead of loading all tool definitions upfront.
27
+
28
+ ## Status
29
+
30
+ - ✅ **M0: Foundation** - Configuration, policy engine, audit logging, `list_servers` tool
31
+ - ✅ **M1: Core** - Proxy infrastructure, `get_server_tools`, `execute_tool`, middleware, metrics, hot reload, OAuth support
32
+ - 🚧 **M2: Production** - HTTP transport, health checks (planned)
33
+ - 🚧 **M3: DX** - Single-agent mode, config validation CLI, Docker (planned)
34
+
35
+ **Current Version:** M1-Core Complete (with OAuth)
36
+
37
+ ## Table of Contents
38
+
39
+ - [Overview](#overview)
40
+ - [Installation](#installation)
41
+ - [Quick Start](#quick-start)
42
+ - [Command-Line Options](#command-line-options)
43
+ - [Configuration File Discovery](#configuration-file-discovery)
44
+ - [Configuration](#configuration)
45
+ - [Usage](#usage)
46
+ - [Gateway Tools](#gateway-tools)
47
+ - [Security Considerations](#security-considerations)
48
+ - [Troubleshooting](#troubleshooting)
49
+ - [Testing](#testing)
50
+ - [Development](#development)
51
+ - [Architecture](#architecture)
52
+ - [Future Features](#future-features)
53
+ - [Documentation](#documentation)
54
+ - [Contributing](#contributing)
55
+ - [License](#license)
56
+ - [Support](#support)
57
+ - [Acknowledgments](#acknowledgments)
58
+
59
+ ## Overview
60
+
61
+ ### The Problem
62
+
63
+ When multiple MCP servers are configured in development environments (Claude Code, Cursor, VS Code), all tool definitions from all servers load into every agent's and subagent's context window at startup:
64
+
65
+ - 5,000-50,000+ tokens consumed upfront
66
+ - 80-95% of loaded tools never used by individual agents
67
+ - Context needed for actual work gets wasted on unused tool definitions
68
+
69
+ ### The Solution
70
+
71
+ The Agent MCP Gateway acts as a single MCP server that proxies to multiple downstream MCP servers based on configurable per-agent rules:
72
+
73
+ - **3 gateway tools** load at startup (~400 tokens)
74
+ - Agents discover and request specific tools on-demand
75
+ - **90%+ context reduction**
76
+ - Policy-based access control per agent/subagent
77
+
78
+ ### How It Works
79
+
80
+ ![Agent MCP Gateway Architecture](https://raw.githubusercontent.com/roddutra/agent-mcp-gateway/main/docs/diagram-snippet.png)
81
+
82
+ The gateway sits between agents and downstream MCP servers, exposing only 3 lightweight tools. When an agent needs specific functionality, it discovers available servers and tools through the gateway, which filters visibility based on policy rules - agents only see servers and tools they have access to. This reduces each agent's context window to only relevant tools, while the gateway handles proxying authorized requests to downstream servers.
83
+
84
+ **[View detailed diagram with examples →](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/diagram-full.png)** (includes downstream servers, tools, and gateway rules examples)
85
+
86
+ ### Key Features
87
+
88
+ - ✅ **On-Demand Tool Discovery** - Load tool definitions only when needed
89
+ - ✅ **Per-Agent Access Control** - Configure which servers/tools each agent can access
90
+ - ✅ **Easy Agent Integration** - Simple template to add gateway support to any agent ([see guide](#configuring-agents-to-use-the-gateway))
91
+ - ✅ **Deny-Before-Allow Policies** - Explicit deny rules take precedence
92
+ - ✅ **Wildcard Support** - Pattern matching for tool names (`get_*`, `*_user`)
93
+ - ✅ **Session Isolation** - Concurrent requests don't interfere
94
+ - ✅ **Transparent Proxying** - Downstream servers unaware of gateway
95
+ - ✅ **Audit Logging** - All operations logged for monitoring
96
+ - ✅ **Performance Metrics** - Track latency and error rates per agent/operation
97
+ - ✅ **Hot Configuration Reload** - Update rules/servers without restart
98
+ - ✅ **Thread-Safe Operations** - Safe concurrent access during reloads
99
+ - ✅ **Diagnostic Tools** - Health monitoring via `get_gateway_status` (debug mode only)
100
+
101
+ ## Installation
102
+
103
+ ### For End Users (Recommended)
104
+
105
+ Install via `uvx` for on-demand usage without persistent installation:
106
+
107
+ ```bash
108
+ # Run directly without installing
109
+ uvx agent-mcp-gateway --help
110
+
111
+ # First-time setup - create config directory
112
+ uvx agent-mcp-gateway --init
113
+
114
+ # Run the gateway (uses configs from ~/.config/agent-mcp-gateway/)
115
+ GATEWAY_MCP_CONFIG=~/.config/agent-mcp-gateway/mcp.json \
116
+ GATEWAY_RULES=~/.config/agent-mcp-gateway/mcp-gateway-rules.json \
117
+ uvx agent-mcp-gateway
118
+ ```
119
+
120
+ Or install persistently with `uv tool`:
121
+
122
+ ```bash
123
+ # Install once
124
+ uv tool install agent-mcp-gateway
125
+
126
+ # Run anytime
127
+ agent-mcp-gateway --help
128
+
129
+ # Update to latest version
130
+ uv tool upgrade agent-mcp-gateway
131
+ ```
132
+
133
+ ### For Developers
134
+
135
+ Clone and install in development mode:
136
+
137
+ ```bash
138
+ # Clone repository
139
+ git clone https://github.com/roddutra/agent-mcp-gateway.git
140
+ cd agent-mcp-gateway
141
+
142
+ # Install dependencies
143
+ uv sync
144
+
145
+ # Run locally
146
+ uv run python main.py --help
147
+ ```
148
+
149
+ ## Quick Start
150
+
151
+ **Note:** This guide assumes you've installed the gateway. See [Installation](#installation) above.
152
+
153
+ ### 1. Set Up Configuration Files
154
+
155
+ The gateway requires two configuration files to operate. Choose your setup method:
156
+
157
+ **Method A: For PyPI Installation (uvx/uv tool)**
158
+
159
+ ```bash
160
+ # Initialize config directory and create template files
161
+ uvx agent-mcp-gateway --init
162
+ # or
163
+ agent-mcp-gateway --init # if installed with uv tool
164
+
165
+ # Edit configs with your servers and rules
166
+ nano ~/.config/agent-mcp-gateway/mcp.json
167
+ nano ~/.config/agent-mcp-gateway/mcp-gateway-rules.json
168
+ ```
169
+
170
+ **Method B: For Local Development**
171
+
172
+ ```bash
173
+ # Copy example files to your project directory
174
+ cp config/.mcp.json.example .mcp.json
175
+ cp config/.mcp-gateway-rules.json.example .mcp-gateway-rules.json
176
+
177
+ # Edit configs with your servers and rules
178
+ # Note: mcp.json is the standard MCP config format used by Claude Code
179
+ ```
180
+
181
+ See [Configuration File Discovery](#configuration-file-discovery) below for details on where the gateway searches for configuration files.
182
+
183
+ ### 2. Add Gateway to Your MCP Client
184
+
185
+ **For PyPI Installation (uvx):**
186
+
187
+ ```bash
188
+ # Claude Code CLI
189
+ claude mcp add agent-mcp-gateway uvx agent-mcp-gateway
190
+
191
+ # Or manual configuration (Claude Desktop, etc.)
192
+ # Add to your MCP client config:
193
+ {
194
+ "mcpServers": {
195
+ "agent-mcp-gateway": {
196
+ "command": "uvx",
197
+ "args": ["agent-mcp-gateway"],
198
+ "env": {
199
+ "GATEWAY_MCP_CONFIG": "~/.config/agent-mcp-gateway/mcp.json",
200
+ "GATEWAY_RULES": "~/.config/agent-mcp-gateway/mcp-gateway-rules.json",
201
+ "GATEWAY_DEFAULT_AGENT": "developer"
202
+ }
203
+ }
204
+ }
205
+ }
206
+ ```
207
+
208
+ **For PyPI Installation (uv tool):**
209
+
210
+ ```json
211
+ {
212
+ "mcpServers": {
213
+ "agent-mcp-gateway": {
214
+ "command": "agent-mcp-gateway",
215
+ "env": {
216
+ "GATEWAY_MCP_CONFIG": "~/.config/agent-mcp-gateway/mcp.json",
217
+ "GATEWAY_RULES": "~/.config/agent-mcp-gateway/mcp-gateway-rules.json",
218
+ "GATEWAY_DEFAULT_AGENT": "developer"
219
+ }
220
+ }
221
+ }
222
+ }
223
+ ```
224
+
225
+ **For Local Development:**
226
+
227
+ ```bash
228
+ # Claude Code CLI
229
+ claude mcp add agent-mcp-gateway \
230
+ uv run --directory /path/to/agent-mcp-gateway python main.py
231
+
232
+ # Or manual configuration
233
+ {
234
+ "mcpServers": {
235
+ "agent-mcp-gateway": {
236
+ "command": "uv",
237
+ "args": ["run", "--directory", "/path/to/agent-mcp-gateway", "python", "main.py"],
238
+ "env": {
239
+ "GATEWAY_DEFAULT_AGENT": "developer"
240
+ }
241
+ }
242
+ }
243
+ }
244
+ ```
245
+
246
+ Replace `/path/to/agent-mcp-gateway` with the actual path to your gateway clone.
247
+
248
+ **Note:** For local development, the `--directory` flag tells `uv run` to change to the project directory before running, ensuring it finds `pyproject.toml` and the gateway configuration files.
249
+
250
+ **Verify Gateway Connection:**
251
+
252
+ After adding the gateway to your MCP client, verify it's working:
253
+
254
+ ```bash
255
+ # Using MCP Inspector (for testing)
256
+ npx @modelcontextprotocol/inspector uv run python main.py
257
+ # Then call list_servers with agent_id parameter
258
+
259
+ # Or ask your agent to list available servers
260
+ # Expected response: List of servers from your .mcp.json
261
+ ```
262
+
263
+ Expected startup output:
264
+ ```
265
+ Loading MCP server configuration from: .mcp.json
266
+ Loading gateway rules from: .mcp-gateway-rules.json
267
+ Gateway initialized successfully
268
+ - X MCP server(s) configured
269
+ - Y agent(s) configured
270
+ - 3 gateway tools available
271
+ ```
272
+
273
+ ### 3. Configure Your Agents
274
+
275
+ The gateway's tool descriptions are self-documenting, but for proper access control you should configure how your agents identify themselves.
276
+
277
+ #### Choose Your Approach
278
+
279
+ **Approach 1: Single-Agent Mode (Simplest)**
280
+
281
+ If all your agents should have the same permissions, configure a default agent using either method:
282
+
283
+ **Option A: Environment Variable**
284
+ ```bash
285
+ # Set in your MCP client configuration
286
+ export GATEWAY_DEFAULT_AGENT=developer
287
+ ```
288
+ **Note:** The agent specified (e.g., "developer") must exist in your `.mcp-gateway-rules.json` file with appropriate permissions.
289
+
290
+ **Option B: "default" Agent in Rules**
291
+ ```json
292
+ {
293
+ "agents": {
294
+ "default": {
295
+ "allow": {
296
+ "servers": ["*"]
297
+ }
298
+ }
299
+ },
300
+ "defaults": {
301
+ "deny_on_missing_agent": false
302
+ }
303
+ }
304
+ ```
305
+ **Note:** Allowing all servers (`"servers": ["*"]`) without specifying tool restrictions grants access to all tools on all servers.
306
+
307
+ With either approach, agents can omit `agent_id` in tool calls - the gateway uses your configured default agent automatically.
308
+
309
+ **Approach 2: Multi-Agent Mode (Recommended for Access Control)**
310
+
311
+ For different agents with different permissions, configure each agent to pass its identity.
312
+
313
+ **Add this to your agent's system prompt** (e.g., `CLAUDE.md`, `.claude/agents/agent-name.md`):
314
+
315
+ ```markdown
316
+ ## MCP Gateway Access
317
+
318
+ **Available Tools (via agent-mcp-gateway):**
319
+
320
+ You have access to MCP servers through the agent-mcp-gateway. The specific servers and tools available to you are determined by the gateway's access control rules.
321
+
322
+ **Tool Discovery Process:**
323
+
324
+ When you need to use tools from downstream MCP servers:
325
+ 1. Use `agent_id: "YOUR_AGENT_NAME"` in ALL gateway tool calls for proper access control
326
+ 2. Call `list_servers` to discover which servers you have access to
327
+ 3. Call `get_server_tools` with the specific server name to discover available tools
328
+ 4. Use `execute_tool` to invoke tools with appropriate parameters
329
+ 5. If you cannot access a tool you need, immediately notify the user
330
+
331
+ **Important:** Always include `agent_id: "YOUR_AGENT_NAME"` in your gateway tool calls. This ensures proper access control and audit logging.
332
+ ```
333
+
334
+ Replace `YOUR_AGENT_NAME` with your agent's identifier (e.g., "researcher", "backend", "admin").
335
+
336
+ **Examples:** See [`.claude/agents/researcher.md`](https://github.com/roddutra/agent-mcp-gateway/blob/main/.claude/agents/researcher.md) and [`.claude/agents/mcp-developer.md`](https://github.com/roddutra/agent-mcp-gateway/blob/main/.claude/agents/mcp-developer.md) for complete configuration examples.
337
+
338
+ ## Command-Line Options
339
+
340
+ ```bash
341
+ # Show version
342
+ agent-mcp-gateway --version
343
+
344
+ # Initialize config directory (first-time setup)
345
+ agent-mcp-gateway --init
346
+
347
+ # Enable debug mode (exposes get_gateway_status diagnostic tool)
348
+ agent-mcp-gateway --debug
349
+
350
+ # Show help
351
+ agent-mcp-gateway --help
352
+ ```
353
+
354
+ **For local development:**
355
+ ```bash
356
+ uv run python main.py --version
357
+ uv run python main.py --init
358
+ uv run python main.py --debug
359
+ uv run python main.py --help
360
+ ```
361
+
362
+ ## Configuration File Discovery
363
+
364
+ The gateway searches for configuration files in this order:
365
+
366
+ ### MCP Server Config (mcp.json)
367
+ 1. `GATEWAY_MCP_CONFIG` environment variable (if set)
368
+ 2. `.mcp.json` in current directory
369
+ 3. `~/.config/agent-mcp-gateway/mcp.json` (home directory)
370
+ 4. `./config/.mcp.json` (fallback)
371
+
372
+ ### Gateway Rules (mcp-gateway-rules.json)
373
+ 1. `GATEWAY_RULES` environment variable (if set)
374
+ 2. `.mcp-gateway-rules.json` in current directory
375
+ 3. `~/.config/agent-mcp-gateway/mcp-gateway-rules.json` (home directory)
376
+ 4. `./config/.mcp-gateway-rules.json` (fallback)
377
+
378
+ **Tip:** Use `agent-mcp-gateway --init` to create the home directory configs on first run.
379
+
380
+ ## Configuration
381
+
382
+ The gateway requires two configuration files:
383
+
384
+ ### 1. MCP Servers Configuration
385
+
386
+ **File:** `mcp.json` (searched in [multiple locations](#configuration-file-discovery))
387
+
388
+ Defines the downstream MCP servers the gateway will proxy to. Uses the standard MCP config format compatible with Claude Code and other coding agents:
389
+
390
+ ```json
391
+ {
392
+ "mcpServers": {
393
+ "brave-search": {
394
+ "description": "Web search via Brave Search API",
395
+ "command": "npx",
396
+ "args": ["-y", "@modelcontextprotocol/server-brave-search"],
397
+ "env": {
398
+ "BRAVE_API_KEY": "${BRAVE_API_KEY}"
399
+ }
400
+ },
401
+ "postgres": {
402
+ "description": "PostgreSQL database access and query execution",
403
+ "command": "uvx",
404
+ "args": ["mcp-server-postgres"],
405
+ "env": {
406
+ "DATABASE_URL": "${DATABASE_URL}"
407
+ }
408
+ },
409
+ "remote-server": {
410
+ "description": "Custom remote API integration",
411
+ "url": "https://example.com/mcp",
412
+ "transport": "http",
413
+ "headers": {
414
+ "Authorization": "Bearer ${API_TOKEN}"
415
+ }
416
+ }
417
+ }
418
+ }
419
+ ```
420
+
421
+ **Server Descriptions (Recommended):**
422
+ Adding a `description` field to each server helps AI agents understand what each server provides and when to use it. Descriptions are always returned by `list_servers`, enabling agents to make informed decisions about which servers to query for tools. While optional, descriptions significantly improve agent tool discovery and decision-making.
423
+
424
+ **Supported Transports:**
425
+ - `stdio` - Local servers via npx/uvx (specified with `command` + `args`)
426
+ - `http` - Remote HTTP servers (specified with `url`)
427
+
428
+ **Environment Variables:**
429
+ - Use `${VAR_NAME}` syntax for environment variable substitution
430
+ - Set variables before running: `export BRAVE_API_KEY=your-key`
431
+
432
+ **Important - GUI Applications (Claude Desktop, etc.):**
433
+ If you use `${VAR_NAME}` syntax in `.mcp.json`, note that macOS GUI applications run in isolated environments without access to your shell's environment variables. For Claude Desktop and similar apps, add API keys to the gateway's `env` object in your MCP client configuration:
434
+
435
+ ```json
436
+ {
437
+ "mcpServers": {
438
+ "agent-mcp-gateway": {
439
+ "command": "uv",
440
+ "args": ["run", "--directory", "/path/to/agent-mcp-gateway", "python", "main.py"],
441
+ "env": {
442
+ "BRAVE_API_KEY": "your-actual-key-here",
443
+ "DATABASE_URL": "postgresql://...",
444
+ "GATEWAY_DEFAULT_AGENT": "claude-desktop"
445
+ }
446
+ }
447
+ }
448
+ }
449
+ ```
450
+
451
+ (If you hardcode values directly in `.mcp.json` without `${VAR_NAME}` syntax, this is not necessary.)
452
+
453
+ ### 2. Gateway Rules Configuration
454
+
455
+ **File:** `mcp-gateway-rules.json` (searched in [multiple locations](#configuration-file-discovery))
456
+
457
+ Defines per-agent access policies using deny-before-allow precedence:
458
+
459
+ ```json
460
+ {
461
+ "agents": {
462
+ "researcher": {
463
+ "allow": {
464
+ "servers": ["brave-search"],
465
+ "tools": {
466
+ "brave-search": ["*"]
467
+ }
468
+ }
469
+ },
470
+ "backend": {
471
+ "allow": {
472
+ "servers": ["postgres"],
473
+ "tools": {
474
+ "postgres": ["query", "list_*"]
475
+ }
476
+ },
477
+ "deny": {
478
+ "tools": {
479
+ "postgres": ["drop_*", "truncate_*"]
480
+ }
481
+ }
482
+ },
483
+ "admin": {
484
+ "allow": {
485
+ "servers": ["*"],
486
+ "tools": {
487
+ "*": ["*"]
488
+ }
489
+ }
490
+ },
491
+ "default": {
492
+ "deny": {
493
+ "servers": ["*"]
494
+ }
495
+ }
496
+ },
497
+ "defaults": {
498
+ "deny_on_missing_agent": false
499
+ }
500
+ }
501
+ ```
502
+
503
+ **Note on "default" Agent:** The special agent named "default" is used as a fallback when `agent_id` is not provided and `deny_on_missing_agent` is `false`. In this example, the default agent denies all servers, following the principle of least privilege. You can also use `GATEWAY_DEFAULT_AGENT` environment variable to specify a different default agent.
504
+
505
+ **Policy Precedence Order:**
506
+ 1. Explicit deny rules (highest priority)
507
+ 2. Explicit allow rules
508
+ 3. Wildcard deny rules
509
+ 4. Wildcard allow rules
510
+ 5. Default policy (lowest priority)
511
+
512
+ **Configuration Flexibility:**
513
+ - Rules can reference servers not currently in `.mcp.json`
514
+ - Undefined server references treated as warnings (not errors)
515
+ - Allows keeping rules for temporarily removed servers
516
+ - Hot reload applies changes immediately without restart
517
+
518
+ **Wildcard Patterns:**
519
+ - `*` - Matches everything
520
+ - `get_*` - Matches tools starting with "get_"
521
+ - `*_user` - Matches tools ending with "_user"
522
+
523
+ **Agent Naming:**
524
+ - Use hierarchical names: `team.role` (e.g., `backend.database`, `frontend.ui`)
525
+ - Alphanumeric characters, hyphens, underscores, and dots allowed
526
+ - **Configure your agents** to pass their identity: See [Configuring Agents to Use the Gateway](#configuring-agents-to-use-the-gateway)
527
+
528
+ ### Configuration Validation
529
+
530
+ The gateway validates configurations at startup and during hot reload:
531
+
532
+ ```bash
533
+ uv run python main.py
534
+ # ✓ Configuration loaded from .mcp.json
535
+ # ⚠ Warning: Agent 'researcher' references undefined server 'unknown-server'
536
+ # ℹ These rules will be ignored until the server is added
537
+ ```
538
+
539
+ **Validation Behavior:**
540
+ - Structural errors (invalid JSON, missing required fields) → Fail startup/reload
541
+ - Undefined server references → Log warnings, continue with valid rules
542
+ - Policy conflicts → Deny-before-allow precedence resolves automatically
543
+
544
+ ### 3. OAuth Support for Downstream Servers
545
+
546
+ OAuth-protected downstream servers (Notion, GitHub) are automatically supported via auto-detection when servers return HTTP 401. The gateway uses FastMCP's OAuth support to handle authentication flows transparently - browser opens once for initial authentication, then tokens are cached for future use. See [OAuth User Guide](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/oauth-user-guide.md) for detailed setup and troubleshooting.
547
+
548
+ **OAuth Limitations:**
549
+
550
+ The gateway supports OAuth servers that implement **Dynamic Client Registration (RFC 7591)**.
551
+
552
+ - ✅ **Supported:** OAuth with auto-detection (e.g., Notion MCP)
553
+ - ❌ **Not Supported:** OAuth with pre-registered apps (e.g., GitHub OAuth flow)
554
+ - 💡 **For GitHub MCP:** Use Personal Access Token instead
555
+
556
+ **GitHub MCP with PAT Example:**
557
+ ```json
558
+ {
559
+ "mcpServers": {
560
+ "github": {
561
+ "url": "https://api.githubcopilot.com/mcp/",
562
+ "headers": {
563
+ "Authorization": "Bearer ${GITHUB_PAT}"
564
+ }
565
+ }
566
+ }
567
+ }
568
+ ```
569
+
570
+ For detailed OAuth setup and troubleshooting, see [OAuth User Guide](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/oauth-user-guide.md).
571
+
572
+ ### 4. Environment Variables Reference
573
+
574
+ | Variable | Description | Default | Example |
575
+ |----------|-------------|---------|---------|
576
+ | `GATEWAY_MCP_CONFIG` | Path to MCP servers configuration file | `.mcp.json`, fallback: `./config/.mcp.json` | `export GATEWAY_MCP_CONFIG=./custom.json` |
577
+ | `GATEWAY_RULES` | Path to gateway rules configuration file | `.mcp-gateway-rules.json`, fallback: `./config/.mcp-gateway-rules.json` | `export GATEWAY_RULES=~/.claude/rules.json` |
578
+ | `GATEWAY_DEFAULT_AGENT` | Default agent identity when `agent_id` not provided (optional) | None | `export GATEWAY_DEFAULT_AGENT=developer` |
579
+ | `GATEWAY_DEBUG` | Enable debug mode to expose `get_gateway_status` tool | `false` | `export GATEWAY_DEBUG=true` |
580
+ | `GATEWAY_AUDIT_LOG` | Path to audit log file | `~/.cache/agent-mcp-gateway/logs/audit.jsonl` | `export GATEWAY_AUDIT_LOG=./audit.jsonl` |
581
+ | `GATEWAY_TRANSPORT` | Transport protocol (stdio or http) | `stdio` | `export GATEWAY_TRANSPORT=stdio` |
582
+ | `GATEWAY_INIT_STRATEGY` | Initialization strategy (eager or lazy) | `eager` | `export GATEWAY_INIT_STRATEGY=eager` |
583
+
584
+ **Note on GUI Applications:** macOS GUI applications (Claude Desktop, etc.) run in isolated environments without access to shell environment variables. If using `${VAR_NAME}` syntax in `.mcp.json`, add required API keys to the gateway's `env` object in your MCP client configuration.
585
+
586
+ ## Usage
587
+
588
+ ### Starting the Gateway
589
+
590
+ **In MCP Clients (Recommended):**
591
+
592
+ Add to your MCP client configuration (e.g., Claude Desktop config):
593
+ ```json
594
+ {
595
+ "mcpServers": {
596
+ "agent-mcp-gateway": {
597
+ "command": "uv",
598
+ "args": ["run", "--directory", "/path/to/agent-mcp-gateway", "python", "main.py"],
599
+ "env": {
600
+ "GATEWAY_MCP_CONFIG": ".mcp.json",
601
+ "GATEWAY_RULES": ".mcp-gateway-rules.json"
602
+ }
603
+ }
604
+ }
605
+ }
606
+ ```
607
+
608
+ Or use Claude Code CLI:
609
+ ```bash
610
+ claude mcp add agent-mcp-gateway \
611
+ uv run --directory /path/to/agent-mcp-gateway python main.py
612
+ ```
613
+
614
+ **For Development/Testing:**
615
+
616
+ ```bash
617
+ # Use default config paths
618
+ uv run python main.py
619
+
620
+ # Or specify custom paths via environment (see Configuration section for all variables)
621
+ export GATEWAY_MCP_CONFIG=./custom-mcp-config.json
622
+ export GATEWAY_RULES=./custom-gateway-rules.json
623
+ uv run python main.py
624
+ ```
625
+
626
+ ### Startup Output
627
+
628
+ ```
629
+ Loading MCP server configuration from: .mcp.json
630
+ Loading gateway rules from: .mcp-gateway-rules.json
631
+ Audit log will be written to: ~/.cache/agent-mcp-gateway/logs/audit.jsonl
632
+
633
+ Initializing proxy connections to downstream servers...
634
+ - 2 proxy client(s) initialized
635
+ * brave-search: ready
636
+ * postgres: ready
637
+ - Metrics collector initialized
638
+ - Access control middleware registered
639
+
640
+ Agent MCP Gateway initialized successfully
641
+ - 2 MCP server(s) configured
642
+ - 3 agent(s) configured
643
+ - Default policy: deny unknown agents
644
+ - 3 gateway tools available: list_servers, get_server_tools, execute_tool
645
+ (4 tools if GATEWAY_DEBUG=true: includes get_gateway_status)
646
+
647
+ Gateway is ready. Running with stdio transport...
648
+ ```
649
+
650
+ ## Gateway Tools
651
+
652
+ The gateway exposes exactly 3 tools to agents. All tools accept an optional `agent_id` parameter for access control. When `agent_id` is not provided, the gateway uses a fallback chain to determine agent identity (see [Agent Identity Modes](#agent-identity-modes)).
653
+
654
+ **For Agent Developers:** To configure your agents to properly use these gateway tools with access control, see [Configuring Agents to Use the Gateway](#configuring-agents-to-use-the-gateway).
655
+
656
+ ### 1. `list_servers`
657
+
658
+ Lists MCP servers available to the calling agent based on policy rules.
659
+
660
+ **Parameters:**
661
+ - `agent_id` (string, optional) - Identifier of the agent making the request (see [Agent Identity Modes](#agent-identity-modes))
662
+ - `include_metadata` (boolean, optional) - Include technical details like transport, command, and url (default: false)
663
+
664
+ **Returns:**
665
+ ```json
666
+ [
667
+ {
668
+ "name": "brave-search",
669
+ "description": "Web search via Brave Search API"
670
+ },
671
+ {
672
+ "name": "postgres",
673
+ "description": "PostgreSQL database access and query execution"
674
+ }
675
+ ]
676
+ ```
677
+
678
+ **With `include_metadata=true`:**
679
+ ```json
680
+ [
681
+ {
682
+ "name": "brave-search",
683
+ "description": "Web search via Brave Search API",
684
+ "transport": "stdio",
685
+ "command": "npx"
686
+ },
687
+ {
688
+ "name": "postgres",
689
+ "description": "PostgreSQL database access and query execution",
690
+ "transport": "stdio",
691
+ "command": "uvx"
692
+ }
693
+ ]
694
+ ```
695
+
696
+ **Note:** Server descriptions are always included (when configured in `.mcp.json`) to help agents understand what each server provides. The `include_metadata` flag only controls whether technical details (transport, command, url) are included.
697
+
698
+ **Example:**
699
+ ```python
700
+ # Basic usage - returns names and descriptions
701
+ result = await client.call_tool("list_servers", {
702
+ "agent_id": "researcher"
703
+ })
704
+
705
+ # With technical metadata
706
+ result = await client.call_tool("list_servers", {
707
+ "agent_id": "researcher",
708
+ "include_metadata": True
709
+ })
710
+ ```
711
+
712
+ ### 2. `get_server_tools`
713
+
714
+ Retrieves tool definitions from a specific MCP server, filtered by agent permissions.
715
+
716
+ **Parameters:**
717
+ - `agent_id` (string, optional) - Identifier of the agent (see [Agent Identity Modes](#agent-identity-modes))
718
+ - `server` (string, required) - Name of the downstream MCP server
719
+ - `names` (string, optional) - Comma-separated list of tool names (e.g., `"tool1,tool2,tool3"`) or single tool name
720
+ - `pattern` (string, optional) - Wildcard pattern for tool names (e.g., `"get_*"`)
721
+ - `max_schema_tokens` (integer, optional) - Token budget limit for schemas
722
+
723
+ **Returns:**
724
+ ```json
725
+ {
726
+ "tools": [
727
+ {
728
+ "name": "brave_web_search",
729
+ "description": "Search the web using Brave Search",
730
+ "inputSchema": {
731
+ "type": "object",
732
+ "properties": {
733
+ "query": {"type": "string"}
734
+ },
735
+ "required": ["query"]
736
+ }
737
+ }
738
+ ],
739
+ "server": "brave-search",
740
+ "total_available": 5,
741
+ "returned": 1,
742
+ "tokens_used": 150
743
+ }
744
+ ```
745
+
746
+ **Example:**
747
+ ```python
748
+ # Get all allowed tools
749
+ tools = await client.call_tool("get_server_tools", {
750
+ "agent_id": "researcher",
751
+ "server": "brave-search"
752
+ })
753
+
754
+ # Get specific tools by name (comma-separated)
755
+ tools = await client.call_tool("get_server_tools", {
756
+ "agent_id": "researcher",
757
+ "server": "brave-search",
758
+ "names": "brave_web_search,brave_local_search"
759
+ })
760
+
761
+ # Get specific tools by pattern
762
+ tools = await client.call_tool("get_server_tools", {
763
+ "agent_id": "backend",
764
+ "server": "postgres",
765
+ "pattern": "get_*"
766
+ })
767
+
768
+ # Limit token usage
769
+ tools = await client.call_tool("get_server_tools", {
770
+ "agent_id": "researcher",
771
+ "server": "brave-search",
772
+ "max_schema_tokens": 1000
773
+ })
774
+ ```
775
+
776
+ ### 3. `execute_tool`
777
+
778
+ Executes a tool on a downstream MCP server with transparent result forwarding.
779
+
780
+ **Parameters:**
781
+ - `agent_id` (string, optional) - Identifier of the agent (see [Agent Identity Modes](#agent-identity-modes))
782
+ - `server` (string, required) - Name of the downstream MCP server
783
+ - `tool` (string, required) - Name of the tool to execute
784
+ - `args` (object, required) - Arguments to pass to the tool
785
+ - `timeout_ms` (integer, optional) - Timeout in milliseconds
786
+
787
+ **Returns:**
788
+ ```json
789
+ {
790
+ "content": [
791
+ {
792
+ "type": "text",
793
+ "text": "Search results: ..."
794
+ }
795
+ ],
796
+ "isError": false
797
+ }
798
+ ```
799
+
800
+ **Example:**
801
+ ```python
802
+ # Execute a tool
803
+ result = await client.call_tool("execute_tool", {
804
+ "agent_id": "researcher",
805
+ "server": "brave-search",
806
+ "tool": "brave_web_search",
807
+ "args": {
808
+ "query": "FastMCP documentation"
809
+ }
810
+ })
811
+
812
+ # With timeout
813
+ result = await client.call_tool("execute_tool", {
814
+ "agent_id": "backend",
815
+ "server": "postgres",
816
+ "tool": "query",
817
+ "args": {
818
+ "sql": "SELECT * FROM users LIMIT 10"
819
+ },
820
+ "timeout_ms": 5000
821
+ })
822
+ ```
823
+
824
+ ### 4. `get_gateway_status` (Debug Mode Only)
825
+
826
+ Returns comprehensive gateway health and diagnostics information.
827
+
828
+ **Important:** This tool is only available when debug mode is enabled (via `GATEWAY_DEBUG=true` environment variable or `--debug` CLI flag). See [Security Considerations](#security-considerations) for details.
829
+
830
+ **Parameters:**
831
+ - `agent_id` (string, optional) - Identifier of the agent (see [Agent Identity Modes](#agent-identity-modes))
832
+
833
+ **Returns:**
834
+ ```json
835
+ {
836
+ "reload_status": {
837
+ "mcp_config": {
838
+ "last_attempt": "2025-10-30T10:30:00Z",
839
+ "last_success": "2025-10-30T10:30:00Z",
840
+ "last_error": null,
841
+ "attempt_count": 1,
842
+ "success_count": 1
843
+ },
844
+ "gateway_rules": {
845
+ "last_attempt": "2025-10-30T10:35:00Z",
846
+ "last_success": "2025-10-30T10:35:00Z",
847
+ "last_error": null,
848
+ "attempt_count": 2,
849
+ "success_count": 2,
850
+ "last_warnings": []
851
+ }
852
+ },
853
+ "policy_state": {
854
+ "total_agents": 3,
855
+ "agent_ids": ["researcher", "backend", "admin"],
856
+ "defaults": {"deny_on_missing_agent": true}
857
+ },
858
+ "available_servers": ["brave-search", "postgres"],
859
+ "config_paths": {
860
+ "mcp_config": "/path/to/.mcp.json",
861
+ "gateway_rules": "/path/to/.mcp-gateway-rules.json"
862
+ },
863
+ "message": "Gateway is operational. Check reload_status for hot reload health."
864
+ }
865
+ ```
866
+
867
+ **Example:**
868
+ ```python
869
+ # Check gateway health and reload status (requires GATEWAY_DEBUG=true)
870
+ status = await client.call_tool("get_gateway_status", {
871
+ "agent_id": "admin"
872
+ })
873
+
874
+ # Verify last reload was successful
875
+ if status["reload_status"]["gateway_rules"]["last_error"]:
876
+ print("Warning: Last rule reload failed!")
877
+ ```
878
+
879
+ ### Error Handling
880
+
881
+ All tools return structured errors with clear messages:
882
+
883
+ ```json
884
+ {
885
+ "error": {
886
+ "code": "DENIED_BY_POLICY",
887
+ "message": "Agent 'frontend' denied access to tool 'drop_table'",
888
+ "rule": "agents.frontend.deny.tools.postgres[0]"
889
+ }
890
+ }
891
+ ```
892
+
893
+ **Error Codes:**
894
+ - `DENIED_BY_POLICY` - Agent lacks permission
895
+ - `SERVER_UNAVAILABLE` - Downstream server unreachable
896
+ - `TOOL_NOT_FOUND` - Requested tool doesn't exist
897
+ - `TIMEOUT` - Operation exceeded time limit
898
+ - `INVALID_AGENT_ID` - Missing or unknown agent identifier
899
+ - `FALLBACK_AGENT_NOT_IN_RULES` - Configured fallback agent not found in gateway rules
900
+ - `NO_FALLBACK_CONFIGURED` - No agent_id provided and no fallback agent configured
901
+
902
+ ### Complete Workflow Example
903
+
904
+ Here's a minimal working example showing the typical gateway workflow:
905
+
906
+ ```python
907
+ from fastmcp import Client
908
+
909
+ async def gateway_workflow():
910
+ async with Client('agent-mcp-gateway') as client:
911
+ # 1. Discover available servers
912
+ servers = await client.call_tool('list_servers', {
913
+ 'agent_id': 'researcher'
914
+ })
915
+ # Response: [{"name": "brave-search", "description": "Web search..."}]
916
+
917
+ # 2. Get tools from specific server
918
+ tools = await client.call_tool('get_server_tools', {
919
+ 'agent_id': 'researcher',
920
+ 'server': 'brave-search'
921
+ })
922
+ # Response: {"tools": [...], "server": "brave-search", ...}
923
+
924
+ # 3. Execute a tool
925
+ result = await client.call_tool('execute_tool', {
926
+ 'agent_id': 'researcher',
927
+ 'server': 'brave-search',
928
+ 'tool': 'brave_web_search',
929
+ 'args': {'query': 'MCP protocol documentation'}
930
+ })
931
+ # Response: {"content": [...search results...], "isError": false}
932
+ ```
933
+
934
+ This workflow demonstrates on-demand tool discovery - load definitions only when needed, not upfront.
935
+
936
+ ### Agent Identity Modes
937
+
938
+ The gateway supports two deployment modes for handling agent identity:
939
+
940
+ #### Single-Agent Mode
941
+
942
+ Use when all agents should have the same permissions (development, personal use, single-agent deployments):
943
+
944
+ ```bash
945
+ # Set default agent via environment variable
946
+ export GATEWAY_DEFAULT_AGENT=developer
947
+ ```
948
+
949
+ Or define a "default" agent in rules:
950
+ ```json
951
+ {
952
+ "agents": {
953
+ "default": {
954
+ "allow": {"servers": ["brave-search", "postgres"]}
955
+ }
956
+ },
957
+ "defaults": {
958
+ "deny_on_missing_agent": false
959
+ }
960
+ }
961
+ ```
962
+
963
+ Agents can omit `agent_id` in tool calls - the gateway automatically uses the configured default.
964
+
965
+ #### Multi-Agent Mode
966
+
967
+ Use when different agents need different permissions (production, multi-agent systems):
968
+
969
+ ```json
970
+ {
971
+ "agents": {
972
+ "researcher": {"allow": {"servers": ["brave-search"]}},
973
+ "backend": {"allow": {"servers": ["postgres"]}}
974
+ },
975
+ "defaults": {
976
+ "deny_on_missing_agent": true // Require explicit agent_id
977
+ }
978
+ }
979
+ ```
980
+
981
+ Configure each agent to pass their identity (see [Configuring Agents to Use the Gateway](#configuring-agents-to-use-the-gateway)).
982
+
983
+ <details>
984
+ <summary><strong>Technical Details: Agent Identity Resolution</strong></summary>
985
+
986
+ When `agent_id` is not provided, the gateway uses this fallback chain:
987
+
988
+ 1. `GATEWAY_DEFAULT_AGENT` environment variable (highest priority)
989
+ 2. Agent named "default" in `.mcp-gateway-rules.json`
990
+ 3. Error if neither configured
991
+
992
+ The `deny_on_missing_agent` setting controls this behavior:
993
+ - `true`: Require explicit `agent_id` (bypass fallback chain)
994
+ - `false`: Use fallback chain when `agent_id` omitted
995
+
996
+ **Security Note:** The fallback mechanism follows the principle of least privilege - it never grants implicit "allow all" access, only the explicitly configured agent's permissions.
997
+
998
+ </details>
999
+
1000
+ ## Security Considerations
1001
+
1002
+ **Rules File Location:** Store `.mcp-gateway-rules.json` in-project for context optimization only. For production access control, store outside project directory (e.g., `~/.claude/mcp-gateway-rules.json`) to prevent agents from reading/modifying permissions.
1003
+
1004
+ **Debug Mode:** The `get_gateway_status` tool exposes gateway internals and is only available when `GATEWAY_DEBUG=true`. Disable in production environments.
1005
+
1006
+ **For comprehensive security guidance:** See [Security Guide](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/security-guide.md) for detailed information on rules file security, debug mode considerations, agent impersonation risks, and production best practices.
1007
+
1008
+ ## Troubleshooting
1009
+
1010
+ ### Gateway Won't Start
1011
+
1012
+ **Symptom:** Error on startup or gateway fails to initialize
1013
+
1014
+ **Solutions:**
1015
+ - **Check configuration files exist:** Verify `.mcp.json` and `.mcp-gateway-rules.json` are in the expected location
1016
+ - **Validate JSON syntax:** Use `python -m json.tool < .mcp.json` to check for syntax errors
1017
+ - **Check Python version:** Ensure Python 3.12+ is installed (`python --version`)
1018
+ - **Verify dependencies:** Run `uv sync` to ensure all packages are installed
1019
+
1020
+ ### Can't Connect to Downstream Server
1021
+
1022
+ **Symptom:** `SERVER_UNAVAILABLE` error when calling tools
1023
+
1024
+ **Solutions:**
1025
+ - **Verify server configuration:** Check server is properly defined in `.mcp.json`
1026
+ - **Test stdio servers:** Ensure command is available (`npx --version`, `uvx --version`)
1027
+ - **Check environment variables:** Verify API keys and credentials are set
1028
+ - **Test HTTP servers:** Try accessing server URL directly in browser
1029
+ - **Review startup logs:** Look for server initialization errors in gateway output
1030
+
1031
+ ### Permission Denied Errors
1032
+
1033
+ **Symptom:** `DENIED_BY_POLICY` when agent tries to use a tool
1034
+
1035
+ **Solutions:**
1036
+ - **Verify agent_id:** Ensure agent is passing correct identity (check audit logs)
1037
+ - **Check agent rules:** Confirm agent exists in `.mcp-gateway-rules.json`
1038
+ - **Review policy precedence:** Remember deny rules take precedence over allow rules
1039
+ - **Test with wildcard:** Try `"tools": {"server-name": ["*"]}` to grant broad access temporarily
1040
+ - **Enable debug mode:** Use `GATEWAY_DEBUG=true` and call `get_gateway_status` to inspect policy state
1041
+
1042
+ ### OAuth Authentication Issues
1043
+
1044
+ **Symptom:** Browser doesn't open or OAuth flow fails
1045
+
1046
+ See detailed troubleshooting in [OAuth User Guide](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/oauth-user-guide.md).
1047
+
1048
+ Quick fixes:
1049
+ - **Clear token cache:** `rm -rf ~/.fastmcp/oauth-mcp-client-cache/`
1050
+ - **Test browser:** `python -m webbrowser https://example.com`
1051
+ - **Check server URL:** Verify correct OAuth server URL in `.mcp.json`
1052
+
1053
+ ### Hot Reload Not Working
1054
+
1055
+ **Symptom:** Changes to config files don't take effect
1056
+
1057
+ **Solutions:**
1058
+ - **Check file watch:** Ensure config files are in expected locations
1059
+ - **Review logs:** Look for reload errors in gateway output
1060
+ - **Manual reload:** Send SIGHUP signal or restart gateway
1061
+ - **Debug mode:** Use `get_gateway_status` to check last reload timestamps
1062
+
1063
+ **For additional help:** See [Security Guide](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/security-guide.md), [OAuth User Guide](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/oauth-user-guide.md), or open a GitHub issue.
1064
+
1065
+ ## Testing
1066
+
1067
+ ### Running Tests
1068
+
1069
+ ```bash
1070
+ # Run all tests
1071
+ uv run pytest
1072
+
1073
+ # Run with coverage
1074
+ uv run pytest --cov=src --cov-report=term
1075
+
1076
+ # Run specific test file
1077
+ uv run pytest tests/test_gateway.py -v
1078
+
1079
+ # Run integration tests only
1080
+ uv run pytest tests/test_integration_m1.py -v
1081
+ ```
1082
+
1083
+ ### Testing with MCP Inspector
1084
+
1085
+ The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is an interactive developer tool for testing and debugging MCP servers.
1086
+
1087
+ #### Install and Run
1088
+
1089
+ **For PyPI Installation (uvx):**
1090
+
1091
+ ```bash
1092
+ # Run Inspector with gateway from PyPI
1093
+ # With environment variables for custom config paths
1094
+ GATEWAY_MCP_CONFIG=~/.config/agent-mcp-gateway/mcp.json \
1095
+ GATEWAY_RULES=~/.config/agent-mcp-gateway/mcp-gateway-rules.json \
1096
+ GATEWAY_DEFAULT_AGENT=researcher \
1097
+ npx @modelcontextprotocol/inspector uvx agent-mcp-gateway
1098
+
1099
+ # Or with default config paths (searches current directory and fallback locations)
1100
+ npx @modelcontextprotocol/inspector uvx agent-mcp-gateway
1101
+
1102
+ # With debug mode enabled
1103
+ GATEWAY_DEBUG=true npx @modelcontextprotocol/inspector uvx agent-mcp-gateway
1104
+ ```
1105
+
1106
+ **For PyPI Installation (uv tool):**
1107
+
1108
+ ```bash
1109
+ # Run Inspector with installed gateway
1110
+ GATEWAY_MCP_CONFIG=~/.config/agent-mcp-gateway/mcp.json \
1111
+ GATEWAY_RULES=~/.config/agent-mcp-gateway/mcp-gateway-rules.json \
1112
+ GATEWAY_DEFAULT_AGENT=researcher \
1113
+ npx @modelcontextprotocol/inspector agent-mcp-gateway
1114
+
1115
+ # Or with default config paths
1116
+ npx @modelcontextprotocol/inspector agent-mcp-gateway
1117
+ ```
1118
+
1119
+ **For Local Development:**
1120
+
1121
+ ```bash
1122
+ # Run Inspector with local gateway project
1123
+ # Environment variables are optional - defaults to .mcp.json and .mcp-gateway-rules.json in project directory
1124
+ GATEWAY_MCP_CONFIG=.mcp.json \
1125
+ GATEWAY_RULES=.mcp-gateway-rules.json \
1126
+ GATEWAY_DEFAULT_AGENT=researcher \
1127
+ npx @modelcontextprotocol/inspector uv run python main.py
1128
+
1129
+ # Or with default config paths
1130
+ npx @modelcontextprotocol/inspector uv run python main.py
1131
+
1132
+ # With debug mode to test get_gateway_status tool
1133
+ npx @modelcontextprotocol/inspector uv run python main.py --debug
1134
+ ```
1135
+
1136
+ This opens a web interface where you can:
1137
+ 1. Connect to the gateway via stdio transport
1138
+ 2. View all three gateway tools
1139
+ 3. Test each tool with custom parameters
1140
+ 4. Inspect request/response messages
1141
+ 5. Monitor logs and notifications
1142
+
1143
+ #### Testing Gateway Tools in Inspector
1144
+
1145
+ **1. Test `list_servers`:**
1146
+ ```json
1147
+ {
1148
+ "agent_id": "researcher"
1149
+ }
1150
+ ```
1151
+
1152
+ Expected: List of servers the "researcher" agent can access.
1153
+
1154
+ **2. Test `get_server_tools`:**
1155
+ ```json
1156
+ {
1157
+ "agent_id": "researcher",
1158
+ "server": "brave-search"
1159
+ }
1160
+ ```
1161
+
1162
+ Expected: Tool definitions from brave-search server.
1163
+
1164
+ **3. Test `execute_tool`:**
1165
+ ```json
1166
+ {
1167
+ "agent_id": "researcher",
1168
+ "server": "brave-search",
1169
+ "tool": "brave_web_search",
1170
+ "args": {
1171
+ "query": "test query"
1172
+ }
1173
+ }
1174
+ ```
1175
+
1176
+ Expected: Search results from Brave (if server configured and running).
1177
+
1178
+ #### Inspector Features
1179
+
1180
+ - **Tools Tab**: View all gateway tools with schemas
1181
+ - **Test Execution**: Call tools with custom inputs
1182
+ - **Message Pane**: See raw JSON-RPC messages
1183
+ - **Logs**: Monitor server logs and notifications
1184
+ - **Connection**: Verify gateway startup and initialization
1185
+
1186
+ #### Troubleshooting with Inspector
1187
+
1188
+ If tools fail:
1189
+ 1. Check the **Logs pane** for error messages
1190
+ 2. Verify your `agent_id` exists in `.mcp-gateway-rules.json`
1191
+ 3. Confirm downstream servers are configured in `.mcp.json`
1192
+ 4. Check that required environment variables are set
1193
+ 5. Review the **Message pane** for policy denial reasons
1194
+
1195
+ ### Manual Testing (without Inspector)
1196
+
1197
+ ```bash
1198
+ # Run the existing integration test
1199
+ uv run python test_integration.py
1200
+
1201
+ # Or use FastMCP Client directly
1202
+ uv run python -c "
1203
+ import asyncio
1204
+ from fastmcp import Client
1205
+
1206
+ async def test():
1207
+ async with Client('main.py') as client:
1208
+ result = await client.call_tool('list_servers', {'agent_id': 'researcher'})
1209
+ print(result)
1210
+
1211
+ asyncio.run(test())
1212
+ "
1213
+ ```
1214
+
1215
+ ## Development
1216
+
1217
+ ### Project Structure
1218
+
1219
+ ```
1220
+ agent-mcp-gateway/
1221
+ ├── src/ # Core gateway implementation
1222
+ ├── tests/ # Test suite
1223
+ ├── config/ # Configuration examples
1224
+ ├── docs/ # Documentation and specifications
1225
+ ├── main.py # Entry point
1226
+ └── pyproject.toml # Python dependencies
1227
+ ```
1228
+
1229
+ ### Adding a New Feature
1230
+
1231
+ 1. **Update specs**: Document in relevant milestone file
1232
+ 2. **Write tests first**: Create test file in `tests/`
1233
+ 3. **Implement feature**: Add code in `src/`
1234
+ 4. **Run tests**: `uv run pytest`
1235
+ 5. **Check coverage**: `uv run pytest --cov=src`
1236
+ 6. **Update docs**: Document in README and relevant files
1237
+ 7. **Commit**: Follow commit message format
1238
+
1239
+ ### Running in Development
1240
+
1241
+ ```bash
1242
+ # Run with verbose logging
1243
+ uv run python main.py
1244
+
1245
+ # Run tests in watch mode
1246
+ uv run pytest-watch
1247
+
1248
+ # Generate coverage report
1249
+ uv run pytest --cov=src --cov-report=html
1250
+ open htmlcov/index.html
1251
+ ```
1252
+
1253
+ ### Code Style
1254
+
1255
+ - Follow existing patterns in M0/M1 code
1256
+ - Use type hints throughout
1257
+ - Write docstrings for all public functions
1258
+ - Keep functions focused and testable
1259
+ - Add tests for all new functionality
1260
+
1261
+ ## Architecture
1262
+
1263
+ ### Component Diagram
1264
+
1265
+ ```
1266
+ ┌─────────────────────────────────────────────────────────┐
1267
+ │ Agent / Client │
1268
+ └─────────────────────┬───────────────────────────────────┘
1269
+
1270
+
1271
+ ┌─────────────────────────────────────────────────────────┐
1272
+ │ Agent MCP Gateway │
1273
+ │ ┌───────────────────────────────────────────────────┐ │
1274
+ │ │ Gateway Tools (3 tools, ~400 tokens) │ │
1275
+ │ │ • list_servers │ │
1276
+ │ │ • get_server_tools │ │
1277
+ │ │ • execute_tool │ │
1278
+ │ └───────────────────────────────────────────────────┘ │
1279
+ │ │ │
1280
+ │ ┌─────────────────────────────────────────────────┐ │
1281
+ │ │ AgentAccessControl Middleware │ │
1282
+ │ │ • Extract agent_id │ │
1283
+ │ │ • Validate permissions │ │
1284
+ │ └─────────────────────────────────────────────────┘ │
1285
+ │ │ │
1286
+ │ ┌─────────────────────────────────────────────────┐ │
1287
+ │ │ PolicyEngine │ │
1288
+ │ │ • Deny-before-allow precedence │ │
1289
+ │ │ • Wildcard matching │ │
1290
+ │ └─────────────────────────────────────────────────┘ │
1291
+ │ │ │
1292
+ │ ┌─────────────────────────────────────────────────┐ │
1293
+ │ │ ProxyManager │ │
1294
+ │ │ • Session isolation │ │
1295
+ │ │ • Connection pooling │ │
1296
+ │ └─────────────────────────────────────────────────┘ │
1297
+ │ │ │
1298
+ │ ┌─────────────────────────────────────────────────┐ │
1299
+ │ │ AuditLogger & MetricsCollector │ │
1300
+ │ └─────────────────────────────────────────────────┘ │
1301
+ └──────────────────────┬──────────────────────────────────┘
1302
+
1303
+ ┌─────────────┼─────────────┐
1304
+ ▼ ▼ ▼
1305
+ ┌─────────┐ ┌─────────┐ ┌─────────┐
1306
+ │ Server │ │ Server │ │ Server │
1307
+ │ A │ │ B │ │ C │
1308
+ │ (stdio) │ │ (stdio) │ │ (HTTP) │
1309
+ └─────────┘ └─────────┘ └─────────┘
1310
+ ```
1311
+
1312
+ ### Request Flow
1313
+
1314
+ 1. **Agent sends request** to gateway tool with `agent_id`
1315
+ 2. **Middleware intercepts**: Extracts and validates `agent_id`
1316
+ 3. **Tool validates**: Checks PolicyEngine for server/tool access
1317
+ 4. **Proxy forwards**: ProxyManager routes to downstream server
1318
+ 5. **Session isolated**: Each request gets fresh connection
1319
+ 6. **Result returns**: Transparently forwarded to agent
1320
+ 7. **Audit logged**: Operation recorded with metrics
1321
+
1322
+ ### Performance Characteristics
1323
+
1324
+ - **Context reduction**: 90%+ (400 tokens vs 5,000-50,000+)
1325
+ - **Added latency**: <100ms (P95)
1326
+ - **Gateway overhead**: <30ms per operation
1327
+ - **Session isolation**: Automatic per-request
1328
+ - **Concurrent requests**: Fully supported
1329
+
1330
+ ## Future Features
1331
+
1332
+ ### M2: Production (Planned)
1333
+
1334
+ 🚧 **Status:** Not yet implemented
1335
+
1336
+ **Features:**
1337
+ - [ ] HTTP transport for gateway server
1338
+ - [ ] Health check endpoints
1339
+ - [ ] Enhanced error handling
1340
+ - [ ] Metrics export API
1341
+ - [ ] Connection pooling optimization
1342
+ - [ ] Rate limiting
1343
+
1344
+ **When available:**
1345
+ ```bash
1346
+ # Run with HTTP transport
1347
+ export GATEWAY_TRANSPORT=http
1348
+ export GATEWAY_PORT=8080
1349
+ uv run python main.py
1350
+
1351
+ # Health check endpoint
1352
+ curl http://localhost:8080/health
1353
+
1354
+ # Metrics endpoint
1355
+ curl http://localhost:8080/metrics
1356
+ ```
1357
+
1358
+ ### M3: Developer Experience (Planned)
1359
+
1360
+ 🚧 **Status:** Not yet implemented
1361
+
1362
+ **Features:**
1363
+ - [ ] Single-agent mode (bypass agent_id requirement)
1364
+ - [ ] Config validation CLI tool
1365
+ - [ ] Docker container with examples
1366
+ - [ ] Interactive setup wizard
1367
+ - [ ] VS Code extension
1368
+
1369
+ **When available:**
1370
+ ```bash
1371
+ # Single-agent mode (no agent_id required)
1372
+ export GATEWAY_DEFAULT_AGENT=developer
1373
+ uv run python main.py
1374
+
1375
+ # Validate configs
1376
+ uv run python -m src.cli validate
1377
+
1378
+ # Run with Docker
1379
+ docker run -v ./config:/config agent-mcp-gateway
1380
+ ```
1381
+
1382
+ ## Documentation
1383
+
1384
+ - [Product Requirements Document](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/specs/PRD.md)
1385
+ - [M0: Foundation Spec](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/specs/m0-foundation.md)
1386
+ - [M0: Success Report](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/milestones/m0-success-report.md)
1387
+ - [M1: Core Spec](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/specs/m1-core.md)
1388
+ - [M1: Success Report](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/milestones/m1-success-report.md)
1389
+ - [FastMCP Implementation Guide](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/fastmcp-implementation-guide.md)
1390
+ - [Claude Code Subagent Limitations](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/claude-code-subagent-mcp-limitations.md)
1391
+
1392
+ ## Contributing
1393
+
1394
+ Contributions welcome! Please:
1395
+
1396
+ 1. Read the [PRD](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/specs/PRD.md) and relevant milestone specs
1397
+ 2. Follow the existing code style and patterns
1398
+ 3. Write tests for all new functionality
1399
+ 4. Ensure all tests pass: `uv run pytest`
1400
+ 5. Update documentation as needed
1401
+ 6. Submit a pull request with clear description
1402
+
1403
+ ## License
1404
+
1405
+ This project is licensed under the MIT License - see the [LICENSE](https://github.com/roddutra/agent-mcp-gateway/blob/main/LICENSE) file for details.
1406
+
1407
+ ## Support
1408
+
1409
+ For issues and questions:
1410
+ - GitHub Issues: [Create an issue](https://github.com/roddutra/agent-mcp-gateway/issues)
1411
+ - Documentation: [docs/](https://github.com/roddutra/agent-mcp-gateway/blob/main/docs/)
1412
+ - MCP Specification: https://modelcontextprotocol.io
1413
+
1414
+ ## Acknowledgments
1415
+
1416
+ Built with:
1417
+ - [FastMCP](https://gofastmcp.com/) - MCP server framework
1418
+ - [Model Context Protocol](https://modelcontextprotocol.io/) - Protocol specification