Skip to main content
Glama
woffko

codex-mcp-longrun

by woffko

Codex MCP Longrun

Codex MCP Longrun is a local STDIO MCP server for bounded, non-interactive command jobs. Its asynchronous workflow returns a job ID promptly so Codex does not need to keep a blocking tool call alive through model-visible wait loops. The experimental codex-longrun launcher can pause a durable Goal while the command runs and reactivate that exact Goal once terminal metadata exists.

It is intended for builds, test suites, packaging jobs, and similar trusted foreground commands. The local server validates the request, supervises the process group, captures bounded output, and persists terminal metadata.

Codex calls longrun.start_job once through codex-longrun
                  |
                  v
The local MCP server starts the command,
returns a job ID, and the bridge pauses the Goal
                  |
                  v
Codex ends the turn; the command runs without model polling
                  |
                  v
Terminal event -> idle check -> Goal reactivated once

The project is currently a Linux/WSL pilot, not a production release.

IMPORTANT

This README describes theexperimental branch and package version 0.4.0a7. Its recommended Goal workflow is codex-longrun plus start_job(wake_policy="goal"). The manual Goal and blocking workflows are compatibility fallbacks and must not be combined with automatic wakeup.

Why use it

Repeatedly checking a long build with model-visible polling tools consumes context and may require additional model turns even when nothing changed. start_job avoids keeping the original tool call pending. It does not make the initial submission or resumed result turn token-free. In an ordinary codex process it cannot wake an idle thread; the opt-in launcher adds that client-side capability through the official experimental App Server protocol.

Current Codex clients may turn a blocking MCP call into an outer executor cell and ask the model to wait for that cell repeatedly. run_and_wait remains a compatibility tool, but the installer exposes it so a Goal can require the verified one-call workflow explicitly. Prefer start_job unless the current client has been verified to keep the original MCP call pending.

While a legacy blocking call remains pending, the server can emit a short MCP progress heartbeat. Heartbeats are disabled by default because they do not prevent an outer Codex executor from yielding. When explicitly enabled, a heartbeat contains only elapsed time, time since the last output, and the number of captured bytes; it never contains command output.

The MCP and Codex documentation does not define a billing or model-token guarantee for progress notifications. Keep them disabled unless a specific client has been verified to render progress without re-entering the model.

Related MCP server: mcp-stdio

Tools

Tool

Purpose

health

Report the version, state paths, allowed roots, and active guardrails

start_job

Start one command and optionally arm a durable Goal wake lease

get_job

Read one bounded status or terminal result for a known job ID

cancel_job

Request process-group cancellation for one exact job ID

run_and_wait

Legacy blocking compatibility mode; exposed for explicit one-call workflows

read_log_tail

Read a bounded tail for a known job ID

Do not repeatedly call get_job in the same turn. Automatic Goal wakeup is available only when Codex was started through codex-longrun and the returned status says automatic_wakeup = true.

One-time secret stdin

Never put a password in argv, an MCP argument, an environment variable, a prompt, or a shell command line.

When a suitable encrypted test-only asset exists in Project Memory, Codex should stage it directly without revealing the value or asking the user to type it again:

project_memory_stage_test_asset_for_longrun(
  project="Product/lab",
  record_id="TEST_ASSET_ID",
  secret_field="password"
)
    -> stdin_secret_id="ONE_TIME_HANDLE"

longrun.start_job(
  argv=[...],
  cwd="/absolute/enrolled/root",
  stdin_secret_id="ONE_TIME_HANDLE",
  wake_policy="goal"
)

Project Memory decrypts locally and returns only the random handle. The model never receives the plaintext. This works in ordinary codex too; use wake_policy="none" there because automatic Goal wakeup requires the codex-longrun launcher.

Only when no suitable encrypted asset is enrolled, stage one finite password or token outside Codex in a second terminal:

~/.local/share/codex-longrun-mcp/.venv/bin/codex-longrun-secret --confirm

The fallback prompt uses getpass; typed characters are not echoed. Stdout contains only a random 32-character one-time handle. Copy that handle—not the password—into the Codex request:

Run the reviewed command with longrun.start_job, the normal argv and cwd,
stdin_secret_id="ONE_TIME_HANDLE", and wake_policy="goal". Never place the
secret value itself in any tool argument.

