Kitty MCP Server
A production-grade MCP server for controlling kitty terminal instances
A production-grade Model Context Protocol (MCP) server for controlling kitty terminal instances.
Overview
- Create, manage, and control kitty terminal instances programmatically
- Send text and key combinations to kitty windows
- Capture scrollback buffer content for command output analysis
- Useful for long running processes, analyzing logs, and automation workflows
- All instances launched with
--app-idfor window identification
Features
- Launch kitty instances with unique Unix sockets and app-id
- Send text and key combinations to windows
- Launch windows within existing instances
- Capture scrollback buffer content
- Manage app-ids for window identification
- List and close instances
- JSON structured logging
- Async/await throughout
- Comprehensive error handling
Installation
Prerequisites
- Python 3.11+
- kitty terminal installed and in PATH
- uv (recommended) or pip
Install from PyPI
# Install from PyPI
pip install kitty-mcp
# Install with uv (recommended)
uv add kitty-mcp
Install from Source
# Clone repository
git clone https://github.com/your-username/kitty-mcp.git
cd kitty-mcp
# Install with uv
uv pip install -e ".[dev]"
# Or with pip
pip install -e ".[dev]"
Usage
Running the Server
# Run directly
python -m kitty_mcp
# Or using the installed script
kitty-mcp
The server communicates via stdio (standard input/output) for MCP compatibility.
Configuration
Create a configuration file at ~/.config/kitty-mcp/config.json:
{
"socket_dir": "/tmp/kitty-mcp",
"max_instances": 10,
"socket_permissions": "0600",
"logging": {
"level": "INFO"
},
"kitty": {
"launch_timeout": 30,
"command_timeout": 30
}
}
Configuration options:
socket_dir: Directory for Unix sockets (default:/tmp/kitty-mcp-<uid>)max_instances: Maximum concurrent instances (default: 10, max: 100)socket_permissions: Socket file permissions (default: "0600")logging.level: Log level (DEBUG, INFO, WARNING, ERROR)kitty.launch_timeout: Timeout for launching kitty (seconds)kitty.command_timeout: Timeout for RC commands (seconds)
Available Tools
launch
Launch a new kitty instance with remote control enabled.
Parameters:
app_id(string, required): Unique identifier for the instanceworking_directory(string, optional): Working directorywindow_class(string, optional): Window class (defaults to app_id)
Returns: {"success": true, "app_id": "...", "socket_path": "...", "pid": 1234}
send_text
Send text to a kitty window.
Parameters:
app_id(string, required): Instance identifiertext(string, required): Text to sendmatch(string, optional): Window matching criteria
send_key
Send key combination to a kitty window.
Parameters:
app_id(string, required): Instance identifierkey(string, required): Key combination (e.g., "ctrl+c", "enter")match(string, optional): Window matching criteria
launch_window
Launch a new window in an existing kitty instance.
Parameters:
app_id(string, required): Instance identifiercommand(array, required): Command to runcwd(string, optional): Working directory
get_scrollback
Capture scrollback buffer content.
Parameters:
app_id(string, required): Instance identifierlines(integer, optional): Number of lines (default: all)match(string, optional): Window matching criteria
Returns: {"success": true, "content": "..."}
close
Close a kitty instance.
Parameters:
app_id(string, required): Instance identifierforce(boolean, optional): Force close
get_app_id
Get the app-id of a running kitty instance.
Parameters:
app_id(string, required): Instance identifier
Returns: {"success": true, "app_id": "...", "configured_app_id": "..."}
set_app_id
Update the app-id tracking for an instance.
Parameters:
app_id(string, required): Current instance identifiernew_app_id(string, required): New identifier
list_instances
List all active managed kitty instances.
Returns: {"success": true, "instances": [...]}
Development
Running Tests
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=kitty_mcp --cov-report=term-missing
# Run only unit tests
uv run pytest tests/unit/
# Run only integration tests (requires kitty)
uv run pytest tests/integration/
Quick Start
- Install kitty-mcp and configure with your MCP client (e.g., OpenCode, Claude Desktop)
- Launch a kitty instance:
result = kitty_launch(app_id="my-terminal", working_directory="/home/user") - Send commands:
kitty_send_text(app_id="my-terminal", text="echo 'Hello World!'") kitty_send_key(app_id="my-terminal", key="enter") - Get output:
output = kitty_get_scrollback(app_id="my-terminal", lines=5) print(output["content"]) # Hello World! - Clean up:
kitty_close(app_id="my-terminal")
MCP Client Configuration
OpenCode
Add to .opencode/opencode.jsonc:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"kitty": {
"type": "local",
"command": ["kitty-mcp"],
"enabled": true
}
}
}
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"kitty": {
"command": "kitty-mcp"
}
}
}
Code Quality
# Type checking
mypy src/
# Linting
ruff check src/
# Format code
ruff format src/
Architecture
┌─────────────────┐
│ MCP Client │ (opencode/Claude Desktop)
│ (stdio IPC) │
└────────┬────────┘
│
▼
┌──────────────────────┐
│ KittyMCP Server │ FastMCP framework
│ ├─ Tool handlers │
│ ├─ State management │
│ ├─ Configuration │
│ └─ Logging │
└────────┬─────────────┘
│ asyncio subprocess
▼
┌──────────────────────┐
│ Kitty RC Commands │ kitten @ --to unix:/socket
└────────┬─────────────┘
│ Unix socket
▼
┌──────────────────────┐
│ Kitty Instance │ allow_remote_control=yes
│ └─ --app-id set │
└──────────────────────┘
Examples
Terminal Automation
# Launch and run commands
kitty_launch(app_id="automation", working_directory="/tmp")
kitty_send_text(app_id="automation", text="ls -la")
kitty_send_key(app_id="automation", key="enter")
output = kitty_get_scrollback(app_id="automation")
print(output["content"])
TUI Application Control
# Control nvim with complex workflows
kitty_launch(app_id="editor", working_directory="/project")
kitty_send_text(app_id="editor", text="nvim")
kitty_send_key(app_id="editor", key="enter")
# Navigate nvim interfaces
kitty_send_key(app_id="editor", key="space")
kitty_send_key(app_id="editor", key="p") # Open projects
kitty_send_key(app_id="editor", key="enter")
Multiple Instance Management
# Launch multiple terminals
for i in range(3):
kitty_launch(app_id=f"terminal-{i}", working_directory=f"/tmp/term-{i}")
# List all instances
instances = kitty_list_instances()
print(f"Active instances: {len(instances['instances'])}")
# Close all
for instance in instances["instances"]:
kitty_close(app_id=instance["app_id"])
Performance
- Command latency: <100ms for RC operations
- Startup time: ~0.5s for MCP server initialization
- Memory usage: <50MB for 10 active instances
- Concurrent support: Up to 100 instances (configurable)
Security
- Socket permissions: User-only (0600) by default
- Command validation: Input sanitization and validation
- Error handling: No sensitive data in logs
- Atomic operations: Safe state persistence
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
License
MIT License - see LICENSE for details.
Changelog
See CHANGELOG.md for version history and release notes.