Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,30 @@ cargo doc --no-deps
cargo llvm-cov --all-features --workspace --codecov --output-path codecov.json
```

## Runtime Quick Reference

- Start with config file: `cargo run -p apollo-mcp-server -- path/to/config.yaml`
- Start from env only: `cargo run -p apollo-mcp-server`
- Config precedence: `APOLLO_MCP_*` env overrides YAML values.
- Supported transports: `stdio` (default) and `streamable_http`; `sse` is not supported.
- YAML env expansion supports `${env.VAR}` and `${env.VAR:-default}`.

### Common Config Keys

- Top-level keys: `endpoint`, `transport`, `operations`, `schema`, `introspection`, `graphos`, `overrides`, `headers`, `forward_headers`, `health_check`, `cors`, `telemetry`, `logging`, `server_info`, `custom_scalars`.
- `auth` must be nested under `transport` (not top-level).
- `operations.source`: `infer` (default), `local`, `manifest`, `collection`, `introspect`, `uplink`.
- `schema.source`: `local` or `uplink`.

### Useful Env Vars

- GraphOS mapping:
- `APOLLO_GRAPH_REF` -> `graphos.apollo_graph_ref`
- `APOLLO_KEY` -> `graphos.apollo_key`
- `APOLLO_UPLINK_ENDPOINTS` -> `graphos.apollo_uplink_endpoints`
- Nested config override format: `APOLLO_MCP_<SECTION>__<NESTED_KEY>=...`
- Example: `APOLLO_MCP_INTROSPECTION__EXECUTE__ENABLED=true`

## Workspace Structure

The project is a Rust workspace with three crates:
Expand Down
3 changes: 0 additions & 3 deletions crates/apollo-mcp-server/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ pub enum ServerError {

#[error("TLS configuration error: {0}")]
Tls(#[from] crate::auth::TlsConfigError),

#[error("Unsupported transport: {0}")]
UnsupportedTransport(String),
}

/// An MCP tool error
Expand Down
19 changes: 10 additions & 9 deletions crates/apollo-mcp-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,16 @@ async fn main() -> anyhow::Result<()> {
.disable_type_description(config.overrides.disable_type_description)
.disable_schema_description(config.overrides.disable_schema_description)
.enable_output_schema(config.overrides.enable_output_schema)
.disable_auth_token_passthrough(match transport {
apollo_mcp_server::server::Transport::Stdio => false,
apollo_mcp_server::server::Transport::SSE { auth, .. } => auth
.map(|a| a.disable_auth_token_passthrough)
.unwrap_or(false),
apollo_mcp_server::server::Transport::StreamableHttp { auth, .. } => auth
.map(|a| a.disable_auth_token_passthrough)
.unwrap_or(false),
})
.disable_auth_token_passthrough(
if let apollo_mcp_server::server::Transport::StreamableHttp {
auth: Some(auth), ..
} = &transport
{
auth.disable_auth_token_passthrough
} else {
false
},
)
.custom_scalar_map(
config
.custom_scalars
Expand Down
49 changes: 30 additions & 19 deletions crates/apollo-mcp-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,29 +61,11 @@ pub enum Transport {
#[default]
Stdio,

/// Host the MCP server on the supplied configuration, using SSE for communication
///
/// Note: This is deprecated in favor of HTTP streams.
#[serde(rename = "sse")]
SSE {
/// Authentication configuration
#[serde(default)]
auth: Option<auth::Config>,

/// The IP address to bind to
#[serde(default = "Transport::default_address")]
address: IpAddr,

/// The port to bind to
#[serde(default = "Transport::default_port")]
port: u16,
},

/// Host the MCP server on the configuration, using streamable HTTP messages.
StreamableHttp {
/// Authentication configuration
#[serde(default)]
auth: Option<auth::Config>,
auth: Option<Box<auth::Config>>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to double check the intent behind this Box. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it, you will run into this linting issue:

error: large size difference between variants
  --> crates/apollo-mcp-server/src/server.rs:59:1
   |
59 | /  pub enum Transport {
60 | |      /// Use standard IO for server <> client communication
61 | |      #[default]
62 | |      Stdio,
   | |      ----- the second-largest variant carries no data at all
...  |
65 | |/     StreamableHttp {
66 | ||         /// Authentication configuration
67 | ||         #[serde(default)]
68 | ||         auth: Option<auth::Config>,
...  ||
84 | ||         host_validation: HostValidationConfig,
85 | ||     },
   | ||_____- the largest variant contains at least 356 bytes
86 | |  }
   | |__^ the entire enum is at least 360 bytes
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#large_enum_variant
   = note: `-D clippy::large-enum-variant` implied by `-D warnings`
   = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]`
help: consider boxing the large fields or introducing indirection in some other way to reduce the total size of the enum
   |
68 -         auth: Option<auth::Config>,
68 +         auth: Box<Option<auth::Config>>,
   |

