Skip to content

Conversation

@bigdevlarry
Copy link
Contributor

The changes add comprehensive support for outputSchema in the Tools definition, enabling MCP servers to specify the expected structure and types of tool responses.

This includes:

  • Added outputSchema parameter to Builder::addTool() method
  • Updated Tool class constructor and JSON serialization to support outputSchema
  • Added validation for outputSchema structure and type requirements
  • Enhanced existing tests to verify outputSchema functionality works correctly
  • Fixed related type annotation issues and code style problems

This allows MCP clients to validate tool responses against the defined schema and provides better type safety and documentation for tool interactions.

Motivation and Context

This was raised as an issue for the output schema to be added

How Has This Been Tested?

Breaking Changes

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

@bigdevlarry
Copy link
Contributor Author

@chr-hertel PR to address #68 is now up for review

@chr-hertel
Copy link
Member

Hi @bigdevlarry, thanks for working on this - look great already. was thinking tho if it makes sense to extend maybe one of our examples - or bring in a new one to demo this?

WDYT & cc @CodeWithKyrian

@bigdevlarry
Copy link
Contributor Author

I didn’t know how to extend but I’m happy with either extending or bringing a new example tho …

@bigdevlarry bigdevlarry force-pushed the no-ability-to-setup-output-schema branch from ebca579 to b9a1058 Compare September 30, 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.

i guess the #[McpTool] attribute also needs to be extended as well

and you could extend the tool in example no5

@bigdevlarry bigdevlarry force-pushed the no-ability-to-setup-output-schema branch from b9a1058 to 4d56220 Compare October 2, 2025 20:30
@bigdevlarry
Copy link
Contributor Author

Okay, that make sense. You can have a look again

@chr-hertel
Copy link
Member

Pipeline issue related to modelcontextprotocol/inspector#834

@CodeWithKyrian
Copy link
Contributor

This is solid work, @bigdevlarry ! Appreciate the effort you put into this!

On a side note, I was wondering if there’s a way we could also infer the outputSchema when it’s not explicitly defined, similar to how we handle inputSchema. Also, I'm thinking of the Schema attribute (or even a dedicated OutputSchema attribute), if and how that could come into play here.

Just a thought though...curious what you all think.

@ineersa
Copy link
Contributor

ineersa commented Oct 4, 2025

https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content

While working on my MCP this one is not seems to be working too.

It looks like if outputSchema provided server must also provide structuredContent alongside content.

I will try this PR in my fork and will try to implement structured content in CallToolResult.

Because of this I wouldn't add auto schema definition, developer should be aware that by adding outputSchema they should also add structuredContent.

@chr-hertel chr-hertel added the Server Issues & PRs related to the Server component label Oct 6, 2025
@bigdevlarry bigdevlarry force-pushed the no-ability-to-setup-output-schema branch 2 times, most recently from 3d52d35 to 16e3b32 Compare October 9, 2025 20:29
@bigdevlarry
Copy link
Contributor Author

@CodeWithKyrian, thanks for the shout and feedback. I've included support to help infer the outputSchema when it’s not explicitly defined, similar to how we handle inputSchema. Also on this one -

Also, I'm thinking of the Schema attribute (or even a dedicated OutputSchema attribute), if and how that could come into play here.

I'm not sure how you mean here. If you create a separate issue with more description, then I can pick it up.

@chr-hertel Could you give the PR another look? I think should be good

@bigdevlarry bigdevlarry force-pushed the no-ability-to-setup-output-schema branch from 16e3b32 to 4f9df3d Compare October 9, 2025 20:42
@bigdevlarry
Copy link
Contributor Author

hi @chr-hertel Still need a review/feedback here

@chr-hertel chr-hertel changed the title issues-68 No Ability to set outputSchema [Server] issues-68 No Ability to set outputSchema Oct 20, 2025
*/
public function getReturnTypeString(?DocBlock $docBlock): ?string
{
if (!$docBlock) {
Copy link
Member

Choose a reason for hiding this comment

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

always like to be explicit

Suggested change
if (!$docBlock) {
if (null === $docBlock) {

}

$returnTags = $docBlock->getTagsByName('return');
if (empty($returnTags)) {
Copy link
Member

Choose a reason for hiding this comment

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

and try to avoid empty:

Suggested change
if (empty($returnTags)) {
if ([] === $returnTags) {

}

$returnTag = $returnTags[0];
if (method_exists($returnTag, 'getType') && $returnTag->getType()) {
Copy link
Member

Choose a reason for hiding this comment

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

can we check for TagWithType instead of using method_exists?

Copy link
Member

Choose a reason for hiding this comment

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

and should be inverted to:

if (!$returnTag instanceof TagWithType) {
    return null;
}

it's better to continue with the style of early exits - like you did in the beginning of the method

Comment on lines +82 to +111
/**
* Generates a JSON Schema object (as a PHP array) for a method's or function's return type.
*
* @return array<string, mixed>|null
*/
public function generateOutputSchema(\ReflectionMethod|\ReflectionFunction $reflection): ?array
{
$docComment = $reflection->getDocComment() ?: null;
$docBlock = $this->docBlockParser->parseDocBlock($docComment);

$docBlockReturnType = $this->docBlockParser->getReturnTypeString($docBlock);
$returnDescription = $this->docBlockParser->getReturnDescription($docBlock);

$reflectionReturnType = $reflection->getReturnType();
$reflectionReturnTypeString = $reflectionReturnType
? $this->getTypeStringFromReflection($reflectionReturnType, $reflectionReturnType->allowsNull())
: null;

// Use DocBlock with generics, otherwise reflection, otherwise DocBlock
$returnTypeString = ($docBlockReturnType && str_contains($docBlockReturnType, '<'))
? $docBlockReturnType
: ($reflectionReturnTypeString ?: $docBlockReturnType);

if (!$returnTypeString || 'void' === strtolower($returnTypeString)) {
return null;
}

return $this->buildOutputSchemaFromType($returnTypeString, $returnDescription);
}

Copy link
Member

Choose a reason for hiding this comment

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

please add tests for this method

Comment on lines +168 to +185
public function getReturnDescription(?DocBlock $docBlock): ?string
{
if (!$docBlock) {
return null;
}

$returnTags = $docBlock->getTagsByName('return');
if (empty($returnTags)) {
return null;
}

$returnTag = $returnTags[0];
$description = method_exists($returnTag, 'getDescription')
? trim((string) $returnTag->getDescription())
: '';

return $description ?: null;
}
Copy link
Member

Choose a reason for hiding this comment

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

similar comments would apply to this method like with getReturnTypeString

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 Status: Needs Work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants