Skip to content

Conversation

@EdouardCourty
Copy link

@EdouardCourty EdouardCourty commented Nov 30, 2025

Add Server Lifecycle Events

This PR introduces a comprehensive PSR-14 compatible event system for the MCP PHP SDK, allowing developers to hook into the server's lifecycle for tools, prompts, resources, ping, and initialize operations.

This will fix #169

Motivation and Context

Currently, there's no standardized way to observe or react to server operations like tool calls, prompt retrievals, or resource reads.

How Has This Been Tested?

  • Unit tests added for all new event classes
  • Tests for event dispatching in all handlers (CallToolHandler, GetPromptHandler, ReadResourceHandler, InitializeHandler, PingHandler)
  • Tests cover request events, result events, and exception events
  • All existing tests continue to pass

Breaking Changes

None. This is a purely additive change. The event dispatcher is optional - servers without an event dispatcher configured will continue to work as before.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

New Event Classes

Server Events:

  • InitializeRequestEvent - Fired when client sends initialize request
  • PingRequestEvent - Fired when client sends ping request

Tool Events:

  • CallToolRequestEvent - Before tool execution
  • CallToolResultEvent - After successful execution
  • CallToolExceptionEvent - On uncaught exception

Prompt Events:

  • GetPromptRequestEvent - Before prompt execution
  • GetPromptResultEvent - After successful execution
  • GetPromptExceptionEvent - On uncaught exception

Resource Events:

  • ReadResourceRequestEvent - Before resource read
  • ReadResourceResultEvent - After successful read
  • ReadResourceExceptionEvent - On uncaught exception

Full documentation available in docs/events.md.

@chr-hertel
Copy link
Member

Nice one, thanks - before going into detailed review we should verify if we want that granularity with the events or if it should rather be one level higher like RequestEvent, NotificationEvent and ResponseEvent and ErrorEvent
that would centralize the dispatching a bit more.

you could still check for the method there, like

public function onRequestEvent(RequestEvent $event): void
{
    if ('tools/list' !== $event->getMethod()) {
        return;
    }
}

or similar.

not super sure about it myself, but i just think of change scenarios and number of events - cc @CodeWithKyrian @Nyholm

@chr-hertel
Copy link
Member

Hey @EdouardCourty, had a brief alignment with @CodeWithKyrian and we would like to go with more generic events - being a more robust solution with changes over time adding more handlers/notification - or with users adding their own.

So it would be

  • RequestEvent
  • NotificationEvent
  • ResponseEvent
  • ErrorEvent

dispatched on Protocol level i assume

do you see that you could solve your use case with that as well?

@EdouardCourty
Copy link
Author

Hey @EdouardCourty, had a brief alignment with @CodeWithKyrian and we would like to go with more generic events - being a more robust solution with changes over time adding more handlers/notification - or with users adding their own.

So it would be

  • RequestEvent

  • NotificationEvent

  • ResponseEvent

  • ErrorEvent

dispatched on Protocol level i assume

do you see that you could solve your use case with that as well?

Alright, this works!
What do you mean by "Protocol level" tho?

@chr-hertel
Copy link
Member

That you presumably would dispatch the events rather in the Protocol class than the RequestHandlerInterface implementations

@Nyholm
Copy link
Contributor

Nyholm commented Dec 27, 2025

Thank you.

Currently, there's no standardized way to observe or react to server operations like tool calls, prompt retrievals, or resource reads.

Can you please elaborate on why? Do you want to be able to modify the request before it is given to the tool? Or do you want to change the result of the tool?

Ie, What do you want to achieve after this PR is merged?

@EdouardCourty
Copy link
Author

Thank you.

Currently, there's no standardized way to observe or react to server operations like tool calls, prompt retrievals, or resource reads.

Can you please elaborate on why? Do you want to be able to modify the request before it is given to the tool? Or do you want to change the result of the tool?

Ie, What do you want to achieve after this PR is merged?

Observing and reacting.

I want to be able to trigger specific logic on each request (like storing these in an external database, or log them in a specific way) or response.

For your other question, I think it could be useful to be able to modify the requests and responses before and after they are processed, leaving the choice to the developers that implement this SDK to use it or not.

Copy link
Contributor

@Nyholm Nyholm left a comment

Choose a reason for hiding this comment

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

I like this PR.

I would like you to:

  1. Remove the abstract classes
  2. Make the event classes final
  3. Remove "use once" variables
  4. Follow up on this comment: #175 (comment)

If you would like help, let me know.

Comment on lines 65 to 67
$toolCallRequestEvent = new CallToolRequestEvent($request);
$this->eventDispatcher?->dispatch($toolCallRequestEvent);

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you skip the variable here and for other similar places?

Suggested change
$toolCallRequestEvent = new CallToolRequestEvent($request);
$this->eventDispatcher?->dispatch($toolCallRequestEvent);
$this->eventDispatcher?->dispatch($new CallToolRequestEvent($request));

/**
* @author Edouard Courty <edouard.courty2@gmail.com>
*/
abstract class AbstractGetPromptEvent
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove this class

/**
* @author Edouard Courty <edouard.courty2@gmail.com>
*/
abstract class AbstractCallToolEvent
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove this class

/**
* @author Edouard Courty <edouard.courty2@gmail.com>
*/
abstract class AbstractReadResourceEvent
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove this class

@Nyholm Nyholm added this to the 0.2.x milestone Dec 27, 2025
@chr-hertel chr-hertel modified the milestones: 0.2.x, 0.4.0 Jan 4, 2026
@EdouardCourty EdouardCourty force-pushed the feat/add-event-support branch from 3d9d559 to 13f306d Compare January 4, 2026 18:08
@EdouardCourty EdouardCourty force-pushed the feat/add-event-support branch from 13f306d to 669a079 Compare January 4, 2026 18:20
@EdouardCourty
Copy link
Author

EdouardCourty commented Jan 4, 2026

Hey @EdouardCourty, had a brief alignment with @CodeWithKyrian and we would like to go with more generic events - being a more robust solution with changes over time adding more handlers/notification - or with users adding their own.

So it would be

  • RequestEvent
  • NotificationEvent
  • ResponseEvent
  • ErrorEvent

dispatched on Protocol level i assume

do you see that you could solve your use case with that as well?

Hi again (following up after @Nyholm's comment.
I agree to this change, but I'd like a clear confirmation of what you guys want.

The RequestEvent / NotificationEvent / etc VS the more precise CallToolEventRequest / CallToolEventException approach means less different event types to handle, which is a great thing.

Also, should the request or response payload be modifiable from the event? Or should the event be read-only ?

Just give me a confirmation and I will do the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Server] Prepare server for integrated events

3 participants