error: could not compile `apollo-mcp-server` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `apollo-mcp-server` (lib test) due to 1 previous error


/// The IP address to bind to
#[serde(default = "Transport::default_address")]
Expand Down Expand Up @@ -191,3 +173,32 @@ impl Server {
StateMachine {}.start(self).await
}
}

#[cfg(test)]
mod tests {
use super::Transport;

#[test]
fn sse_transport_is_rejected_at_parse_time() {
let yaml = "type: sse\nport: 8000";
let result = serde_yaml::from_str::<Transport>(yaml);
assert!(result.is_err(), "Expected SSE transport to be rejected");
}

#[test]
fn stdio_transport_parses() {
let yaml = "type: stdio";
let result = serde_yaml::from_str::<Transport>(yaml);
assert!(result.is_ok(), "Expected stdio transport to parse");
}

#[test]
fn streamable_http_transport_parses() {
let yaml = "type: streamable_http\nport: 9000";
let result = serde_yaml::from_str::<Transport>(yaml);
assert!(
result.is_ok(),
"Expected streamable_http transport to parse"
);
}
}
65 changes: 2 additions & 63 deletions crates/apollo-mcp-server/src/server/states/starting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ impl Starting {

let cancellation_token = CancellationToken::new();

// Create health check if enabled (only for StreamableHttp transport)
// Create health checks only when StreamableHttp transport is enabled.
let health_check = match (&self.config.transport, self.config.health_check.enabled) {
(Transport::StreamableHttp { .. }, true) => {
Some(HealthCheck::new(self.config.health_check.clone()))
}
_ => None, // No health check for SSE, Stdio, or when disabled
_ => None, // No health checks for Stdio or when disabled.
};

let running = Running {
Expand Down Expand Up @@ -261,18 +261,6 @@ impl Starting {
}
});
}
Transport::SSE {
auth: _,
address: _,
port: _,
} => {
// SSE transport has been removed in rmcp 0.11+
// Users should migrate to streamable_http transport
return Err(ServerError::UnsupportedTransport(
"SSE transport is no longer supported. Please use streamable_http transport instead. \
Update your config to use `transport: { type: streamable_http }`.".to_string()
));
}
Transport::Stdio => {
info!("Starting MCP server in stdio mode");
let service = running
Expand Down Expand Up @@ -348,53 +336,4 @@ mod tests {
let running = starting.start();
assert!(running.await.is_ok());
}

#[tokio::test]
async fn start_sse_server_returns_unsupported_error() {
let starting = Starting {
config: Config {
transport: Transport::SSE {
auth: None,
address: "127.0.0.1".parse().unwrap(),
port: 7798,
},
endpoint: Url::parse("http://localhost:4000").expect("valid url"),
mutation_mode: MutationMode::All,
execute_introspection: true,
headers: HeaderMap::new(),
forward_headers: vec![],
validate_introspection: true,
introspect_introspection: true,
search_introspection: true,
introspect_minify: false,
search_minify: false,
execute_tool_hint: None,
introspect_tool_hint: None,
search_tool_hint: None,
validate_tool_hint: None,
explorer_graph_ref: None,
custom_scalar_map: None,
disable_type_description: false,
disable_schema_description: false,
enable_output_schema: false,
disable_auth_token_passthrough: false,
search_leaf_depth: 5,
index_memory_bytes: 1024 * 1024 * 1024,
health_check: HealthCheckConfig::default(),
cors: Default::default(),
server_info: Default::default(),
},
schema: Schema::parse_and_validate("type Query { hello: String }", "test.graphql")
.expect("Valid schema"),
operations: vec![],
};
let result = starting.start().await;
match result {
Err(ServerError::UnsupportedTransport(msg)) => {
assert!(msg.contains("SSE transport is no longer supported"));
}
Err(e) => panic!("Expected UnsupportedTransport error, got: {:?}", e),
Ok(_) => panic!("Expected error, got Ok"),
}
}
}
6 changes: 6 additions & 0 deletions docs/source/config-file.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@
| `"stdio"` | Use standard IO for communication between the server and client |
| `"streamable_http"` | Host the MCP server on the configuration, using streamable HTTP messages |

<Note>

SSE transport is no longer supported by Apollo MCP Server. Use `streamable_http` for HTTP-based connections.

Check notice on line 232 in docs/source/config-file.mdx

View check run for this annotation

Apollo Librarian / AI Style Review

docs/source/config-file.mdx#L232

Use active voice to make the instruction more direct and clear. ```suggestion Apollo MCP Server no longer supports SSE transport. Use `streamable_http` for HTTP-based connections. ```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be helpful to add a version number here if there's a large chance folks are still using older versions! "no longer supported by Apollo MCP Server as of vx.x.x"


</Note>

##### Transport Type Specific options

Some transport types support further configuration. For `streamable_http`, you can set `address`, `port`, `stateful_mode`, and `host_validation`.
Expand Down
Loading