cooperage 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. cooperage-0.1.0/.env.example +58 -0
  2. cooperage-0.1.0/.github/workflows/publish-images.yml +70 -0
  3. cooperage-0.1.0/.github/workflows/test.yml +29 -0
  4. cooperage-0.1.0/.gitignore +20 -0
  5. cooperage-0.1.0/CONTRIBUTING.md +89 -0
  6. cooperage-0.1.0/Dockerfile +13 -0
  7. cooperage-0.1.0/Dockerfile.ui +15 -0
  8. cooperage-0.1.0/LICENSE +21 -0
  9. cooperage-0.1.0/PKG-INFO +18 -0
  10. cooperage-0.1.0/README.md +231 -0
  11. cooperage-0.1.0/ROADMAP.md +77 -0
  12. cooperage-0.1.0/assets/favicon.png +0 -0
  13. cooperage-0.1.0/assets/logo.png +0 -0
  14. cooperage-0.1.0/chart/Chart.yaml +6 -0
  15. cooperage-0.1.0/chart/templates/configmap.yaml +33 -0
  16. cooperage-0.1.0/chart/templates/deployment.yaml +59 -0
  17. cooperage-0.1.0/chart/templates/ingress.yaml +33 -0
  18. cooperage-0.1.0/chart/templates/namespace.yaml +7 -0
  19. cooperage-0.1.0/chart/templates/pvc.yaml +19 -0
  20. cooperage-0.1.0/chart/templates/rbac.yaml +40 -0
  21. cooperage-0.1.0/chart/templates/secrets.yaml +1 -0
  22. cooperage-0.1.0/chart/templates/service.yaml +18 -0
  23. cooperage-0.1.0/chart/templates/serviceaccount.yaml +8 -0
  24. cooperage-0.1.0/chart/templates/ui.yaml +53 -0
  25. cooperage-0.1.0/chart/values.yaml +83 -0
  26. cooperage-0.1.0/cooperage/__init__.py +0 -0
  27. cooperage-0.1.0/cooperage/cli/__init__.py +0 -0
  28. cooperage-0.1.0/cooperage/cli/main.py +205 -0
  29. cooperage-0.1.0/cooperage/core/__init__.py +0 -0
  30. cooperage-0.1.0/cooperage/core/audit.py +97 -0
  31. cooperage-0.1.0/cooperage/core/auth.py +103 -0
  32. cooperage-0.1.0/cooperage/core/config.py +58 -0
  33. cooperage-0.1.0/cooperage/core/errors.py +82 -0
  34. cooperage-0.1.0/cooperage/core/models.py +57 -0
  35. cooperage-0.1.0/cooperage/gateway/__init__.py +0 -0
  36. cooperage-0.1.0/cooperage/gateway/server.py +994 -0
  37. cooperage-0.1.0/cooperage/orchestrator/__init__.py +16 -0
  38. cooperage-0.1.0/cooperage/orchestrator/base.py +87 -0
  39. cooperage-0.1.0/cooperage/orchestrator/docker.py +204 -0
  40. cooperage-0.1.0/cooperage/orchestrator/kubernetes.py +377 -0
  41. cooperage-0.1.0/cooperage/registry/__init__.py +0 -0
  42. cooperage-0.1.0/cooperage/registry/registry.py +41 -0
  43. cooperage-0.1.0/cooperage/session/__init__.py +0 -0
  44. cooperage-0.1.0/cooperage/session/manager.py +340 -0
  45. cooperage-0.1.0/docker-compose.yml +31 -0
  46. cooperage-0.1.0/docs/writing-servers.md +273 -0
  47. cooperage-0.1.0/example-servers/image-analyzer/Dockerfile +18 -0
  48. cooperage-0.1.0/example-servers/image-analyzer/requirements.txt +5 -0
  49. cooperage-0.1.0/example-servers/image-analyzer/server.py +94 -0
  50. cooperage-0.1.0/example-servers/synthetic-image-generator/Dockerfile +16 -0
  51. cooperage-0.1.0/example-servers/synthetic-image-generator/requirements.txt +4 -0
  52. cooperage-0.1.0/example-servers/synthetic-image-generator/server.py +198 -0
  53. cooperage-0.1.0/pyproject.toml +43 -0
  54. cooperage-0.1.0/pytest.ini +6 -0
  55. cooperage-0.1.0/scripts/bump-version.sh +54 -0
  56. cooperage-0.1.0/servers/compute/Dockerfile +17 -0
  57. cooperage-0.1.0/servers/compute/requirements.txt +8 -0
  58. cooperage-0.1.0/servers/compute/server.py +78 -0
  59. cooperage-0.1.0/servers/workspace/Dockerfile +16 -0
  60. cooperage-0.1.0/servers/workspace/requirements.txt +3 -0
  61. cooperage-0.1.0/servers/workspace/server.py +115 -0
  62. cooperage-0.1.0/tests/__init__.py +0 -0
  63. cooperage-0.1.0/tests/conftest.py +12 -0
  64. cooperage-0.1.0/tests/test_audit.py +161 -0
  65. cooperage-0.1.0/tests/test_cloud_integration.py +152 -0
  66. cooperage-0.1.0/tests/test_gateway.py +325 -0
  67. cooperage-0.1.0/tests/test_gateway_extended.py +190 -0
  68. cooperage-0.1.0/tests/test_models.py +48 -0
  69. cooperage-0.1.0/tests/test_orchestrator.py +185 -0
  70. cooperage-0.1.0/tests/test_orchestrator_kubernetes.py +294 -0
  71. cooperage-0.1.0/tests/test_registry.py +75 -0
  72. cooperage-0.1.0/tests/test_sdk.py +83 -0
  73. cooperage-0.1.0/tests/test_sdk_docs.py +83 -0
  74. cooperage-0.1.0/tests/test_session_manager.py +167 -0
  75. cooperage-0.1.0/tests/test_session_manager_extended.py +223 -0
  76. cooperage-0.1.0/tests/test_simulator_server.py +129 -0
  77. cooperage-0.1.0/ui/app.py +542 -0
  78. cooperage-0.1.0/uv.lock +2145 -0
