Skip to content

Commit 8af2ed6

Browse files
feat(docker): add Docker support with multi-platform builds
- Add Dockerfile with multi-stage build for optimal image size - Add docker-compose.yml for easier container management - Add comprehensive Docker documentation in README.Docker.md - Add GitHub Actions workflow to build and publish to ghcr.io - Update CLAUDE.md with Docker commands - Support for linux/amd64 and linux/arm64 platforms
1 parent 2a0665d commit 8af2ed6

File tree

6 files changed

+436
-0
lines changed

6 files changed

+436
-0
lines changed

.dockerignore

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Dependencies
2+
node_modules/
3+
.pnpm-store/
4+
5+
# Build output
6+
dist/
7+
8+
# Git
9+
.git/
10+
.gitignore
11+
12+
# IDE
13+
.vscode/
14+
.idea/
15+
*.swp
16+
*.swo
17+
18+
# OS
19+
.DS_Store
20+
Thumbs.db
21+
22+
# Logs
23+
*.log
24+
npm-debug.log*
25+
pnpm-debug.log*
26+
27+
# Environment files
28+
.env
29+
.env.local
30+
.env.*.local
31+
32+
# Testing
33+
coverage/
34+
.nyc_output/
35+
36+
# Documentation
37+
*.md
38+
!README.md
39+
!LICENSE
40+
41+
# CI/CD
42+
.github/
43+
.claude/
44+
45+
# Docker
46+
Dockerfile
47+
.dockerignore
48+
docker-compose*.yml

.github/workflows/docker.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Build and Publish Docker Image
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
tags:
8+
- 'v*'
9+
pull_request:
10+
branches:
11+
- main
12+
workflow_dispatch:
13+
14+
env:
15+
REGISTRY: ghcr.io
16+
IMAGE_NAME: ${{ github.repository }}
17+
18+
jobs:
19+
build:
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
packages: write
24+
25+
steps:
26+
- name: Checkout repository
27+
uses: actions/checkout@v4
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@v3
31+
32+
- name: Log in to the Container registry
33+
if: github.event_name != 'pull_request'
34+
uses: docker/login-action@v3
35+
with:
36+
registry: ${{ env.REGISTRY }}
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: Extract metadata
41+
id: meta
42+
uses: docker/metadata-action@v5
43+
with:
44+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
45+
tags: |
46+
type=ref,event=branch
47+
type=ref,event=pr
48+
type=semver,pattern={{version}}
49+
type=semver,pattern={{major}}.{{minor}}
50+
type=semver,pattern={{major}}
51+
type=raw,value=latest,enable={{is_default_branch}}
52+
53+
- name: Build and push Docker image
54+
uses: docker/build-push-action@v5
55+
with:
56+
context: .
57+
platforms: linux/amd64,linux/arm64
58+
push: ${{ github.event_name != 'pull_request' }}
59+
tags: ${{ steps.meta.outputs.tags }}
60+
labels: ${{ steps.meta.outputs.labels }}
61+
cache-from: type=gha
62+
cache-to: type=gha,mode=max

