Skip to content

Runtime CLI Discovery - Zero Maintenance

Overview

Instead of maintaining a static catalog of CLI tools, NCP now automatically discovers what's installed on your system at runtime. This approach:

  • Zero maintenance - No hardcoded tool definitions
  • Always current - Parses actual --help output
  • User-specific - Only shows what YOU have installed
  • Version-agnostic - Works with any tool version

Architecture

1. CLI Scanner (src/services/cli-scanner.ts)

Discovers tools at runtime:

typescript
const scanner = new CLIScanner();
const tools = await scanner.scanSystem();
// Returns: All useful CLI tools installed on this system

How it works:

  1. Use compgen -c to list all available commands
  2. Filter to likely useful tools (exclude shell built-ins)
  3. Test each tool with --help flags
  4. Parse help output to extract:
    • Description
    • Capabilities (keywords)
    • Category (media, data, network, etc.)

Smart filtering:

  • Excludes: cd, echo, test (shell built-ins)
  • Includes: Tools with useful keywords (convert, process, search, etc.)
  • Categorizes: Based on description and capabilities

2. CLI Suggestions MCP (src/internal-mcps/cli-suggestions.ts)

New tools available:

cli:scan

Scan system for all available CLI tools

javascript
run("cli:scan")

Output:

🔍 System Scan Complete

Found **42** CLI tools

media (12 tools)
   ffmpeg, ffprobe, imagemagick, yt-dlp ...

data (5 tools)
   jq, yq, csvkit ...

development (8 tools)
   git, node, npm, docker ...

Search for tools by capability

javascript
run("cli:search", { query: "convert video" })

Output:

🔍 CLI Tools for "convert video":

**ffmpeg** - Complete solution to record, convert and stream audio and video
   Category: media
   Path: /opt/homebrew/bin/ffmpeg
   Capabilities: convert, video, audio, encode, mp4, webm
   Add to NCP: run("ncp:add", { mcp_name: "cli:ffmpeg" })

**handbrake** - Video transcoder
   Category: media
   Path: /usr/local/bin/HandBrakeCLI
   ...

cli:check

Check if a specific tool is installed

javascript
run("cli:check", { tool_name: "ffmpeg" })

Output:

✅ ffmpeg is installed

Description: Complete solution to record, convert and stream audio and video
Category: media
Path: /opt/homebrew/bin/ffmpeg
Capabilities: convert, video, audio, encode, decode, mp4, webm, avi

Add to NCP: run("ncp:add", { mcp_name: "cli:ffmpeg" })

cli:browse

Browse tools by category

javascript
run("cli:browse", { category: "media" })

Output:

📚 media tools (12 found):

**ffmpeg** - Complete solution to record, convert and stream audio and video
   /opt/homebrew/bin/ffmpeg
   Add: run("ncp:add", { mcp_name: "cli:ffmpeg" })

**imagemagick** - Create, edit, compose digital images
   /usr/local/bin/convert
   Add: run("ncp:add", { mcp_name: "cli:imagemagick" })
...

User Workflow (Zero Knowledge Required)

Scenario 1: Auto-scan on startup (with shell access)

javascript
// 1. User initializes NCP with Shell MCP installed
// Auto-scan detects shell access and scans in background
// → Discovers ffmpeg, jq, git, etc. are installed

// 2. User asks AI to convert video
find("convert video")
// → Returns: ffmpeg:convert, handbrake:transcode (if installed)

// All discovered automatically - zero manual steps!

Scenario 2: Fallback scan on empty results

javascript
// 1. User asks AI to convert video
find("convert video")
// → No results initially

// 2. NCP detects empty results + shell access
// → Triggers CLI scan automatically
// → Retries search after scan

// 3. Returns discovered tools
// → ffmpeg:convert (0.82 confidence)
// → handbrake:transcode (0.76 confidence)

// Auto-recovery - zero manual intervention!

Scenario 3: Manual discovery (advanced users)

javascript
// 1. User explicitly scans
run("cli:scan")
// → Discovers ffmpeg, handbrake, etc. are installed

// 2. Search for specific capabilities
run("cli:search", { query: "convert video" })
// → Returns ffmpeg, handbrake with descriptions

// 3. Add specific tool
run("ncp:add", { mcp_name: "cli:ffmpeg" })
// → ffmpeg now indexed for discovery

Conditional Auto-Scanning

Auto-scanning is smart and non-intrusive:

When it triggers:

  • On startup: If Shell or desktop-commander MCP is present
  • On empty search: If find() returns no results and shell access available
  • Force mode: Set NCP_FORCE_CLI_SCAN=true to always scan

When it DOESN'T trigger:

  • ❌ No shell access (no way to discover tools)
  • ❌ User disabled it (NCP_DISABLE_CLI_SCAN=true)
  • ❌ Already scanned (1 hour cache)

Environment Variables:

