From f2b973bcec6ba865014069f7fdfe706d40c880e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 07:39:30 +0000 Subject: [PATCH 1/4] Initial plan From e0ccbcc7df083256cc6c6584f76999cea1c64ab1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 07:48:42 +0000 Subject: [PATCH 2/4] Implement TransporterPool for connection reuse Co-authored-by: nikajorjika <4212052+nikajorjika@users.noreply.github.com> --- src/Core/TransporterPool.php | 73 +++++++++++ src/MCPClient.php | 13 +- src/MCPClientServiceProvider.php | 9 +- tests/Core/TransporterPoolTest.php | 189 +++++++++++++++++++++++++++++ tests/MCPClient/MCPClientTest.php | 30 ++--- 5 files changed, 292 insertions(+), 22 deletions(-) create mode 100644 src/Core/TransporterPool.php create mode 100644 tests/Core/TransporterPoolTest.php diff --git a/src/Core/TransporterPool.php b/src/Core/TransporterPool.php new file mode 100644 index 0000000..5905927 --- /dev/null +++ b/src/Core/TransporterPool.php @@ -0,0 +1,73 @@ + + */ + private array $transporters = []; + + public function __construct( + private readonly TransporterFactory $factory = new TransporterFactory + ) {} + + /** + * Get or create a transporter for the given server. + * + * @param string $serverName The name of the server + * @param array $config The server configuration + * @return Transporter + */ + public function get(string $serverName, array $config): Transporter + { + if (!isset($this->transporters[$serverName])) { + $this->transporters[$serverName] = $this->factory->make($config); + } + + return $this->transporters[$serverName]; + } + + /** + * Remove a specific transporter from the pool. + * + * @param string $serverName The name of the server + * @return void + */ + public function forget(string $serverName): void + { + unset($this->transporters[$serverName]); + } + + /** + * Clear all transporters from the pool. + * + * @return void + */ + public function clear(): void + { + $this->transporters = []; + } + + /** + * Get list of active server names. + * + * @return array + */ + public function getActiveServers(): array + { + return array_keys($this->transporters); + } +} diff --git a/src/MCPClient.php b/src/MCPClient.php index 573ae06..eb9eeee 100755 --- a/src/MCPClient.php +++ b/src/MCPClient.php @@ -3,7 +3,7 @@ namespace Redberry\MCPClient; use Redberry\MCPClient\Contracts\MCPClient as IMCPClient; -use Redberry\MCPClient\Core\TransporterFactory; +use Redberry\MCPClient\Core\TransporterPool; use Redberry\MCPClient\Core\Transporters\Transporter; class MCPClient implements IMCPClient @@ -14,12 +14,14 @@ class MCPClient implements IMCPClient private Transporter $transporter; + private string $currentServerName; + /** * Connects to a specified MCP server. */ public function __construct( array $config, - private readonly TransporterFactory $factory = new TransporterFactory + private readonly TransporterPool $pool = new TransporterPool ) { $this->config = $config; } @@ -30,7 +32,8 @@ public function connect(string $serverName): IMCPClient $this->ensureConfigurationValidity(); - $this->transporter = $this->getTransporter($this->serverConfig); + $this->currentServerName = $serverName; + $this->transporter = $this->getTransporter($serverName, $this->serverConfig); return $this; } @@ -84,9 +87,9 @@ public function resources(): Collection return new Collection($resources); } - private function getTransporter(array $config): Transporter + private function getTransporter(string $serverName, array $config): Transporter { - return $this->factory->make($config); + return $this->pool->get($serverName, $config); } private function ensureConfigurationValidity(): void diff --git a/src/MCPClientServiceProvider.php b/src/MCPClientServiceProvider.php index 80c2b3d..3d0a81f 100644 --- a/src/MCPClientServiceProvider.php +++ b/src/MCPClientServiceProvider.php @@ -3,7 +3,7 @@ namespace Redberry\MCPClient; use Redberry\MCPClient\Commands\MCPClientCommand; -use Redberry\MCPClient\Core\TransporterFactory; +use Redberry\MCPClient\Core\TransporterPool; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; @@ -25,10 +25,15 @@ public function configurePackage(Package $package): void 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(TransporterFactory::class)); + return new MCPClient($servers, $app->make(TransporterPool::class)); }); } } diff --git a/tests/Core/TransporterPoolTest.php b/tests/Core/TransporterPoolTest.php new file mode 100644 index 0000000..de8baea --- /dev/null +++ b/tests/Core/TransporterPoolTest.php @@ -0,0 +1,189 @@ + 'http', 'base_url' => 'https://example.com']; + + $mockFactory->shouldReceive('make') + ->once() + ->with($config) + ->andReturn($mockTransporter); + + $pool = new TransporterPool($mockFactory); + $transporter = $pool->get('github', $config); + + expect($transporter)->toBe($mockTransporter); + }); + + it('returns same transporter on subsequent calls', function () { + $mockFactory = Mockery::mock(TransporterFactory::class); + $mockTransporter = Mockery::mock(Transporter::class); + + $config = ['type' => 'http', 'base_url' => 'https://example.com']; + + // Factory should only be called once + $mockFactory->shouldReceive('make') + ->once() + ->with($config) + ->andReturn($mockTransporter); + + $pool = new TransporterPool($mockFactory); + + // First call + $transporter1 = $pool->get('github', $config); + + // Second call - should return same instance + $transporter2 = $pool->get('github', $config); + + expect($transporter1)->toBe($mockTransporter) + ->and($transporter2)->toBe($mockTransporter) + ->and($transporter1)->toBe($transporter2); + }); + + it('forget removes transporter from pool', function () { + $mockFactory = Mockery::mock(TransporterFactory::class); + $mockTransporter1 = Mockery::mock(Transporter::class); + $mockTransporter2 = Mockery::mock(Transporter::class); + + $config = ['type' => 'http', 'base_url' => 'https://example.com']; + + // Factory should be called twice (before and after forget) + $mockFactory->shouldReceive('make') + ->twice() + ->with($config) + ->andReturn($mockTransporter1, $mockTransporter2); + + $pool = new TransporterPool($mockFactory); + + // First call + $transporter1 = $pool->get('github', $config); + expect($transporter1)->toBe($mockTransporter1); + + // Forget the transporter + $pool->forget('github'); + + // Next call should create a new transporter + $transporter2 = $pool->get('github', $config); + expect($transporter2)->toBe($mockTransporter2); + }); + + it('clear removes all transporters', function () { + $mockFactory = Mockery::mock(TransporterFactory::class); + $mockTransporter1 = Mockery::mock(Transporter::class); + $mockTransporter2 = Mockery::mock(Transporter::class); + + $config1 = ['type' => 'http', 'base_url' => 'https://github.com']; + $config2 = ['type' => 'http', 'base_url' => 'https://gitlab.com']; + + $mockFactory->shouldReceive('make') + ->with($config1) + ->andReturn($mockTransporter1); + + $mockFactory->shouldReceive('make') + ->with($config2) + ->andReturn($mockTransporter2); + + $pool = new TransporterPool($mockFactory); + + // Add two transporters + $pool->get('github', $config1); + $pool->get('gitlab', $config2); + + expect($pool->getActiveServers())->toHaveCount(2) + ->toContain('github') + ->toContain('gitlab'); + + // Clear all + $pool->clear(); + + expect($pool->getActiveServers())->toBeEmpty(); + }); + + it('getActiveServers returns list of server names', function () { + $mockFactory = Mockery::mock(TransporterFactory::class); + $mockTransporter1 = Mockery::mock(Transporter::class); + $mockTransporter2 = Mockery::mock(Transporter::class); + $mockTransporter3 = Mockery::mock(Transporter::class); + + $config1 = ['type' => 'http', 'base_url' => 'https://github.com']; + $config2 = ['type' => 'http', 'base_url' => 'https://gitlab.com']; + $config3 = ['type' => 'stdio', 'command' => ['npx', 'test']]; + + $mockFactory->shouldReceive('make') + ->with($config1) + ->andReturn($mockTransporter1); + + $mockFactory->shouldReceive('make') + ->with($config2) + ->andReturn($mockTransporter2); + + $mockFactory->shouldReceive('make') + ->with($config3) + ->andReturn($mockTransporter3); + + $pool = new TransporterPool($mockFactory); + + expect($pool->getActiveServers())->toBeEmpty(); + + $pool->get('github', $config1); + expect($pool->getActiveServers())->toBe(['github']); + + $pool->get('gitlab', $config2); + expect($pool->getActiveServers())->toHaveCount(2) + ->toContain('github') + ->toContain('gitlab'); + + $pool->get('npx_server', $config3); + expect($pool->getActiveServers())->toHaveCount(3) + ->toContain('github') + ->toContain('gitlab') + ->toContain('npx_server'); + }); + + it('handles multiple different servers correctly', function () { + $mockFactory = Mockery::mock(TransporterFactory::class); + $mockTransporter1 = Mockery::mock(Transporter::class); + $mockTransporter2 = Mockery::mock(Transporter::class); + + $config1 = ['type' => 'http', 'base_url' => 'https://github.com']; + $config2 = ['type' => 'stdio', 'command' => ['npx', 'test']]; + + $mockFactory->shouldReceive('make') + ->once() + ->with($config1) + ->andReturn($mockTransporter1); + + $mockFactory->shouldReceive('make') + ->once() + ->with($config2) + ->andReturn($mockTransporter2); + + $pool = new TransporterPool($mockFactory); + + // Get different servers + $t1 = $pool->get('github', $config1); + $t2 = $pool->get('npx_server', $config2); + + // Should be different instances + expect($t1)->toBe($mockTransporter1) + ->and($t2)->toBe($mockTransporter2) + ->and($t1)->not->toBe($t2); + + // Getting same servers again should return same instances + $t1Again = $pool->get('github', $config1); + $t2Again = $pool->get('npx_server', $config2); + + expect($t1Again)->toBe($mockTransporter1) + ->and($t2Again)->toBe($mockTransporter2); + }); +}); diff --git a/tests/MCPClient/MCPClientTest.php b/tests/MCPClient/MCPClientTest.php index a4b6ca4..955a45c 100644 --- a/tests/MCPClient/MCPClientTest.php +++ b/tests/MCPClient/MCPClientTest.php @@ -2,7 +2,7 @@ use Illuminate\Support\Facades\Config; use Redberry\MCPClient\Collection; -use Redberry\MCPClient\Core\TransporterFactory; +use Redberry\MCPClient\Core\TransporterPool; use Redberry\MCPClient\Core\Transporters\Transporter; use Redberry\MCPClient\Enums\Transporters; use Redberry\MCPClient\MCPClient; @@ -37,15 +37,15 @@ test('connect sets server config and transporter', function () { - $mockFactory = Mockery::mock(TransporterFactory::class); + $mockPool = Mockery::mock(TransporterPool::class); $mockTransporter = Mockery::mock(Transporter::class); - $mockFactory->shouldReceive('make') + $mockPool->shouldReceive('get') ->once() - ->with(config('mcp-client.servers.using_enum')) + ->with('using_enum', config('mcp-client.servers.using_enum')) ->andReturn($mockTransporter); - $client = new MCPClient(config('mcp-client.servers'), $mockFactory); + $client = new MCPClient(config('mcp-client.servers'), $mockPool); $connected = $client->connect('using_enum'); expect($connected)->toBeInstanceOf(MCPClient::class); @@ -53,15 +53,15 @@ test('connect sets server config and transporter when type is not enum', function () { - $mockFactory = Mockery::mock(TransporterFactory::class); + $mockPool = Mockery::mock(TransporterPool::class); $mockTransporter = Mockery::mock(Transporter::class); - $mockFactory->shouldReceive('make') + $mockPool->shouldReceive('get') ->once() - ->with(config('mcp-client.servers.without_enum')) + ->with('without_enum', config('mcp-client.servers.without_enum')) ->andReturn($mockTransporter); - $client = new MCPClient(config('mcp-client.servers'), $mockFactory); + $client = new MCPClient(config('mcp-client.servers'), $mockPool); $connected = $client->connect('without_enum'); expect($connected)->toBeInstanceOf(MCPClient::class); @@ -69,16 +69,16 @@ test('tools returns collection of tools', function () { $mockTransporter = Mockery::mock(Transporter::class); - $mockFactory = Mockery::mock(TransporterFactory::class); + $mockPool = Mockery::mock(TransporterPool::class); $mockTransporter->shouldReceive('request') ->once() ->with('tools/list') ->andReturn(['tools' => [['name' => 'tool1'], ['name' => 'tool2']]]); - $mockFactory->shouldReceive('make')->andReturn($mockTransporter); + $mockPool->shouldReceive('get')->andReturn($mockTransporter); - $client = new MCPClient(config('mcp-client.servers'), $mockFactory); + $client = new MCPClient(config('mcp-client.servers'), $mockPool); $client->connect('using_enum'); $tools = $client->tools(); @@ -88,15 +88,15 @@ test('resources returns collection of resources', function () { $mockTransporter = Mockery::mock(Transporter::class); - $mockFactory = Mockery::mock(TransporterFactory::class); + $mockPool = Mockery::mock(TransporterPool::class); $mockTransporter->shouldReceive('request') ->once() ->with('resources/list') ->andReturn(['resources' => [['id' => 1], ['id' => 2]]]); - $mockFactory->shouldReceive('make')->andReturn($mockTransporter); + $mockPool->shouldReceive('get')->andReturn($mockTransporter); - $client = new MCPClient(config('mcp-client.servers'), $mockFactory); + $client = new MCPClient(config('mcp-client.servers'), $mockPool); $client->connect('using_enum'); $resources = $client->resources(); From a66960a1d36c0468de1b002fef5e383df251dd40 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 07:51:06 +0000 Subject: [PATCH 3/4] Add integration test for transporter reuse Co-authored-by: nikajorjika <4212052+nikajorjika@users.noreply.github.com> --- tests/MCPClient/MCPClientTest.php | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/MCPClient/MCPClientTest.php b/tests/MCPClient/MCPClientTest.php index 955a45c..c3e48ab 100644 --- a/tests/MCPClient/MCPClientTest.php +++ b/tests/MCPClient/MCPClientTest.php @@ -115,4 +115,37 @@ $client->resources(); // should throw })->throws(RuntimeException::class, 'Server configuration is not set. Please connect to a server first.'); + + test('multiple connects to same server reuse transporter', function () { + $mockPool = Mockery::mock(TransporterPool::class); + $mockTransporter = Mockery::mock(Transporter::class); + + // The pool's get method will be called twice (once per connect) + // but it should return the same transporter instance + $mockPool->shouldReceive('get') + ->twice() + ->with('using_enum', config('mcp-client.servers.using_enum')) + ->andReturn($mockTransporter); + + $mockTransporter->shouldReceive('request') + ->with('tools/list') + ->andReturn(['tools' => [['name' => 'tool1']]]); + + $mockTransporter->shouldReceive('request') + ->with('resources/list') + ->andReturn(['resources' => [['id' => 1]]]); + + $client = new MCPClient(config('mcp-client.servers'), $mockPool); + + // First connect + $client->connect('using_enum'); + $tools = $client->tools(); + + // Second connect to the same server - pool returns the same transporter + $client->connect('using_enum'); + $resources = $client->resources(); + + expect($tools)->toBeInstanceOf(Collection::class) + ->and($resources)->toBeInstanceOf(Collection::class); + }); }); From 6b485c3337266244e2cde65db65999d55e0b6a13 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 07:55:27 +0000 Subject: [PATCH 4/4] Address code review feedback: remove unused property and simplify factory usage Co-authored-by: nikajorjika <4212052+nikajorjika@users.noreply.github.com> --- src/Core/TransporterPool.php | 6 +- src/MCPClient.php | 3 - tests/Core/TransporterPoolTest.php | 132 ++++++----------------------- 3 files changed, 29 insertions(+), 112 deletions(-) diff --git a/src/Core/TransporterPool.php b/src/Core/TransporterPool.php index 5905927..83e179a 100644 --- a/src/Core/TransporterPool.php +++ b/src/Core/TransporterPool.php @@ -20,10 +20,6 @@ class TransporterPool */ private array $transporters = []; - public function __construct( - private readonly TransporterFactory $factory = new TransporterFactory - ) {} - /** * Get or create a transporter for the given server. * @@ -34,7 +30,7 @@ public function __construct( public function get(string $serverName, array $config): Transporter { if (!isset($this->transporters[$serverName])) { - $this->transporters[$serverName] = $this->factory->make($config); + $this->transporters[$serverName] = TransporterFactory::make($config); } return $this->transporters[$serverName]; diff --git a/src/MCPClient.php b/src/MCPClient.php index eb9eeee..93364e1 100755 --- a/src/MCPClient.php +++ b/src/MCPClient.php @@ -14,8 +14,6 @@ class MCPClient implements IMCPClient private Transporter $transporter; - private string $currentServerName; - /** * Connects to a specified MCP server. */ @@ -32,7 +30,6 @@ public function connect(string $serverName): IMCPClient $this->ensureConfigurationValidity(); - $this->currentServerName = $serverName; $this->transporter = $this->getTransporter($serverName, $this->serverConfig); return $this; diff --git a/tests/Core/TransporterPoolTest.php b/tests/Core/TransporterPoolTest.php index de8baea..e2f65c8 100644 --- a/tests/Core/TransporterPoolTest.php +++ b/tests/Core/TransporterPoolTest.php @@ -2,42 +2,25 @@ declare(strict_types=1); -use Redberry\MCPClient\Core\TransporterFactory; use Redberry\MCPClient\Core\TransporterPool; -use Redberry\MCPClient\Core\Transporters\Transporter; +use Redberry\MCPClient\Core\Transporters\HttpTransporter; +use Redberry\MCPClient\Core\Transporters\StdioTransporter; describe('TransporterPool', function () { it('creates transporter on first call', function () { - $mockFactory = Mockery::mock(TransporterFactory::class); - $mockTransporter = Mockery::mock(Transporter::class); + $config = ['type' => 'http', 'base_url' => 'https://example.com', 'timeout' => 30]; - $config = ['type' => 'http', 'base_url' => 'https://example.com']; - - $mockFactory->shouldReceive('make') - ->once() - ->with($config) - ->andReturn($mockTransporter); - - $pool = new TransporterPool($mockFactory); + $pool = new TransporterPool(); $transporter = $pool->get('github', $config); - expect($transporter)->toBe($mockTransporter); + expect($transporter)->toBeInstanceOf(HttpTransporter::class); }); it('returns same transporter on subsequent calls', function () { - $mockFactory = Mockery::mock(TransporterFactory::class); - $mockTransporter = Mockery::mock(Transporter::class); - - $config = ['type' => 'http', 'base_url' => 'https://example.com']; + $config = ['type' => 'http', 'base_url' => 'https://example.com', 'timeout' => 30]; - // Factory should only be called once - $mockFactory->shouldReceive('make') - ->once() - ->with($config) - ->andReturn($mockTransporter); - - $pool = new TransporterPool($mockFactory); + $pool = new TransporterPool(); // First call $transporter1 = $pool->get('github', $config); @@ -45,55 +28,34 @@ // Second call - should return same instance $transporter2 = $pool->get('github', $config); - expect($transporter1)->toBe($mockTransporter) - ->and($transporter2)->toBe($mockTransporter) + expect($transporter1)->toBeInstanceOf(HttpTransporter::class) + ->and($transporter2)->toBeInstanceOf(HttpTransporter::class) ->and($transporter1)->toBe($transporter2); }); it('forget removes transporter from pool', function () { - $mockFactory = Mockery::mock(TransporterFactory::class); - $mockTransporter1 = Mockery::mock(Transporter::class); - $mockTransporter2 = Mockery::mock(Transporter::class); - - $config = ['type' => 'http', 'base_url' => 'https://example.com']; + $config = ['type' => 'http', 'base_url' => 'https://example.com', 'timeout' => 30]; - // Factory should be called twice (before and after forget) - $mockFactory->shouldReceive('make') - ->twice() - ->with($config) - ->andReturn($mockTransporter1, $mockTransporter2); - - $pool = new TransporterPool($mockFactory); + $pool = new TransporterPool(); // First call $transporter1 = $pool->get('github', $config); - expect($transporter1)->toBe($mockTransporter1); + expect($transporter1)->toBeInstanceOf(HttpTransporter::class); // Forget the transporter $pool->forget('github'); // Next call should create a new transporter $transporter2 = $pool->get('github', $config); - expect($transporter2)->toBe($mockTransporter2); + expect($transporter2)->toBeInstanceOf(HttpTransporter::class) + ->and($transporter1)->not->toBe($transporter2); }); it('clear removes all transporters', function () { - $mockFactory = Mockery::mock(TransporterFactory::class); - $mockTransporter1 = Mockery::mock(Transporter::class); - $mockTransporter2 = Mockery::mock(Transporter::class); - - $config1 = ['type' => 'http', 'base_url' => 'https://github.com']; - $config2 = ['type' => 'http', 'base_url' => 'https://gitlab.com']; - - $mockFactory->shouldReceive('make') - ->with($config1) - ->andReturn($mockTransporter1); - - $mockFactory->shouldReceive('make') - ->with($config2) - ->andReturn($mockTransporter2); + $config1 = ['type' => 'http', 'base_url' => 'https://github.com', 'timeout' => 30]; + $config2 = ['type' => 'http', 'base_url' => 'https://gitlab.com', 'timeout' => 30]; - $pool = new TransporterPool($mockFactory); + $pool = new TransporterPool(); // Add two transporters $pool->get('github', $config1); @@ -110,28 +72,10 @@ }); it('getActiveServers returns list of server names', function () { - $mockFactory = Mockery::mock(TransporterFactory::class); - $mockTransporter1 = Mockery::mock(Transporter::class); - $mockTransporter2 = Mockery::mock(Transporter::class); - $mockTransporter3 = Mockery::mock(Transporter::class); + $config1 = ['type' => 'http', 'base_url' => 'https://github.com', 'timeout' => 30]; + $config2 = ['type' => 'http', 'base_url' => 'https://gitlab.com', 'timeout' => 30]; - $config1 = ['type' => 'http', 'base_url' => 'https://github.com']; - $config2 = ['type' => 'http', 'base_url' => 'https://gitlab.com']; - $config3 = ['type' => 'stdio', 'command' => ['npx', 'test']]; - - $mockFactory->shouldReceive('make') - ->with($config1) - ->andReturn($mockTransporter1); - - $mockFactory->shouldReceive('make') - ->with($config2) - ->andReturn($mockTransporter2); - - $mockFactory->shouldReceive('make') - ->with($config3) - ->andReturn($mockTransporter3); - - $pool = new TransporterPool($mockFactory); + $pool = new TransporterPool(); expect($pool->getActiveServers())->toBeEmpty(); @@ -142,48 +86,28 @@ expect($pool->getActiveServers())->toHaveCount(2) ->toContain('github') ->toContain('gitlab'); - - $pool->get('npx_server', $config3); - expect($pool->getActiveServers())->toHaveCount(3) - ->toContain('github') - ->toContain('gitlab') - ->toContain('npx_server'); }); it('handles multiple different servers correctly', function () { - $mockFactory = Mockery::mock(TransporterFactory::class); - $mockTransporter1 = Mockery::mock(Transporter::class); - $mockTransporter2 = Mockery::mock(Transporter::class); - - $config1 = ['type' => 'http', 'base_url' => 'https://github.com']; - $config2 = ['type' => 'stdio', 'command' => ['npx', 'test']]; - - $mockFactory->shouldReceive('make') - ->once() - ->with($config1) - ->andReturn($mockTransporter1); - - $mockFactory->shouldReceive('make') - ->once() - ->with($config2) - ->andReturn($mockTransporter2); + $config1 = ['type' => 'http', 'base_url' => 'https://github.com', 'timeout' => 30]; + $config2 = ['type' => 'stdio', 'command' => ['echo', 'test'], 'timeout' => 30]; - $pool = new TransporterPool($mockFactory); + $pool = new TransporterPool(); // Get different servers $t1 = $pool->get('github', $config1); $t2 = $pool->get('npx_server', $config2); - // Should be different instances - expect($t1)->toBe($mockTransporter1) - ->and($t2)->toBe($mockTransporter2) + // Should be different instances and different types + expect($t1)->toBeInstanceOf(HttpTransporter::class) + ->and($t2)->toBeInstanceOf(StdioTransporter::class) ->and($t1)->not->toBe($t2); // Getting same servers again should return same instances $t1Again = $pool->get('github', $config1); $t2Again = $pool->get('npx_server', $config2); - expect($t1Again)->toBe($mockTransporter1) - ->and($t2Again)->toBe($mockTransporter2); + expect($t1Again)->toBe($t1) + ->and($t2Again)->toBe($t2); }); });