Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.git
.github
.venv
venv
env
ENV
__pycache__
*.py[cod]
*.egg-info
build
dist
.pytest_cache
.coverage
htmlcov
site
.cache
.DS_Store
.idea
.vscode
docs
mkdocs.yml
docs-requirements.txt
*.md
!README.md
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# syntax=docker/dockerfile:1.6
FROM python:3.12-slim AS base

ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_NO_CACHE_DIR=1

# pexpect spawns child processes; ensure a usable shell + common utilities
# for TUI applications under test.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash \
coreutils \
ncurses-bin \
procps \
tini \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Install Python deps first for better layer caching
COPY requirements.txt ./
RUN pip install -r requirements.txt

COPY . .

# stdio-based MCP server — keep stdin open when running interactively
ENTRYPOINT ["/usr/bin/tini", "--", "python", "/app/server.py"]
96 changes: 96 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,22 @@ source .venv/bin/activate
uv pip install -e .
```

### Run with Docker

Build the image:

```bash
docker build -t mcp-tui-test:latest .
```

Run the server (stdio is the MCP transport, so use `-i` and skip `-d`):

```bash
docker run --rm -i mcp-tui-test:latest
```

The published image (if you prefer not to build locally) can also be pulled from GHCR once tagged: `ghcr.io/georgepearse/mcp-tui-test:latest`.

## Usage

### Running the MCP Server
Expand Down Expand Up @@ -100,6 +116,86 @@ Or if installed as a package:
}
```

Or via Docker:

```json
{
"mcpServers": {
"tui-test": {
"command": "docker",
"args": ["run", "--rm", "-i", "mcp-tui-test:latest"]
}
}
}
```

### Configure in opencode

opencode reads MCP servers from `~/.config/opencode/opencode.jsonc` (or your project-local `opencode.jsonc`). Add an entry under `mcp`:

Run from PyPI/Git via `uvx`:

```jsonc
{
"mcp": {
"mcp-tui-test": {
"type": "local",
"command": [
"uvx",
"git+https://github.com/GeorgePearse/mcp-tui-test.git"
],
"enabled": true
}
}
}
```

Run via Docker (each invocation spins up a fresh container over stdio):

```jsonc
{
"mcp": {
"mcp-tui-test": {
"type": "local",
"command": ["docker", "run", "--rm", "-i", "mcp-tui-test:latest"],
"enabled": true
}
}
}
```

### Configure in Cursor

Add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` in your project:

```json
{
"mcpServers": {
"tui-test": {
"command": "uvx",
"args": ["git+https://github.com/GeorgePearse/mcp-tui-test.git"]
}
}
}
```

Or via Docker:

```json
{
"mcpServers": {
"tui-test": {
"command": "docker",
"args": ["run", "--rm", "-i", "mcp-tui-test:latest"]
}
}
}
```

### Configure in Continue / Cline / Zed

Most MCP-aware clients accept the same `command` + `args` shape shown above. Use either the `uvx` form (no local checkout needed) or the `docker run --rm -i mcp-tui-test:latest` form (after building the image once).

## Available Tools

### `launch_tui`
Expand Down
82 changes: 82 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
version: "3"

# Useful operations for the mcp-tui-test Docker container.
# Run `task --list` to see available tasks.

vars:
IMAGE: mcp-tui-test
TAG: latest
CONTAINER: mcp-tui-test

tasks:
default:
desc: List available tasks
cmds:
- task --list

docker:build:
desc: Build the Docker image
cmds:
- docker build -t {{.IMAGE}}:{{.TAG}} .

docker:rebuild:
desc: Build the Docker image without cache
cmds:
- docker build --no-cache -t {{.IMAGE}}:{{.TAG}} .

docker:run:
desc: Run the MCP server in the foreground (stdio attached) — use this for MCP clients
deps: [docker:build]
cmds:
- docker run --rm -i --name {{.CONTAINER}} {{.IMAGE}}:{{.TAG}}

docker:start:
desc: Start the container detached (keeps stdin open so the MCP server stays alive)
deps: [docker:build]
cmds:
- docker rm -f {{.CONTAINER}} 2>/dev/null || true
- docker run -d -i --name {{.CONTAINER}} {{.IMAGE}}:{{.TAG}}
- echo "Started {{.CONTAINER}}. Attach with 'task docker:attach' or view logs with 'task docker:logs'."

docker:stop:
desc: Stop the running container gracefully
cmds:
- docker stop {{.CONTAINER}} 2>/dev/null || true

docker:kill:
desc: Force-kill and remove the running container
cmds:
- docker kill {{.CONTAINER}} 2>/dev/null || true
- docker rm -f {{.CONTAINER}} 2>/dev/null || true

docker:restart:
desc: Restart the container
cmds:
- task: docker:kill
- task: docker:start

docker:logs:
desc: Tail container logs
cmds:
- docker logs -f {{.CONTAINER}}

docker:attach:
desc: Attach to the running container's stdio (Ctrl+P Ctrl+Q to detach)
cmds:
- docker attach {{.CONTAINER}}

docker:shell:
desc: Open a bash shell inside the running container
cmds:
- docker exec -it {{.CONTAINER}} /bin/bash

docker:status:
desc: Show container status
cmds:
- docker ps -a --filter name={{.CONTAINER}}

docker:clean:
desc: Remove the container and the image
cmds:
- docker rm -f {{.CONTAINER}} 2>/dev/null || true
- docker rmi {{.IMAGE}}:{{.TAG}} 2>/dev/null || true