-
Notifications
You must be signed in to change notification settings - Fork 56
Description
Hey team! 👋
First off, I want to say that the work on the MCP PHP SDK is really impressive - building a solid foundation for MCP implementations is no small task, and the current structure shows thoughtful consideration of the developer experience.
I've been diving deeper into the codebase and wanted to start a discussion about our approach to static factory methods like Server::make()
. I'm curious about the team's thoughts on this pattern and whether we might want to explore some alternatives.
What I'm Noticing
Looking at patterns like this:
// Current approach
$server = Server::make()
->withTool($tool)
->build();
I'm wondering if we might be solving a problem that doesn't quite exist in the SDK context. The make()
method saves a few characters (Server::make()
vs new ServerBuilder()
), but I'm starting to think it might be creating some unintended constraints.
Potential Challenges I'm Seeing
A few things that caught my attention:
Dependency Injection Integration: The static approach makes it trickier to work with DI containers, which many modern PHP applications rely on. Developers can't easily inject dependencies into the builder or resolve it through their container.
Testing Flexibility: Static methods can be harder to mock and test, especially when applications need to customize the builder behavior.
Framework Integration: Applications using frameworks like Symfony, Laravel (ironically), or other DI-heavy setups might find it challenging to integrate with static factory patterns.
What I'm Thinking About
Since MCP servers typically get initialized once per application lifecycle, I'm wondering if the convenience factor is as important as the flexibility factor. Most of the time, this initialization code runs once when the app starts up, then the server runs indefinitely processing requests.
What do you think about an approach more like this?
// Direct construction (DI-friendly)
$builder = new ServerBuilder($logger, $registry, $messageFactory);
$server = $builder
->addTool($tool)
->build();
// Or with container resolution
$builder = $container->get(ServerBuilderInterface::class);
$server = $builder->addTool($tool)->build();
Exploring Options
I'm not suggesting we need to change everything immediately, but maybe we could explore a few approaches:
- Keep both patterns: Maintain the static methods for quick setup while ensuring direct construction works well too
- Gradual transition: Slowly move toward more explicit construction while maintaining backward compatibility
- Separate convenience layer: Keep the core SDK minimal and perhaps create a separate package for convenience methods
Questions for Discussion
- What's been your experience with the current pattern? Are there specific use cases where the static approach has been particularly helpful?
- Have you run into any challenges integrating with DI containers or testing frameworks?
- Would there be interest in exploring more explicit dependency injection patterns?
I'd love to hear everyone's thoughts on this! I might be overthinking it, but I wanted to get the conversation started. Happy to pair with anyone who wants to explore different approaches or discuss this further.
What do you all think? Am I missing something important about the current approach, or does this direction seem worth exploring?