-
-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Summary
Priority: 🔴 HIGH
Impact: 50-80% reduction in latency for subsequent requests
Difficulty: Medium
Testing Checklist
- TransporterPool correctly stores and retrieves transporters
- Same transporter instance is returned for same server name
-
forget()method removes specific transporter -
clear()method removes all transporters - MCPClient uses TransporterPool instead of creating new instances
- All existing MCPClient tests still pass
- Multiple connects to same server reuse transporter
Expected Outcome
After implementing this:
- First
connect()call: Creates new transporter (same as before) - Subsequent
connect()calls to same server: Reuses existing transporter (MUCH faster) - Users can force reconnection with
reconnect()method if needed
Problem
Currently, every time MCPClient::connect() is called, a new transporter instance is created. This means:
-
For HTTP transporters:
- A new Guzzle HTTP client is instantiated
- A new session initialization handshake occurs (extra network round-trip)
- Memory overhead from multiple client instances
-
For STDIO transporters:
- A new process is spawned every time
- Process startup overhead (even with reduced delays)
- Initialization handshakes are repeated unnecessarily
Example of Current Inefficiency
// User code that makes multiple requests
$client = app(MCPClient::class);
// First request - creates new transporter, initializes session
$client->connect('github')->tools();
// Second request - creates ANOTHER new transporter, initializes ANOTHER session
$client->connect('github')->resources();
// Third request - yet ANOTHER new transporter and session
$client->connect('github')->callTool('search', ['query' => 'test']);Each of these creates a brand new transporter instance, even though they're connecting to the same server!
Proposed Solution
Create a TransporterPool class that maintains a singleton registry of active transporters and reuses them.
Implementation Steps
Step 1: Create TransporterPool Class
Create file: src/Core/TransporterPool.php
Step 2: Update MCPClient to Use TransporterPool
Modify src/MCPClient.php:
Step 3: Update Service Provider
Modify src/MCPClientServiceProvider.php:
public function packageBooted(): void
{
// Register TransporterPool as singleton
$this->app->singleton(TransporterPool::class, function ($app) {
return new TransporterPool();
});
$this->app->bind(MCPClient::class, function ($app) {
$servers = $app['config']->get('mcp-client.servers', []);
return new MCPClient($servers, $app->make(TransporterPool::class));
});
}Step 4: Create Tests
Create file: tests/Core/TransporterPoolTest.php
- creates transporter on first call
- returns same transporter on subsequent calls
- forget removes transporter from pool
- clear removes all transporters
- getActiveServers returns list of server names
Step 5: Update Existing Tests
Update tests/MCPClient/MCPClientTest.php to use TransporterPool instead of TransporterFactory:
Replace all instances of:
$mockFactory = Mockery::mock(TransporterFactory::class);With:
$mockPool = Mockery::mock(TransporterPool::class);And update the expectations from shouldReceive('make') to shouldReceive('get').
Alternatives Considered
No response
Package Version
1
PHP Version
8.4
Laravel Version
12
Notes
No response