Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ LOCAL_SHELL_MCP_OAUTH_JWT_SECRET=change-me-64-hex-random-secret
# Keep false unless the container is disposable and intentionally fully controlled by ChatGPT.
LOCAL_SHELL_MCP_ALLOW_FULL_CONTAINER=false

# Remote-only controller mode. Stateless mode implies disable_local and avoids
# controller-local persistent state; use Redis when state must survive cold starts.
LOCAL_SHELL_MCP_DISABLE_LOCAL=false
LOCAL_SHELL_MCP_STATELESS_CONTROLLER=false
LOCAL_SHELL_MCP_STATE_BACKEND=file
LOCAL_SHELL_MCP_STATE_BACKEND_URL=
LOCAL_SHELL_MCP_STATE_BACKEND_PREFIX=local-shell-mcp

# Persist GitHub CLI, Git HTTPS credentials, GitCode credentials, SSH keys, .netrc, and GPG state across container rebuilds.
# The Docker Compose example stores them in the local-shell-mcp-credentials volume.
LOCAL_SHELL_MCP_PERSISTENT_CREDENTIALS=true
Expand Down
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ services:
LOCAL_SHELL_MCP_OAUTH_ADMIN_PIN: "${LOCAL_SHELL_MCP_OAUTH_ADMIN_PIN:-}"
LOCAL_SHELL_MCP_OAUTH_JWT_SECRET: "${LOCAL_SHELL_MCP_OAUTH_JWT_SECRET:-}"
LOCAL_SHELL_MCP_ALLOW_FULL_CONTAINER: "${LOCAL_SHELL_MCP_ALLOW_FULL_CONTAINER:-false}"
LOCAL_SHELL_MCP_DISABLE_LOCAL: "${LOCAL_SHELL_MCP_DISABLE_LOCAL:-false}"
LOCAL_SHELL_MCP_STATELESS_CONTROLLER: "${LOCAL_SHELL_MCP_STATELESS_CONTROLLER:-false}"
LOCAL_SHELL_MCP_STATE_BACKEND: "${LOCAL_SHELL_MCP_STATE_BACKEND:-file}"
LOCAL_SHELL_MCP_STATE_BACKEND_URL: "${LOCAL_SHELL_MCP_STATE_BACKEND_URL:-}"
LOCAL_SHELL_MCP_STATE_BACKEND_PREFIX: "${LOCAL_SHELL_MCP_STATE_BACKEND_PREFIX:-local-shell-mcp}"
LOCAL_SHELL_MCP_PERSISTENT_CREDENTIALS: "${LOCAL_SHELL_MCP_PERSISTENT_CREDENTIALS:-true}"
LOCAL_SHELL_MCP_CREDENTIALS_DIR: "/persist/credentials"
LOCAL_SHELL_MCP_REMOTE_ENABLED: "${LOCAL_SHELL_MCP_REMOTE_ENABLED:-true}"
Expand Down
36 changes: 36 additions & 0 deletions docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ For local-only testing, `auth_bypass_localhost` is enabled by default. Do not ex
| `audit_log_path` | `LOCAL_SHELL_MCP_AUDIT_LOG_PATH` | `PosixPath('/workspace/.local-shell-mcp/audit.jsonl')` | |
| `agent_config_dir` | `LOCAL_SHELL_MCP_AGENT_CONFIG_DIR` | `PosixPath('/workspace/.local-shell-mcp/agent_config')` | |
| `allow_full_container` | `LOCAL_SHELL_MCP_ALLOW_FULL_CONTAINER` | `False` | Disables workspace/path restrictions when true; use only inside disposable boundaries. |
| `disable_local` | `LOCAL_SHELL_MCP_DISABLE_LOCAL` | `False` | Disables the controller host as a shell/file/browser execution target. Remote workers and control-plane services remain available. |
Comment thread
fwerkor marked this conversation as resolved.
| `stateless_controller` | `LOCAL_SHELL_MCP_STATELESS_CONTROLLER` | `False` | Makes the controller suitable for ephemeral/serverless instances: implies `disable_local`, disables local file links/wallpaper caching, and defaults `state_backend` to `memory`. With the default `auth_mode=oauth`, configure a strong `oauth_jwt_secret` explicitly. |
| `state_backend` | `LOCAL_SHELL_MCP_STATE_BACKEND` | `'file'` | `file`, `memory`, or `redis`. Use Redis when serverless controller state must survive cold starts. |
| `state_backend_url` | `LOCAL_SHELL_MCP_STATE_BACKEND_URL` | `None` | Redis connection URL when `state_backend=redis`. Redacted from diagnostics. |
| `state_backend_prefix` | `LOCAL_SHELL_MCP_STATE_BACKEND_PREFIX` | `'local-shell-mcp'` | Namespace for memory/Redis control-plane state. |