The handle expires after five minutes by default and is consumed once. The server validates the backing file's owner, 0600 mode, link count, type, age, and size with O_NOFOLLOW; it opens and immediately unlinks the file, then passes only the open descriptor to the supervised command's stdin. The handle and secret content are not stored in job metadata.

Secret-stdin jobs always suppress stdout and stderr capture. Their log and tail remain empty even if the command accidentally echoes the password. Consequently, success_contains and failure_contains are rejected for these jobs; use the exit code and non-secret result artifacts instead. A command can still write the password into its own files or send it over the network, so review the command itself and its artifact paths before using this feature.

This is a single finite stdin payload for a non-interactive program. Commands that require a TTY, repeated prompts, conversational input, or privilege elevation remain unsupported.

This mechanism prevents the value from entering Codex transcripts, MCP arguments, process argv/environment, and Longrun output storage. Before it is consumed, the value exists briefly in a local 0600 file. It does not defend against root, another compromised process running as the same OS user, memory inspection, or filesystem forensics. Use an external secret broker or run the command manually when that stronger boundary is required.

Requirements

  • Linux or WSL;

  • Codex CLI with App Server Unix transport and Goal APIs (tested with Codex CLI 0.147.0);

  • uv;

  • a trusted project directory for LONGRUN_ALLOWED_ROOTS.

The dependency lock currently installs Python MCP SDK 2.0.0 in an isolated virtual environment.

Install from scratch

Clone the repository and install the locked runtime:

git clone https://github.com/woffko/codex-mcp-longrun.git
cd codex-mcp-longrun
git switch experimental
./scripts/install-runtime.sh

The default runtime location is:

~/.local/share/codex-longrun-mcp/.venv

Register the server in Codex and replace /absolute/path/to/project with one trusted project root:

./scripts/configure-codex.py \
  --config "$HOME/.codex/config.toml" \
  --command "$HOME/.local/share/codex-longrun-mcp/.venv/bin/codex-mcp-longrun" \
  --server-cwd "$HOME/.local/share/codex-longrun-mcp" \
  --state-dir "$HOME/.local/state/codex-longrun" \
  --allowed-root /absolute/path/to/project

The configuration script:

  • refuses to overwrite an existing mcp_servers.longrun entry;

  • creates a timestamped private backup under ~/.codex/backups;

  • keeps the MCP optional with required = false;

  • allows only health, start_job, get_job, cancel_job, run_and_wait, and read_log_tail;

  • forwards LONGRUN_BRIDGE_SOCKET only when the opt-in launcher sets it;

  • configures command start, cancellation, and log reads to require approval;

  • keeps bounded metadata-only get_job reads automatic;

  • disables shell and privilege-elevation executables;

  • disables progress heartbeats by default;

  • limits all live jobs across local Codex sessions to four by default;

  • keeps one-time stdin handles for 300 seconds and limits their payload to 64 KiB by default;

  • gives Codex a tool timeout slightly longer than the server's 12-hour limit.

Start a new Codex process after configuration. Existing on-screen processes do not hot-load new MCP servers. Use the codex-longrun commands in the next section for event-driven Goal wakeup. Ordinary Codex can still resume the same saved session in manual fallback mode:

cd /absolute/path/to/project
codex resume SESSION_ID

Changing the shell directory first is important for project-scoped .codex/config.toml discovery. Do not assume that a later Codex -C option retroactively changes which configuration layers were loaded.

Verify registration:

codex mcp get longrun
codex mcp list

For an existing installation, apply the guarded config upgrade before reinstalling. It adds the bridge socket passthrough and keeps run_and_wait available without changing allowed roots or unrelated Codex settings:

./scripts/upgrade-codex.py --config "$HOME/.codex/config.toml" --dry-run
./scripts/upgrade-codex.py --config "$HOME/.codex/config.toml"
./scripts/install-runtime.sh

Event-driven Goal launcher

Use codex-longrun instead of codex for sessions that should suspend a Goal without model-visible polling. This is the recommended workflow on the experimental branch:

~/.local/share/codex-longrun-mcp/.venv/bin/codex-longrun \
  -C /absolute/path/to/project

~/.local/share/codex-longrun-mcp/.venv/bin/codex-longrun \
  resume -C /absolute/path/to/project SESSION_ID

