← ./articles

For rmcp StreamableHttpServerConfig, Use the Builder Instead of a Struct Literal

Rust's #[non_exhaustive] is not a nuisance. It is part of the API contract.

In rmcp, StreamableHttpServerConfig is a non-exhaustive struct. If you try to construct it with a struct literal from another crate, the compiler is supposed to stop you. Use the provided builder-style methods instead.

The symptom: struct literal configuration fails

The broken shape looks like this:

let config = StreamableHttpServerConfig {
    allowed_hosts: vec!["localhost".to_string()],
};

For a non-exhaustive struct, downstream crates cannot assume they know every field. Future versions may add fields without making existing builder-based code source-incompatible.

The fix is not to fight the compiler. Use the public construction path.

Use default plus with_allowed_hosts

Use default() and the builder method:

use rmcp::transport::streamable_http_server::tower::StreamableHttpServerConfig;

let config = StreamableHttpServerConfig::default()
    .with_allowed_hosts(["localhost", "127.0.0.1", "::1"]);

This keeps your code compatible with the crate's intended configuration surface.

Make DNS rebinding protection explicit

Allowed hosts are not just convenience. They are part of the HTTP server's DNS rebinding protection story.

Even if the default already limits hosts to loopback names, setting them explicitly can make the security boundary visible at the call site:

let allowed_hosts = ["localhost", "127.0.0.1", "::1"];

let config = StreamableHttpServerConfig::default()
    .with_allowed_hosts(allowed_hosts);

That is easier to review than relying on a default hidden behind library code.

Do not widen hosts casually

Be careful with:

  • 0.0.0.0
  • LAN IPs
  • wildcard host behavior
  • reverse proxy host rewrites
  • public tunnels

If the MCP server is meant to be local-only, the host allowlist should say so. If it is intentionally exposed beyond loopback, document the authentication and network boundary separately.

Why this matters for MCP servers

MCP tools may expose local files, project state, logs, or privileged app actions. A transport config mistake can turn a local integration into a network-accessible endpoint.

Configuration code is security code when it decides who can connect.

Verification checklist

Before shipping:

  • compile from a clean checkout
  • confirm no struct literal is used for non-exhaustive config
  • set allowed hosts explicitly
  • test localhost, 127.0.0.1, and an unallowed host
  • document whether the server is loopback-only
  • avoid exposing local MCP servers through tunnels without a separate security review

References