### Limits

Expand Down Expand Up @@ -100,6 +105,17 @@ For local-only testing, `auth_bypass_localhost` is enabled by default. Do not ex
| `remote_job_timeout_s` | `LOCAL_SHELL_MCP_REMOTE_JOB_TIMEOUT_S` | `3600` | |
| `remote_max_pending_jobs` | `LOCAL_SHELL_MCP_REMOTE_MAX_PENDING_JOBS` | `256` | Maximum queued or pending jobs per worker. |
| `remote_cancelled_job_ttl_s` | `LOCAL_SHELL_MCP_REMOTE_CANCELLED_JOB_TTL_S` | `3600` | Retention time for cancellation tombstones used to skip timed-out queued jobs. |
| `remote_transfer_strategy` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_STRATEGY` | `'auto'` | `auto`, `relay`, `direct`, or `object_store`. `auto` tries enabled peer-direct, then configured S3, then bounded-memory controller relay. |
| `remote_peer_transfer_enabled` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_ENABLED` | `False` | Opt in to a one-shot HTTP receiver on the destination worker for worker-to-worker direct transfer. Enable only on a trusted private network such as a VPC/Tailscale network. |
| `remote_peer_transfer_bind_host` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_BIND_HOST` | `'0.0.0.0'` | Bind address for the one-shot destination-worker receiver. |
| `remote_peer_transfer_advertise_host` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_ADVERTISE_HOST` | `None` | Address advertised to the source worker; defaults to the destination worker hostname/FQDN. |
| `remote_peer_transfer_port` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_PORT` | `0` | Receiver port; `0` chooses an ephemeral port. |
| `remote_peer_transfer_timeout_s` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_TIMEOUT_S` | `3600` | Lifetime/timeout for a one-shot direct receiver. |
| `remote_transfer_s3_bucket` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_BUCKET` | `None` | Optional S3-compatible bucket used for presigned worker-to-worker transfers. Requires the `s3` extra. |
| `remote_transfer_s3_prefix` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_PREFIX` | `'local-shell-mcp'` | Object-key prefix for temporary transfer objects. |
| `remote_transfer_s3_region` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_REGION` | `None` | Optional S3 region. |
| `remote_transfer_s3_endpoint_url` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_ENDPOINT_URL` | `None` | Optional S3-compatible endpoint URL. |
| `remote_transfer_s3_presign_ttl_s` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_PRESIGN_TTL_S` | `3600` | Presigned PUT/GET URL lifetime. Temporary objects are deleted after transfer. |

### Shell and executable paths

Expand Down Expand Up @@ -146,6 +162,7 @@ mode: mcp
workspace_root: /workspace
auth_mode: oauth
remote_enabled: true
disable_local: false
ui_enabled: true
ui_path: /ui
file_download_enabled: true
Expand All @@ -154,6 +171,25 @@ shell_env_blocked_prefixes:
- DOCKER_
```

Serverless controller with durable Redis state:

```yaml
mode: mcp
stateless_controller: true
state_backend: redis
state_backend_url: redis://redis.internal:6379/0
remote_transfer_strategy: auto
```

`stateless_controller` removes the need for a persistent controller volume. The `memory`
backend is intentionally ephemeral: a cold start invalidates pending remote invites and worker
identities and discards OAuth clients, jobs, and audit records. Use Redis when any of that state
must survive cold starts, including durable worker revocation semantics. With the default
`auth_mode=oauth`, inject at least 32 bytes of random key material through
`LOCAL_SHELL_MCP_OAUTH_JWT_SECRET`. Active remote RPC queues/futures are process-local, so
deployments that use remote workers should currently run one active controller instance at a
time rather than multiple load-balanced controller replicas.

## Operational advice