CLAUDE.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Commands
6+
7+
### Build & Development
8+
```bash
9+
pnpm build # Compile TypeScript to JavaScript (tsup)
10+
pnpm build:watch # Watch mode for development
11+
pnpm check # Run prettier check + TypeScript type checking
12+
pnpm lint-fix # Auto-fix formatting with prettier
13+
```
14+
15+
### Running the Proxy
16+
```bash
17+
# After building, run the proxy
18+
node dist/proxy.js <remote-server-url> [port] [options]
19+
20+
# Test client mode
21+
node dist/client.js <remote-server-url> [options]
22+
```
23+
24+
### Docker
25+
```bash
26+
# Build Docker image
27+
docker build -t mcp-remote:latest .
28+
29+
# Run with Docker
30+
docker run -it mcp-remote:latest https://remote.mcp.server/sse
31+
32+
# Run with docker-compose
33+
docker-compose run mcp-remote https://remote.mcp.server/sse
34+
35+
# Run with persistent token storage
36+
docker run -it -v mcp-auth:/home/mcp/.mcp-auth mcp-remote:latest https://remote.mcp.server/sse
37+
```
38+
39+
## Architecture Overview
40+
41+
This project acts as a bidirectional proxy between:
42+
- **Local stdio transport** (used by Claude Desktop, Cursor, Windsurf)
43+
- **Remote HTTP/SSE transport** with OAuth 2.0 authentication
44+
45+
### Key Components
46+
47+
1. **proxy.ts**: Main entry point that handles stdio ↔ remote communication
48+
- Reads from stdin, writes to stdout
49+
- Implements transport strategy pattern (http-first, sse-first, http-only, sse-only)
50+
- Manages OAuth authentication flow when needed
51+
52+
2. **client.ts**: Standalone test client for debugging remote connections
53+
- Useful for testing OAuth flows outside of MCP clients
54+
- Run with `npx -p mcp-remote@latest mcp-remote-client <url>`
55+
56+
3. **lib/coordination.ts**: OAuth flow orchestration
57+
- Spins up temporary Express server for OAuth callbacks
58+
- Handles authorization code exchange
59+
- Manages browser opening for auth
60+
61+
4. **lib/mcp-auth-config.ts**: Token persistence and management
62+
- Stores OAuth tokens in `~/.mcp-auth/`
63+
- Automatic token refresh
64+
- Debug logging to `~/.mcp-auth/{server_hash}_debug.log` when --debug flag is used
65+
66+
5. **lib/utils.ts**: Core transport and connection logic
67+
- Implements reconnection with exponential backoff
68+
- Handles both HTTP and SSE transports
69+
- Message proxying between transports
70+
71+
### OAuth Flow
72+
1. If server requires auth, proxy intercepts auth error
73+
2. Spins up local Express server on configurable port (default: 3334)
74+
3. Opens browser for user authorization
75+
4. Receives callback with authorization code
76+
5. Exchanges code for tokens
77+
6. Stores tokens locally for reuse
78+
7. Automatically refreshes tokens when expired
79+
80+
### Transport Strategies
81+
- Default behavior: Try HTTP first, fall back to SSE
82+
- Configurable via `--transport` flag
83+
- Handles connection failures and retries gracefully
84+
85+
## Important Notes
86+
87+
- No test suite exists - testing is manual via the client command
88+
- Uses pnpm package manager (v10.11.0)
89+
- TypeScript strict mode enabled
90+
- ES modules output only
91+
- Prettier formatting with 140 char lines, single quotes, no semicolons
92+
- OAuth tokens stored in `~/.mcp-auth/` (or `$MCP_REMOTE_CONFIG_DIR`)
93+
- Debug logs available with `--debug` flag for troubleshooting auth issues

Dockerfile

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Build stage
2+
FROM node:22-alpine AS builder
3+
4+
# Install pnpm globally with specific version from package.json
5+
RUN corepack enable && corepack prepare pnpm@10.11.0 --activate
6+
7+
# Set working directory
8+
WORKDIR /app
9+
10+
# Copy package files
11+
COPY package.json pnpm-lock.yaml ./
12+
13+
# Install dependencies
14+
RUN pnpm install --frozen-lockfile
15+
16+
# Copy source code
17+
COPY tsconfig.json ./
18+
COPY src ./src
19+
20+
# Build the project
21+
RUN pnpm build
22+
23+
# Runtime stage
24+
FROM node:22-alpine
25+
26+
# Install pnpm for runtime (needed for running the tool)
27+
RUN corepack enable && corepack prepare pnpm@10.11.0 --activate
28+
29+
# Create non-root user
30+
RUN addgroup -g 1001 -S mcp && \
31+
adduser -S mcp -u 1001
32+
33+
# Set working directory
34+
WORKDIR /app
35+
36+
# Copy package files
37+
COPY package.json pnpm-lock.yaml ./
38+
39+
# Install production dependencies only
40+
RUN pnpm install --prod --frozen-lockfile && \
41+
pnpm store prune
42+
43+
# Copy built files from builder
44+
COPY --from=builder /app/dist ./dist
45+
46+
# Copy other necessary files
47+
COPY README.md LICENSE ./
48+
49+
# Create directory for auth tokens (will be mounted as volume)
50+
RUN mkdir -p /home/mcp/.mcp-auth && \
51+
chown -R mcp:mcp /home/mcp/.mcp-auth
52+
53+
# Switch to non-root user
54+
USER mcp
55+
56+
# Set environment variable for config directory
57+
ENV MCP_REMOTE_CONFIG_DIR=/home/mcp/.mcp-auth
58+
59+
# Default to proxy command
60+
ENTRYPOINT ["node", "dist/proxy.js"]
61+
62+
# Default arguments (can be overridden)
63+
CMD ["--help"]

0 commit comments

Comments
 (0)