bash
# Disable auto-scanning (manual only)
export NCP_DISABLE_CLI_SCAN=true

# Force scanning even without shell access
export NCP_FORCE_CLI_SCAN=true

Benefits vs. Static Catalog

Static Catalog (Old Approach)

❌ Requires manual maintenance ❌ Gets outdated when tools change ❌ Shows tools user doesn't have ❌ Hardcoded knowledge of specific versions ❌ Missing new/uncommon tools

Runtime Discovery (New Approach)

✅ Zero maintenance required ✅ Always reflects current tool version ✅ Only shows installed tools ✅ Works with any tool version ✅ Discovers ALL installed tools

Implementation Details

Scanning Algorithm

typescript
1. Get all commands: compgen -c
2. Filter candidates:
   - Exclude shell built-ins (cd, echo, etc.)
   - Include tools with useful keywords
   - Limit to ~100 for performance

3. For each candidate:
   - Check if executable: which <tool>
   - Try help flags: --help, -h, help
   - Parse help output:
     * Extract description (first meaningful line)
     * Extract capabilities (verbs, file types)
     * Categorize (media, data, network, etc.)

4. Cache results (1 hour TTL)
5. Return discovered tools

Performance

  • Initial scan: ~2-5 seconds for 100 tools
  • Cached results: <10ms
  • Cache TTL: 1 hour
  • Force refresh: Available via force_refresh parameter

Smart Categorization

Tools are auto-categorized based on keywords:

typescript
'media':      video, audio, image, ffmpeg, mp4, mp3
'data':       json, xml, csv, parse, jq
'documents':  pdf, markdown, pandoc, docx
'development': git, npm, docker, build
'network':    http, api, curl, download
'search':     grep, find, search
'archive':    zip, tar, compress
'security':   encrypt, hash, crypto
'utilities':  (fallback)

Example: ffmpeg Discovery

javascript
// Scan discovers ffmpeg
{
  name: "ffmpeg",
  path: "/opt/homebrew/bin/ffmpeg",
  description: "Complete solution to record, convert and stream audio and video",
  category: "media",
  capabilities: [
    "ffmpeg",
    "convert",
    "process",
    "encode",
    "decode",
    "video",
    "audio",
    "mp4",
    "webm",
    "avi",
    "mp3",
    "aac"
  ]
}

// User searches: "convert video"
// Match score: HIGH (contains "convert" and "video")
// Returned as top result

// After adding via ncp:add:
// - CLI parser extracts operations from ffmpeg --help
// - 16 operations indexed (convert, extract_audio, etc.)
// - Available via find("convert video")

Comparison

Before (Static Catalog)

Problem: ffmpeg 6.0 changes syntax, catalog is outdated

javascript
run("cli:suggest", { query: "convert video" })
// Returns: ffmpeg with hardcoded v5.0 knowledge
// User installs ffmpeg 7.0
// Suggestions are wrong!

After (Runtime Discovery)

Solution: Parse actual current version

javascript
run("cli:scan")
// Runs: ffmpeg --help (whatever version is installed)
// Parses: Current syntax, current options
// Always correct!

Migration Path

Old static catalog can coexist during transition:

  1. Phase 1: Add runtime scanner (this PR)
  2. Phase 2: Use scanner for discovery, catalog for installation hints
  3. Phase 3: Remove static catalog completely

Testing

javascript
// Test scanning
const scanner = new CLIScanner();
const tools = await scanner.scanSystem();
console.log(`Found ${tools.length} tools`);

// Test search
const results = await scanner.searchTools("convert video");
console.log(results.map(t => t.name));

// Test categorization
const mediaTools = await scanner.getToolsByCategory("media");
console.log(mediaTools);

Implemented Features

  • [x] Conditional auto-scanning - Triggers based on shell access
  • [x] Fallback on empty results - Auto-scans and retries when no tools found
  • [x] Environment variable controls - NCP_DISABLE_CLI_SCAN, NCP_FORCE_CLI_SCAN
  • [x] Smart caching - 1 hour TTL, prevents redundant scans
  • [x] Non-blocking background scans - No impact on initialization speed

Future Enhancements

  • [ ] Parallel scanning for speed (currently sequential)
  • [ ] Parse man pages for richer descriptions
  • [ ] Tool usage analytics (most used tools)
  • [ ] Auto-suggest based on file types in context
  • [ ] Integration with package managers (brew, apt) for installation hints
  • [ ] Tool version compatibility warnings
  • [ ] Smart re-scan triggers (new tools installed, PATH changes)

Conclusion

Runtime CLI discovery with conditional auto-scanning eliminates maintenance burden while providing accurate, user-specific tool suggestions. The system:

  1. Automatically discovers what's installed when shell access is available
  2. Falls back gracefully when searches return empty results
  3. Respects user control via environment variables
  4. Parses current help output ensuring recommendations are always correct and up-to-date

Zero maintenance, maximum utility.

Released under the Elastic License 2.0.