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
42 changes: 42 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Dependencies
node_modules/

# Build output (will be built in container)
dist/

# Git
.git/
.gitignore

# Environment files (secrets should be passed at runtime)
.env
.env.*
!.env.example

# IDE and editor files
.vscode/
.idea/
*.swp
*.swo
.DS_Store

# Logs
*.log
npm-debug.log*
pnpm-debug.log*

# Test files
*.test.ts
*.spec.ts
__tests__/
coverage/

# Documentation (not needed in image)
*.md
!README.md

# Misc
.aider*
*.tgz
CODEOWNERS

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dist/

# Dependencies
node_modules/
.pnpm-store/

# Environment variables
.env
Expand Down
55 changes: 55 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# IcePanel MCP Server Dockerfile
# Multi-stage build for minimal production image

# Stage 1: Build
FROM node:22-alpine AS builder

WORKDIR /app

# Copy package files
COPY package.json pnpm-lock.yaml ./

# Install pnpm and dependencies
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN pnpm install

# Copy source code
COPY tsconfig.json ./
COPY src/ ./src/
COPY bin/ ./bin/

# Build TypeScript
RUN pnpm run build

# Stage 2: Production
FROM node:22-alpine AS production

WORKDIR /app

# Copy package files
COPY package.json pnpm-lock.yaml ./

# Install pnpm and production dependencies only
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN pnpm install --prod

# Copy built files from builder stage
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/bin ./bin

# Environment variables (to be provided at runtime)
# Required:
# API_KEY - Your IcePanel API key
# ORGANIZATION_ID - Your IcePanel organization ID
# Optional:
# ICEPANEL_API_BASE_URL - Override API base URL
# MCP_TRANSPORT - Transport type: 'stdio' (default) or 'sse'
# MCP_PORT - HTTP port for SSE transport (default: 3000)

# Default port for SSE transport (can be overridden with --port flag)
EXPOSE 3000

# Run the MCP server
# Supports CLI flags: --transport <stdio|sse> --port <number>
# Example: docker run -p 3000:3000 ... icepanel-mcp-server --transport sse --port 3000
ENTRYPOINT ["node", "bin/icepanel-mcp-server.js"]
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ Please use MCP Servers with caution; only install tools you trust.
- `API_KEY`: Your IcePanel API key (required)
- `ORGANIZATION_ID`: Your IcePanel organization ID (required)
- `ICEPANEL_API_BASE_URL`: (Optional) Override the API base URL for different environments
- `MCP_TRANSPORT`: (Optional) Transport type: `stdio` (default) or `sse`
- `MCP_PORT`: (Optional) HTTP port for SSE transport (default: 3000)

#### CLI Flags

When running directly or via Docker, you can use these flags:

- `--transport <stdio|sse>`: Transport type (overrides `MCP_TRANSPORT`)
- `--port <number>`: HTTP port for SSE transport (overrides `MCP_PORT`)

#### Configure your MCP Client

Expand All @@ -59,6 +68,75 @@ Add this to your MCP Clients' MCP config file:
}
```

## 🐳 Docker

You can also run the IcePanel MCP Server as a Docker container.

### Build the Docker Image

```bash
docker build -t icepanel-mcp-server .
```

### Run with Docker

```bash
docker run -i --rm \
-e API_KEY="your-api-key" \
-e ORGANIZATION_ID="your-org-id" \
icepanel-mcp-server
```

### Configure MCP Client for Docker (stdio)

Add this to your MCP Clients' MCP config file:

```json
{
"mcpServers": {
"@icepanel/icepanel": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "API_KEY=your-api-key",
"-e", "ORGANIZATION_ID=your-org-id",
"icepanel-mcp-server"
]
}
}
}
```

### Run with HTTP/SSE Transport

For standalone HTTP server mode, use the `--transport sse` flag:

```bash
docker run -d -p 9846:9846 \
-e API_KEY="your-api-key" \
-e ORGANIZATION_ID="your-org-id" \
icepanel-mcp-server --transport sse --port 9846
```

The server exposes:
- `GET /sse` - SSE endpoint for establishing connection
- `POST /messages` - Endpoint for client messages
- `GET /health` - Health check endpoint

### Configure MCP Client for HTTP/SSE

For MCP clients that support HTTP/SSE transport:

```json
{
"mcpServers": {
"@icepanel/icepanel": {
"url": "http://localhost:9846/sse"
}
}
}
```

## ✉️ Support

- Reach out to [Support](mailto:support@icepanel.io) if you experience any issues.
Expand Down
53 changes: 48 additions & 5 deletions bin/icepanel-mcp-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,62 @@
* IcePanel MCP Server
*
* Environment variables:
* - API_KEY: Your IcePanel API key
* - ORGANIZATION_ID: Your IcePanel organization ID
* - API_KEY: Your IcePanel API key (required)
* - ORGANIZATION_ID: Your IcePanel organization ID (required)
* - ICEPANEL_API_BASE_URL: (Optional) Override the API base URL for different environments
* - MCP_TRANSPORT: Transport type: 'stdio' (default) or 'sse'
* - MCP_PORT: HTTP server port for SSE transport (default: 3000)
*
* CLI flags:
* - --transport <stdio|sse>: Transport type (overrides MCP_TRANSPORT)
* - --port <number>: HTTP port for SSE transport (overrides MCP_PORT)
*/

// Parse any environment variables passed as arguments
process.argv.slice(2).forEach(arg => {
// Parse command line arguments
const args = process.argv.slice(2);
let transport = process.env.MCP_TRANSPORT || 'stdio';
let port = parseInt(process.env.MCP_PORT || '3000', 10);

for (let i = 0; i < args.length; i++) {
const arg = args[i];

// Handle --transport flag
if (arg === '--transport' && args[i + 1]) {
transport = args[i + 1];
i++; // Skip next arg
continue;
}

// Handle --port flag
if (arg === '--port' && args[i + 1]) {
port = parseInt(args[i + 1], 10);
i++; // Skip next arg
continue;
}

// Handle environment variables passed as arguments (KEY=value format)
const match = arg.match(/^([^=]+)=(.*)$/);
if (match) {
const [, key, value] = match;
process.env[key] = value.replace(/^["'](.*)["']$/, '$1'); // Remove quotes if present
}
});
}

// Validate transport
if (!['stdio', 'sse'].includes(transport)) {
console.error(`Invalid transport: ${transport}. Must be 'stdio' or 'sse'.`);
process.exit(1);
}

// Validate port
if (isNaN(port) || port < 1 || port > 65535) {
console.error(`Invalid port: ${port}. Must be a number between 1 and 65535.`);
process.exit(1);
}

// Store config for main module
process.env._MCP_TRANSPORT = transport;
process.env._MCP_PORT = String(port);

import('../dist/main.js').catch(err => {
console.error('Failed to start IcePanel MCP Server:', err);
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "1.9.0",
"cors": "^2.8.5",
"express": "^5.0.1",
"fuse.js": "^7.1.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/node": "^22.0.0",
"tsx": "^4.7.0",
"typescript": "^5.8.0"
Expand Down
Loading