Skip to main content
Glama

can-see

npm version npm downloads license node

MCP server that lets AI agents see and interact with terminal/CLI applications through virtual terminals and PNG screenshots.

Built for Claude Code and any MCP-compatible agent.

Why?

Some things are easier to show than describe. When debugging a TUI app, an interactive CLI wizard, or anything with visual terminal output, can-see lets the agent see exactly what you see — colors, layout, cursor position, and all.

How it works

  1. Launch a CLI app in a virtual terminal (node-pty + @xterm/headless)

  2. Screenshot the terminal as a PNG image (rendered via node-canvas)

  3. Send keys/text to interact with the app

  4. Screenshot again to see the result

  5. Close the session when done

Installation

npm install -g can-see

Prerequisites

can-see depends on node-canvas (Cairo) and node-pty, which require native compilation. Most systems will need:

  • Windows: Visual Studio Build Tools (C++ workload) — npm install --global windows-build-tools or install from Visual Studio Installer

  • macOS: Xcode Command Line Tools — xcode-select --install

  • Linux: sudo apt install build-essential libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev librsvg2-dev

Configuration

Claude Code

Add to your project's .mcp.json:

{
  "mcpServers": {
    "can-see": {
      "command": "npx",
      "args": ["-y", "can-see"]
    }
  }
}

Or if installed globally:

{
  "mcpServers": {
    "can-see": {
      "command": "can-see"
    }
  }
}

Other MCP clients

can-see uses stdio transport. Point your MCP client at the can-see binary or npx -y can-see.

Tools

Tool

Description

launch

Start a CLI app in a virtual terminal. Returns a sessionId. Accepts optional env to set environment variables.

screenshot

Capture the terminal as a PNG image.

screenshot_region

Capture a specific rectangular area of the terminal.

screenshot_text_region

Find text in the viewport and capture the surrounding area as a PNG.

capture_baseline

Snapshot terminal state for later diff comparison.

diff_screenshot

Compare current state against baseline with highlighted changes.

get_cell_info

Query character, colors, and attributes at specific cell(s). Supports compact mode for reduced output.

read_text

Read the terminal buffer as plain text.

read_scrollback

Read text that scrolled above the visible viewport.

wait_for_text

Wait until specific text appears in the terminal buffer.

wait_for_idle

Wait until terminal output has been stable for a given duration. Supports stableMs for content-comparison mode (for apps with timers/spinners), excludeRows to ignore specific rows, and excludePattern (regex) for dynamic row exclusion.

wait_for_color

Wait until a specific color appears at a position.

wait_for_exit

Wait until the process exits and return its exit code and signal.

start_recording

Begin capturing frames for an animated GIF.

stop_recording

Stop recording and return the animated GIF with metadata (frameCount, durationMs). Auto-trims frames or saves to file if GIF exceeds inline size limit.

send_keys

Send keystrokes (e.g., Enter, Ctrl+C, ['Down', 'Down', 'Enter']).

send_text

Type a string of text into the app.

get_process_status

Get process status — distinguish "app is idle" from "app has exited". Returns PID, running state, exit code.

list_sessions

List all active terminal sessions.

close

Kill the app and clean up. Always close when done.

close_all

Kill all active sessions at once. Useful for cleanup between test runs.

Supported keys

Enter, Tab, Escape, Backspace, Space, Up, Down, Left, Right, Home, End, Delete, PageUp, PageDown, Ctrl+A through Ctrl+Z.

Environment variables

Variable

Default

Description

DEFAULT_COLS

120

Terminal width in columns

DEFAULT_ROWS

30

Terminal height in rows

IDLE_TIMEOUT_MS

300000

Auto-close idle sessions after this many ms (5 min)

Example usage

From an MCP-connected agent:

Agent: I'll launch your app to see what's happening.
→ launch("node", ["app.js"])  → sessionId: "abc-123"

Agent: Let me wait for the app to start.
→ wait_for_text("abc-123", "Ready")  → Found "Ready" after 1200ms

Agent: Let me read the current output.
→ read_text("abc-123")  → "Welcome to MyApp\nReady\n> "

Agent: I can see the prompt. Let me select option 2.
→ send_keys("abc-123", ["Down", "Enter"])

Agent: Waiting for the screen to settle.
→ wait_for_idle("abc-123")  → Terminal idle for 520ms

Agent: Let me check the result.
→ screenshot("abc-123")  → [PNG image showing result]

Agent: Done, closing the session.
→ close("abc-123")

Changelog

0.5.0

New tools:

  • wait_for_exit — wait for process exit, get exit code and signal

  • close_all — kill all active sessions at once

  • get_process_status — distinguish "app is idle" from "app has exited"

  • screenshot_text_region — find text in viewport, capture surrounding area as PNG

Enhancements:

  • launch accepts env parameter for custom environment variables

  • wait_for_idle supports excludePattern (regex) for dynamic row exclusion in stableMs mode

  • stop_recording returns frameCount and durationMs metadata alongside GIF

  • get_cell_info supports compact option for reduced output ({char, fg, bold} only)

Bug fixes:

  • Fixed wait_for_text and wait_for_color race condition where text/color present in the final buffer was missed when the process exited simultaneously

  • Added mutual exclusion validation when both stableMs and idleMs are passed to wait_for_idle

License

MIT

A
license - permissive license
-
quality - not tested
A
maintenance

Maintenance

Maintainers
<1hResponse time
Release cycle
1Releases (12mo)

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

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

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/HurleySk/can-see'

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