|
Entropic 2.14.3
Local-first agentic inference engine
|
Stdio transport: fork/exec child, pipe stdin/stdout. More...
#include <entropic/mcp/transport_stdio.h>


Public Member Functions | |
| StdioTransport (std::string command, std::vector< std::string > args, std::map< std::string, std::string > env={}, uint32_t default_timeout_ms=30000) | |
| Construct with command, arguments, and environment. | |
| StdioTransport (std::string display_name, std::string command, std::vector< std::string > args, std::map< std::string, std::string > env, uint32_t default_timeout_ms) | |
| Construct with a display name for stderr labeling (gh#19). | |
| ~StdioTransport () override | |
| Destructor — ensures child is cleaned up. | |
| bool | open () override |
| Spawn child process and open pipes. | |
| void | close () override |
| Send SIGTERM, reap the child, join the stderr pump, close pipes. | |
| std::string | send_request (const std::string &request_json, uint32_t timeout_ms=0) override |
| Send JSON-RPC request via stdin, read response from stdout. | |
| bool | is_connected () const override |
| Check if child process is alive. | |
| void | interrupt () override |
| Abort any blocking read and mark transport uncancellable. | |
| void | clear_interrupt () override |
| Release the cancel flag so this transport works again. | |
| bool | request_cancelled () const |
| Whether THIS request must abort (gh#158, v2.13.0). | |
| bool | is_interrupted () const override |
| Whether an interrupt is currently short-circuiting calls. | |
| const std::string & | display_name () const |
| Get the sanitized display name used for stderr labeling. | |
| void | set_working_dir (std::string dir) |
| Set the child's working directory, before connect (gh#166). | |
Stdio transport: fork/exec child, pipe stdin/stdout.
JSON-RPC 2.0 over newline-delimited JSON. Child process lifetime tied to transport lifetime (SIGTERM on close, SIGKILL if needed).
Definition at line 37 of file transport_stdio.h.
| entropic::StdioTransport::StdioTransport | ( | std::string | command, |
| std::vector< std::string > | args, | ||
| std::map< std::string, std::string > | env = {}, |
||
| uint32_t | default_timeout_ms = 30000 |
||
| ) |
Construct with command, arguments, and environment.
| command | Executable to spawn. |
| args | Command-line arguments. |
| env | Environment variable overrides (merged with parent). |
| default_timeout_ms | Default timeout for send_request (0 = 30s). |
| command | Executable to spawn. |
| args | Command-line arguments. |
| env | Environment variable overrides. |
| default_timeout_ms | Default request timeout. @dg_internal |
Definition at line 85 of file transport_stdio.cpp.
| entropic::StdioTransport::StdioTransport | ( | std::string | display_name, |
| std::string | command, | ||
| std::vector< std::string > | args, | ||
| std::map< std::string, std::string > | env, | ||
| uint32_t | default_timeout_ms | ||
| ) |
Construct with a display name for stderr labeling (gh#19).
Construct with explicit display name (gh#19, v2.1.5).
The display name is used as the bracketed label on every child stderr line, replacing the v2.1.4 behavior of using the resolved spawn command (argv[0]). When multiple servers spawn via the same entrypoint (e.g. /usr/bin/env python), the command-based label collides and consumers cannot tell servers apart. The display name (typically the registered server name) is unique per registration and free of leading slashes, which also avoids Rich BBCode parsing collisions on consumers that pipe stderr through rich.console.print.
| display_name | Bracketed label used for stderr lines and lifecycle log messages. Should be the server name passed to entropic_register_mcp_server. |
| command | Executable to spawn. |
| args | Command-line arguments. |
| env | Environment variable overrides. |
| default_timeout_ms | Default timeout for send_request. |
Use this overload when registering an MCP server so stderr lines carry the registered server name instead of the resolved spawn command.
| display_name | Bracketed label for stderr/lifecycle logs. |
| command | Executable to spawn. |
| args | Command-line arguments. |
| env | Environment variable overrides. |
| default_timeout_ms | Default request timeout. @dg_internal |
Definition at line 111 of file transport_stdio.cpp.
|
override |
Destructor — ensures child is cleaned up.
@dg_internal
Definition at line 129 of file transport_stdio.cpp.
|
overridevirtual |
Release the cancel flag so this transport works again.
Release the cancel flag so subsequent calls are attempted.
gh#150: cancel_flag_ was set in exactly one place and cleared in none, so the first interrupt() disabled the transport permanently. AgentEngine::reset_interrupt() now drives this at the start of each run, which is what makes an interrupt scoped to one run rather than to the process.
@req REQ-MCP-025
Driven by AgentEngine::reset_interrupt() at the start of a run, which is what scopes an interrupt to one run instead of to the process.
@req REQ-MCP-025
Reimplemented from entropic::Transport.
Definition at line 370 of file transport_stdio.cpp.
|
overridevirtual |
Send SIGTERM, reap the child, join the stderr pump, close pipes.
gh#158 (v2.13.0): the stderr thread is joined BEFORE the fds are closed. Closing first raced the pump on stderr_fd_ — a ThreadSanitizer finding, and a use-after-close if the number had been handed to another thread's open() in between.
@dg_internal
Implements entropic::Transport.
Definition at line 219 of file transport_stdio.cpp.
|
inline |
Get the sanitized display name used for stderr labeling.
Exposed for unit tests (gh#19) and consumer diagnostics. The value is the bracketed label that appears in log lines from the stderr pump and lifecycle events. Sanitization (leading / stripped, bracket / control chars removed) is applied at construction.
Definition at line 187 of file transport_stdio.h.
|
overridevirtual |
Abort any blocking read and mark transport uncancellable.
Cancel any in-flight read by tripping cancel_flag_.
Sets cancel_flag_ which poll_until_ready() checks after every poll tick. The next send_request() returns empty immediately. (P1-10, 2.0.6-rc16)
read_line / poll_until_ready short-circuit the next poll tick so the pending send_request returns empty within ~50ms (one poll slice). Subsequent send_request calls also early-exit until the flag is cleared by clear_interrupt() or by a successful open().
This is what bounds Ctrl+C to ~100ms instead of waiting out a transport timeout.
gh#150: this doc previously said the flag was "cleared implicitly by a successful open()". It was not, and nothing else cleared it either — the flag was a latch, and one interrupt disabled the transport for the life of the process. The claim is now true because open() and clear_interrupt() below actually implement it. The comment is called out rather than quietly corrected because it cost the reporting consumer a debugging session pointed at the wrong subsystem.
@req REQ-MCP-025
Reimplemented from entropic::Transport.
Definition at line 357 of file transport_stdio.cpp.
|
overridevirtual |
Check if child process is alive.
Check if child process is alive via kill(pid, 0).
Implements entropic::Transport.
Definition at line 325 of file transport_stdio.cpp.
|
overridevirtual |
Whether an interrupt is currently short-circuiting calls.
Whether calls are currently being short-circuited.
Reimplemented from entropic::Transport.
Definition at line 380 of file transport_stdio.cpp.
|
overridevirtual |
Spawn child process and open pipes.
Implements entropic::Transport.
Definition at line 157 of file transport_stdio.cpp.
| bool entropic::StdioTransport::request_cancelled | ( | ) | const |
Whether THIS request must abort (gh#158, v2.13.0).
Whether THIS request should abort (gh#158, v2.13.0).
The handle-wide latch OR the cancel token of the run that issued this call. See the definition for why a per-session interrupt must not use the latch.
Two independent reasons, and they mean different things.
cancel_flag_ is the HANDLE-WIDE latch gh#150 built: set by ServerManager::interrupt_external_tools() on every transport at once, which is what entropic_interrupt() ("stop everything") wants.
current_run_cancelled() is the token of the run that issued THIS call, published to this thread by the engine (RunCancelScope). Once runs are keyed per session, entropic_interrupt_session("A") must abort A's in-flight tool call and leave B's alone — so it sets only A's token and never touches the latch. Reaching for the latch there would abort B and hand it an empty result indistinguishable from a real one, which is the gh#150 defect arriving through a different door.
A transport used outside any run (discovery, the initialize handshake) sees no token and is governed by the latch alone, exactly as before.
Definition at line 408 of file transport_stdio.cpp.
|
overridevirtual |
Send JSON-RPC request via stdin, read response from stdout.
gh#158 (v2.13.0): an abandoned read marks the pipe desynced, and the next request drains the server's late reply before writing. See desynced_.
| request_json | JSON-RPC request string. |
| timeout_ms | Timeout in milliseconds (0 = default). |
| request_json | JSON-RPC request string. |
| timeout_ms | Timeout in ms (0 = the transport's default). |
Implements entropic::Transport.
Definition at line 258 of file transport_stdio.cpp.
|
inline |
Set the child's working directory, before connect (gh#166).
An external MCP server is a separate process that has always taken whatever cwd the HOST happened to have — which makes a repo-scoped server (clew-mcp --repo .) useless once one handle serves several workspaces. ServerManager fills this from its own root.
| dir | Directory to chdir into on spawn ("" = inherit). @req REQ-MCP-027 |
Definition at line 201 of file transport_stdio.h.