From ba809b6e12a6967256b24872707ece09100a5b94 Mon Sep 17 00:00:00 2001 From: Dale Seo Date: Thu, 11 Sep 2025 10:32:52 -0400 Subject: [PATCH 1/5] feat: improve search tool description --- crates/apollo-mcp-server/src/introspection/tools/search.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/apollo-mcp-server/src/introspection/tools/search.rs b/crates/apollo-mcp-server/src/introspection/tools/search.rs index 3e146b63..ead56a17 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/search.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/search.rs @@ -75,7 +75,7 @@ impl Search { tool: Tool::new( SEARCH_TOOL_NAME, format!( - "Search a GraphQL schema{}", + "Search a GraphQL schema for types matching the provided search terms. Returns complete type definitions including all related types needed to construct GraphQL operations. For best results, use specific type names (which can be discovered using the introspect tool starting from the root Query or Mutation types). Avoid reusing previously searched terms for more efficient exploration.{}", if minify { " - T=type,I=input,E=enum,U=union,F=interface;s=String,i=Int,f=Float,b=Boolean,d=ID;!=required,[]=list,<>=implements" } else { From ab28138bb2941a9bf3ff4c02989201be52e167ad Mon Sep 17 00:00:00 2001 From: Dale Seo Date: Thu, 11 Sep 2025 10:38:59 -0400 Subject: [PATCH 2/5] feat: improve introspect tool description --- .../src/introspection/tools/introspect.rs | 10 +++------- .../src/introspection/tools/search.rs | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/crates/apollo-mcp-server/src/introspection/tools/introspect.rs b/crates/apollo-mcp-server/src/introspection/tools/introspect.rs index 436c89e3..1af80600 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/introspect.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/introspect.rs @@ -125,13 +125,9 @@ fn tool_description( "Get GraphQL type information - T=type,I=input,E=enum,U=union,F=interface;s=String,i=Int,f=Float,b=Boolean,d=ID;!=required,[]=list,<>=implements;".to_string() } else { format!( - "Get detailed information about types from the GraphQL schema.{}{}", - root_query_type - .map(|t| format!(" Use the type name `{t}` to get root query fields.")) - .unwrap_or_default(), - root_mutation_type - .map(|t| format!(" Use the type name `{t}` to get root mutation fields.")) - .unwrap_or_default() + "Get information about a given GraphQL type defined in the schema. Instructions: Always use this tool first to get the fields for the root query ({} type) or mutation ({} type), then use the search tool with all of the relevant field return type and argument input types (ignore default GraphQL scalars) as search terms, only use this tool once when fulfilling a request.", + root_query_type.as_deref().unwrap_or("Query"), + root_mutation_type.as_deref().unwrap_or("Mutation") ) } } diff --git a/crates/apollo-mcp-server/src/introspection/tools/search.rs b/crates/apollo-mcp-server/src/introspection/tools/search.rs index ead56a17..d470f0d2 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/search.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/search.rs @@ -75,7 +75,7 @@ impl Search { tool: Tool::new( SEARCH_TOOL_NAME, format!( - "Search a GraphQL schema for types matching the provided search terms. Returns complete type definitions including all related types needed to construct GraphQL operations. For best results, use specific type names (which can be discovered using the introspect tool starting from the root Query or Mutation types). Avoid reusing previously searched terms for more efficient exploration.{}", + "Search a GraphQL schema for types matching the provided search terms. Returns complete type definitions including all related types needed to construct GraphQL operations. Instructions: For best results, use specific type names (which can be discovered using the introspect tool starting from the root Query or Mutation types). Avoid reusing previously searched terms for more efficient exploration.{}", if minify { " - T=type,I=input,E=enum,U=union,F=interface;s=String,i=Int,f=Float,b=Boolean,d=ID;!=required,[]=list,<>=implements" } else { From 840e07fd1c26d2bcf8a3e0bc9356b36776c485f0 Mon Sep 17 00:00:00 2001 From: Dale Seo Date: Thu, 11 Sep 2025 12:01:23 -0400 Subject: [PATCH 3/5] test: add tests to verify updated tool descriptions --- .../src/introspection/tools/introspect.rs | 48 +++++++++++++++++++ .../src/introspection/tools/search.rs | 32 +++++++++++++ 2 files changed, 80 insertions(+) diff --git a/crates/apollo-mcp-server/src/introspection/tools/introspect.rs b/crates/apollo-mcp-server/src/introspection/tools/introspect.rs index 1af80600..9e8d37b4 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/introspect.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/introspect.rs @@ -136,3 +136,51 @@ fn tool_description( fn default_depth() -> usize { 1 } + +#[cfg(test)] +mod tests { + use super::*; + use apollo_compiler::Schema; + use apollo_compiler::validation::Valid; + use rstest::{fixture, rstest}; + use std::sync::Arc; + use tokio::sync::Mutex; + + const TEST_SCHEMA: &str = include_str!("testdata/schema.graphql"); + + #[fixture] + fn schema() -> Valid { + Schema::parse(TEST_SCHEMA, "schema.graphql") + .expect("Failed to parse test schema") + .validate() + .expect("Failed to validate test schema") + } + + #[rstest] + #[tokio::test] + async fn test_tool_description(schema: Valid) { + let introspect = Introspect::new(Arc::new(Mutex::new(schema)), None, None, false); + + let description = introspect.tool.description.unwrap(); + + assert!( + description + .contains("Get information about a given GraphQL type defined in the schema") + ); + assert!(description.contains("Instructions: Always use this tool first")); + // Should not contain minification legend + assert!(!description.contains("T=type,I=input")); + } + + #[rstest] + #[tokio::test] + async fn test_tool_description_minified(schema: Valid) { + let introspect = Introspect::new(Arc::new(Mutex::new(schema)), None, None, true); + + let description = introspect.tool.description.unwrap(); + + // Should contain minification legend + assert!(description.contains("T=type,I=input,E=enum,U=union,F=interface")); + assert!(description.contains("s=String,i=Int,f=Float,b=Boolean,d=ID")); + } +} diff --git a/crates/apollo-mcp-server/src/introspection/tools/search.rs b/crates/apollo-mcp-server/src/introspection/tools/search.rs index d470f0d2..fb63be03 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/search.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/search.rs @@ -246,4 +246,36 @@ mod tests { "Expected to find the createUser mutation in search results" ); } + + #[rstest] + #[tokio::test] + async fn test_tool_description_non_minified(schema: Valid) { + let schema = Arc::new(Mutex::new(schema)); + let search = Search::new(schema.clone(), false, 1, 15_000_000, false) + .expect("Failed to create search tool"); + + let description = search.tool.description.unwrap(); + + assert!( + description + .contains("Search a GraphQL schema for types matching the provided search terms") + ); + assert!(description.contains("Instructions: For best results, use specific type names")); + // Should not contain minification legend + assert!(!description.contains("T=type,I=input")); + } + + #[rstest] + #[tokio::test] + async fn test_tool_description_minified(schema: Valid) { + let schema = Arc::new(Mutex::new(schema)); + let search = Search::new(schema.clone(), false, 1, 15_000_000, true) + .expect("Failed to create search tool"); + + let description = search.tool.description.unwrap(); + + // Should contain minification legend + assert!(description.contains("T=type,I=input,E=enum,U=union,F=interface")); + assert!(description.contains("s=String,i=Int,f=Float,b=Boolean,d=ID")); + } } From b9c3b9116a363186e790e9b28380c6928f1de8a9 Mon Sep 17 00:00:00 2001 From: Dale Seo Date: Thu, 11 Sep 2025 12:02:49 -0400 Subject: [PATCH 4/5] chore: add changeset --- .changesets/feat_imporove_tool_descriptions.md | 3 +++ .../src/introspection/tools/introspect.rs | 8 +++++--- .../apollo-mcp-server/src/introspection/tools/search.rs | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 .changesets/feat_imporove_tool_descriptions.md diff --git a/.changesets/feat_imporove_tool_descriptions.md b/.changesets/feat_imporove_tool_descriptions.md new file mode 100644 index 00000000..980dcb53 --- /dev/null +++ b/.changesets/feat_imporove_tool_descriptions.md @@ -0,0 +1,3 @@ +### feat: Enhance tool descriptions - @DaleSeo PR #350 + +This PR enhances the descriptions of the introspect and search tools to offer clearer guidance for AI models on efficient GraphQL schema exploration patterns. diff --git a/crates/apollo-mcp-server/src/introspection/tools/introspect.rs b/crates/apollo-mcp-server/src/introspection/tools/introspect.rs index 9e8d37b4..91f1b07e 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/introspect.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/introspect.rs @@ -125,7 +125,7 @@ fn tool_description( "Get GraphQL type information - T=type,I=input,E=enum,U=union,F=interface;s=String,i=Int,f=Float,b=Boolean,d=ID;!=required,[]=list,<>=implements;".to_string() } else { format!( - "Get information about a given GraphQL type defined in the schema. Instructions: Always use this tool first to get the fields for the root query ({} type) or mutation ({} type), then use the search tool with all of the relevant field return type and argument input types (ignore default GraphQL scalars) as search terms, only use this tool once when fulfilling a request.", + "Get information about a given GraphQL type defined in the schema. Instructions: Use this tool to explore the schema by providing specific type names. Start with the root query ({}) or mutation ({}) types to discover available fields. If the search tool is also available, use this tool first to get the fields, then use the search tool with relevant field return types and argument input types (ignore default GraphQL scalars) as search terms.", root_query_type.as_deref().unwrap_or("Query"), root_mutation_type.as_deref().unwrap_or("Mutation") ) @@ -158,7 +158,7 @@ mod tests { #[rstest] #[tokio::test] - async fn test_tool_description(schema: Valid) { + async fn test_tool_description_non_minified(schema: Valid) { let introspect = Introspect::new(Arc::new(Mutex::new(schema)), None, None, false); let description = introspect.tool.description.unwrap(); @@ -167,9 +167,11 @@ mod tests { description .contains("Get information about a given GraphQL type defined in the schema") ); - assert!(description.contains("Instructions: Always use this tool first")); + assert!(description.contains("Instructions: Use this tool to explore the schema")); // Should not contain minification legend assert!(!description.contains("T=type,I=input")); + // Should mention conditional search tool usage + assert!(description.contains("If the search tool is also available")); } #[rstest] diff --git a/crates/apollo-mcp-server/src/introspection/tools/search.rs b/crates/apollo-mcp-server/src/introspection/tools/search.rs index fb63be03..5d7a5356 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/search.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/search.rs @@ -75,7 +75,7 @@ impl Search { tool: Tool::new( SEARCH_TOOL_NAME, format!( - "Search a GraphQL schema for types matching the provided search terms. Returns complete type definitions including all related types needed to construct GraphQL operations. Instructions: For best results, use specific type names (which can be discovered using the introspect tool starting from the root Query or Mutation types). Avoid reusing previously searched terms for more efficient exploration.{}", + "Search a GraphQL schema for types matching the provided search terms. Returns complete type definitions including all related types needed to construct GraphQL operations. Instructions: If the introspect tool is also available, you can discover type names by using the introspect tool starting from the root Query or Mutation types. Avoid reusing previously searched terms for more efficient exploration.{}", if minify { " - T=type,I=input,E=enum,U=union,F=interface;s=String,i=Int,f=Float,b=Boolean,d=ID;!=required,[]=list,<>=implements" } else { @@ -260,7 +260,8 @@ mod tests { description .contains("Search a GraphQL schema for types matching the provided search terms") ); - assert!(description.contains("Instructions: For best results, use specific type names")); + assert!(description.contains("Instructions: If the introspect tool is also available")); + assert!(description.contains("Avoid reusing previously searched terms")); // Should not contain minification legend assert!(!description.contains("T=type,I=input")); } From 0ac88e2c98b8ab47931fffda68be194da16135fd Mon Sep 17 00:00:00 2001 From: Dale Seo Date: Mon, 15 Sep 2025 14:21:28 -0400 Subject: [PATCH 5/5] chore: rename test methods --- .../apollo-mcp-server/src/introspection/tools/introspect.rs | 6 ++++-- crates/apollo-mcp-server/src/introspection/tools/search.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/apollo-mcp-server/src/introspection/tools/introspect.rs b/crates/apollo-mcp-server/src/introspection/tools/introspect.rs index 91f1b07e..4757d013 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/introspect.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/introspect.rs @@ -158,7 +158,7 @@ mod tests { #[rstest] #[tokio::test] - async fn test_tool_description_non_minified(schema: Valid) { + async fn test_introspect_tool_description_is_not_minified(schema: Valid) { let introspect = Introspect::new(Arc::new(Mutex::new(schema)), None, None, false); let description = introspect.tool.description.unwrap(); @@ -176,7 +176,9 @@ mod tests { #[rstest] #[tokio::test] - async fn test_tool_description_minified(schema: Valid) { + async fn test_introspect_tool_description_is_minified_with_an_appropriate_legend( + schema: Valid, + ) { let introspect = Introspect::new(Arc::new(Mutex::new(schema)), None, None, true); let description = introspect.tool.description.unwrap(); diff --git a/crates/apollo-mcp-server/src/introspection/tools/search.rs b/crates/apollo-mcp-server/src/introspection/tools/search.rs index 5d7a5356..6d8a70c2 100644 --- a/crates/apollo-mcp-server/src/introspection/tools/search.rs +++ b/crates/apollo-mcp-server/src/introspection/tools/search.rs @@ -249,7 +249,7 @@ mod tests { #[rstest] #[tokio::test] - async fn test_tool_description_non_minified(schema: Valid) { + async fn test_search_tool_description_is_not_minified(schema: Valid) { let schema = Arc::new(Mutex::new(schema)); let search = Search::new(schema.clone(), false, 1, 15_000_000, false) .expect("Failed to create search tool");