Skip to content

Expand MCP tool metadata: explicit output schemas and hint annotations#34

Closed
aerdasaliko wants to merge 8 commits intogalaxyproject:mainfrom
aerdasaliko:main
Closed

Expand MCP tool metadata: explicit output schemas and hint annotations#34
aerdasaliko wants to merge 8 commits intogalaxyproject:mainfrom
aerdasaliko:main

Conversation

@aerdasaliko
Copy link
Copy Markdown

Description

  • Define structured output schemas and annotations (readOnly/destructive/idempotent/openWorld hints) for each tool.
  • Clarify return structures (pagination metadata, previews, workflow invocation details, etc.) to improve MCP tool discovery and validation.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • ⬆️ Dependency update
  • 🧰 Maintenance/chore

@aerdasaliko aerdasaliko marked this pull request as draft February 18, 2026 11:25
Copy link
Copy Markdown
Member

@dannon dannon left a comment

Choose a reason for hiding this comment

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

Thanks for putting this together — adding output schemas and annotations is a worthwhile improvement.

A few things to address before this can move forward:

String concatenation bug (throughout)

Python's implicit string concatenation is biting you in several places where adjacent strings lack a trailing space, producing mangled descriptions. For example in search_tools:

"description": "Tools whose names match the query string, returned as an array."
"Each object contains a tool id..."

This concatenates to "...array.Each object..." (no space after the period). The same issue appears in:

  • run_tool outputs — "execution.Each"
  • get_tool_panel"tools.Each"
  • create_history id — "identifier.This" and "such as:run_tool"
  • get_job_details dataset_id — "retrieved.Reusable"
  • upload_file_from_url outputs — "URL.Each"
  • get_iwc_workflows"manifest.'trsID'"
  • search_iwc_workflows trsID — "workflow.Can"
  • list_workflows items — "attributes.The"
  • get_workflow_details description — "steps,inputs" (missing space after comma) and "parameters.An"

Fix is straightforward — add a trailing space before the closing quote on each first string, or wrap in parentheses:

"description": (
    "Tools whose names match the query string, returned as an array. "
    "Each object contains a tool id..."
),

list_history_ids return type change

This PR changes the return type from list[dict[str, str]] to dict[str, Any] and wraps the return value in {"histories": [...]}. That's a behavioral change to existing clients, not just metadata. If we want this change it should be called out explicitly and the existing tests updated.

cancel_workflow_invocation missing description

Every other tool has a description= in the decorator — this one was missed.

upload_file_from_url missing required

The nearly identical upload_file has "required": ["outputs", "jobs", ...] in its schema, but upload_file_from_url doesn't. Looks like an oversight.

Inconsistent idempotentHint

Some read-only tools include idempotentHint: True (e.g. search_tools, get_tool_details) while others that are equally idempotent omit it (e.g. get_user, get_histories, list_history_ids, get_history_contents, get_dataset_details). Worth making this consistent — if a tool is read-only and deterministic given the same server state, it should have idempotentHint: True.

Rebase needed

The main branch has moved since this was opened (fastmcp 3 bump and IWC function fixes). You'll want to rebase on current main to make sure the decorator kwargs work with fastmcp >= 3.0.0.

@aerdasaliko
Copy link
Copy Markdown
Author

Thanks for the thorough review!

I've made the following initial quick fixes:

  • Fixed the string concatenation bug overall
  • Added the missing description for cancel_workflow_invocation
  • Added the missing required field in the output schema for upload_file_from_url

Regarding list_history_ids return type:
I made this change because output schemas must be object types ("type": "object") due to the MCP specification limitations. A similar issue was discussed here: OpenLiberty/open-liberty#33746.

As for idempotentHint, my hesitation was around functions like get_history_contents, where repeated calls can return different results over short intervals (e.g., when a dataset transitions from uploading to ok). I was worried that might conflict with the intent of idempotentHint, however, since the definition refers to the effect of repeated calls rather than the output itself, I agree that it makes sense to be consistent. I’ll update the remaining read-only tools to include idempotentHint: True.

@aerdasaliko
Copy link
Copy Markdown
Author

Thanks for the feedback. I'm closing this PR as it's become too stale. Feel free to reopen if this work is still needed

@aerdasaliko aerdasaliko closed this Apr 7, 2026
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.

2 participants