@itonskie/argus
v0.1.3
Published
Keyboard-first TUI for inspecting and exercising MCP servers over stdio.
Readme
argus
A keyboard-first TUI for inspecting and exercising Model Context Protocol (MCP) servers over stdio.
Point argus at any MCP server, browse its tools / resources / prompts, and invoke them with auto-generated forms — without leaving the terminal.
Why
Building MCP servers today usually means hand-rolling JSON-RPC payloads to test them, or living inside Anthropic's web inspector. Neither is built for power users iterating fast. argus is the tool MCP developers actually want at their fingertips: instant connection, schema-driven forms, vim-style navigation.
The name comes from Argus Panoptes — the many-eyed watcher of Greek myth. Fitting for a tool whose job is to see everything an MCP server exposes.
Features
- Connect to any MCP server over stdio
- Browse tools, resources, and prompts exposed by the server
- Invoke any tool through an auto-generated form driven by its JSON Schema — falls back gracefully to a raw-JSON textarea for shapes the form-renderer can't ladder into inputs
- Open large responses in
$PAGER - Nothing written to disk — every session is ephemeral
Coming later: SSE / HTTP transports, save-and-replay sessions, OAuth flows, multi-server-at-once.
Stack
- Node 20+ / TypeScript (strict)
- Ink — React for terminals
- @modelcontextprotocol/sdk — official MCP client SDK
- ajv — JSON Schema validation for dynamic forms
- tsup — bundling
- Vitest + ink-testing-library — tests
- Biome — lint + format
- pnpm — package manager (dev)
Install
Requires Node 20+.
# One-shot — fetches, runs, discards.
npx @itonskie/argus <path-to-mcp-server-script>
# Or install globally.
npm i -g @itonskie/argus
argus <path-to-mcp-server-script><path-to-mcp-server-script> is a JavaScript entry point (.js / .mjs / .cjs) or an executable that speaks MCP over stdio. argus spawns it as a child process and connects over stdio.
Development
pnpm install # first-time setup
pnpm build # bundle dist/argus.js + dist/test-server-fixture.js
pnpm test # build + full Vitest suite
pnpm typecheck # tsc --noEmit
pnpm lint # biome check
pnpm startup-budget # cold-start-to-first-paint (target <200ms)
pnpm smoke # boot argus against @modelcontextprotocol/server-filesystemManual smoke test
pnpm smoke is the release gate (engineering-spec §7.3). It installs @modelcontextprotocol/server-filesystem into a throwaway temp dir, seeds two sample files, and launches argus wired to it. Walk the golden path: highlight read_file → Enter → type hello.txt → submit → response renders → q exits cleanly. The temp dir is deleted on exit.
Terminal-size + accessibility modes
argus supports three environment overrides for a11y and terminal compat (design-spec §1, §2.3, §6):
# Force ASCII borders + spinner (| / - \) — no Unicode required.
ARGUS_ASCII=1 argus <path>
# Drop all color; focus indicator falls back to a bold Unicode border.
NO_COLOR=1 argus <path>
# Static "…" spinner instead of the braille dot rotation.
PREFERS_REDUCED_MOTION=1 argus <path>Below 80×24 argus swaps the three-pane layout for a single-line
argus requires 80×24 terminal — current: NxN message. Resize the terminal
back up and the layout returns automatically — focus and selection are
preserved across the resize.
Startup budget
argus targets < 200ms cold-start-to-first-paint. @modelcontextprotocol/sdk and ajv must be loaded via dynamic import() inside the modules that use them, never at file top-level. See ADR 2.
Run the check locally:
pnpm startup-budgetIt builds the bundle, spawns dist/argus.js against the fixture five times, and reports the median wall-clock time from spawn to first byte on stdout. Exits 1 if median > 200ms. CI runs the same check on every PR.
Debugging a regression:
- Grep the entry (
src/argus.ts) and any file it statically imports for top-levelimportof a heavyweight dep. Move it to a dynamicimport()inside the function that needs it. - Use
import type { X }for any type-only imports of a lazy-loaded module — otherwise TypeScript's emit pulls it in at runtime. - Anything that runs before Ink's first render belongs on a strict diet: argv parse,
statSync, mount. That's it.
Release
Cutting a release publishes @itonskie/argus to the npm registry.
Bump
versioninpackage.json(e.g.0.1.0).Commit and push.
Tag the commit
vX.Y.Zand push the tag:git tag v0.1.0 git push origin v0.1.0.github/workflows/publish.ymlruns on thev*tag: full CI on Node 20 + 22, thenpnpm publish --access publicusing theNPM_TOKENrepo secret. The workflow refuses to publish if the tag version andpackage.jsonversion disagree.
The shipped tarball is a single-file, zero-runtime-dep bundle — tsup inlines @modelcontextprotocol/sdk, ajv, ink, react, and everything else. Users only need Node 20+. See engineering-spec §8 and tests/packaging.test.ts for the guarantee.