The launcher starts the unmodified official codex app-server, a same-user Goal bridge, a bounded TUI compatibility proxy on private Unix sockets, and the official TUI in --remote mode. It does not build or replace Codex. Ordinary codex commands retain the manual two-turn behavior.

The launcher resolves Codex -C/--cd before starting App Server and starts both App Server and the remote TUI with that real process working directory. This ensures that project-scoped .codex/config.toml is loaded even when codex-longrun itself was invoked from another directory.

On Linux/WSL, App Server, the Goal bridge, and the TUI proxy run below isolated supervisors. Each supervisor combines kernel parent-death delivery with a launcher-owned pipe, then terminates the daemon's complete process group with SIGTERM and bounded SIGKILL escalation. The interactive TUI keeps its controlling terminal and uses a lighter exec guard. Every guard rechecks PPID after arming to close the fork-to-arm race. This prevents a Node shim or native App Server from surviving its launcher and retaining a thread-store writer lock; normal exits still use the launcher's graceful finally cleanup first.

Large Legacy session compatibility

Codex App Server defines thread/read(includeTurns=true) as a full-history operation. A very large Legacy JSONL session can therefore produce a single WebSocket response larger than the official TUI's receive limit. The launcher now routes only TUI traffic through a local compatibility proxy:

official TUI -> tui.sock proxy -> official App Server
                                      ^
                                      |
                          Goal bridge stays direct

The default auto mode forwards normal traffic unchanged. For a Legacy rollout at least 64 MiB in size, or when its local size cannot be determined safely, it replaces only the TUI's full thread/read response with the latest five turns obtained through experimental thread/turns/list(itemsView="full"). If that bounded tail is unavailable or exceeds 16 MiB, the TUI receives the thread summary with an empty visible turn list instead of an oversized frame.

This affects visible scrollback only. thread/resume, live events, approvals, server requests, and all other JSON-RPC messages remain transparent, so App Server still loads the original session as the model-visible thread context. The proxy never edits, migrates, truncates, or rewrites a session JSONL file. The tested Codex 0.147.0 TUI resumes with excludeTurns=true and then hydrates Legacy scrollback through thread/read, which is the request the proxy bounds.

Legacy pagination may still require App Server to scan the complete JSONL file once, so the first bounded tail can take time even though its returned frame is small. The result is a compatibility guard, not a session-file migration.

Launcher controls are consumed locally and are not passed to Codex:

# Default: protect large Legacy sessions and show a five-turn tail.
codex-longrun --longrun-legacy-history auto resume -C /project SESSION_ID

# Fastest safe fallback: show no old turns for any Legacy session.
codex-longrun --longrun-legacy-history omit resume -C /project SESSION_ID

# Disable the compatibility guard. Large sessions may fail in the TUI.
codex-longrun --longrun-legacy-history off resume -C /project SESSION_ID

Advanced bounds can be changed with --longrun-history-threshold-mib, --longrun-history-tail-turns, and --longrun-history-timeout-sec. Use codex-longrun --bridge-help for the accepted ranges. The implementation follows the official Codex App Server protocol; both the remote TUI transport and turn pagination are experimental upstream.

Do not combine this workflow with manual /goal pause, manual /goal resume, or run_and_wait for the same job. The bridge owns the Goal status transition, and an unexpected manual transition deliberately abandons its wake lease.

For an active durable Goal, call start_job with wake_policy="goal". The MCP server takes the thread identity from Codex request metadata, not from a model-controlled argument. Before the command starts, the bridge verifies the active Goal and changes it to paused. After terminal metadata is committed, the bridge waits for the current turn to become idle and changes the same Goal to active. That status transition starts the next Goal turn; the bridge does not also call turn/start.

Only one automatic wake lease may be active for a Goal. Clearing, completing, blocking, editing, or manually resuming that Goal abandons the lease rather than overriding the user. An ambiguous activation failure is never retried automatically; resume the Goal manually in that case.

Copy-paste automatic Goal contract

Replace the placeholders and start Codex through codex-longrun first:

