Skip to content

Conversation

@Adebayo120
Copy link
Contributor

This PR implements the Model Context Protocol (MCP) logging specification, providing centralized logging capabilities with auto-injection support for capability handlers. This enables developers to debug across multiple MCP servers from a single client interface, addressing the challenge of distributed logging in MCP ecosystems.

Motivation and Context

Fixes #70

This implementation addresses the missing logging functionality as outlined in the MCP logging specification.

Problem solved:

  • Developers working with 10-15 MCP servers struggle with debugging across distributed logs
  • No centralized logging mechanism for MCP servers
  • Missing client-controlled log level filtering
  • No easy way to access logging within tools/resources/prompts

Key benefits:

  • Centralized logging: All server logs flow to the client for unified debugging
  • Client-controlled filtering: Clients can set log levels to reduce noise
  • Auto-injection: Zero-configuration logger access in capability handlers
  • Fallback support: Compatible with existing external PSR-3 loggers

How Has This Been Tested?

Comprehensive test coverage:

  • 360 unit tests with 1530 assertions - all passing
  • 0 PHPStan errors - full static analysis compliance
  • 0 PHP CS Fixer issues - code style compliance

Test scenarios:

  • Auto-injection of McpLogger into tools, resources, and prompts
  • Client log level filtering (debug → emergency levels)
  • Fallback to external PSR-3 loggers when MCP transport unavailable
  • Notification serialization and transport integration
  • Error handling and graceful degradation
  • Builder configuration and server lifecycle integration

Working examples:

  • examples/stdio-logging-showcase/ - Complete demonstration of auto-injection
  • Updated calculator example with comprehensive logging

Breaking Changes

None. This implementation maintains full backward compatibility:

  • Existing servers continue to work without modification
  • Logging is opt-in via ->enableMcpLogging()
  • No changes to existing method signatures
  • Auto-injection only occurs when McpLogger or LoggerInterface parameters are declared

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

Implementation highlights:

Core Components:

  • McpLogger: PSR-3 compliant logger with MCP notification transport
  • NotificationSender: Handles delivery of log messages to clients
  • SetLogLevelHandler: Processes client log level configuration requests
  • LoggingLevel enum: RFC-5424 compliant severity levels with indexing

Auto-injection mechanism:

#[McpTool(name: 'my_tool')]
public function myTool(string $input, McpLogger $logger): array {
    $logger->info('Tool called', ['input' => $input]);
    // Logger automatically injected - no configuration needed!
    return ['result' => 'processed'];
}

@Adebayo120 Adebayo120 force-pushed the feature/mcp-logging-specification branch from 34ae3c3 to 035b75e Compare October 10, 2025 05:39
@giacomomasseron
Copy link

Why you use Yoda style?

Is it necessary?

@Adebayo120
Copy link
Contributor Author

I was only trying to follow the project convention and ensure the PR focuses on the feature, rather than refactoring. The Yoda style is not necessary, but that's what the project mostly uses at the moment. I believe refactoring is an implementation that is worthy of its own PR

@giacomomasseron

@Adebayo120 Adebayo120 force-pushed the feature/mcp-logging-specification branch from 953aca7 to 30f8f42 Compare October 11, 2025 20:00
Copy link
Member

@chr-hertel chr-hertel left a comment

Choose a reason for hiding this comment

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

Hi @Adebayo120 - thanks a lot for giving this a try!

I did a first round of review, and didn't tackle all yet - since this is a larger feature, i guess we will need a couple of rounds and discussions - also with @CodeWithKyrian.
Just want to be transparent about that from the start, but we'll guide you through it, if you're up for that.

Please have a look at my comments, and also have a look at the examples here with Inspector:
image

at first glance i found two issues here:

  1. the logger appears as tool argument in the schema
  2. setting a higher log level raises errors

let me know if you have some questions!

@Adebayo120
Copy link
Contributor Author

