Skip to content
Open
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 demo/src/Mcp/Prompts/CurrentTimePrompt.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

use Mcp\Capability\Attribute\McpPrompt;

#[McpPrompt(name: 'time-analysis')]
class CurrentTimePrompt
{
#[McpPrompt(name: 'time-analysis')]
public function getTimeAnalysisPrompt(): array
public function __invoke(): array
{
return [
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

use Mcp\Capability\Attribute\McpResourceTemplate;

#[McpResourceTemplate(uriTemplate: 'time://{timezone}', name: 'time-by-timezone')]
class CurrentTimeResourceTemplate
{
#[McpResourceTemplate(uriTemplate: 'time://{timezone}', name: 'time-by-timezone')]
public function getTimeByTimezone(string $timezone): array
public function __invoke(string $timezone): array
{
try {
$time = (new \DateTime('now', new \DateTimeZone($timezone)))->format('Y-m-d H:i:s T');
Expand Down
4 changes: 2 additions & 2 deletions demo/src/Mcp/Resources/CurrentTimeResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

use Mcp\Capability\Attribute\McpResource;

#[McpResource(uri: 'time://current', name: 'current-time-resource')]
class CurrentTimeResource
{
#[McpResource(uri: 'time://current', name: 'current-time-resource')]
public function getCurrentTimeResource(): array
public function __invoke(): array
{
return [
'uri' => 'time://current',
Expand Down
16 changes: 12 additions & 4 deletions demo/src/Mcp/Tools/CurrentTimeTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,28 @@
namespace App\Mcp\Tools;

use Mcp\Capability\Attribute\McpTool;
use Psr\Log\LoggerInterface;

/**
* Returns the current time in UTC.
*
* @author Tom Hart <[email protected]>
*/
#[McpTool(name: 'current-time')]
class CurrentTimeTool
{
public function __construct(
private readonly LoggerInterface $logger,
) {
}

/**
* Returns the current time in UTC.
*
* @param string $format The format of the time, e.g. "Y-m-d H:i:s"
*/
#[McpTool(name: 'current-time')]
public function getCurrentTime(string $format = 'Y-m-d H:i:s'): string
public function __invoke(string $format = 'Y-m-d H:i:s'): string
{
$this->logger->info('CurrentTimeTool called', ['format' => $format]);

return (new \DateTime('now', new \DateTimeZone('UTC')))->format($format);
}
}
16 changes: 8 additions & 8 deletions docs/bundles/mcp-bundle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ Actions that can be executed::

use Mcp\Capability\Attribute\McpTool;

#[McpTool(name: 'current-time')]
class CurrentTimeTool
{
#[McpTool(name: 'current-time')]
public function getCurrentTime(string $format = 'Y-m-d H:i:s'): string
public function __invoke(string $format = 'Y-m-d H:i:s'): string
{
return (new \DateTime('now', new \DateTimeZone('UTC')))->format($format);
}
Expand All @@ -52,10 +52,10 @@ System instructions for AI context::

use Mcp\Capability\Attribute\McpPrompt;

#[McpPrompt(name: 'time-analysis')]
class TimePrompts
{
#[McpPrompt(name: 'time-analysis')]
public function getTimeAnalysisPrompt(): array
public function __invoke(): array
{
return [
['role' => 'user', 'content' => 'You are a time management expert.']
Expand All @@ -70,10 +70,10 @@ Static data that can be read::

use Mcp\Capability\Attribute\McpResource;

#[McpResource(uri: 'time://current', name: 'current-time')]
class TimeResource
{
#[McpResource(uri: 'time://current', name: 'current-time')]
public function getCurrentTimeResource(): array
public function __invoke(): array
{
return [
'uri' => 'time://current',
Expand All @@ -97,10 +97,10 @@ Dynamic resources with parameters:

use Mcp\Capability\Attribute\McpResourceTemplate;

#[McpResourceTemplate(uriTemplate: 'time://{timezone}', name: 'time-by-timezone')]
class TimeResourceTemplate
{
#[McpResourceTemplate(uriTemplate: 'time://{timezone}', name: 'time-by-timezone')]
public function getTimeByTimezone(string $timezone): array
public function __invoke(string $timezone): array
{
$time = (new \DateTime('now', new \DateTimeZone($timezone)))->format('Y-m-d H:i:s T');
return [
Expand Down
6 changes: 3 additions & 3 deletions src/mcp-bundle/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Mcp\Server;
use Mcp\Server\Builder;
use Mcp\Server\ServerBuilder;

return static function (ContainerConfigurator $container): void {
$container->services()
Expand All @@ -21,8 +21,8 @@
->args(['mcp'])
->tag('monolog.logger', ['channel' => 'mcp'])

->set('mcp.server.builder', Builder::class)
->factory([Server::class, 'builder'])
->set('mcp.server.builder', ServerBuilder::class)
->factory([Server::class, 'make'])
Comment on lines +24 to +25
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is basically reverting #697 - could be an outdated mcp/sdk version or branched off an old main?

->call('setServerInfo', [param('mcp.app'), param('mcp.version')])
->call('setPaginationLimit', [param('mcp.pagination_limit')])
->call('setInstructions', [param('mcp.instructions')])
Expand Down
8 changes: 7 additions & 1 deletion src/mcp-bundle/src/DependencyInjection/McpPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

final class McpPass implements CompilerPassInterface
{
Expand All @@ -35,7 +36,12 @@ public function process(ContainerBuilder $container): void
return;
}

$serviceLocatorRef = ServiceLocatorTagPass::register($container, $allMcpServices);
$serviceReferences = [];
foreach (array_keys($allMcpServices) as $serviceId) {
$serviceReferences[$serviceId] = new Reference($serviceId);
}

$serviceLocatorRef = ServiceLocatorTagPass::register($container, $serviceReferences);

$container->getDefinition('mcp.server.builder')
->addMethodCall('setContainer', [$serviceLocatorRef]);
Expand Down
22 changes: 22 additions & 0 deletions src/mcp-bundle/tests/DependencyInjection/McpPassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@

use PHPUnit\Framework\TestCase;
use Symfony\AI\McpBundle\DependencyInjection\McpPass;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

/**
* @covers \Symfony\AI\McpBundle\DependencyInjection\McpPass
Expand Down Expand Up @@ -53,6 +55,18 @@ public function testCreatesServiceLocatorForAllMcpServices()
$this->assertArrayHasKey('prompt_service', $services);
$this->assertArrayHasKey('resource_service', $services);
$this->assertArrayHasKey('template_service', $services);

// Verify services are ServiceClosureArguments wrapping References
$this->assertInstanceOf(ServiceClosureArgument::class, $services['tool_service']);
$this->assertInstanceOf(ServiceClosureArgument::class, $services['prompt_service']);
$this->assertInstanceOf(ServiceClosureArgument::class, $services['resource_service']);
$this->assertInstanceOf(ServiceClosureArgument::class, $services['template_service']);

// Verify the underlying values are References
$this->assertInstanceOf(Reference::class, $services['tool_service']->getValues()[0]);
$this->assertInstanceOf(Reference::class, $services['prompt_service']->getValues()[0]);
$this->assertInstanceOf(Reference::class, $services['resource_service']->getValues()[0]);
$this->assertInstanceOf(Reference::class, $services['template_service']->getValues()[0]);
}

public function testDoesNothingWhenNoMcpServicesTagged()
Expand Down Expand Up @@ -115,5 +129,13 @@ public function testHandlesPartialMcpServices()
$this->assertArrayHasKey('prompt_service', $services);
$this->assertArrayNotHasKey('resource_service', $services);
$this->assertArrayNotHasKey('template_service', $services);

// Verify services are ServiceClosureArguments wrapping References
$this->assertInstanceOf(ServiceClosureArgument::class, $services['tool_service']);
$this->assertInstanceOf(ServiceClosureArgument::class, $services['prompt_service']);

// Verify the underlying values are References
$this->assertInstanceOf(Reference::class, $services['tool_service']->getValues()[0]);
$this->assertInstanceOf(Reference::class, $services['prompt_service']->getValues()[0]);
}
}
Loading