Commit 60a2abb
Fix MCP HTTP transport for PHP-FPM/Apache: Auto-register clients + OAuth compliance
## Critical Transport Architecture Fix
This commit resolves two fundamental issues that prevented MCP HTTP transport
from working correctly with traditional PHP servers (PHP-FPM, Apache) while
maintaining compatibility with long-running processes (ReactPHP).
### 🔧 Problem 1: Client Registration Lost Between Requests
**Root Cause:**
Each HTTP request in PHP-FPM/Apache runs in a separate PHP process, causing:
- SSE stream (GET /sse) creates LaravelHttpTransport instance php-mcp#1
- POST requests (/message) create LaravelHttpTransport instance php-mcp#2
- Client registered in instance php-mcp#1 is not available in instance php-mcp#2
- Result: "Client not actively managed by this transport" errors
**Solution:**
Auto-registration in `LaravelHttpTransport::sendToClientAsync()`:
- Automatically emit `client_connected` event for unknown clients
- Ensures clients are active before processing messages
- Maintains backward compatibility with ReactPHP (no-op for already active clients)
### 🔧 Problem 2: OAuth Standard Compliance
**Root Cause:**
Original package used non-standard parameter naming that violates OAuth spec:
- Used: `clientId` (camelCase)
- OAuth Standard: `client_id` (snake_case)
- Real MCP clients (Claude Desktop) send `client_id` parameter
**Solution:**
- Updated SSE endpoint to accept `client_id` query parameter
- Consistent `client_id` usage in all log messages
- Maintains fallback to session ID if no `client_id` provided
### 🔧 Problem 3: Service Provider Architecture
**Root Cause:**
Multiple controller instantiations called `server->listen()` repeatedly, causing:
- Event handlers registered multiple times
- Transport state inconsistencies
- Memory leaks and performance issues
**Solution:**
- Moved `server->listen()` to McpServiceProvider singleton registration
- Removed redundant `server->listen()` calls from controller constructor
- Proper logger injection in service provider
## 🧪 Tested Scenarios
✅ **PHP-FPM/Apache (Separate Processes)**
- Each request gets clean transport instance
- Auto-registration ensures client connectivity
- No shared state issues
✅ **ReactPHP (Long-Running Process)**
- Existing clients remain active
- Auto-registration is no-op for active clients
- No performance impact
✅ **Claude Desktop Integration**
- Recognizes all MCP tools correctly
- Proper `client_id` parameter handling
- SSE stream maintains connection
## 🔍 Technical Details
**Modified Files:**
- `src/Transports/LaravelHttpTransport.php`: Auto-registration logic
- `src/Http/Controllers/McpController.php`: OAuth compliance + service provider cleanup
- `src/McpServiceProvider.php`: Centralized transport initialization
**Key Changes:**
1. Auto-registration in `sendToClientAsync()` when client not found
2. SSE endpoint accepts `client_id` query parameter
3. Service provider handles transport listening lifecycle
4. Consistent `client_id` logging throughout
## 🚀 Impact
**Before:** MCP HTTP transport only worked with ReactPHP
**After:** Works with all PHP server configurations
**Deployment:** Zero breaking changes - existing code continues to work
**Performance:** Minimal overhead (~1 isset() check per message)
This fix enables MCP HTTP transport to work reliably in production PHP
environments while maintaining the existing API and functionality.
Fixes issues with:
- Traditional PHP-FPM deployments
- Apache mod_php configurations
- Docker containers with nginx+php-fpm
- Shared hosting environments
- Any setup where each HTTP request runs in separate PHP process
Co-authored-by: Claude (Anthropic) <[email protected]>1 parent 1dbac58 commit 60a2abb
File tree
3 files changed
+44
-8
lines changed- src
- Http/Controllers
- Transports
3 files changed
+44
-8
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
29 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| |||
88 | 89 | | |
89 | 90 | | |
90 | 91 | | |
91 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
92 | 97 | | |
93 | 98 | | |
94 | 99 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
116 | 116 | | |
117 | 117 | | |
118 | 118 | | |
119 | | - | |
120 | | - | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
121 | 129 | | |
122 | 130 | | |
123 | 131 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
38 | 39 | | |
39 | 40 | | |
40 | 41 | | |
| |||
68 | 69 | | |
69 | 70 | | |
70 | 71 | | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
71 | 79 | | |
72 | | - | |
73 | | - | |
74 | | - | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
75 | 98 | | |
76 | 99 | | |
77 | 100 | | |
| |||
0 commit comments