Skip to content

Commit f44b468

Browse files
authored
Merge pull request #412 from apollographql/singleton-graphql-client
chore: Only initialize a single HTTP client for graphql requests
2 parents 4bbbbe2 + 0179bf0 commit f44b468

File tree

2 files changed

+17
-7
lines changed

2 files changed

+17
-7
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
### chore: Only initialize a single HTTP client for graphql requests - @swcollard PR #412
2+
3+
Currently the MCP Server spins up a new HTTP client every time it wants to make a request to the downstream graphql endpoint. This change creates a static reqwest client that gets initialized using LazyLock and reused on each graphql request.
4+
5+
This change is based on the suggestion from the reqwest [documentation](https://docs.rs/reqwest/latest/reqwest/struct.Client.html)
6+
> "The Client holds a connection pool internally, so it is advised that you create one and reuse it."

crates/apollo-mcp-server/src/graphql.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
//! Execute GraphQL operations from an MCP tool
22
3+
use std::sync::LazyLock;
4+
35
use crate::errors::McpError;
46
use crate::generated::telemetry::{TelemetryAttribute, TelemetryMetric};
57
use crate::meter;
68
use opentelemetry::KeyValue;
79
use reqwest::header::{HeaderMap, HeaderValue};
8-
use reqwest_middleware::{ClientBuilder, Extension};
10+
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware, Extension};
911
use reqwest_tracing::{OtelName, TracingMiddleware};
1012
use rmcp::model::{CallToolResult, Content, ErrorCode};
1113
use serde_json::{Map, Value};
@@ -24,6 +26,13 @@ pub struct OperationDetails {
2426
pub operation_name: Option<String>,
2527
}
2628

29+
static GRAPHQL_CLIENT: LazyLock<ClientWithMiddleware> = LazyLock::new(|| {
30+
ClientBuilder::new(reqwest::Client::new())
31+
.with_init(Extension(OtelName("mcp-graphql-client".into())))
32+
.with(TracingMiddleware::default())
33+
.build()
34+
});
35+
2736
/// Able to be executed as a GraphQL operation
2837
pub trait Executable {
2938
/// Get the persisted query ID to be executed, if any
@@ -86,12 +95,7 @@ pub trait Executable {
8695
}
8796
}
8897

89-
let client = ClientBuilder::new(reqwest::Client::new())
90-
.with_init(Extension(OtelName("mcp-graphql-client".into())))
91-
.with(TracingMiddleware::default())
92-
.build();
93-
94-
let result = client
98+
let result = GRAPHQL_CLIENT
9599
.post(request.endpoint.as_str())
96100
.headers(self.headers(&request.headers))
97101
.body(Value::Object(request_body).to_string())

0 commit comments

Comments
 (0)