npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gcszhn/mcp-sentinel-cli

v1.4.0

Published

Harness-agnostic MCP stdio CLI that acts as a sentinel between any agent and MCP servers — polling long-running tasks on the agent's behalf so that token-costly status loops never enter the LLM inference path

Readme

@gcszhn/mcp-sentinel-cli

A harness-agnostic MCP stdio CLI that acts as a sentinel between any AI agent and MCP servers: it polls long-running MCP tool calls on the agent's behalf so token-costly status loops never enter the LLM inference path.

This is the harness-neutral adapter for @gcszhn/mcp-sentinel-core. Register it as an ordinary MCP server in whatever harness you use (Codex, OpenCode, DeepSeek Harness, …) — it auto-discovers the MCP servers that harness already exposes.

Usage

mcp-sentinel mcp --harness <codex|opencode|custom|none> [--mcp-config <file>]

The mcp subcommand starts the sentinel as a stdio MCP server exposing the four mcp_sentinel_* tools. The MCP servers it can poll are discovered from the selected harness:

| Harness | Source | | ---------- | -------------------------------------------- | | codex | codex mcp list --json | | opencode | opencode debug config (JSON mcp object) | | custom | a JSON file passed via --mcp-config | | none | no discovery (empty config) |

The sentinel skips entries the harness has disabled (enabled: false, or Codex's disabled_reason) and its own entry so it never polls a disabled server or itself. Self-detection compares the entry's launch command against the sentinel's own process.argv — never the server name — so a self entry registered under any name is still skipped. No sentinel-specific MCP setup is ever required.

Custom config (--harness custom)

The custom config is a JSON file whose entries follow OpenCode's MCP config field names (local servers use command (array) + cwd + environment; remote servers use url + headers). The top-level servers map is required; the Codex .mcp.json shape (mcpServers) and a bare { name: entry } map are also accepted.

A JSON Schema ships with the package at schema/mcp-config.schema.json (also available on npm as node_modules/@gcszhn/mcp-sentinel-cli/schema/mcp-config.schema.json). Point your editor at it via $schema for validation and autocomplete:

// mcp.json
{
  "$schema": "./node_modules/@gcszhn/mcp-sentinel-cli/schema/mcp-config.schema.json",
  "servers": {
    "mock-ci": {
      "type": "local",
      "command": ["bun", "run", "mock-server.ts"],
      "cwd": "/tmp",
      "environment": { "KEY": "v" },
      "enabled": true
    },
    "remote": {
      "type": "remote",
      "url": "https://example.com/mcp",
      "headers": { "X-Api-Key": "..." }
    }
  }
}
mcp-sentinel mcp --harness custom --mcp-config ./mcp.json

enabled: false entries are skipped. Like every harness, the sentinel also skips its own entry (matched by launch command, not by name).

Install (Codex, one command)

scripts/install-codex-mcp.sh

Builds the package and registers [mcp_servers.mcp-sentinel] in ~/.codex/config.toml running mcp-sentinel mcp --harness codex. Start a new Codex thread afterwards. For other harnesses, register mcp-sentinel mcp --harness <harness> (or --mcp-config) as an MCP server in that harness's config.

Tools

mcp_sentinel_poll

Submit a long-running MCP tool call and poll it at regular intervals until a condition is met. Returns a sentinel ID immediately.

| Parameter | Type | Default | Description | | ---------- | ------ | ---------- | ------------------------------------------ | | server | string | required | MCP server name (from the harness config) | | tool | string | required | Tool name to call on the server | | args | object | {} | Arguments for the tool | | interval | number | 5000 | Poll interval in milliseconds | | timeout | number | optional | Max poll duration in ms (unset = no limit) | | until | object | required | Condition object |

mcp_sentinel_status

Check status, list active tasks, or cancel a running task (action = status | list | cancel).

mcp_sentinel_attach

Block the agent, waiting for a sentinel to complete. Zero token cost during the wait.

mcp_sentinel_read

Read raw poll outputs with offset/limit pagination.

mcp_sentinel_set_notifier_commands

Install a command-based notification handler. The CLI has no harness message channel, so by default background sentinel completions are collected with mcp_sentinel_attach / status / read. This tool registers a notifier that, when a sentinel resolves, builds a notification message and runs each command template in order to deliver it.

| Parameter | Type | Default | Description | | --------- | ------------- | ---------- | ----------------------------------- | | commands | string[] | required | Command templates, each with exactly one {} placeholder for the message |

Each template must contain exactly one {} placeholder where the notification message is injected. Every other argument must be a concrete literal. Important: environment variables are session-scoped, but the MCP server is a single global process shared by all sessions. A template runs via a shell inside that server process, so any $VAR in a template resolves against the server process's environment — not your session's. This tool never resolves environment variables. To target your own session (e.g. a Codex thread id), read the real value first and inline it as a literal. It can target an agent, a user, or anything else; the command need not actually send a message:

// 1) Read the real session value in your session, then inline it:
//    echo $CODEX_THREAD_ID   -->  cd1234-...
// 2) Register with the concrete value baked in:
{ "commands": ["codex queue --thread \"cd1234-...\" --message \"{}\""] }

// Just echo the message (no delivery at all).
{ "commands": ["echo \"{}\""] }

Commands run sequentially. A failing command is logged but never affects the sentinel task state — the task remains queryable via the other tools.

The call returns a notifier_id (a uuid). Because the MCP server is loaded globally (shared by every session), each session's command list is registered under its own id; a single dispatcher reads the task's sessionID (set from the notifier_id you pass to mcp_sentinel_poll) and runs only that session's commands. This keeps notifications from leaking across sessions. Pass the notifier_id to mcp_sentinel_poll to associate the two:

{ "server": "mock-ci", "tool": "get_job_status", "args": { "job_id": "e2e" }, "interval": 1000, "notifier_id": "<uuid from above>", "until": { "path": "status", "is": "eq", "value": "completed" } }

Condition model

Conditions are pure declarative data:

{ "path": "status", "is": "eq", "value": "completed" }
{ "and": [
  { "path": "status", "is": "eq", "value": "completed" },
  { "path": "tasks[0].exit_code", "is": "eq", "value": 0 }
] }

See the repository root README.md for the full operator and path syntax.

Environment variables

| Variable | Default | Description | | ----------------------- | --------- | ----------------------------------------- | | SENTINEL_MAX_POLL_LOG | unlimited | Max poll log entries per task (FIFO trim) | | SENTINEL_TASK_TTL_MS | unlimited | Auto-cleanup completed tasks after N ms | | CODEX_BIN | resolved | Override the codex CLI binary path |

License

MIT