Skip to content

feat: Add Tool.outputSchema and CallToolResult.structuredContent #302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

pantanurag555
Copy link

@pantanurag555 pantanurag555 commented Jun 9, 2025

Motivation and Context

This PR adds support for Tool.outputSchema and CallToolResult.structuredContent that was introduced in the specification in modelcontextprotocol/modelcontextprotocol@03dc24b.
Resolves #285

Changes in this PR:

  • Implement support for outputSchema in Tool and structuredContent in CallToolResult.
  • Add a client-side cache that maintains track of all server tools and their output schemas (if any).
  • Implement a mechanism to refresh the client side cache when encountering a tool call request for an uncached tool.
  • Implement json validation between tool's output schema and result's structured content, when an output schema is specified for the tool.

How Has This Been Tested?

  • Added unit test
  • Added integration tests to test success and failure of client-side json validation

Breaking Changes

A new field for structuredContent was added to CallToolResult as part of the changes. CallToolResult fields were modified from (List<Content> content, Boolean isError) -> (List<Content> content, Boolean isError, Map<String, Object> structuredContent).

In order to maintain backward compatibility with earlier initializations of CallToolResult that relied on just specifying (List<Content> , Boolean), a new constructor was created that would accept (List<Content> , Boolean). This ensured that no further changes were required to the unit tests across java-sdk. There is already a preexisting constructor for CallToolResult that accepts (String, Boolean).

The addition of the new constructor can lead to constructor ambiguity in case a CallToolResult was created with content set to null (since null can be either String or List). Example, CallToolResult(null, true). Such initializations would now require explicit typecasting to ensure that they are compiled successfully. This can be treated as a breaking change. I am open to suggestions on a better way to tackle this.

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

- Implement support for outputSchema in Tool and structuredContent in
  CallToolResult.
- Add a client-side cache that maintains track of all server tools and
  their output schemas (if any).
- Implement a mechanism to refresh the client side cache when
  encountering a tool call request for an uncached tool.
- Implement json validation between tool's output schema and result's
  structured content, when an output schema is specified for the tool.
Comment on lines +205 to +210
<!-- Json validator dependency -->
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.5.7</version>
</dependency>
Copy link
Contributor

Choose a reason for hiding this comment

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

Worth getting extra clarification from maintainers on if we want schema validation as part of this or a separate effort, along the lines of the discussion in #271.

Copy link
Author

Choose a reason for hiding this comment

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

Discussed some of the issues offline with @LucaButBoring. I wanted to get clarity around the scope of the work on the issue that I had created. There are a few questions that we might want to answer regarding the output validation:

  1. Do we want validation to be part of this PR or do we want to separate it out and think more about how we can cache/validate the results?
  2. Should cache be in the client class or should we construct a separate cache class?
  3. Should there be refresh intervals for cache invalidation? How else can we deal with it and should it be configurable by the client?
  4. Is a Map the best way to represent cache or should we opt for an in-memory cache implementation like Guava Cache?

Would like inputs from the maintainers to decide on the best way to proceed.

Comment on lines 274 to 278
catch (JsonProcessingException e) {
// Log error if output schema can't be parsed to prevent erroring out for
// successful call tool request
logger.error("Encountered exception when parsing outputSchema: {}", e);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Worth getting other opinions on this, I think this should be rethrown (potentially wrapped in McpError to keep it unchecked).

Copy link
Author

Choose a reason for hiding this comment

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

I agree. For now, changing this to log a warning. This leaves the option open for the client side implementation to proceed as it deems fit. I would like feedback from others about what would be the ideal behavior in this scenario.

@LucaButBoring
Copy link
Contributor

Just gave this a preliminary review by request, review done for now.

@pantanurag555
Copy link
Author

Addressed all comments from @LucaButBoring barring a few that where I would like a discussion with maintainers/others from the community.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add OutputSchema to Tool and CallToolResult.structuredContent
2 participants