Skip to main content
Glama
luc-vocab
by luc-vocab
README.md
# gemini-3-pro-mcp-streamable-http-mcp

A Docker-based deployment that wraps the [RLabs-Inc/gemini-mcp](https://github.com/RLabs-Inc/gemini-mcp) stdio MCP server with [supergateway](https://github.com/supercorp-ai/supergateway) to expose it over **Streamable HTTP**. Includes a Python test suite that validates the full image-edit workflow end-to-end.

## Architecture

```
Client (MCP SDK)
    │
    │  Streamable HTTP  (POST/GET http://host:8000/mcp)
    ▼
┌────────────────────────────────────────────┐
│  Docker Container                          │
│                                            │
│  supergateway                              │
│    --stdio "gemini-mcp"                    │
│    --outputTransport streamableHttp        │
│    --port 8000                             │
│         │                                  │
│         │ stdio (stdin/stdout)             │
│         ▼                                  │
│  @rlabs-inc/gemini-mcp                     │
│    (talks to Google Gemini API)            │
└────────────────────────────────────────────┘
```

**supergateway** spawns `gemini-mcp` as a child process, speaks MCP over stdio with it, and re-exposes every tool over a single Streamable HTTP endpoint at `/mcp`.

## Prerequisites

- Docker
- A [Google Gemini API key](https://aistudio.google.com/apikey)
- Python 3.10+ (for running the tests)

## Quick Start

### Build the image

```bash
docker build -t gemini-mcp .
```

### Run the container

```bash
docker run -e GEMINI_API_KEY=your_key_here -p 8000:8000 gemini-mcp
```

The MCP server is now available at `http://localhost:8000/mcp`.

### Connect from any MCP client

Any client that supports Streamable HTTP transport can connect. For example, with the MCP Python SDK:

```python
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async with streamablehttp_client("http://localhost:8000/mcp") as (read, write, _):
    async with ClientSession(read, write) as session:
        await session.initialize()
        tools = await session.list_tools()
        print([t.name for t in tools.tools])
```

## File Reference

| File | Purpose |
|---|---|
| `Dockerfile` | Builds the container image: installs `supergateway` and `@rlabs-inc/gemini-mcp` globally on `node:22-slim`, then runs supergateway on port 8000 with Streamable HTTP output. |
| `test_gemini_mcp.py` | Pytest test suite that builds the image, starts a container, connects via the MCP Python SDK, and exercises the image-edit workflow. |
| `requirements.txt` | Python dependencies for the test suite. |

## Dockerfile

```dockerfile
FROM node:22-slim
RUN npm install -g supergateway @rlabs-inc/gemini-mcp
ENV GEMINI_API_KEY=""
EXPOSE 8000
CMD ["supergateway", "--stdio", "gemini-mcp", \
     "--outputTransport", "streamableHttp", "--port", "8000"]
```

| Layer | What it does |
|---|---|
| `node:22-slim` | Minimal Node.js 22 runtime. |
| `npm install -g` | Pre-installs both packages so startup is fast (no `npx` download on every boot). |
| `ENV GEMINI_API_KEY` | Declares the variable; the actual key is injected at `docker run` time via `-e`. |
| `EXPOSE 8000` | Documents the listening port. |
| `CMD` | Launches supergateway, which spawns `gemini-mcp` over stdio and bridges it to Streamable HTTP on port 8000. |

## Test Suite

### Dependencies

Install with:

```bash
pip install -r requirements.txt
```

| Package | Role |
|---|---|
| `mcp` | Official MCP Python SDK -- provides `ClientSession` and the Streamable HTTP transport client. |
| `pytest` | Test runner. |
| `pytest-asyncio` | Enables `async def` test functions. |
| `Pillow` | Image validation (format detection, integrity check via `verify()`). |
| `docker` | Python Docker SDK -- builds images, manages container lifecycle. |

### Running the tests

```bash
GEMINI_API_KEY=your_key pytest test_gemini_mcp.py -v
```

The test suite is fully self-contained: it builds the Docker image, starts the container, runs the tests, and tears the container down afterward.

### Fixtures

| Fixture | Scope | Description |
|---|---|---|
| `gemini_api_key` | session | Reads `GEMINI_API_KEY` from the environment. Skips all tests if unset. |
| `docker_client` | session | Creates a Docker SDK client from the local Docker daemon. |
| `gemini_container` | session | Builds the image, removes stale containers, starts a fresh container on port 18000, polls until the TCP port is accepting connections, yields the container, and force-removes it on teardown. |

### Tests

#### `test_list_tools`

Connects to the MCP server and verifies that the expected image-edit tools are exposed:
- `gemini-start-image-edit`
- `gemini-continue-image-edit`
- `gemini-end-image-edit`

#### `test_image_edit_workflow`

End-to-end image editing round-trip:

1. **Start session** -- calls `gemini-start-image-edit` with a prompt ("a simple red circle on a white background"), asserts an `ImageContent` and `TextContent` block are returned, extracts the session ID.
2. **Apply edit** -- calls `gemini-continue-image-edit` with the session ID and an edit instruction ("change the red circle to a blue star"), asserts a new image is returned.
3. **Download** -- base64-decodes the image data and writes it to a temp file.
4. **Validate** -- opens the bytes with Pillow, calls `verify()` to check integrity, asserts width/height > 0 and format is PNG/JPEG/WEBP/GIF. Also validates the file written to disk.
5. **Close session** -- calls `gemini-end-image-edit` to clean up the server-side session.

### Configuration constants

| Constant | Default | Purpose |
|---|---|---|
| `IMAGE_NAME` | `gemini-mcp-test` | Docker image tag used during the test run. |
| `CONTAINER_NAME` | `gemini-mcp-test-container` | Container name (allows cleanup of stale runs). |
| `HOST_PORT` | `18000` | Host port mapped to container port 8000. |
| `MCP_URL` | `http://localhost:18000/mcp` | Full MCP endpoint URL. |
| `STARTUP_TIMEOUT` | `120` | Max seconds to wait for the container to accept TCP connections. |
| `MCP_CALL_TIMEOUT` | `180` | Read timeout (seconds) for individual MCP tool calls to the Gemini API. |

## Environment Variables

| Variable | Required | Description |
|---|---|---|
| `GEMINI_API_KEY` | Yes | Google Gemini API key. Passed to the container at runtime. |

The `@rlabs-inc/gemini-mcp` package also supports optional variables (`GEMINI_OUTPUT_DIR`, `GEMINI_TOOL_PRESET`, `GEMINI_PRO_MODEL`, etc.) which can be passed through with additional `-e` flags on `docker run`.

## License

See upstream projects for license terms:
- [supergateway](https://github.com/supercorp-ai/supergateway)
- [gemini-mcp](https://github.com/RLabs-Inc/gemini-mcp)