pub struct McpServerManager { /* private fields */ }tools only.Expand description
Manages the full lifecycle of multiple local MCP server child processes.
McpServerManager spawns processes, connects them via TokioChildProcess
transport into McpToolset instances, monitors
health, auto-restarts on crash with exponential backoff, and aggregates tools
from all managed servers behind the Toolset trait.
§Construction
Use McpServerManager::new with a map of server configurations, then chain
builder methods to configure handlers and intervals:
use adk_tool::mcp::manager::{McpServerConfig, McpServerManager};
use std::collections::HashMap;
use std::time::Duration;
let configs = HashMap::from([
("my-server".to_string(), McpServerConfig {
command: "/opt/company/bin/workspace-mcp".to_string(),
args: vec!["--stdio".to_string(), "--root".to_string(), "/srv/workspace".to_string()],
..Default::default()
}),
]);
let manager = McpServerManager::new(configs)
.with_health_check_interval(Duration::from_secs(15))
.with_grace_period(Duration::from_secs(3))
.with_name("my_manager");Implementations§
Source§impl McpServerManager
impl McpServerManager
Sourcepub fn new(configs: HashMap<String, McpServerConfig>) -> McpServerManager
Available on crate feature mcp only.
pub fn new(configs: HashMap<String, McpServerConfig>) -> McpServerManager
mcp only.Create a new McpServerManager from a map of server configurations.
Each entry is keyed by a unique server ID. Servers with disabled: true
are initialized with ServerStatus::Disabled; all others start as
ServerStatus::Stopped.
No servers are started automatically — call start_server
or start_all to begin spawning processes.
Sourcepub fn from_json(json: &str) -> Result<McpServerManager, AdkError>
Available on crate feature mcp only.
pub fn from_json(json: &str) -> Result<McpServerManager, AdkError>
mcp only.Create a new McpServerManager by parsing a JSON string in Kiro mcp.json format.
The JSON must contain a top-level mcpServers object mapping server IDs
to their configurations. CamelCase JSON field names are automatically
mapped to snake_case Rust fields.
§Errors
Returns AdkError::Tool if the JSON is malformed or missing required fields.
§Example
let json = r#"{
"mcpServers": {
"workspace": {
"command": "/opt/company/bin/workspace-mcp",
"args": ["--stdio", "--root", "/srv/workspace"]
}
}
}"#;
let manager = McpServerManager::from_json(json)?;Sourcepub fn from_json_file(
path: impl AsRef<Path>,
) -> Result<McpServerManager, AdkError>
Available on crate feature mcp only.
pub fn from_json_file( path: impl AsRef<Path>, ) -> Result<McpServerManager, AdkError>
mcp only.Create a new McpServerManager by reading and parsing a JSON file from disk.
The file must contain JSON in Kiro mcp.json format (see from_json).
File reading is synchronous, which is acceptable for config loading at startup.
§Errors
Returns AdkError::Tool if the file cannot be read or the JSON is malformed.
§Example
let manager = McpServerManager::from_json_file("mcp.json")?;Sourcepub fn with_elicitation_handler(
self,
handler: Arc<dyn ElicitationHandler>,
) -> McpServerManager
Available on crate feature mcp only.
pub fn with_elicitation_handler( self, handler: Arc<dyn ElicitationHandler>, ) -> McpServerManager
mcp only.Set the elicitation handler used for all managed server connections.
The handler is preserved across server restarts via Arc sharing.
Sourcepub fn with_resource_notification_handler(
self,
handler: Arc<dyn ResourceNotificationHandler>,
) -> McpServerManager
Available on crate feature mcp only.
pub fn with_resource_notification_handler( self, handler: Arc<dyn ResourceNotificationHandler>, ) -> McpServerManager
mcp only.Set the resource notification handler used for all managed connections.
The handler is retained across manual and automatic server restarts.
Sourcepub fn with_health_check_interval(self, interval: Duration) -> McpServerManager
Available on crate feature mcp only.
pub fn with_health_check_interval(self, interval: Duration) -> McpServerManager
mcp only.Set the interval between health check cycles.
Default: 30 seconds.
Sourcepub fn with_grace_period(self, period: Duration) -> McpServerManager
Available on crate feature mcp only.
pub fn with_grace_period(self, period: Duration) -> McpServerManager
mcp only.Set the grace period reserved for managed-session shutdown.
Default: 5 seconds.
Sourcepub fn with_name(self, name: impl Into<String>) -> McpServerManager
Available on crate feature mcp only.
pub fn with_name(self, name: impl Into<String>) -> McpServerManager
mcp only.Set the name returned by the Toolset::name() implementation.
Default: "mcp_server_manager".
Sourcepub async fn start_server(&self, id: &str) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn start_server(&self, id: &str) -> Result<(), AdkError>
mcp only.Start a managed MCP server by ID.
Spawns the configured command as a child process, creates a
TokioChildProcess transport, and connects via McpToolset with the
configured elicitation (and optionally sampling) handler.
If the server is already Running, this is a no-op and returns Ok(()).
§Errors
Returns AdkError::Tool if:
- The server ID does not exist
- The child process fails to spawn
- The MCP handshake fails
§Example
manager.start_server("my-server").await?;Sourcepub async fn stop_server(&self, id: &str) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn stop_server(&self, id: &str) -> Result<(), AdkError>
mcp only.Stop a managed MCP server by ID.
Cancels the MCP session via the toolset’s cancellation token, drops the
McpToolset connection, and sets the status to Stopped.
If the server is not running, this is a no-op and returns Ok(()).
§Errors
Returns AdkError::Tool if the server ID does not exist.
§Example
manager.stop_server("my-server").await?;Sourcepub async fn restart_server(&self, id: &str) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn restart_server(&self, id: &str) -> Result<(), AdkError>
mcp only.Restart a managed MCP server by ID.
Sets the status to Restarting, stops the server, then starts it again.
The same ElicitationHandler and SamplingHandler Arcs are preserved
across the restart.
§Errors
Returns AdkError::Tool if:
- The server ID does not exist
- The start phase fails (status set to
FailedToStart)
§Example
manager.restart_server("my-server").await?;Sourcepub async fn server_status(&self, id: &str) -> Result<ServerStatus, AdkError>
Available on crate feature mcp only.
pub async fn server_status(&self, id: &str) -> Result<ServerStatus, AdkError>
mcp only.Return the current ServerStatus for a given server ID.
§Errors
Returns AdkError::Tool if the server ID does not exist.
§Example
let status = manager.server_status("my-server").await?;
assert_eq!(status, ServerStatus::Running);Sourcepub async fn list_server_resources(
&self,
id: &str,
) -> Result<Vec<Resource>, AdkError>
Available on crate feature mcp only.
pub async fn list_server_resources( &self, id: &str, ) -> Result<Vec<Resource>, AdkError>
mcp only.List static resources published by one running managed server.
Sourcepub async fn list_server_resource_templates(
&self,
id: &str,
) -> Result<Vec<ResourceTemplate>, AdkError>
Available on crate feature mcp only.
pub async fn list_server_resource_templates( &self, id: &str, ) -> Result<Vec<ResourceTemplate>, AdkError>
mcp only.List URI templates published by one running managed server.
Sourcepub async fn list_server_prompts(
&self,
id: &str,
) -> Result<Vec<Prompt>, AdkError>
Available on crate feature mcp only.
pub async fn list_server_prompts( &self, id: &str, ) -> Result<Vec<Prompt>, AdkError>
mcp only.List prompt templates published by one running managed server.
Sourcepub async fn read_server_resource(
&self,
id: &str,
uri: &str,
) -> Result<Vec<ResourceContents>, AdkError>
Available on crate feature mcp only.
pub async fn read_server_resource( &self, id: &str, uri: &str, ) -> Result<Vec<ResourceContents>, AdkError>
mcp only.Read one resource from a running managed server.
Sourcepub async fn subscribe_server_resource(
&self,
id: &str,
uri: &str,
) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn subscribe_server_resource( &self, id: &str, uri: &str, ) -> Result<(), AdkError>
mcp only.Subscribe to updates for one resource on a running managed server.
Sourcepub async fn unsubscribe_server_resource(
&self,
id: &str,
uri: &str,
) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn unsubscribe_server_resource( &self, id: &str, uri: &str, ) -> Result<(), AdkError>
mcp only.Remove a resource subscription from one running managed server.
Sourcepub async fn get_server_prompt(
&self,
id: &str,
name: &str,
arguments: Option<Map<String, Value>>,
) -> Result<GetPromptResult, AdkError>
Available on crate feature mcp only.
pub async fn get_server_prompt( &self, id: &str, name: &str, arguments: Option<Map<String, Value>>, ) -> Result<GetPromptResult, AdkError>
mcp only.Resolve one prompt from a running managed server.
Sourcepub async fn all_statuses(&self) -> HashMap<String, ServerStatus>
Available on crate feature mcp only.
pub async fn all_statuses(&self) -> HashMap<String, ServerStatus>
mcp only.Return a map of all server IDs to their current ServerStatus.
§Example
let statuses = manager.all_statuses().await;
for (id, status) in &statuses {
println!("{id}: {status:?}");
}Sourcepub async fn running_server_count(&self) -> usize
Available on crate feature mcp only.
pub async fn running_server_count(&self) -> usize
mcp only.Return the number of servers currently in ServerStatus::Running status.
§Example
let count = manager.running_server_count().await;
println!("{count} servers running");Sourcepub fn start_monitoring(&self)
Available on crate feature mcp only.
pub fn start_monitoring(&self)
mcp only.Start the background health monitoring task.
Spawns a tokio::spawn task that periodically checks each Running
server by calling McpToolset::is_closed().
If a server’s connection is closed, the monitor sets its status to
Crashed and, if a RestartPolicy is configured, attempts auto-restart
with exponential backoff.
The monitoring loop runs until stop_monitoring
is called, which cancels the background task via the internal
CancellationToken.
§Example
manager.start_monitoring();
// ... later ...
manager.stop_monitoring();Sourcepub fn stop_monitoring(&self)
Available on crate feature mcp only.
pub fn stop_monitoring(&self)
mcp only.Stop the background health monitoring task.
Cancels the monitoring loop spawned by start_monitoring.
This is a no-op if monitoring was never started or has already been stopped.
§Example
manager.stop_monitoring();Sourcepub async fn add_server(
&self,
id: String,
config: McpServerConfig,
) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn add_server( &self, id: String, config: McpServerConfig, ) -> Result<(), AdkError>
mcp only.Register a new server configuration at runtime.
The new server is initialized with ServerStatus::Disabled if
config.disabled is true, or ServerStatus::Stopped otherwise.
It will not be started automatically — call
start_server to begin spawning the process.
§Errors
Returns AdkError::Tool if a server with the given ID already exists.
§Example
let config = McpServerConfig {
command: "/opt/company/bin/billing-mcp".to_string(),
args: vec!["--stdio".to_string()],
..Default::default()
};
manager.add_server("new-server".to_string(), config).await?;Sourcepub async fn server_config(&self, id: &str) -> Result<McpServerConfig, AdkError>
Available on crate feature mcp only.
pub async fn server_config(&self, id: &str) -> Result<McpServerConfig, AdkError>
mcp only.Return a copy of one server’s current configuration.
Sourcepub async fn all_configs(&self) -> HashMap<String, McpServerConfig>
Available on crate feature mcp only.
pub async fn all_configs(&self) -> HashMap<String, McpServerConfig>
mcp only.Return a snapshot of every managed server configuration.
Sourcepub async fn update_server(
&self,
id: &str,
config: McpServerConfig,
) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn update_server( &self, id: &str, config: McpServerConfig, ) -> Result<(), AdkError>
mcp only.Replace a server configuration at runtime.
A running server is stopped and restarted with the new configuration. If the replacement fails to start, the previous configuration is restored and restarted before the error is returned.
Sourcepub async fn enable_server(&self, id: &str) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn enable_server(&self, id: &str) -> Result<(), AdkError>
mcp only.Enable a disabled server without starting it.
Sourcepub async fn disable_server(&self, id: &str) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn disable_server(&self, id: &str) -> Result<(), AdkError>
mcp only.Stop and disable a server until it is explicitly enabled again.
Sourcepub async fn to_json(&self) -> Result<String, AdkError>
Available on crate feature mcp only.
pub async fn to_json(&self) -> Result<String, AdkError>
mcp only.Serialize the current in-memory configuration as compatible mcp.json.
Sourcepub async fn save_json_file(
&self,
path: impl AsRef<Path>,
) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn save_json_file( &self, path: impl AsRef<Path>, ) -> Result<(), AdkError>
mcp only.Persist the current configuration using an atomic temporary-file rename.
Sourcepub async fn remove_server(&self, id: &str) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn remove_server(&self, id: &str) -> Result<(), AdkError>
mcp only.Sourcepub async fn start_all(&self) -> HashMap<String, Result<(), AdkError>>
Available on crate feature mcp only.
pub async fn start_all(&self) -> HashMap<String, Result<(), AdkError>>
mcp only.Start all non-disabled servers and report each result independently.
Collects all server IDs where disabled == false, then starts each one
via start_server. Failures are logged but do not
prevent other servers from starting. Registry mutations are serialized
while each child process completes its MCP handshake.
§Returns
A HashMap<String, Result<()>> with per-server outcomes. Disabled servers
are not included in the result.
§Example
let results = manager.start_all().await;
for (id, result) in &results {
match result {
Ok(()) => println!("{id}: started"),
Err(e) => eprintln!("{id}: failed to start: {e}"),
}
}Sourcepub async fn shutdown(&self) -> Result<(), AdkError>
Available on crate feature mcp only.
pub async fn shutdown(&self) -> Result<(), AdkError>
mcp only.Shut down all managed servers and stop health monitoring.
This method first stops the health monitoring task, then stops all
running servers by cancelling their MCP sessions and dropping the child
transports. After shutdown, all server statuses are set to Stopped.
§Example
manager.shutdown().await?;
// All servers are now stopped, safe to drop the managerTrait Implementations§
Source§impl Drop for McpServerManager
impl Drop for McpServerManager
Source§impl Toolset for McpServerManager
impl Toolset for McpServerManager
Source§fn tools<'life0, 'async_trait>(
&'life0 self,
ctx: Arc<dyn ReadonlyContext>,
) -> Pin<Box<dyn Future<Output = Result<Vec<Arc<dyn Tool>>, AdkError>> + Send + 'async_trait>>where
'life0: 'async_trait,
McpServerManager: 'async_trait,
fn tools<'life0, 'async_trait>(
&'life0 self,
ctx: Arc<dyn ReadonlyContext>,
) -> Pin<Box<dyn Future<Output = Result<Vec<Arc<dyn Tool>>, AdkError>> + Send + 'async_trait>>where
'life0: 'async_trait,
McpServerManager: 'async_trait,
Auto Trait Implementations§
impl !Freeze for McpServerManager
impl !RefUnwindSafe for McpServerManager
impl !UnwindSafe for McpServerManager
impl Send for McpServerManager
impl Sync for McpServerManager
impl Unpin for McpServerManager
impl UnsafeUnpin for McpServerManager
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> MaybeSend for Twhere
T: Send,
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.