Skip to content

Commit 16f9ad8

Browse files
author
klapaudius
committed
#62 TestMcpToolCommand do not show tools from dynamic providers
1 parent 2976688 commit 16f9ad8

File tree

5 files changed

+143
-154
lines changed

5 files changed

+143
-154
lines changed

src/Command/TestMcpPromptCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ private function listAllPrompts(): int
279279
$prompts = $this->promptRepository->getPrompts();
280280

281281
if (empty($prompts)) {
282-
$this->io->warning('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml');
282+
$this->io->warning('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml or create a PromptProvider.');
283283

284284
return Command::SUCCESS;
285285
}
@@ -315,7 +315,7 @@ protected function askForPrompt(): ?string
315315
$prompts = $this->promptRepository->getPrompts();
316316

317317
if (empty($prompts)) {
318-
$this->io->warning('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml');
318+
$this->io->warning('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml or create a PromptProvider.');
319319

320320
return null;
321321
}

src/Command/TestMcpToolCommand.php

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use KLP\KlpMcpServer\Services\ToolService\BaseToolInterface;
88
use KLP\KlpMcpServer\Services\ToolService\Schema\StructuredSchema;
99
use KLP\KlpMcpServer\Services\ToolService\StreamableToolInterface;
10+
use KLP\KlpMcpServer\Services\ToolService\ToolRepository;
1011
use Symfony\Component\Console\Attribute\AsCommand;
1112
use Symfony\Component\Console\Command\Command;
1213
use Symfony\Component\Console\Input\InputArgument;
@@ -19,8 +20,10 @@
1920
#[AsCommand(name: 'mcp:test-tool', description: 'Test an MCP tool with simulated inputs')]
2021
class TestMcpToolCommand extends Command
2122
{
22-
public function __construct(private readonly ContainerInterface $container)
23-
{
23+
public function __construct(
24+
private readonly ToolRepository $toolRepository,
25+
private readonly ContainerInterface $container
26+
) {
2427
parent::__construct();
2528
}
2629

@@ -140,7 +143,7 @@ function (array $notification) use (&$sentNotifications) {
140143
/**
141144
* Resolves and retrieves an instance of a tool based on the provided identifier
142145
* from the input or user prompt. The method checks for a matching class name,
143-
* an exact tool match, or a case-insensitive tool name match from the configured tools.
146+
* an exact tool match, or a case-insensitive tool name match from the registered tools.
144147
*
145148
* @return StreamableToolInterface Returns the tool instance if found.
146149
*
@@ -155,32 +158,51 @@ public function getToolInstance(): StreamableToolInterface
155158
}
156159

157160
$toolInstance = null;
158-
// First check if the identifier is a direct class name
161+
162+
// Strategy 1: Check if identifier is a fully-qualified class name
163+
// This allows: php bin/console mcp:test-tool "App\MCP\Tools\MyTool"
159164
if (class_exists($identifier)) {
160-
$toolInstance = $this->container->get($identifier);
165+
// First check if we have this tool class in ToolRepository
166+
foreach ($this->toolRepository->getTools() as $tool) {
167+
if (get_class($tool) === $identifier) {
168+
$toolInstance = $tool;
169+
break;
170+
}
171+
}
172+
173+
// Fallback: Try to instantiate directly from container for backward compatibility
174+
// This handles edge cases where a tool class exists but isn't registered
175+
if (! $toolInstance) {
176+
$toolInstance = $this->container->get($identifier);
177+
}
161178
}
162179

180+
// Strategy 2: Look up by tool name or partial class name
163181
if (! $toolInstance) {
164-
// Load all registered tools from config
165-
$configuredTools = $this->container->getParameter('klp_mcp_server.tools');
166-
167-
// Check for the class match
168-
foreach ($configuredTools as $toolClass) {
169-
$instance = $this->container->get($toolClass);
170-
if ( // Check for the exact class match
171-
str_ends_with($toolClass, "\\{$identifier}")
172-
|| $toolClass === $identifier
173-
// Check for tool name match (case-insensitive)
174-
|| strtolower($instance->getName()) === strtolower($identifier)
175-
) {
182+
$registeredTools = $this->toolRepository->getTools();
183+
184+
// First try exact tool name match (case-insensitive)
185+
foreach ($registeredTools as $toolName => $instance) {
186+
if (strtolower($toolName) === strtolower($identifier)) {
176187
$toolInstance = $instance;
177188
break;
178189
}
179190
}
191+
192+
// If not found, try partial class name match
193+
if (! $toolInstance) {
194+
foreach ($registeredTools as $toolName => $instance) {
195+
$toolClass = get_class($instance);
196+
if (str_ends_with($toolClass, "\\{$identifier}") || $toolClass === $identifier) {
197+
$toolInstance = $instance;
198+
break;
199+
}
200+
}
201+
}
180202
}
181203

182-
if ($toolInstance
183-
&& ! ($toolInstance instanceof StreamableToolInterface)) {
204+
// Validate the tool implements StreamableToolInterface
205+
if ($toolInstance && ! ($toolInstance instanceof StreamableToolInterface)) {
184206
$toolClass = get_class($toolInstance);
185207
throw new TestMcpToolCommandException("The class '{$toolClass}' does not implement StreamableToolInterface.");
186208
}
@@ -332,30 +354,29 @@ public function askForInputData(StructuredSchema|array $schema): ?array
332354
*/
333355
private function listAllTools(): int
334356
{
335-
$configuredTools = $this->container->getParameter('klp_mcp_server.tools');
357+
// Get all registered tools from ToolRepository
358+
$registeredTools = $this->toolRepository->getTools();
336359

337-
if (empty($configuredTools)) {
338-
$this->io->warning('No MCP tools are configured. Add tools in config/package/klp-mcp-server.yaml');
360+
if (empty($registeredTools)) {
361+
$this->io->warning('No MCP tools are configured. Add tools in config/package/klp-mcp-server.yaml or create a ToolProvider.');
339362

340363
return Command::SUCCESS;
341364
}
342365

343366
$tools = [];
344367

345-
foreach ($configuredTools as $toolClass) {
368+
foreach ($registeredTools as $toolName => $instance) {
346369
try {
347-
if (class_exists($toolClass)) {
348-
$instance = $this->container->get($toolClass);
349-
if ($instance instanceof BaseToolInterface) {
350-
$tools[] = [
351-
'name' => $instance->getName(),
352-
'class' => $toolClass,
353-
'description' => substr($instance->getDescription(), 0, 50),
354-
];
355-
}
370+
if ($instance instanceof BaseToolInterface) {
371+
$tools[] = [
372+
'name' => $instance->getName(),
373+
'class' => get_class($instance),
374+
'description' => substr($instance->getDescription(), 0, 50),
375+
];
356376
}
357377
} catch (\Throwable $e) {
358-
$this->io->warning("Couldn't load tool class: {$toolClass}");
378+
$toolClass = get_class($instance);
379+
$this->io->warning("Couldn't load tool: {$toolClass}");
359380
}
360381
}
361382

@@ -376,29 +397,27 @@ private function listAllTools(): int
376397
*/
377398
protected function askForTool(): ?string
378399
{
379-
$configuredTools = $this->container->getParameter('klp_mcp_server.tools');
400+
$registeredTools = $this->toolRepository->getTools();
380401

381-
if (empty($configuredTools)) {
382-
$this->io->warning('No MCP tools are configured. Add tools in config/package/klp-mcp-server.yaml');
402+
if (empty($registeredTools)) {
403+
$this->io->warning('No MCP tools are configured. Add tools in config/package/klp-mcp-server.yaml or create a ToolProvider.');
383404

384405
return null;
385406
}
386407

387408
$choices = [];
388-
$validTools = [];
409+
$validToolNames = [];
389410

390-
foreach ($configuredTools as $toolClass) {
411+
foreach ($registeredTools as $toolName => $instance) {
391412
try {
392-
if (class_exists($toolClass)) {
393-
$instance = $this->container->get($toolClass);
394-
if ($instance instanceof BaseToolInterface) {
395-
$name = $instance->getName();
396-
$choices[] = "{$name} ({$toolClass})";
397-
$validTools[] = $toolClass;
398-
}
413+
if ($instance instanceof BaseToolInterface) {
414+
$name = $instance->getName();
415+
$class = get_class($instance);
416+
$choices[] = "{$name} ({$class})";
417+
$validToolNames[] = $name; // Store tool name instead of class
399418
}
400419
} catch (\Throwable) {
401-
// Skip tools that can't be loaded
420+
// Skip tools that can't be processed
402421
}
403422
}
404423

@@ -413,7 +432,7 @@ protected function askForTool(): ?string
413432
$choices
414433
);
415434

416-
return $validTools[$selectedIndex] ?? null;
435+
return $validToolNames[$selectedIndex] ?? null;
417436
}
418437

419438
/**

src/Resources/config/services.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ services:
6868
klp_mcp_server.command.test_tool:
6969
class: KLP\KlpMcpServer\Command\TestMcpToolCommand
7070
arguments:
71+
- '@klp_mcp_server.tool_repository'
7172
- '@service_container'
7273
tags:
7374
- { name: 'console.command' }

tests/Command/TestMcpPromptCommandTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public function test_get_prompt_instance_no_prompt_provided_and_no_prompt_config
6161
$this->ioMock
6262
->expects($this->once())
6363
->method('warning')
64-
->with('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml');
64+
->with('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml or create a PromptProvider.');
6565

6666
$this->expectException(TestMcpPromptCommandException::class);
6767
$this->expectExceptionMessage('No prompt specified.');
@@ -348,7 +348,7 @@ public function test_list_all_prompts_when_no_prompts_configured_displays_warnin
348348
$this->ioMock
349349
->expects($this->once())
350350
->method('warning')
351-
->with('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml');
351+
->with('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml or create a PromptProvider.');
352352

353353
$result = $this->command->execute($this->inputMock, $this->outputMock);
354354

@@ -431,7 +431,7 @@ public function test_ask_for_prompt_no_prompts_returns_null(): void
431431
$this->ioMock
432432
->expects($this->once())
433433
->method('warning')
434-
->with('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml');
434+
->with('No MCP prompts are configured. Add prompts in config/packages/klp_mcp_server.yaml or create a PromptProvider.');
435435

436436
$result = $this->invokePrivateMethod('askForPrompt');
437437

0 commit comments

Comments
 (0)