/goal Complete [OBJECTIVE] without stopping until [VERIFIABLE END STATE]. For every reviewed, trusted, non-interactive command expected to run longer than about 30 seconds, call longrun.start_job exactly once with argv as an array, an absolute cwd, sufficient hard and no-output timeouts, and wake_policy="goal". Require automatic_wakeup=true in the returned status. After start_job returns, report the job ID and state, end the current turn, and do not call get_job, run_and_wait, a generic wait tool, write_stdin, log-tail checks, or any polling loop in that turn. Do not manually pause or resume this Goal; the local bridge owns those transitions, will pause this Goal while the command runs, and will reactivate this exact Goal only after terminal metadata is committed. In the automatically resumed turn, call longrun.get_job exactly once for the recorded job ID, analyze that terminal result, and continue the Goal. If automatic_wakeup is false or Goal wakeup setup fails, stop and report the failure instead of polling. Never put a secret value in argv, MCP arguments, prompts, or environment. If one reviewed command needs one finite secret stdin payload, prefer project_memory_stage_test_asset_for_longrun for an enrolled encrypted test asset and pass only its handle as stdin_secret_id; use codex-longrun-secret only when no suitable asset exists; secret-stdin output is intentionally suppressed.

Waiting inside the bridge does not invoke the model. The initial submission and the automatically resumed turn still use model context and tokens; this is not a universal billing guarantee.

collaboration.wait_agent waits for delegated model agents; it has no relationship to a Longrun process and must never be used to wait for a Longrun job. The same prohibition applies to generic wait tools, write_stdin, log tails, and status loops in the submission turn.

If the Goal never pauses

Inspect the start_job result. A bridge-enabled submission must have all of:

wake_policy = "goal"
automatic_wakeup = true
wake_delivery = "armed"

wake_policy="none" deliberately bypasses the bridge, so the Goal remains active and native Goal continuation may immediately start another model turn. Do not wait in that turn. If a codex-longrun session returns automatic_wakeup=false, stop and report the setup failure instead of falling back to collaboration.wait_agent or polling. Use none only for ordinary Codex or an explicitly requested manual fallback.

Enroll additional projects

The global server is visible to new Codex processes, but command tools accept working directories only under exact trusted roots. Add another project with the idempotent enrollment command:

./scripts/enroll-project.py \
  --config "$HOME/.codex/config.toml" \
  --allowed-root /absolute/path/to/another-project \
  --dry-run

./scripts/enroll-project.py \
  --config "$HOME/.codex/config.toml" \
  --allowed-root /absolute/path/to/another-project

The script creates a private backup, preserves unrelated TOML data, validates the complete update, and refuses / or the current user's home directory. Start a new Codex process after enrollment.

Codex agents performing a session or project integration should follow the Codex Agent Integration Runbook.

Fallback and compatibility workflows

The automatic Goal contract above is the primary experimental workflow. Use the alternatives in this section only when the session was started with ordinary codex, automatic wakeup setup failed before command start, or a specific client has already been verified for one blocking MCP call. Do not mix contracts for the same job.

The job supports:

  • a hard timeout;

  • an optional no-output timeout;

  • expected success and failure substrings;

  • a bounded result tail;

  • graceful termination followed by forced process-group cleanup.

Keep the originating interactive Codex process open while the job runs. A one-shot codex exec client exits after its response and closes its MCP server; the supervisor then terminates the command by design. This parent-death rule prevents detached work from outliving the client that started it.

Manual fallback with ordinary Codex

An ordinary codex process has no bridge socket and cannot wake an idle Goal. Use wake_policy="none" to make that manual behavior explicit:

Use longrun.start_job exactly once for ["cargo", "test"], with an absolute cwd
and wake_policy="none". Report the job ID and end the turn without polling.

Later, request one bounded status read:

Call longrun.get_job once for JOB_ID. If it is still running, report the state
and do not poll again in this turn.

For a durable Goal, the user must pause it before waiting and resume it for the agreed result check. The MCP server alone cannot control a Goal; only the opt-in App Server bridge can do so.

Copy-paste manual Goal contract

An ordinary Codex process does not wake a paused Goal automatically. Put the no-polling contract directly in the Goal objective, then pause and resume the Goal from the Codex CLI as shown below.

Replace the bracketed placeholders and paste this as one command:

