Skip to content

Commit 1f899a1

Browse files
author
Matthew Hawkins
committed
Minify introspect return value
1 parent cafb43c commit 1f899a1

File tree

2 files changed

+117
-12
lines changed

2 files changed

+117
-12
lines changed

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

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::errors::McpError;
2+
use crate::introspection::tools::introspect::minify::Minify;
23
use crate::schema_from_type;
34
use crate::schema_tree_shake::{DepthLimit, SchemaTreeShaker};
45
use apollo_compiler::Schema;
@@ -13,6 +14,8 @@ use serde::Deserialize;
1314
use std::sync::Arc;
1415
use tokio::sync::Mutex;
1516

17+
mod minify;
18+
1619
/// The name of the tool to get GraphQL schema type information
1720
pub const INTROSPECT_TOOL_NAME: &str = "introspect";
1821

@@ -37,23 +40,15 @@ pub struct Input {
3740
impl Introspect {
3841
pub fn new(
3942
schema: Arc<Mutex<Valid<Schema>>>,
40-
root_query_type: Option<String>,
43+
_root_query_type: Option<String>,
4144
root_mutation_type: Option<String>,
4245
) -> Self {
4346
Self {
4447
schema,
4548
allow_mutations: root_mutation_type.is_some(),
4649
tool: Tool::new(
4750
INTROSPECT_TOOL_NAME,
48-
format!(
49-
"Get detailed information about types from the GraphQL schema.{}{}",
50-
root_query_type
51-
.map(|t| format!(" Use the type name `{t}` to get root query fields."))
52-
.unwrap_or_default(),
53-
root_mutation_type
54-
.map(|t| format!(" Use the type name `{t}` to get root mutation fields."))
55-
.unwrap_or_default()
56-
),
51+
"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;",
5752
schema_from_type!(Input),
5853
),
5954
}
@@ -113,8 +108,8 @@ impl Introspect {
113108
extended_type.name() != root_name || type_name == root_name.as_str()
114109
})
115110
})
116-
.map(|(_, extended_type)| extended_type.serialize())
117-
.map(|serialized| serialized.to_string())
111+
.map(|(_, extended_type)| extended_type)
112+
.map(ExtendedType::minify)
118113
.map(Content::text)
119114
.collect(),
120115
is_error: None,
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use apollo_compiler::schema::{ExtendedType, Type};
2+
3+
pub trait Minify {
4+
fn minify(&self) -> String;
5+
}
6+
7+
// TODO: descriptions
8+
impl Minify for ExtendedType {
9+
fn minify(&self) -> String {
10+
match self {
11+
ExtendedType::Scalar(scalar_type) => match scalar_type.name.as_str() {
12+
"String" => "s",
13+
"Int" => "i",
14+
"Float" => "f",
15+
"Boolean" => "b",
16+
"ID" => "d",
17+
_ => scalar_type.name.as_str(),
18+
}
19+
.to_string(),
20+
ExtendedType::Object(object_type) => {
21+
let mut fields = String::new();
22+
for (field_name, field) in object_type.fields.iter() {
23+
fields.push_str(field_name.as_str());
24+
if !field.arguments.is_empty() {
25+
fields.push('(');
26+
fields.push_str(
27+
field
28+
.arguments
29+
.iter()
30+
.map(|arg| type_name(&arg.ty))
31+
.collect::<Vec<String>>()
32+
.join(",")
33+
.as_str(),
34+
);
35+
fields.push(')');
36+
}
37+
fields.push(':');
38+
fields.push_str(&type_name(&field.ty));
39+
fields.push(',');
40+
}
41+
fields.pop();
42+
format!("T:{}:{}", object_type.name, fields)
43+
}
44+
ExtendedType::Interface(interface_type) => {
45+
let mut fields = String::new();
46+
for (field_name, field) in interface_type.fields.iter() {
47+
fields.push_str(field_name.as_str());
48+
if !field.arguments.is_empty() {
49+
fields.push('(');
50+
fields.push_str(
51+
field
52+
.arguments
53+
.iter()
54+
.map(|arg| type_name(&arg.ty))
55+
.collect::<Vec<String>>()
56+
.join(",")
57+
.as_str(),
58+
);
59+
fields.push(')');
60+
}
61+
fields.push(':');
62+
fields.push_str(&type_name(&field.ty));
63+
fields.push(',');
64+
}
65+
fields.pop();
66+
format!("F:{}:{}", interface_type.name, fields)
67+
}
68+
ExtendedType::Union(union_type) => {
69+
let mut types = String::new();
70+
for type_name in union_type.members.iter() {
71+
types.push_str(type_name.as_str());
72+
types.push(',');
73+
}
74+
types.pop();
75+
format!("U:{}:{}", union_type.name, types)
76+
}
77+
ExtendedType::Enum(enum_type) => {
78+
let mut values = String::new();
79+
for value in enum_type.values.keys() {
80+
values.push_str(value.as_str());
81+
values.push(',');
82+
}
83+
values.pop();
84+
format!("E:{}:{}", enum_type.name, values)
85+
}
86+
ExtendedType::InputObject(input_object_type) => {
87+
let mut fields = String::new();
88+
for (field_name, field) in input_object_type.fields.iter() {
89+
fields.push_str(field_name.as_str());
90+
fields.push(':');
91+
fields.push_str(&type_name(&field.ty));
92+
fields.push(',');
93+
}
94+
fields.pop();
95+
format!("I:{}:{}", input_object_type.name, fields)
96+
}
97+
}
98+
}
99+
}
100+
101+
fn type_name(ty: &Type) -> String {
102+
let name = ty.inner_named_type().as_str();
103+
if ty.is_list() {
104+
format!("[{name}]")
105+
} else if ty.is_non_null() {
106+
format!("{name}!")
107+
} else {
108+
name.to_string()
109+
}
110+
}

0 commit comments

Comments
 (0)