Skip to content

Commit 52b1e86

Browse files
committed
fix(mcp): accept 'pattern' as an alias for 'query' on grep/find_files
multi_grep uses 'patterns' while grep/find_files use 'query'; LLMs routinely confuse the two and trip on 'missing field `query`' (#311). Add a serde alias so the wrong-but-intuitive name also works without changing the published JSON schema.
1 parent 2e2a7a0 commit 52b1e86

1 file changed

Lines changed: 30 additions & 0 deletions

File tree

crates/fff-mcp/src/server.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ fn make_grep_options(
8585
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
8686
pub struct FindFilesParams {
8787
/// Fuzzy search query. Supports path prefixes and glob constraints.
88+
// `pattern` alias for consistency with grep's alias and the common
89+
// file-search parameter name (#311).
90+
#[serde(alias = "pattern")]
8891
pub query: String,
8992
/// Max results (default 20).
9093
#[serde(rename = "maxResults")]
@@ -98,6 +101,10 @@ pub struct FindFilesParams {
98101
pub struct GrepParams {
99102
/// Search text or regex query with optional constraint prefixes.
100103
/// Matches within single lines only — use ONE specific term, not multiple words.
104+
// `pattern` alias: LLMs that have seen multi_grep (which uses `patterns`)
105+
// routinely call grep with `pattern`; accept it instead of erroring out
106+
// with an unhelpful "missing field `query`" (#311).
107+
#[serde(alias = "pattern")]
101108
pub query: String,
102109
/// Max matching lines (default 20).
103110
#[serde(rename = "maxResults")]
@@ -709,4 +716,27 @@ mod tests {
709716
assert_eq!(normalize_max_results(Some(10.0), 20), 10);
710717
assert_eq!(normalize_max_results(Some(10.7), 20), 11);
711718
}
719+
720+
#[test]
721+
fn grep_params_accepts_pattern_alias() {
722+
// Issue #311: LLMs flip between `query` and `pattern`; accept both.
723+
let via_query: GrepParams =
724+
serde_json::from_str(r#"{"query":"foo"}"#).expect("query field");
725+
assert_eq!(via_query.query, "foo");
726+
727+
let via_pattern: GrepParams =
728+
serde_json::from_str(r#"{"pattern":"foo"}"#).expect("pattern alias");
729+
assert_eq!(via_pattern.query, "foo");
730+
}
731+
732+
#[test]
733+
fn find_files_params_accepts_pattern_alias() {
734+
let via_query: FindFilesParams =
735+
serde_json::from_str(r#"{"query":"foo"}"#).expect("query field");
736+
assert_eq!(via_query.query, "foo");
737+
738+
let via_pattern: FindFilesParams =
739+
serde_json::from_str(r#"{"pattern":"foo"}"#).expect("pattern alias");
740+
assert_eq!(via_pattern.query, "foo");
741+
}
712742
}

0 commit comments

Comments
 (0)