/goal Complete [OBJECTIVE] without stopping until [VERIFIABLE END STATE]. For every reviewed, trusted, non-interactive command expected to run longer than about 30 seconds, call longrun.start_job exactly once with argv as an array, an absolute cwd, sufficient hard and no-output timeouts, and wake_policy="none". After start_job returns, report the job ID and state, end the turn, and do not call get_job, run_and_wait, a generic wait tool, write_stdin, log-tail checks, or any polling loop in that turn. Do not claim automatic wakeup. When I later resume this Goal and provide the job ID, call longrun.get_job exactly once. If the job is still running, report that state and end the turn without polling. Continue the Goal only after a terminal result. Never put a secret value in argv, MCP arguments, prompts, or environment. If one reviewed command needs one finite secret stdin payload, prefer project_memory_stage_test_asset_for_longrun for an enrolled encrypted test asset and pass only its handle as stdin_secret_id; use codex-longrun-secret only when no suitable asset exists; secret-stdin output is intentionally suppressed.

After Codex reports the job ID, pause the Goal before another autonomous turn starts:

/goal pause

When you are ready to read the result, resume the Goal and provide the exact job ID in the next message:

/goal resume
Call longrun.get_job exactly once for JOB_ID. If it is terminal, continue the Goal from that result. If it is still running, report the state and do not poll again in this turn.

This manual pause/resume step is only a fallback for ordinary codex; do not perform it after start_job has returned automatic_wakeup=true under codex-longrun. Starting a job alone is not proof that the Goal will wake when the process exits.

Legacy uninterrupted Goal contract

Use this variant only when longrun.run_and_wait is explicitly exposed in the current Codex session and that client has been verified to keep one MCP tool call pending without re-entering the model. The Goal stays active: the command runs inside the current turn, and Codex continues only after the same tool call returns its terminal result.

Replace the bracketed placeholders and paste this as one command:

/goal Complete [OBJECTIVE] without stopping until [VERIFIABLE END STATE]. For every reviewed, trusted, non-interactive command expected to run longer than about 30 seconds, call longrun.run_and_wait exactly once with argv as an array, an absolute cwd, and sufficient hard and no-output timeouts. Remain in that single MCP call until it returns a terminal result. Do not use longrun.start_job, longrun.get_job, a generic wait tool, write_stdin, log-tail checks, status polling, repeated tool calls, or periodic model commentary while the call is pending. Treat MCP progress notifications as UI-only progress and do not respond to them with another model turn. Continue this Goal only after the original run_and_wait call returns. Never put a secret value in argv, MCP arguments, prompts, or environment. If one reviewed command needs one finite secret stdin payload, prefer project_memory_stage_test_asset_for_longrun for an enrolled encrypted test asset and pass only its handle as stdin_secret_id; use codex-longrun-secret only when no suitable asset exists; secret-stdin output is intentionally suppressed.

This pattern avoids deliberate model-visible polling and does not require pausing the Goal. It is not a universal billing guarantee: a Codex client that converts a pending MCP call into repeated model turns can still consume tokens. Use the event-driven codex-longrun contract on an unverified client.

Progress heartbeats

Heartbeat timing is server-wide and can be changed in the [mcp_servers.longrun.env] section of the Codex configuration:

Environment variable

Default

Meaning

LONGRUN_HEARTBEAT_INITIAL_SEC

0

Delay before the first notification; 0 disables heartbeats

LONGRUN_HEARTBEAT_INTERVAL_SEC

900

Interval between later notifications

LONGRUN_MAX_ACTIVE_JOBS

4

Maximum live jobs across local Codex MCP server processes

LONGRUN_SECRET_TTL_SEC

300

Maximum age of an unconsumed one-time stdin handle

LONGRUN_MAX_STDIN_SECRET_BYTES

65536

Maximum staged secret stdin payload

longrun.health reports the effective values. The server silently disables heartbeats for the current job if notification delivery fails; the command continues running and still returns its terminal result. Clients that do not request progress simply receive no heartbeat.

Job logs and metadata are private local files under:

~/.local/state/codex-longrun/jobs

Logs are capped at 128 MiB by the default installer configuration. The result returns only a bounded tail and the local paths.

Security boundary

This server runs commands with the operating-system permissions of the account running Codex. It is not a security sandbox.

LONGRUN_ALLOWED_ROOTS validates the resolved working directory, but a launched program can still access any files, networks, and processes available to the same user. Treat the allowed-root check as a routing guard, not an authorization boundary.

