Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Facades/Relay.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
use Prism\Relay\RelayFactory;

/**
* @method static RelayFactory make(string $serverName)
* @method static array<int, Tool> tools(string $serverName)
* @method static \Prism\Relay\Relay make(string $serverName, array $config = null)
* @method static array<int, Tool> tools(string $serverName, array $config = null)
*
* @see RelayFactory
*/
Expand Down
10 changes: 9 additions & 1 deletion src/Relay.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ class Relay
protected Transport $transport;

/**
* @param array<string, mixed>|null $customConfig
*
* @throws ServerConfigurationException
*/
public function __construct(protected string $serverName)
public function __construct(protected string $serverName, protected ?array $customConfig = null)
{
$this->resolveServerConfig();
$this->initializeTransport();
Expand Down Expand Up @@ -513,6 +515,12 @@ protected function convertResponseToString(mixed $response): string
*/
protected function resolveServerConfig(): void
{
if ($this->customConfig !== null) {
$this->serverConfig = $this->customConfig;

return;
}

if (function_exists('app') && app()->bound('config')) {
$servers = config('relay.servers', []);

Expand Down
11 changes: 7 additions & 4 deletions src/RelayFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,24 @@
class RelayFactory
{
/**
* @param array<string, mixed>|null $config
*
* @throws ServerConfigurationException
*/
public function make(string $serverName): Relay
public function make(string $serverName, ?array $config = null): Relay
{
return new Relay($serverName);
return new Relay($serverName, $config);
}

/**
* @param array<string, mixed>|null $config
* @return array<int, Tool>
*
* @throws ServerConfigurationException
* @throws ToolDefinitionException
*/
public function tools(string $serverName): array
public function tools(string $serverName, ?array $config = null): array
{
return $this->make($serverName)->tools();
return $this->make($serverName, $config)->tools();
}
}
54 changes: 54 additions & 0 deletions tests/Feature/Facades/RelayFacadeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,57 @@
->toBeArray()
->toHaveCount(2);
});

it('can make relay with custom config through facade', function (): void {
$customConfig = [
'transport' => \Prism\Relay\Enums\Transport::Http,
'url' => 'http://custom.example.com/api',
'timeout' => 45,
];

$relay = Relay::make('custom_facade_server', $customConfig);

expect($relay)
->toBeInstanceOf(RelayClass::class)
->and($relay->getServerName())
->toBe('custom_facade_server');
});

it('can get tools with custom config through facade', function (): void {
$customConfig = [
'transport' => \Prism\Relay\Enums\Transport::Http,
'url' => 'http://tools.example.com/api',
'timeout' => 30,
];

// Mock the factory to test the facade call
$mock = $this->mock(RelayFactory::class);
$mock->shouldReceive('tools')
->once()
->with('custom_tools_server', $customConfig)
->andReturn([
new \Prism\Prism\Tool,
]);

app()->instance('relay', $mock);

$tools = Relay::tools('custom_tools_server', $customConfig);

expect($tools)
->toBeArray()
->toHaveCount(1);
});

it('facade make method works without config parameter', function (): void {
config()->set('relay.servers.standard_test', [
'url' => 'http://standard.example.com/api',
'timeout' => 30,
]);

$relay = Relay::make('standard_test');

expect($relay)
->toBeInstanceOf(RelayClass::class)
->and($relay->getServerName())
->toBe('standard_test');
});
76 changes: 76 additions & 0 deletions tests/Unit/RelayFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,79 @@
$factory = new RelayFactory;
expect(method_exists($factory, 'tools'))->toBeTrue();
});

it('creates a Relay instance with custom config', function (): void {
$customConfig = [
'transport' => \Prism\Relay\Enums\Transport::Http,
'url' => 'http://custom.example.com/api',
'timeout' => 45,
];

$factory = new RelayFactory;
$relay = $factory->make('custom_server', $customConfig);

expect($relay)
->toBeInstanceOf(Relay::class)
->and($relay->getServerName())
->toBe('custom_server');
});

it('creates Relay with custom config when config parameter is provided', function (): void {
$customConfig = [
'transport' => \Prism\Relay\Enums\Transport::Stdio,
'command' => ['echo', 'test'],
'timeout' => 60,
'env' => ['TEST_VAR' => 'test_value'],
];

$factory = new RelayFactory;
$relay = $factory->make('stdio_server', $customConfig);

expect($relay)
->toBeInstanceOf(Relay::class)
->and($relay->getServerName())
->toBe('stdio_server');
});

it('uses Laravel config when no custom config provided', function (): void {
config()->set('relay.servers.laravel_server', [
'url' => 'http://laravel.example.com/api',
'timeout' => 30,
]);

$factory = new RelayFactory;

// Test both ways produce same result
$relay1 = $factory->make('laravel_server');
$relay2 = $factory->make('laravel_server', null);

expect($relay1)
->toBeInstanceOf(Relay::class)
->and($relay2)
->toBeInstanceOf(Relay::class)
->and($relay1->getServerName())
->toBe('laravel_server')
->and($relay2->getServerName())
->toBe('laravel_server');
});

it('tools method works with custom config', function (): void {
$customConfig = [
'transport' => \Prism\Relay\Enums\Transport::Http,
'url' => 'http://tools.example.com/api',
'timeout' => 30,
];

$factory = new RelayFactory;

// Verify method exists and accepts config parameter
expect(method_exists($factory, 'tools'))->toBeTrue();

// Test method signature (this will call the method but we expect it might fail due to no real server)
try {
$factory->tools('tools_server', $customConfig);
} catch (\Throwable $e) {
// Expected to fail since we don't have a real MCP server, but method should accept the parameters
expect($e)->toBeInstanceOf(\Throwable::class);
}
});
Loading