- Keep `allow_full_container=false` unless the container or VM is disposable.
Expand Down
29 changes: 29 additions & 0 deletions docs/reference/configuration.zh-Hant.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ LOCAL_SHELL_MCP_OAUTH_JWT_SECRET=change-me-long-random-secret
| `audit_log_path` | `LOCAL_SHELL_MCP_AUDIT_LOG_PATH` | `PosixPath('/workspace/.local-shell-mcp/audit.jsonl')` | 審計日誌路徑。 |
| `agent_config_dir` | `LOCAL_SHELL_MCP_AGENT_CONFIG_DIR` | `PosixPath('/workspace/.local-shell-mcp/agent_config')` | agent 配置目錄。 |
| `allow_full_container` | `LOCAL_SHELL_MCP_ALLOW_FULL_CONTAINER` | `False` | 爲 true 時禁用工作區 / 路徑限制;只在一次性邊界內使用。 |
| `disable_local` | `LOCAL_SHELL_MCP_DISABLE_LOCAL` | `False` | 停用控制器主機作為 shell / 檔案 / 瀏覽器執行目標;遠端 worker 與控制平面服務仍可使用。 |
| `stateless_controller` | `LOCAL_SHELL_MCP_STATELESS_CONTROLLER` | `False` | 面向臨時實例/serverless 的無狀態控制器模式;隱含 `disable_local`,預設使用記憶體狀態後端。使用預設的 `auth_mode=oauth` 時,需要明確設定強 `oauth_jwt_secret`。 |
| `state_backend` | `LOCAL_SHELL_MCP_STATE_BACKEND` | `'file'` | `file`、`memory` 或 `redis`;serverless 冷啟動後需要保留狀態時使用 Redis。 |
| `state_backend_url` | `LOCAL_SHELL_MCP_STATE_BACKEND_URL` | `None` | `state_backend=redis` 時的 Redis URL;診斷輸出會隱藏。 |
| `state_backend_prefix` | `LOCAL_SHELL_MCP_STATE_BACKEND_PREFIX` | `'local-shell-mcp'` | 記憶體/Redis 控制平面狀態的命名空間。 |

### 限制

Expand Down Expand Up @@ -88,6 +93,17 @@ LOCAL_SHELL_MCP_OAUTH_JWT_SECRET=change-me-long-random-secret
| `remote_job_timeout_s` | `LOCAL_SHELL_MCP_REMOTE_JOB_TIMEOUT_S` | `3600` | 遠程 job 默認超時。 |
| `remote_max_pending_jobs` | `LOCAL_SHELL_MCP_REMOTE_MAX_PENDING_JOBS` | `256` | 每個 worker 最多排隊或等待完成的 job 數。 |
| `remote_cancelled_job_ttl_s` | `LOCAL_SHELL_MCP_REMOTE_CANCELLED_JOB_TTL_S` | `3600` | 用於跳過已超時排隊任務的取消標記保留時間。 |
| `remote_transfer_strategy` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_STRATEGY` | `'auto'` | `auto`、`relay`、`direct` 或 `object_store`;`auto` 依次嘗試已啟用的 worker 直傳、S3,再退回 controller 有界記憶體 relay。 |
| `remote_peer_transfer_enabled` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_ENABLED` | `False` | 啟用目標 worker 的一次性 HTTP receiver 進行 worker→worker 直傳;僅建議在 VPC/Tailscale 等可信私網中開啟。 |
| `remote_peer_transfer_bind_host` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_BIND_HOST` | `'0.0.0.0'` | 一次性 receiver 的監聽位址。 |
| `remote_peer_transfer_advertise_host` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_ADVERTISE_HOST` | `None` | 告知來源 worker 的目標位址;預設使用目標 worker 主機名/FQDN。 |
| `remote_peer_transfer_port` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_PORT` | `0` | receiver 連接埠;`0` 表示自動選擇臨時連接埠。 |
| `remote_peer_transfer_timeout_s` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_TIMEOUT_S` | `3600` | 一次性直傳 receiver 的超時/存活時間。 |
| `remote_transfer_s3_bucket` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_BUCKET` | `None` | 可選 S3 相容 bucket,用於預簽名 URL 傳輸;需安裝 `s3` extra。 |
| `remote_transfer_s3_prefix` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_PREFIX` | `'local-shell-mcp'` | 臨時物件 key 前綴。 |
| `remote_transfer_s3_region` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_REGION` | `None` | 可選 S3 region。 |
| `remote_transfer_s3_endpoint_url` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_ENDPOINT_URL` | `None` | 可選 S3 相容 endpoint。 |
| `remote_transfer_s3_presign_ttl_s` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_PRESIGN_TTL_S` | `3600` | 預簽名 PUT/GET URL 有效期;傳輸結束後自動刪除臨時物件。 |

### Shell 與可執行路徑

Expand Down Expand Up @@ -134,12 +150,25 @@ mode: mcp
workspace_root: /workspace
auth_mode: oauth
remote_enabled: true
disable_local: false
file_download_enabled: true
shell_env_blocked_prefixes:
- LOCAL_SHELL_MCP_
- DOCKER_
```

Serverless 控制器並使用 Redis 持久化控制平面狀態:

```yaml
mode: mcp
stateless_controller: true
state_backend: redis
state_backend_url: redis://redis.internal:6379/0
remote_transfer_strategy: auto
```

`stateless_controller` 不要求 controller 掛載持久卷。`memory` 後端是完全臨時的:冷啟動會使待使用的 remote invite 和 worker identity 失效,並丟棄 OAuth client、job 與 audit 狀態。需要這些狀態跨冷啟動保留(包括可靠的 worker revoke 語義)時應使用 Redis。使用預設的 `auth_mode=oauth` 時,同時透過 `LOCAL_SHELL_MCP_OAUTH_JWT_SECRET` 注入至少 32 位元組的隨機密鑰。當前遠端 RPC 的活動佇列/等待 future 仍位於 controller 程序內,因此使用 remote worker 時應保持單個 active controller 實例,而不是多個負載平衡副本。

## 運維建議

- 除非容器或 VM 是一次性的,否則保持 `allow_full_container=false`。
Expand Down
29 changes: 29 additions & 0 deletions docs/reference/configuration.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ LOCAL_SHELL_MCP_OAUTH_JWT_SECRET=change-me-long-random-secret
| `audit_log_path` | `LOCAL_SHELL_MCP_AUDIT_LOG_PATH` | `PosixPath('/workspace/.local-shell-mcp/audit.jsonl')` | 审计日志路径。 |
| `agent_config_dir` | `LOCAL_SHELL_MCP_AGENT_CONFIG_DIR` | `PosixPath('/workspace/.local-shell-mcp/agent_config')` | agent 配置目录。 |
| `allow_full_container` | `LOCAL_SHELL_MCP_ALLOW_FULL_CONTAINER` | `False` | 为 true 时禁用工作区 / 路径限制;只在一次性边界内使用。 |
| `disable_local` | `LOCAL_SHELL_MCP_DISABLE_LOCAL` | `False` | 禁用控制器主机作为 shell / 文件 / 浏览器执行目标;远程 worker 与控制平面服务仍可使用。 |
| `stateless_controller` | `LOCAL_SHELL_MCP_STATELESS_CONTROLLER` | `False` | 面向临时实例/serverless 的无状态控制器模式;隐含 `disable_local`,默认使用内存状态后端。使用默认的 `auth_mode=oauth` 时,需要显式配置强 `oauth_jwt_secret`。 |
| `state_backend` | `LOCAL_SHELL_MCP_STATE_BACKEND` | `'file'` | `file`、`memory` 或 `redis`;serverless 冷启动后需要保留状态时使用 Redis。 |
| `state_backend_url` | `LOCAL_SHELL_MCP_STATE_BACKEND_URL` | `None` | `state_backend=redis` 时的 Redis URL;诊断输出会隐藏。 |
| `state_backend_prefix` | `LOCAL_SHELL_MCP_STATE_BACKEND_PREFIX` | `'local-shell-mcp'` | 内存/Redis 控制面状态的命名空间。 |

### 限制

Expand Down Expand Up @@ -88,6 +93,17 @@ LOCAL_SHELL_MCP_OAUTH_JWT_SECRET=change-me-long-random-secret
| `remote_job_timeout_s` | `LOCAL_SHELL_MCP_REMOTE_JOB_TIMEOUT_S` | `3600` | 远程 job 默认超时。 |
| `remote_max_pending_jobs` | `LOCAL_SHELL_MCP_REMOTE_MAX_PENDING_JOBS` | `256` | 每个 worker 最多排队或等待完成的 job 数。 |
| `remote_cancelled_job_ttl_s` | `LOCAL_SHELL_MCP_REMOTE_CANCELLED_JOB_TTL_S` | `3600` | 用于跳过已超时排队任务的取消标记保留时间。 |
| `remote_transfer_strategy` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_STRATEGY` | `'auto'` | `auto`、`relay`、`direct` 或 `object_store`;`auto` 依次尝试已启用的 worker 直传、S3,再回退到 controller 有界内存 relay。 |
| `remote_peer_transfer_enabled` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_ENABLED` | `False` | 启用目标 worker 的一次性 HTTP receiver 进行 worker→worker 直传;仅建议在 VPC/Tailscale 等可信私网中开启。 |
| `remote_peer_transfer_bind_host` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_BIND_HOST` | `'0.0.0.0'` | 一次性 receiver 的监听地址。 |
| `remote_peer_transfer_advertise_host` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_ADVERTISE_HOST` | `None` | 告知源 worker 的目标地址;默认使用目标 worker 主机名/FQDN。 |
| `remote_peer_transfer_port` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_PORT` | `0` | receiver 端口;`0` 表示自动选择临时端口。 |
| `remote_peer_transfer_timeout_s` | `LOCAL_SHELL_MCP_REMOTE_PEER_TRANSFER_TIMEOUT_S` | `3600` | 一次性直传 receiver 的超时/存活时间。 |
| `remote_transfer_s3_bucket` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_BUCKET` | `None` | 可选 S3 兼容 bucket,用于预签名 URL 传输;需安装 `s3` extra。 |
| `remote_transfer_s3_prefix` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_PREFIX` | `'local-shell-mcp'` | 临时对象 key 前缀。 |
| `remote_transfer_s3_region` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_REGION` | `None` | 可选 S3 region。 |
| `remote_transfer_s3_endpoint_url` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_ENDPOINT_URL` | `None` | 可选 S3 兼容 endpoint。 |
| `remote_transfer_s3_presign_ttl_s` | `LOCAL_SHELL_MCP_REMOTE_TRANSFER_S3_PRESIGN_TTL_S` | `3600` | 预签名 PUT/GET URL 有效期;传输结束后自动删除临时对象。 |

### Shell 与可执行路径

Expand Down Expand Up @@ -134,12 +150,25 @@ mode: mcp
workspace_root: /workspace
auth_mode: oauth
remote_enabled: true
disable_local: false
file_download_enabled: true
shell_env_blocked_prefixes:
- LOCAL_SHELL_MCP_
- DOCKER_
```