Additional safeguards include:

  • shell and privilege-elevation executable rejection by default;

  • no tool parameter for injecting environment variables;

  • a small allowlist of inherited environment names;

  • no raw argument array in job metadata, only a redacted display and digest;

  • private one-time stdin handles whose values never enter MCP, argv, environment, metadata, logs, or tails;

  • mandatory output suppression whenever secret stdin is used;

  • private state directories and files;

  • bounded logs and result tails;

  • a Linux supervisor that terminates the full command process group on normal completion, timeout, cancellation, or abrupt MCP-parent death;

  • startup recovery for incomplete metadata left by an interrupted server.

Never pass passwords, tokens, API keys, private keys, cookies, or other secret values in arguments, MCP fields, prompts, or environment. Use the one-time stdin workflow only for a reviewed command that accepts one finite stdin payload. Normal command output is written to the local job log; secret-stdin jobs are the exception and suppress all captured output. Redaction remains best-effort metadata hygiene, not general secret detection.

Do not use the server for interactive programs, REPLs, TUI applications, TTY-dependent or repeated password prompts, indefinite servers, daemons, detached jobs, untrusted repositories, or unreviewed commands.

Test

Create the development environment and run the integration suite:

uv sync --frozen --no-dev
.venv/bin/python -m unittest discover -s tests -v

The suite covers the STDIO handshake, asynchronous submission and later terminal reads, cross-session visibility and cancellation, active-job limits, protocol-level progress delivery, environment isolation, allowed-root and shell rejection, successful and failed commands, hard and inactivity timeouts, log truncation, cancellation, descendant cleanup, abrupt parent death, metadata recovery, safe config enrollment and upgrades, backup permissions, idempotency, broad-root rejection, sanitized session-polling audits, and one-time secret stdin with mandatory output suppression and no metadata/log/tail disclosure.

Upgrade and rollback

After pulling a reviewed update, preview and apply the guarded configuration upgrade, then reinstall the isolated runtime:

./scripts/upgrade-codex.py --config "$HOME/.codex/config.toml" --dry-run
./scripts/upgrade-codex.py --config "$HOME/.codex/config.toml"
./scripts/install-runtime.sh

The upgrade creates a private timestamped backup, preserves unrelated TOML and explicit heartbeat policy, enables the asynchronous tool allowlist, and is idempotent. Use --reset-heartbeat only when an existing nonzero heartbeat should be changed to zero.

To disable the server without deleting local state:

codex mcp remove longrun

Alternatively, restore the timestamped config.toml.before-longrun-* backup created under ~/.codex/backups. Start a new Codex process after changing the configuration.

The runtime and state directories are independent of the project repository. Removing the MCP configuration does not remove either directory automatically.

References

Available Tools

3 tools
healthCheck longrun MCP healthA
Read-only

Return server paths, versions, and configured guardrails.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
okYes
state_dirYes
allow_shellYes
mcp_versionYes
allowed_rootsYes
max_log_bytesYes
python_versionYes
server_versionYes
max_timeout_secYes
forwarded_env_namesYes
heartbeat_initial_secYes
recovered_orphan_jobsYes
heartbeat_interval_secYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already provide readOnlyHint=true, establishing this as a safe read operation. The description adds useful specifics about the returned data (paths, versions, guardrails) without contradicting the annotations. It does not disclose potential side effects, but none are expected given the read-only nature.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, focused sentence that conveys all necessary information. There is no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has no parameters, includes an output schema, and is annotated as read-only, the description is fully adequate. It states what the tool returns, and the output schema handles the rest. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, and the description rightly omits parameter details. Since there are no parameters to document, the baseline of 4 for a zero-parameter tool is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'Return' and enumerates the exact resources (server paths, versions, guardrails), making the tool's purpose unmistakable. It is clearly distinct from siblings run_and_wait and read_log_tail, which involve execution and log reading respectively.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance is given for when to use this tool versus alternatives. However, the name 'health' and description imply it is for status checks, which serves as a weak implicit usage signal. No alternatives are mentioned or exclusions stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_log_tailRead a bounded tail from a longrun jobA
Read-only

