Skip to content

fix(macros): accept const paths and concat! in tool/prompt descriptions - #1243

Open
atirna wants to merge 1 commit into
modelcontextprotocol:mainfrom
atirna:fix/tool-description-non-literal-exprs
Open

fix(macros): accept const paths and concat! in tool/prompt descriptions#1243
atirna wants to merge 1 commit into
modelcontextprotocol:mainfrom
atirna:fix/tool-description-non-literal-exprs

Conversation

@atirna

@atirna atirna commented Sep 3, 2026

Copy link
Copy Markdown

Fixes #1175

Motivation and Context

description in #[tool] and #[prompt] only accepted a bare string literal, while neighbouring attributes on the very same items are more permissive: #[doc] on the function accepts include_str! and that value reaches the published description, and #[schemars(extend(...))] on the argument struct accepts const paths.

So the published text could already be sourced from outside the attribute, just not through the field that names it. On a server with many tools, keeping the short broadcast description next to the longer fetchable one is much easier when both can be declared together and the short one referenced from the attribute:

const GET_PROJECT_DESCRIPTION: &str = "...";

#[tool(description = GET_PROJECT_DESCRIPTION)]

How Has This Been Tested?

  • before, on current main: a small crate with #[tool(description = SOME_CONST)] fails with error: Unexpected type path, and `#[tool(description = concat!("a", "b"))]` fails with `error: Unexpected type `macro
  • after: both compile, and the generated <fn>_tool_attr().description equals the const value / "ab"; a bare string literal, #[doc]-derived and include_str! descriptions keep working; description = 42 is still rejected with a normal type error at the attribute
  • added regression tests in test_tool_macros.rs (const path, concat!) and test_prompt_macros.rs (const path); cargo test -p rmcp-macros, the focused integration tests, and the full cargo test -p rmcp --features "client server transport-io which-command" suite pass locally, plus cargo clippy --all-targets --all-features -- -D warnings and cargo +nightly fmt --all -- --check

Implementation notes: the field is parsed through darling's PreservedStrExpr, whose FromMeta keeps a string literal a literal instead of parsing its contents as code, so existing description = "..." usage is unchanged; the generated code stores a &'static str either way, exactly as before.

Breaking Changes

None. Existing string-literal descriptions compile to the same code; only inputs that previously failed to compile are now accepted.

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

The description field of #[tool] and #[prompt] only accepted a bare
string literal, while #[doc] on the same item accepts include_str! and
#[schemars] on the argument struct accepts const paths. Parse the field
as an expression through darling's PreservedStrExpr, which keeps a
string literal a literal, so a const path or concat! now works too.

Fixes modelcontextprotocol#1175
@atirna
atirna requested a review from a team as a code owner September 3, 2026 04:55
@github-actions github-actions Bot added T-test Testing related changes T-macros Macro changes labels Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-macros Macro changes T-test Testing related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

#[tool(description = …)] accepts only a bare literal, while #[doc] and #[schemars] on the same items accept include_str! and const paths

1 participant