@@ -0,0 +1,58 @@
1
+ # Copy to .env and fill in values as needed.
2
+ # All variables use the COOPERAGE_ prefix.
3
+
4
+ # ── Orchestrator ─────────────────────────────────────────────────────────────
5
+ # "docker" (default) or "kubernetes"
6
+ COOPERAGE_ORCHESTRATOR=docker
7
+
8
+ # ── Docker ───────────────────────────────────────────────────────────────────
9
+ COOPERAGE_DOCKER_SOCKET=unix:///var/run/docker.sock
10
+ COOPERAGE_CONTAINER_PORT_RANGE_START=9000
11
+ COOPERAGE_CONTAINER_PORT_RANGE_END=9999
12
+
13
+ # ── Kubernetes ───────────────────────────────────────────────────────────────
14
+ COOPERAGE_K8S_NAMESPACE=cooperage
15
+ COOPERAGE_K8S_NODE_PORT_RANGE_START=30000
16
+ COOPERAGE_K8S_NODE_PORT_RANGE_END=32767
17
+ COOPERAGE_K8S_HOST_PATH_PREFIX=/run/cooperage
18
+
19
+ # ── Sessions ─────────────────────────────────────────────────────────────────
20
+ # Session auto-expiry in seconds (default: 30 min)
21
+ COOPERAGE_SESSION_TTL_SECONDS=1800
22
+ # How often to scan for expired sessions (seconds)
23
+ COOPERAGE_SESSION_CLEANUP_INTERVAL=60
24
+ # Stop idle containers after N seconds of no tool calls
25
+ COOPERAGE_CONTAINER_IDLE_TIMEOUT=600
26
+ # Reset session TTL on each tool call
27
+ COOPERAGE_SESSION_EXTEND_ON_ACTIVITY=true
28
+ # How long to wait for a container to become ready (seconds)
29
+ COOPERAGE_CONTAINER_STARTUP_TIMEOUT=120
30
+
31
+ # ── Persistence ──────────────────────────────────────────────────────────────
32
+ # Where to store registry and session state (defaults to ~/.cooperage/)
33
+ # COOPERAGE_REGISTRY_PATH=/data/cooperage/registry.json
34
+ # COOPERAGE_SESSIONS_PATH=/data/cooperage/sessions.json
35
+
36
+ # ── Gateway ──────────────────────────────────────────────────────────────────
37
+ COOPERAGE_GATEWAY_HOST=0.0.0.0
38
+ COOPERAGE_GATEWAY_PORT=8080
39
+ # URL shown to users after session creation (e.g. your hosted UI)
40
+ # COOPERAGE_UI_URL=http://localhost:8501
41
+
42
+ # ── Resource limits ──────────────────────────────────────────────────────────
43
+ COOPERAGE_DEFAULT_CPU_LIMIT=1.0
44
+ COOPERAGE_DEFAULT_MEMORY_LIMIT=512m
45
+
46
+ # ── Network isolation ────────────────────────────────────────────────────────
47
+ COOPERAGE_NETWORK_ISOLATION=true
48
+
49
+ # ── Image registry ───────────────────────────────────────────────────────────
50
+ # Prepend a registry mirror to all image pulls (air-gapped / internal mirror)
51
+ # COOPERAGE_IMAGE_REGISTRY_PREFIX=registry.corp.internal/
52
+ # Path to registry credentials JSON (for private registries)
53
+ # COOPERAGE_REGISTRY_AUTH_PATH=/etc/cooperage/registry-auth.json
54
+
55
+ # ── Enterprise auth & audit ──────────────────────────────────────────────────
56
+ # Authentication, OIDC/SSO, per-tenant RBAC, session quotas, and audit logging
57
+ # are provided by the cooperage-enterprise package. See:
58
+ # https://github.com/cooperage-io/cooperage-enterprise
@@ -0,0 +1,70 @@
1
+ name: Publish container images
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+
8
+ env:
9
+ REGISTRY: ghcr.io
10
+ ORG: cooperage-io
11
+
12
+ jobs:
13
+ build-and-push:
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ contents: read
17
+ packages: write
18
+
19
+ strategy:
20
+ matrix:
21
+ include:
22
+ - image: cooperage
23
+ context: .
24
+ dockerfile: Dockerfile
25
+ - image: cooperage-workspace
26
+ context: ./servers/workspace
27
+ dockerfile: ./servers/workspace/Dockerfile
28
+ - image: cooperage-compute
29
+ context: ./servers/compute
30
+ dockerfile: ./servers/compute/Dockerfile
31
+ - image: cooperage-ui
32
+ context: .
33
+ dockerfile: Dockerfile.ui
34
+ - image: cooperage-synthetic-image-generator
35
+ context: ./example-servers/synthetic-image-generator
36
+ dockerfile: ./example-servers/synthetic-image-generator/Dockerfile
37
+ - image: cooperage-image-analyzer
38
+ context: ./example-servers/image-analyzer
39
+ dockerfile: ./example-servers/image-analyzer/Dockerfile
40
+
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+
44
+ - uses: docker/login-action@v3
45
+ with:
46
+ registry: ${{ env.REGISTRY }}
47
+ username: ${{ github.actor }}
48
+ password: ${{ secrets.GITHUB_TOKEN }}
49
+
50
+ - uses: docker/metadata-action@v5
51
+ id: meta
52
+ with:
53
+ images: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image }}
54
+ tags: |
55
+ type=raw,value=latest,enable={{is_default_branch}}
56
+ type=sha,prefix=
57
+ type=semver,pattern={{version}}
58
+ type=semver,pattern={{major}}.{{minor}}
59
+
60
+ - uses: docker/setup-buildx-action@v3
61
+
62
+ - uses: docker/build-push-action@v6
63
+ with:
64
+ context: ${{ matrix.context }}
65
+ file: ${{ matrix.dockerfile }}
66
+ push: true
67
+ tags: ${{ steps.meta.outputs.tags }}
68
+ labels: ${{ steps.meta.outputs.labels }}
69
+ cache-from: type=gha
70
+ cache-to: type=gha,mode=max
@@ -0,0 +1,29 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: astral-sh/setup-uv@v4
14
+ - run: uv sync --dev
15
+ - run: uv run ruff check .
16
+
17
+ test:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: "3.13"
25
+
26
+ - uses: astral-sh/setup-uv@v4
27
+
28
+ - run: uv sync --dev
29
+ - run: uv run pytest tests/ -q --ignore=tests/test_cloud_integration.py
@@ -0,0 +1,20 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ .env
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .DS_Store
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ .mypy_cache/
13
+ .coverage
14
+ htmlcov/
15
+ *.log
16
+ git_logs.txt
17
+ .claude/settings.local.json
18
+ donot-commit/
19
+ cooperage-enterprise/
20
+ .vscode/
@@ -0,0 +1,89 @@
1
+ # Contributing to Cooperage
2
+
3
+ ## Setup
4
+
5
+ ```bash
6
+ git clone https://github.com/cooperage-io/cooperage
7
+ cd cooperage
8
+ uv sync
9
+ ```
10
+
11
+ ## Running tests
12
+
13
+ ```bash
14
+ uv run pytest
15
+ ```
16
+
17
+ All tests are mocked — no Docker daemon or Kubernetes cluster required.
18
+
19
+ ## Linting
20
+
21
+ ```bash
22
+ uv run ruff check cooperage/
23
+ uv run ruff check --fix cooperage/ # auto-fix
24
+ ```
25
+
26
+ ## Project structure
27
+
28
+ ```
29
+ cooperage/ # core package
30
+ cli/ # cooperage CLI (typer)
31
+ core/ # models, config
32
+ gateway/ # MCP gateway server
33
+ orchestrator/ # docker.py, kubernetes.py
34
+ registry/ # server registration
35
+ session/ # session + container lifecycle
36
+ servers/
37
+ workspace/ # built-in workspace server (auto-registered by gateway)
38
+ example-servers/
39
+ image-analyzer/ # example: analyze images with numpy/PIL
40
+ synthetic-image-generator/ # example: generate synthetic satellite imagery
41
+ tests/
42
+ ```
43
+
44
+ ## Adding an example server
45
+
46
+ 1. Create `example-servers/<name>/server.py` using FastMCP:
47
+ ```python
48
+ from mcp.server.fastmcp import FastMCP
49
+ mcp = FastMCP("my-server", json_response=True, stateless_http=True)
50
+
51
+ @mcp.tool()
52
+ def my_tool(arg: str) -> str:
53
+ """Tool description."""
54
+ ...
55
+
56
+ if __name__ == "__main__":
57
+ import os, uvicorn
58
+ uvicorn.run(mcp.streamable_http_app(), host="0.0.0.0", port=int(os.environ.get("PORT", "8000")))
59
+ ```
60
+ 2. Add a `Dockerfile` and `requirements.txt`
61
+ 3. Build: `docker build -t my-server:latest example-servers/<name>`
62
+ 4. Register: `cooperage register --name <name> --image my-server:latest`
63
+
64
+ ## Versioning
65
+
66
+ Cooperage follows [Semantic Versioning](https://semver.org/). The version appears in two places that must stay in sync:
67
+
68
+ - `pyproject.toml` → `project.version`
69
+ - `chart/Chart.yaml` → `version` and `appVersion`
70
+
71
+ ### Cutting a release
72
+
73
+ 1. Run the bump script from main:
74
+ ```bash
75
+ ./scripts/bump-version.sh 0.2.0
76
+ ```
77
+ This updates both files, commits, and tags in one step.
78
+ 2. Push:
79
+ ```bash
80
+ git push origin main --tags
81
+ ```
82
+
83
+ Tags trigger CI to publish versioned images to `ghcr.io/cooperage-io/` (e.g. `cooperage:0.2.0` alongside `cooperage:latest`).
84
+
85
+ ## Submitting changes
86
+
87
+ - Keep PRs focused — one thing at a time
88
+ - Tests required for gateway or orchestrator changes
89
+ - Run ruff before pushing
@@ -0,0 +1,13 @@
1
+ FROM python:3.11-slim
2
+
3
+ # Install uv
4
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
5
+
6
+ WORKDIR /app
7
+
8
+ COPY pyproject.toml .
9
+ COPY cooperage/ cooperage/
10
+
11
+ RUN uv pip install --system --no-cache .
12
+
13
+ CMD ["cooperage", "start", "--sse"]
@@ -0,0 +1,15 @@
1
+ FROM python:3.11-slim
2
+
3
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
4
+
5
+ WORKDIR /app
6
+
7
+ RUN uv pip install --system --no-cache streamlit httpx
8
+
9
+ COPY ui/app.py app.py
10
+ COPY assets/logo.png logo.png
11
+ COPY assets/favicon.png favicon.png
12
+
13
+ EXPOSE 8501
14
+
15
+ CMD ["streamlit", "run", "app.py", "--server.address=0.0.0.0", "--server.port=8501", "--browser.gatherUsageStats=false"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Evan Lavizadeh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: cooperage
3
+ Version: 0.1.0
4
+ Summary: Ephemeral container orchestration for MCP servers
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: anyio>=4.0.0
8
+ Requires-Dist: docker>=7.0.0
9
+ Requires-Dist: fastapi>=0.115.0
10
+ Requires-Dist: httpx-sse>=0.4.0
11
+ Requires-Dist: httpx>=0.27.0
12
+ Requires-Dist: kubernetes>=28.0.0
13
+ Requires-Dist: mcp[cli]>=1.0.0
14
+ Requires-Dist: pydantic-settings>=2.0.0
15
+ Requires-Dist: pydantic>=2.0.0
16
+ Requires-Dist: rich>=13.0.0
17
+ Requires-Dist: typer>=0.12.0
18
+ Requires-Dist: uvicorn[standard]>=0.30.0
@@ -0,0 +1,231 @@
1
+ <p align="center">
2
+ <img src="assets/logo.png" alt="Cooperage" width="420">
3
+ </p>
4
+
5
+ ---
6
+
7
+ MCP makes it easy to give LLMs tools. Cooperage makes those tools *scalable* — each tool call runs in an isolated container with dedicated compute and a shared workspace volume. No infra to manage. Just register a Docker image and let your LLM orchestrate it.
8
+
9
+ ## Why this exists
10
+
11
+ Writing an MCP server is easy. Deploying it somewhere an LLM can actually *use* it — for stateful runs, large datasets, multi-step pipelines — is not. Cooperage is the missing layer between "I have tools" and "my LLM can run them at scale on my own infrastructure."
12
+
13
+ The key thing that makes Cooperage different: **multiple containers per session, one shared `/workspace` volume.** A generator writes a file, an analyzer reads it, a report writer summarizes it — all orchestrated by the LLM, all passing data through the same volume. No other platform does this.
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ LLM (Claude Desktop / API)
19
+ │ MCP (stdio or HTTP)
20
+
21
+ ┌─────────────────────────┐
22
+ │ Cooperage Gateway │ ← single MCP server the LLM talks to
23
+ └────────────┬────────────┘
24
+ │ HTTP JSON-RPC
25
+ ┌───────┴───────┐
26
+ ▼ ▼
27
+ [Container A] [Container B] ephemeral containers,
28
+ your MCP server your MCP server spun up per session
29
+ └───────┬───────┘
30
+ shared /workspace volume data persists across calls
31
+ ```
32
+
33
+ ## Quick start
34
+
35
+ **Prerequisites:** Python 3.11+, [uv](https://docs.astral.sh/uv/getting-started/installation/), Docker Desktop running.
36
+
37
+ ```bash
38
+ # Install
39
+ git clone https://github.com/cooperage-io/cooperage.git && cd cooperage
40
+ uv sync
41
+
42
+ # Build the example server
43
+ docker buildx build --load -t cooperage-image-analyzer:latest example-servers/image-analyzer/
44
+
45
+ # Register it
46
+ uv run cooperage register \
47
+ --name image-analyzer \
48
+ --image cooperage-image-analyzer:latest \
49
+ --description "Analyze images and data in /workspace using numpy/PIL"
50
+ ```
51
+
52
+ ### Connect to Claude Desktop
53
+
54
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "cooperage": {
60
+ "command": "/Users/YOUR_USERNAME/.local/bin/uv",
61
+ "args": ["--directory", "/path/to/cooperage", "run", "--no-active", "cooperage", "start"]
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ Restart Claude Desktop. You should see the hammer icon — Cooperage is connected.
68
+
69
+ ### HTTP mode (for programmatic access)
70
+
71
+ ```bash
72
+ uv run cooperage start --sse
73
+ ```
74
+
75
+ This starts the gateway on `http://localhost:8080/mcp` as a Streamable HTTP MCP server.
76
+
77
+ ## What the LLM sees
78
+
79
+ These are the tools exposed to the LLM via MCP:
80
+
81
+ | Tool | What it does |
82
+ |------|-------------|
83
+ | `cooperage_list_servers` | List available servers and whether their images are cached. |
84
+ | `cooperage_pull_server` | Pre-pull a server image to avoid cold-start latency. |
85
+ | `cooperage_create_session` | Create a workspace session. Returns a `session_id`. |
86
+ | `cooperage_list_tools` | List tools on a server. Starts the container if needed. |
87
+ | `cooperage_call_tool` | Call a tool on a server. Starts the container if needed. |
88
+ | `cooperage_workspace_read` | Read a file from `/workspace`. Handles binary + base64. |
89
+ | `cooperage_workspace_write` | Write a file to `/workspace`. |
90
+ | `cooperage_workspace_list` | List files in `/workspace`. |
91
+ | `cooperage_run_script` | Run a Python script in the compute container. |
92
+ | `cooperage_run_bash` | Run a bash script in the compute container. |
93
+ | `cooperage_end_session` | Tear down containers and delete the workspace volume. |
94
+
95
+ The gateway also exposes [MCP Resources](https://modelcontextprotocol.io/docs/concepts/resources) for reading registry and session state programmatically.
96
+
97
+ ## Multi-container pipelines
98
+
99
+ This is the core use case. Containers in the same session share `/workspace`:
100
+
101
+ ```
102
+ cooperage_call_tool(session, "scene-generator", "generate", {type: "urban"})
103
+ → container A starts, writes /workspace/scene.png
104
+
105
+ cooperage_call_tool(session, "image-analyzer", "analyze", {path: "scene.png"})
106
+ → container B starts, reads /workspace/scene.png
107
+
108
+ cooperage_workspace_read(session, "analysis.json")
109
+ → LLM reads the result directly
110
+ ```
111
+
112
+ Two containers. One session. One shared volume. Your proprietary tools stay in your Docker images, on your infrastructure.
113
+
114
+ ## Writing your own server
115
+
116
+ Package any MCP server as a Docker image:
117
+
118
+ 1. Expose MCP on port `8000` (configurable at registration)
119
+ 2. Use `FastMCP` with `json_response=True, stateless_http=True`
120
+ 3. Read/write `/workspace` for cross-container data sharing
121
+
122
+ See the full guide: **[Writing Servers for Cooperage](docs/writing-servers.md)**
123
+
124
+ For working examples, see [example-servers/image-analyzer/](example-servers/image-analyzer/) and [example-servers/synthetic-image-generator/](example-servers/synthetic-image-generator/).
125
+
126
+ ```bash
127
+ uv run cooperage register \
128
+ --name my-server \
129
+ --image my-org/my-server:latest \
130
+ --description "Does the thing" \
131
+ --repo-url https://github.com/my-org/my-server # optional — lets the LLM clone and debug
132
+ ```
133
+
134
+ ## Kubernetes backend
135
+
136
+ Cooperage has a drop-in Kubernetes backend. Containers run as Pods with NodePort Services; the shared workspace uses `hostPath` volumes (or a ReadWriteMany PVC on multi-node clusters).
137
+
138
+ ```bash
139
+ # Bootstrap the namespace
140
+ COOPERAGE_ORCHESTRATOR=kubernetes uv run cooperage init-k8s
141
+
142
+ # Start the gateway
143
+ COOPERAGE_ORCHESTRATOR=kubernetes uv run cooperage start
144
+ ```
145
+
146
+ The tools and LLM config are identical — only the backend changes.
147
+
148
+ ## Web UI
149
+
150
+ Cooperage ships with a Streamlit-based dashboard for monitoring sessions, viewing container status, and browsing workspace files.
151
+
152
+ ```bash
153
+ uv run cooperage ui
154
+ ```
155
+
156
+ Supports file preview (images, HTML, CSV, PDF) and file upload.
157
+
158
+ ## Enterprise
159
+
160
+ For multi-tenant deployments with authentication (API keys, JWT, OIDC/SSO), per-tenant RBAC, session quotas, and audit logging, see [cooperage-enterprise](https://github.com/cooperage-io/cooperage-enterprise).
161
+
162
+ **Other features included in the open-source core:**
163
+ - Per-container CPU and memory limits (default: 1 CPU, 512 MB)
164
+ - Per-session network isolation (Docker bridge networks / K8s NetworkPolicy)
165
+ - Private image registry authentication
166
+ - Container idle timeout with automatic cleanup
167
+ - Session TTL extension on activity
168
+
169
+ ## Configuration
170
+
171
+ All settings use the `COOPERAGE_` prefix and can go in a `.env` file. See [`.env.example`](.env.example).
172
+
173
+ | Variable | Default | Description |
174
+ |----------|---------|-------------|
175
+ | `COOPERAGE_ORCHESTRATOR` | `docker` | `docker` or `kubernetes` |
176
+ | `COOPERAGE_SESSION_TTL_SECONDS` | `1800` | Session auto-expiry |
177
+ | `COOPERAGE_CONTAINER_IDLE_TIMEOUT` | `600` | Stop idle containers after N seconds |
178
+ | `COOPERAGE_CONTAINER_STARTUP_TIMEOUT` | `120` | Seconds to wait for container readiness |
179
+ | `COOPERAGE_DEFAULT_CPU_LIMIT` | `1.0` | CPU limit per container |
180
+ | `COOPERAGE_DEFAULT_MEMORY_LIMIT` | `512m` | Memory limit per container |
181
+ | `COOPERAGE_NETWORK_ISOLATION` | `true` | Per-session network isolation |
182
+ | `COOPERAGE_UI_URL` | — | UI base URL (shown to users after session creation) |
183
+ | `COOPERAGE_K8S_NAMESPACE` | `cooperage` | Kubernetes namespace |
184
+
185
+ ## CLI
186
+
187
+ ```
188
+ cooperage register Register a Docker image as an MCP server
189
+ cooperage deregister Remove a server from the registry
190
+ cooperage list-servers List registered servers
191
+ cooperage sessions List active sessions
192
+ cooperage start Start the gateway (stdio default, --sse for HTTP)
193
+ cooperage init-k8s Bootstrap the Cooperage K8s namespace
194
+ cooperage ui Launch the web dashboard
195
+ ```
196
+
197
+ ## Comparison
198
+
199
+ | | Containers per session | Shared workspace | Infrastructure | Image source |
200
+ |-|------------------------|-----------------|----------------|--------------|
201
+ | **Cooperage** | Multiple (one per server) | Shared `/workspace` volume | Docker or Kubernetes | Any registry |
202
+ | **Manus** | Single VM | `/home/ubuntu` in one sandbox | Manus cloud only | Pre-installed runtimes |
203
+ | **Docker MCP Toolkit** | Multiple | Each container isolated | Docker Desktop only | Docker catalog |
204
+ | **AWS Bedrock AgentCore** | One (tools colocated) | Partial — 1 GB, preview | AWS only | ECR |
205
+ | **Google ADK + Vertex** | No container orchestration | Memory state only | GCP only | — |
206
+ | **Azure AI Foundry** | No container orchestration | Thread state only | Azure only | — |
207
+
208
+ ### Cooperage vs Manus
209
+
210
+ Manus gives every agent a single pre-built Ubuntu VM with Python, Node.js, and Chromium. MCP servers are external API bridges — the agent calls out to them via `manus-mcp-cli`. It's a managed, general-purpose sandbox that works well for everyday tasks with zero setup.
211
+
212
+ Cooperage takes a different approach: there is no pre-built VM. The LLM dynamically spins up purpose-built containers, each running its own MCP server, all sharing a `/workspace` volume. MCP isn't a bridge to external services — it's the native interface between the LLM and the compute.
213
+
214
+ **Choose Manus** if you want a turnkey managed environment and don't need to control the infrastructure.
215
+
216
+ **Choose Cooperage** if you need:
217
+ - **Self-hosted / on-prem deployment** — your cluster, your network, your data
218
+ - **Custom runtimes** — CUDA, GDAL, proprietary SDKs, anything you can put in a Docker image
219
+ - **Multi-tool pipelines** — containers with different dependencies composing through `/workspace`
220
+ - **Enterprise auth and isolation** — OIDC, JWT, per-tenant RBAC, network policies, resource limits
221
+
222
+
223
+ ## Tests
224
+
225
+ ```bash
226
+ uv run pytest -v
227
+ ```
228
+
229
+ ## License
230
+
231
+ [MIT](LICENSE)
@@ -0,0 +1,77 @@
1
+ # Cooperage Roadmap
2
+
3
+ ## Done
4
+
5
+ ### Core
6
+ - [x] MCP gateway with core tools — `list_servers`, `create_session`, `end_session`, `list_sessions`, `call_tool`, `list_tools`, `pull_server`
7
+ - [x] Docker orchestrator — ephemeral containers, shared `/workspace` volume per session, TTL + idle cleanup
8
+ - [x] Kubernetes orchestrator — drop-in backend, Pods + NodePort Services + hostPath workspace, `cooperage init-k8s`, pod affinity for multi-node
9
+ - [x] Built-in workspace server — `workspace_write/read/list/delete`, auto-registered, pre-warmed on session create
10
+ - [x] Built-in compute server — `run_script` (Python) and `run_bash`, numpy/pandas/scipy/matplotlib/sklearn pre-installed, `uv` for live package installs
11
+ - [x] File-based session persistence — stdio and SSE gateway share state via configurable path
12
+ - [x] Container idle timeout + session activity TTL extension
13
+ - [x] Network isolation — per-session bridge networks
14
+ - [x] Resource limits — CPU/memory configurable at registration and via config
15
+ - [x] `repo_url` on `ServerDef` — LLM can inspect server source when debugging
16
+
17
+ ### Auth (extracted to [cooperage-enterprise](https://github.com/cooperage-io/cooperage-enterprise))
18
+ - [x] API key auth
19
+ - [x] HS256 JWT auth
20
+ - [x] OIDC / RS256 JWT auth (Azure AD, Okta, Auth0)
21
+ - [x] Per-tenant session isolation and RBAC (`allowed_servers`, `max_sessions`)
22
+ - [x] Audit logging (JSON-lines event log)
23
+ - [x] Plugin interface — open core ships with `AuthProvider` and `AuditSink` protocols
24
+
25
+ ### Deployment
26
+ - [x] DigitalOcean droplet — gateway + UI running in production at `137.184.119.104`
27
+ - [x] All images published to `ghcr.io/cooperage-io/` via GitHub Actions CI
28
+ - [x] Hosted Streamlit UI — live session/container/workspace viewer at port 8501
29
+ - [x] `cooperage start --proxy <url>` — Claude Desktop (stdio) → remote cloud gateway bridge
30
+ - [x] `COOPERAGE_UI_URL` — gateway returns session-scoped UI link in `create_session` response
31
+
32
+ ### Developer Experience
33
+ - [x] `cooperage ui` — local Streamlit viewer with session selector, container panel, file preview, upload
34
+ - [x] Image preview — binary files base64-encoded, rendered in browser
35
+ - [x] `simulator` + `analysis` example servers
36
+ - [x] 161 unit tests (mocked) + cloud integration test suite against live droplet
37
+ - [x] MIT license, cooperage-io GitHub org
38
+ - [x] Helm chart — gateway Deployment + ServiceAccount + Role + ConfigMap + Ingress + UI sidecar
39
+ - [x] `/health` endpoint — K8s liveness/readiness probes
40
+ - [x] Persistent gateway state — PVC for sessions.json + registry.json
41
+ - [x] Image registry prefix — `COOPERAGE_IMAGE_REGISTRY_PREFIX` for air-gapped clusters
42
+ - [x] CI — GitHub Actions for tests + image publishing
43
+
44
+ ---
45
+
46
+ ## Up Next
47
+
48
+ - **GPU support for K8s workloads** — allow MCP tool servers to request GPU resources on enterprise Kubernetes clusters.
49
+ - Extend `ResourceLimits` model with `gpu: int | None` and `gpu_type: str | None` (default `nvidia.com/gpu`) fields.
50
+ - Wire GPU limits into the Pod spec in `KubernetesOrchestrator.start_container` as extended resource requests/limits (e.g. `nvidia.com/gpu: "1"`).
51
+ - Add configurable `tolerations` and `nodeSelector` to `ServerDef` so pods land on tainted GPU nodes.
52
+ - Add `default_gpu_tolerations` to `Settings` / Helm `values.yaml` for cluster-wide defaults.
53
+ - GPU-enabled tool server images use `nvidia/cuda` base images with CUDA libraries pre-installed; Cooperage handles scheduling.
54
+ - Docker orchestrator: pass `--gpus` flag via `device_requests` in the Docker SDK for local dev parity.
55
+ - Example server: `gpu-compute` — CUDA-aware compute server with PyTorch/JAX pre-installed, registered with `"resources": {"gpu": 1}`.
56
+ - Enterprise considerations: quota enforcement per tenant (max GPUs), audit log entries for GPU allocation, idle timeout tuning for expensive GPU pods.
57
+
58
+ ---
59
+
60
+ ## Backlog
61
+
62
+ - **Fly.io / Railway backend** — simpler cloud alternative to K8s or bare Docker VM
63
+ - **Dynamic resource sizing** — today resource limits are static (global defaults or per-server overrides at registration). Add support for: resource usage telemetry (CPU/memory per container, exposed as a gateway tool or resource), right-sizing recommendations based on historical usage, and optional Kubernetes VPA (Vertical Pod Autoscaler) integration for containers that consistently over- or under-request.
64
+ - **Workspace storage limits** — workspace volume is currently unbounded (hostPath on K8s, Docker volume locally). Add configurable per-session storage quotas and surface usage in the UI and `cooperage_list_sessions` output.
65
+ - **`cooperage deploy` CLI** — thin wrapper to provision cloud infra (droplet or K8s) and deploy the stack
66
+ - **K8s: RWX PVC workspace** — optional alternative to hostPath + pod affinity for clusters with RWX StorageClass
67
+ - **K8s: Ingress support** — replace NodePort with Ingress/ClusterIP for production on-prem routing
68
+ - **Session sharing** — read-only `session_id` tokens so a user can watch a session without write access
69
+ - **Webhook / event stream** — push session/container lifecycle events to an external URL
70
+ - **Server search / lazy listing** — `cooperage_search_servers` tool that accepts a query and returns matching servers by name/description, so large registries don't flood the context window. `cooperage_list_servers` would return names only (no descriptions) by default, with descriptions opt-in via a flag.
71
+ - **Configurable output paths in example servers** — simulator should accept an `output_path` parameter instead of always overwriting `scene.png`. Prevents the copy-after-generate footgun in multi-step pipelines.
72
+ - **Structured error handling** — tools should return structured error responses (error code, message, partial results) instead of null/silent failures. Critical for enterprise use where tools may run for minutes before failing.
73
+ - **Provenance / artifact lineage** — extend audit log to record which tool wrote which workspace file, enabling full artifact traceability across multi-container pipelines.
74
+ - **Multi-agent demo** — orchestrator agent creates a session and passes `session_id` to parallel subagents, each calling a different server. Validates concurrent tool calls. Target framework: Claude Agent SDK.
75
+ - **`cooperage.io` domain + public landing page** — set up domain, simple landing page with live demo link and install instructions.
76
+ - **Audit log rotation** — cap audit log file size and keep N compressed backups (Python `RotatingFileHandler` or logrotate config). Currently grows unbounded.
77
+ - **Interactive terminal in UI** — web-based terminal (xterm.js) in the Streamlit dashboard that connects to a session's compute container. Enables users to run bash interactively without CLI access to the host. Requires a websocket endpoint on the gateway. `cooperage exec` CLI command as a simpler alternative for local Docker deployments.
Binary file
Binary file
@@ -0,0 +1,6 @@
1
+ apiVersion: v2
2
+ name: cooperage
3
+ description: MCP gateway that orchestrates ephemeral container-based tool servers
4
+ type: application
5
+ version: 0.1.0
6
+ appVersion: "0.1.0"