Serverless 控制器并使用 Redis 持久化控制面状态:

```yaml
mode: mcp
stateless_controller: true
state_backend: redis
state_backend_url: redis://redis.internal:6379/0
remote_transfer_strategy: auto
```

`stateless_controller` 不要求 controller 挂载持久卷。`memory` 后端是完全临时的:冷启动会使待使用的 remote invite 和 worker identity 失效,并丢弃 OAuth client、job 与 audit 状态。需要这些状态跨冷启动保留(包括可靠的 worker revoke 语义)时应使用 Redis。使用默认的 `auth_mode=oauth` 时,同时通过 `LOCAL_SHELL_MCP_OAUTH_JWT_SECRET` 注入至少 32 字节的随机密钥。当前远程 RPC 的活动队列/等待 future 仍位于 controller 进程内,因此使用 remote worker 时应保持单个 active controller 实例,而不是多个负载均衡副本。

## 运维建议

- 除非容器或 VM 是一次性的,否则保持 `allow_full_container=false`。
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ When `machine` is supplied, the call additionally requires `remote:use` and runs

### `remote_transfer`

Start a tracked job that copies a file or directory between the controller and remote machines. Remote uploads use resumable raw-binary chunks; use job_list, job_tail, job_stop, and job_retry to manage the transfer.
Start a tracked job that copies a file or directory between the controller and remote machines. Remote uploads use resumable raw-binary chunks; use job_list, job_tail, job_stop, and job_retry to manage the transfer. Worker-to-worker transfers never stage the payload on controller disk: `auto` can use an opt-in peer-direct path, an S3-compatible presigned object path, or a bounded-memory controller relay fallback.

| Parameter | Type | Required/default | Description |
|---|---|---|---|
Expand All @@ -492,7 +492,7 @@ Start a tracked job that copies a file or directory between the controller and r

OAuth scopes: `shell:read, shell:write, shell:execute, browser:use, file:share, remote:use`.

At least one of `source_machine` and `destination_machine` must be supplied. Omitted endpoints refer to the controller workspace; the source may be either a file or a directory.
At least one of `source_machine` and `destination_machine` must be supplied. Omitted endpoints refer to the controller workspace; the source may be either a file or a directory. With `disable_local=true`, both endpoints must be remote workers.

### `create_file_link`

Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ dev = [
"pytest-asyncio>=0.23.0",
"ruff>=0.5.0",
]
redis = [
"redis>=5.0.0,<7",
]
Comment on lines +47 to +49

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Install Redis support in the published container

In the documented Docker Compose serverless setup, setting LOCAL_SHELL_MCP_STATE_BACKEND=redis cannot work with the published image: Redis is defined only in this optional extra, while the Dockerfile installs .[dev] and requirements-agent.txt contains no Redis client. The first state-store access therefore raises the missing-redis runtime error and breaks OAuth and other control-plane operations; install the redis extra in the official runtime image that now exposes this configuration.

Useful? React with 👍 / 👎.

s3 = [
"boto3>=1.34.0,<2",
]
docs = [
"mkdocs-material>=9.5",
"mkdocs-static-i18n>=1.3",
Expand Down
Loading