Adebayo120 commented Oct 12, 2025

Going through comments and updating, thank you so much @chr-hertel

@Adebayo120
Copy link
Contributor Author

Hi @Adebayo120 - thanks a lot for giving this a try!

I did a first round of review, and didn't tackle all yet - since this is a larger feature, i guess we will need a couple of rounds and discussions - also with @CodeWithKyrian. Just want to be transparent about that from the start, but we'll guide you through it, if you're up for that.

Please have a look at my comments, and also have a look at the examples here with Inspector: image

at first glance i found two issues here:

  1. the logger appears as tool argument in the schema
  2. setting a higher log level raises errors

let me know if you have some questions!

  1. I have added implementation to excluded autoInjected ClientLogger
  2. setting a higher log level raises errors: As far as I can see in the implementation, we don't throw an error when a higher log level is called; we only log a message on the server

@Adebayo120 Adebayo120 force-pushed the feature/mcp-logging-specification branch from e6e49b3 to 0eecd64 Compare October 19, 2025 22:25
@Adebayo120
Copy link
Contributor Author

@chr-hertel, I have updated the PR as suggested and tested as shown in the attached screenshot. It works great for me
. Please let me know if there are any updates I need to make to the PR

Screenshot 2025-10-20 at 00 06 02

@chr-hertel
Copy link
Member

@Adebayo120 thanks for following up - can you extend one of the HTTP examples to include client logging as well?

Comment on lines +809 to +810
return 'Mcp\\Capability\\Logger\\ClientLogger' === $typeName
|| 'Psr\\Log\\LoggerInterface' === $typeName;
Copy link
Member

Choose a reason for hiding this comment

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

please use ::class instead

Copy link
Member

Choose a reason for hiding this comment

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

actually you could simplify this to sth like

Suggested change
return 'Mcp\\Capability\\Logger\\ClientLogger' === $typeName
|| 'Psr\\Log\\LoggerInterface' === $typeName;
return in_array($type->getName(), [ClientLogger::class, LoggerInterface::class], true);

* @param string $message The message to process
* @param \Mcp\Capability\Logger\ClientLogger $logger Auto-injected logger
*/
public function withClientLogger(string $message, \Mcp\Capability\Logger\ClientLogger $logger): string
Copy link
Member

Choose a reason for hiding this comment

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

use an import instead of FQCN inline

Comment on lines +336 to +344
// Should include the message parameter
$this->assertArrayHasKey('message', $schema['properties']);
$this->assertEquals(['type' => 'string', 'description' => 'The message to process'], $schema['properties']['message']);

// Should NOT include the logger parameter
$this->assertArrayNotHasKey('logger', $schema['properties']);

// Required array should only contain client parameters
$this->assertEquals(['message'], $schema['required']);
Copy link
Member

Choose a reason for hiding this comment

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

those comments are not needed - just make it look like vibe coded

@chr-hertel chr-hertel changed the title Implemented MCP logging specification with auto-injection [Server] Implemented MCP logging specification with auto-injection Oct 20, 2025
@chr-hertel chr-hertel added the Server Issues & PRs related to the Server component label Oct 20, 2025
@chr-hertel
Copy link
Member

@Adebayo120 please wait before continuing here - with #109 there is a competing solution that also covers other client-facing features - doesn't really make sense to work on the same thing.

Or do I miss something @CodeWithKyrian that your PR wouldn't cover? also addresses the STDIO vs HTTP question that is rather unsolved here, right?

@Adebayo120
Copy link
Contributor Author

@CodeWithKyrian could you please help here

@chr-hertel
Copy link
Member

There is still something in the PR we could need - mostly the SetLogLevelHandler. but it requires some rebase on adoption of the ClientGateway instead of the ClientLogger

@Adebayo120 are you still up for that?

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

Labels

Server Issues & PRs related to the Server component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Server] Add more Logging and Notifications

3 participants