Read only the bounded tail stored for a known job ID.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYes
tail_bytesNo
tail_linesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
tailYes
job_idYes
source_pathYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint=true, so the description's 'Read only' adds no new safety info. It does add that the tail is 'stored' and 'bounded', which hints at behavior (not live streaming, limited size), but lacks details on error handling or response structure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence with no redundancy. It front-loads the core action and resource without waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is relatively simple with an output schema (so return values are covered), but the description lacks parameter semantics and usage guidance. It is not fully complete for a 3-parameter tool with zero schema description coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate by explaining parameters. It only mentions 'known job ID' and 'bounded tail', but does not explain tail_bytes or tail_lines, their defaults, or how they interact. The agent must rely on schema names/types alone, which is insufficient.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific action ('Read only') and resource ('bounded tail stored for a known job ID'), distinguishing it from siblings like health (status) and run_and_wait (execution). The title reinforces the longrun job context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'known job ID' implies this tool is used after a job has been created (likely via run_and_wait), but no explicit when/when-not guidance or alternatives are mentioned. Usage context is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_and_waitRun a long command and wait locallyA
Destructive

Run one approved non-interactive process and return one bounded terminal result.

ParametersJSON Schema
NameRequiredDescriptionDefault
cwdYesAbsolute working directory inside LONGRUN_ALLOWED_ROOTS.
argvYesCommand and arguments as an array. Shell and privilege-elevation commands are disabled.
tail_bytesNo
tail_linesNo
timeout_secNo
failure_containsNo
grace_period_secNo
success_containsNo
no_output_timeout_secNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
cwdYes
tailNo
errorNo
stateYes
job_idYes
log_pathYes
exit_codeYes
duration_secYes
failure_matchNo
log_truncatedYes
metadata_pathYes
success_matchNo
started_at_utcYes
command_displayYes
finished_at_utcYes
output_bytes_seenYes
output_bytes_loggedYes

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate destructive behavior, but the description adds valuable context: the process must be 'approved' and 'non-interactive', and the result is 'bounded'. This goes beyond annotations by conveying safety and output-limitation constraints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, front-loaded sentence with zero wasted words. Every term ('approved', 'non-interactive', 'bounded') carries meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although an output schema exists and annotations provide a safety baseline, the description fails to mention critical operational details such as waiting behavior, timeouts, output truncation, or success/failure matching. Given the tool's nine parameters, this is insufficient for a new agent to use it effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With only 22% schema description coverage and no parameter details in the description, the agent receives no help understanding the seven undocumented parameters (tail_bytes, timeout_sec, success_contains, etc.). The description adds no parameter semantics beyond what the schema already provides for cwd and argv.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Run') and resource ('one approved non-interactive process') and clearly distinguishes this tool from siblings health and read_log_tail, which are about reading logs/state rather than executing commands. The phrase 'bounded terminal result' further clarifies the scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use for running approved non-interactive commands and implies it waits for a result, but it does not explicitly state when to prefer this tool over alternatives or when not to use it. No exclusions or sibling comparisons are provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A3.6/5.0
Disambiguation5/5

Each tool has a distinct role: health checks server status, run_and_wait executes a process and returns a result, and read_log_tail retrieves logs for a specific job. There is no overlap or ambiguity between them.

Naming Consistency2/5

Tool names are inconsistent in style: 'health' is a simple noun, 'run_and_wait' is a verb phrase, and 'read_log_tail' is a verb-noun-noun compound. No uniform pattern (e.g., verb_noun) is followed.

Tool Count3/5

Three tools is a minimal set, but it covers the core needs of a long-run execution server: health check, run a command, and read logs. It feels slightly thin but is not unreasonably sparse for a focused utility.

Completeness3/5

The surface covers the basic workflow of running a process and checking its logs, but lacks obvious lifecycle management tools like cancel, list jobs, or check status. The domain is narrow, yet significant gaps remain for robust long-running job handling.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides a secure, token-authenticated command execution tool over MCP Streamable HTTP, with a default-deny allowlist and shell metacharacter rejection.
    16
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    A minimal, zero-dependency MCP server that enables defining and running tools over stdio transport, without extra features like HTTP or resources.
    15
    1
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    A local, evidence-driven MCP runtime and control plane for open-source maintainers that provides workspace-bounded tools including controlled file operations, command execution, validation primitives, durable execution records, and human review workflows via stdio and Streamable HTTP transports.
    33
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/woffko/codex-mcp-longrun'

If you have feedback or need assistance with the MCP directory API, please join our Discord server