Skip to content

Commit ab881a4

Browse files
authored
fix: Validate ExecutableDocument in validate tool (#329)
The validate tool was parsing the operation passed in to it against the schema but it wasn't performing the validate function on the `ExecutableDocument` returned by the Parser. This led to cases where missing required arguments were not caught by the Tool. This change also updates the input schema to the execute tool to make it more clear to the LLM that it needs to provide a valid JSON object
1 parent eedc53e commit ab881a4

File tree

5 files changed

+55
-4
lines changed

5 files changed

+55
-4
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
### fix: Validate ExecutableDocument in validate tool - @swcollard PR #329
2+
3+
Contains fixes for https://github.com/apollographql/apollo-mcp-server/issues/327
4+
5+
The validate tool was parsing the operation passed in to it against the schema but it wasn't performing the validate function on the ExecutableDocument returned by the Parser. This led to cases where missing required arguments were not caught by the Tool.
6+
7+
This change also updates the input schema to the execute tool to make it more clear to the LLM that it needs to provide a valid JSON object

crates/apollo-mcp-server/src/introspection/tools/execute.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ pub struct Input {
2626
/// The GraphQL operation
2727
query: String,
2828

29-
/// The variable values
29+
/// The variable values represented as JSON
30+
#[schemars(schema_with = "String::json_schema", default)]
3031
variables: Option<Value>,
3132
}
3233

crates/apollo-mcp-server/src/introspection/tools/validate.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ impl Validate {
6464
let schema_guard = self.schema.lock().await;
6565
Parser::new()
6666
.parse_executable(&schema_guard, input.operation.as_str(), "operation.graphql")
67+
.map_err(|e| McpError::new(ErrorCode::INVALID_PARAMS, e.to_string(), None))?
68+
.validate(&schema_guard)
6769
.map_err(|e| McpError::new(ErrorCode::INVALID_PARAMS, e.to_string(), None))?;
6870
Ok(CallToolResult {
6971
content: vec![Content::text("Operation is valid")],
@@ -80,7 +82,11 @@ mod tests {
8082
static SCHEMA: std::sync::LazyLock<Arc<Mutex<Valid<Schema>>>> =
8183
std::sync::LazyLock::new(|| {
8284
Arc::new(Mutex::new(
83-
Schema::parse_and_validate("type Query { id: ID! }", "schema.graphql").unwrap(),
85+
Schema::parse_and_validate(
86+
"type Query { id: ID! hello(name: String!): String! }",
87+
"schema.graphql",
88+
)
89+
.unwrap(),
8490
))
8591
});
8692

@@ -110,4 +116,13 @@ mod tests {
110116
});
111117
assert!(validate.execute(input).await.is_err());
112118
}
119+
120+
#[tokio::test]
121+
async fn validate_invalid_argument() {
122+
let validate = Validate::new(SCHEMA.clone());
123+
let input = json!({
124+
"operation": "query { hello }"
125+
});
126+
assert!(validate.execute(input).await.is_err());
127+
}
113128
}

e2e/mcp-server-tester/local-operations/tool-tests.yaml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,18 @@ tools:
6262
expect:
6363
success: false
6464
error:
65-
contains: 'Error: type `Launch` does not have a field `invalid`'
65+
contains: 'Error: type `Launch` does not have a field `invalid`'
66+
67+
- name: 'Validates a launches query with an missing argument'
68+
tool: 'validate'
69+
params:
70+
operation: >
71+
query Agency {
72+
agency {
73+
id
74+
}
75+
}
76+
expect:
77+
success: false
78+
error:
79+
contains: 'Error: the required argument `Query.agency(id:)` is not provided'

e2e/mcp-server-tester/pq-manifest/tool-tests.yaml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,18 @@ tools:
6262
expect:
6363
success: false
6464
error:
65-
contains: 'Error: type `Launch` does not have a field `invalid`'
65+
contains: 'Error: type `Launch` does not have a field `invalid`'
66+
67+
- name: 'Validates a launches query with an missing argument'
68+
tool: 'validate'
69+
params:
70+
operation: >
71+
query Agency {
72+
agency {
73+
id
74+
}
75+
}
76+
expect:
77+
success: false
78+
error:
79+
contains: 'Error: the required argument `Query.agency(id:)` is not provided'

0 commit comments

Comments
 (0)