From eea1599a517734f269a083d830f3e64ab69604e2 Mon Sep 17 00:00:00 2001 From: leonid-zats <57621436+leonid-zats@users.noreply.github.com> Date: Sun, 12 Oct 2025 15:43:58 +0300 Subject: [PATCH 1/3] refresh token --- Cargo.lock | 261 ++++++++++-------- .../apollo-mcp-server/src/config_manager.rs | 4 +- crates/apollo-mcp-server/src/main.rs | 37 ++- crates/apollo-mcp-server/src/token_manager.rs | 3 + 4 files changed, 194 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70b9862c..72a05e2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -629,6 +629,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.42" @@ -768,9 +774,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -1182,21 +1188,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1361,9 +1352,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasi 0.14.7+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -1630,31 +1623,32 @@ dependencies = [ ] [[package]] -name = "hyper-timeout" -version = "0.5.2" +name = "hyper-rustls" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ + "http", "hyper", "hyper-util", - "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pki-types", "tokio", + "tokio-rustls", "tower-service", ] [[package]] -name = "hyper-tls" -version = "0.6.0" +name = "hyper-timeout" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "bytes", - "http-body-util", "hyper", "hyper-util", - "native-tls", + "pin-project-lite", "tokio", - "tokio-native-tls", "tower-service", ] @@ -2129,6 +2123,12 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lz-str" version = "0.2.1" @@ -2258,23 +2258,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nom" version = "7.1.3" @@ -2470,60 +2453,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea" -[[package]] -name = "openssl" -version = "0.10.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "openssl-probe" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" -[[package]] -name = "openssl-src" -version = "300.5.3+3.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - [[package]] name = "opentelemetry" version = "0.30.0" @@ -2904,6 +2839,61 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2", + "thiserror 2.0.17", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.17", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.41" @@ -3102,20 +3092,22 @@ dependencies = [ "http-body", "http-body-util", "hyper", - "hyper-tls", + "hyper-rustls", "hyper-util", "js-sys", "log", - "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -3322,15 +3314,53 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "rustls" +version = "0.23.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ + "web-time", "zeroize", ] +[[package]] +name = "rustls-webpki" +version = "0.103.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -3406,9 +3436,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.1" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ "bitflags 2.9.4", "core-foundation", @@ -3698,6 +3728,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -4018,6 +4054,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.47.1" @@ -4050,12 +4101,12 @@ dependencies = [ ] [[package]] -name = "tokio-native-tls" -version = "0.3.1" +name = "tokio-rustls" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "native-tls", + "rustls", "tokio", ] @@ -4498,12 +4549,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" diff --git a/crates/apollo-mcp-server/src/config_manager.rs b/crates/apollo-mcp-server/src/config_manager.rs index 9cf763cd..0344c772 100644 --- a/crates/apollo-mcp-server/src/config_manager.rs +++ b/crates/apollo-mcp-server/src/config_manager.rs @@ -44,7 +44,9 @@ impl ConfigManager { .lines() .map(|line| { if line.contains("Authorization: Bearer") { - format!("Authorization: Bearer {}", new_token) + // Preserve leading whitespace (indentation) + let indent = line.chars().take_while(|c| c.is_whitespace()).collect::(); + format!("{}Authorization: Bearer {}", indent, new_token) } else { line.to_string() } diff --git a/crates/apollo-mcp-server/src/main.rs b/crates/apollo-mcp-server/src/main.rs index 0d80e937..7fae33b1 100644 --- a/crates/apollo-mcp-server/src/main.rs +++ b/crates/apollo-mcp-server/src/main.rs @@ -7,6 +7,7 @@ use apollo_mcp_server::custom_scalar_map::CustomScalarMap; use apollo_mcp_server::errors::ServerError; use apollo_mcp_server::operations::OperationSource; use apollo_mcp_server::server::Server; +use apollo_mcp_server::startup; use clap::Parser; use clap::builder::Styles; use clap::builder::styling::{AnsiColor, Effects}; @@ -36,8 +37,12 @@ struct Args { #[tokio::main] async fn main() -> anyhow::Result<()> { - let config: runtime::Config = match Args::parse().config { - Some(config_path) => runtime::read_config(config_path)?, + let args = Args::parse(); + let config_path = args.config.clone(); + + // Read config for initial setup (telemetry) + let mut config: runtime::Config = match config_path.clone() { + Some(ref path) => runtime::read_config(path.clone())?, None => runtime::read_config_from_env().unwrap_or_default(), }; @@ -48,6 +53,34 @@ async fn main() -> anyhow::Result<()> { env!("CARGO_PKG_VERSION") ); + // Check if token refresh is enabled + if startup::is_token_refresh_enabled() { + if let (Some(refresh_token), Some(refresh_url), Some(graphql_endpoint), Some(config_file)) = ( + startup::get_refresh_token(), + startup::get_refresh_url(), + startup::get_graphql_endpoint(), + config_path.as_ref(), + ) { + info!("Token refresh enabled, initializing..."); + if let Err(e) = startup::initialize_with_token_refresh( + config_file.to_string_lossy().to_string(), + refresh_token, + refresh_url, + graphql_endpoint, + ) + .await + { + warn!("Token refresh initialization failed: {}", e); + } else { + // Re-read config to get the refreshed token + info!("Re-reading config file to load refreshed token..."); + config = runtime::read_config(config_file.clone())?; + } + } else { + warn!("Token refresh enabled but missing required environment variables"); + } + } + let schema_source = match config.schema { runtime::SchemaSource::Local { path } => SchemaSource::File { path, watch: true }, runtime::SchemaSource::Uplink => SchemaSource::Registry(config.graphos.uplink_config()?), diff --git a/crates/apollo-mcp-server/src/token_manager.rs b/crates/apollo-mcp-server/src/token_manager.rs index e688bf7e..c51aa9ef 100644 --- a/crates/apollo-mcp-server/src/token_manager.rs +++ b/crates/apollo-mcp-server/src/token_manager.rs @@ -10,12 +10,15 @@ use tracing::{debug, error, info, warn}; #[derive(Debug, Serialize)] struct RefreshTokenRequest { + #[serde(rename = "refreshToken")] refresh_token: String, } #[derive(Debug, Deserialize)] struct RefreshTokenResponse { + #[serde(rename = "accessToken")] access_token: String, + #[serde(rename = "expiresIn")] expires_in: Option, } From 47a2db6d20643564fb5544d8216a914d610feeba Mon Sep 17 00:00:00 2001 From: leonid-zats <57621436+leonid-zats@users.noreply.github.com> Date: Sun, 12 Oct 2025 16:06:38 +0300 Subject: [PATCH 2/3] fixes --- crates/apollo-mcp-server/src/config_manager.rs | 5 ++++- crates/apollo-mcp-server/src/main.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/apollo-mcp-server/src/config_manager.rs b/crates/apollo-mcp-server/src/config_manager.rs index 0344c772..7a6a96a0 100644 --- a/crates/apollo-mcp-server/src/config_manager.rs +++ b/crates/apollo-mcp-server/src/config_manager.rs @@ -45,7 +45,10 @@ impl ConfigManager { .map(|line| { if line.contains("Authorization: Bearer") { // Preserve leading whitespace (indentation) - let indent = line.chars().take_while(|c| c.is_whitespace()).collect::(); + let indent = line + .chars() + .take_while(|c| c.is_whitespace()) + .collect::(); format!("{}Authorization: Bearer {}", indent, new_token) } else { line.to_string() diff --git a/crates/apollo-mcp-server/src/main.rs b/crates/apollo-mcp-server/src/main.rs index 7fae33b1..00c16aca 100644 --- a/crates/apollo-mcp-server/src/main.rs +++ b/crates/apollo-mcp-server/src/main.rs @@ -39,7 +39,7 @@ struct Args { async fn main() -> anyhow::Result<()> { let args = Args::parse(); let config_path = args.config.clone(); - + // Read config for initial setup (telemetry) let mut config: runtime::Config = match config_path.clone() { Some(ref path) => runtime::read_config(path.clone())?, From 0eff5ae2eba3cdc63368fc4b099e7378389a5721 Mon Sep 17 00:00:00 2001 From: leonid-zats <57621436+leonid-zats@users.noreply.github.com> Date: Sun, 12 Oct 2025 16:06:47 +0300 Subject: [PATCH 3/3] Update ci.yml --- .github/workflows/ci.yml | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 947ad89e..e8d490f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,39 +78,3 @@ jobs: - name: Check documentation run: cargo doc --no-deps --workspace - - build: - name: Build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - - - name: Cache cargo registry - uses: actions/cache@v4 - with: - path: ~/.cargo/registry - key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo index - uses: actions/cache@v4 - with: - path: ~/.cargo/git - key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo build - uses: actions/cache@v4 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - - - name: Build release binary - run: cargo build --release --package apollo-mcp-server - - - name: Upload binary artifact - uses: actions/upload-artifact@v4 - with: - name: apollo-mcp-server-linux-x86_64 - path: target/release/apollo-mcp-server