Summary
A comma anywhere inside an @desc(...) annotation truncates type parsing. The capture used for the type expression ([^,}]+ in compile_tagged_record / parse_record_type, and String#split(",") in parse_call_params) stops at the first comma regardless of whether that comma is part of natural English in the description text.
The result: naturally-written descriptions silently corrupt the generated JSON Schema.
Affected versions
Observed against mcp_authorization 0.3.0. The regexes look the same on main.
Reproduction
Minimal handler:
class Handlers::CreateBook
include McpAuthorization::DSL
def description
"Create a book"
end
# @rbs import error
# @rbs type book_input = {
# title: String @desc(Title displayed to readers),
# page_count: Integer? @desc(Total pages, including front matter),
# genre: String? @desc(Optional, defaults to general fiction)
# }
# @rbs type success = { success: true, id: Integer }
# @rbs type output = success | error
#: (book: book_input) -> output
def call(book:)
{ success: true, id: 1 }
end
end
When this handler is wrapped by an McpAuthorization::Tool subclass and surfaced via tools/list, the inputSchema for book is:
{
"type": "object",
"properties": {
"title": { "type": "string", "description": "Title displayed to readers" }
},
"required": ["title"]
}
page_count and genre are missing entirely. The commas inside their @desc(...) text caused [^,}]+ to stop mid-type, and the trailing fragments (including front matter), defaults to general fiction)) no longer matched the next \w+: pattern, so those fields were dropped.
Where it happens
In lib/mcp_authorization/rbs_schema_compiler.rb:
-
compile_tagged_record (~line 654):
inner.scan(/(\w+\??)\s*:\s*([^,}]+)/) do |match|
-
parse_record_type (~line 1052):
inner.scan(/(\w+):\s*([^,}]+)/) do |match|
-
parse_call_params (~line 1002):
$1.to_s.split(",").each do |param|
A comma inside @desc(...) on a call-signature parameter splits the parameter into pieces; both halves then fail the \A(\?)?([\w]+):\s*(.+)\z per-param regex and get skipped.
Expected behavior
Commas inside @desc(...) (and other @tag(...) parens) should be treated as part of the tag's payload, not as field separators. Authors should be able to write natural English in descriptions without worrying about delimiter collisions.
Workaround
Strip all commas from @desc(...) text — replace with em-dashes, semicolons, or rephrase. Tedious for anything written conversationally.
Suggested fix direction
A couple of approaches that would work:
- Strip balanced-paren tags first. Before splitting the inner body by field, walk the string with a small bracket-aware scanner that removes
@\w+\(...\) segments (matching nested parens) and stashes them for later extract_tags consumption. Then the field-splitter only sees bare key: type pairs.
- Or switch the field-splitter from regex to a small state machine that tracks paren depth and splits on commas only when depth is zero.
Either keeps backward compatibility with simple cases and unblocks natural descriptions. Happy to send a PR if a maintainer can confirm which direction they'd prefer.
Summary
A comma anywhere inside an
@desc(...)annotation truncates type parsing. The capture used for the type expression ([^,}]+incompile_tagged_record/parse_record_type, andString#split(",")inparse_call_params) stops at the first comma regardless of whether that comma is part of natural English in the description text.The result: naturally-written descriptions silently corrupt the generated JSON Schema.
Affected versions
Observed against
mcp_authorization 0.3.0. The regexes look the same onmain.Reproduction
Minimal handler:
When this handler is wrapped by an
McpAuthorization::Toolsubclass and surfaced viatools/list, theinputSchemaforbookis:{ "type": "object", "properties": { "title": { "type": "string", "description": "Title displayed to readers" } }, "required": ["title"] }page_countandgenreare missing entirely. The commas inside their@desc(...)text caused[^,}]+to stop mid-type, and the trailing fragments (including front matter),defaults to general fiction)) no longer matched the next\w+:pattern, so those fields were dropped.Where it happens
In
lib/mcp_authorization/rbs_schema_compiler.rb:compile_tagged_record(~line 654):parse_record_type(~line 1052):parse_call_params(~line 1002):A comma inside
@desc(...)on a call-signature parameter splits the parameter into pieces; both halves then fail the\A(\?)?([\w]+):\s*(.+)\zper-param regex and get skipped.Expected behavior
Commas inside
@desc(...)(and other@tag(...)parens) should be treated as part of the tag's payload, not as field separators. Authors should be able to write natural English in descriptions without worrying about delimiter collisions.Workaround
Strip all commas from
@desc(...)text — replace with em-dashes, semicolons, or rephrase. Tedious for anything written conversationally.Suggested fix direction
A couple of approaches that would work:
@\w+\(...\)segments (matching nested parens) and stashes them for laterextract_tagsconsumption. Then the field-splitter only sees barekey: typepairs.Either keeps backward compatibility with simple cases and unblocks natural descriptions. Happy to send a PR if a maintainer can confirm which direction they'd prefer.