Initial commit: Komodo MCP server
- KomodoClient for Komodo Core API - MCP tools: list_servers, list_deployments, list_stacks, get_container_status - Raw API pass-through: komodo_api_call - API documentation resource: komodo://api-reference - Docker multi-stage build with uv
This commit is contained in:
7
.env.example
Normal file
7
.env.example
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Komodo Core Connection
|
||||||
|
KOMODO_URL=https://komodo.example.com
|
||||||
|
KOMODO_API_KEY=your-api-key
|
||||||
|
KOMODO_API_SECRET=your-api-secret
|
||||||
|
|
||||||
|
# MCP Transport Security (optional)
|
||||||
|
MCP_ALLOWED_HOSTS=localhost:*,127.0.0.1:*
|
||||||
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
31
Dockerfile
Normal file
31
Dockerfile
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Stage 1: Builder for dependencies
|
||||||
|
FROM python:3.11-slim-bullseye AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install uv
|
||||||
|
RUN pip install uv
|
||||||
|
|
||||||
|
# Copy only dependency files first to leverage Docker cache
|
||||||
|
COPY pyproject.toml ./
|
||||||
|
|
||||||
|
# Install dependencies with uv
|
||||||
|
RUN uv pip install --system .
|
||||||
|
|
||||||
|
# Stage 2: Final image
|
||||||
|
FROM python:3.11-slim-bullseye
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy installed dependencies from builder
|
||||||
|
COPY --from=builder /usr/local/lib/python3.11/site-packages/ /usr/local/lib/python3.11/site-packages/
|
||||||
|
COPY --from=builder /usr/local/bin/ /usr/local/bin/
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY server.py ./
|
||||||
|
|
||||||
|
# Expose the port Uvicorn will listen on
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Run the server
|
||||||
|
CMD ["python", "server.py"]
|
||||||
78
IMPLEMENTATION.md
Normal file
78
IMPLEMENTATION.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# Implementation Details
|
||||||
|
|
||||||
|
Technical documentation for the Komodo MCP Server.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ MCP Client (AI Agent) │
|
||||||
|
└─────────────────────────┬───────────────────────────────┘
|
||||||
|
│ SSE
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ Docker Container (komodo-mcp) │
|
||||||
|
│ ┌───────────────────────────────────────────────────┐ │
|
||||||
|
│ │ FastMCP + uvicorn (:8000) │ │
|
||||||
|
│ └───────────────────────────────────────────────────┘ │
|
||||||
|
│ ┌───────────────────────────────────────────────────┐ │
|
||||||
|
│ │ KomodoClient │ │
|
||||||
|
│ │ (httpx → Komodo Core API) │ │
|
||||||
|
│ └─────────────────────────┬─────────────────────────┘ │
|
||||||
|
└─────────────────────────────┼───────────────────────────┘
|
||||||
|
│ HTTPS
|
||||||
|
▼
|
||||||
|
┌──────────────────┐
|
||||||
|
│ Komodo Core │
|
||||||
|
│ (REST API) │
|
||||||
|
└────────┬─────────┘
|
||||||
|
│
|
||||||
|
┌─────────────────┼─────────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||||
|
│ Periphery│ │ Periphery│ │ Periphery│
|
||||||
|
│ Server 1 │ │ Server 2 │ │ Server N │
|
||||||
|
└──────────┘ └──────────┘ └──────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
### KomodoClient
|
||||||
|
- HTTP client using `httpx`
|
||||||
|
- Handles authentication via `X-Api-Key` and `X-Api-Secret` headers
|
||||||
|
- Methods: `read()`, `write()`, `execute()` mapping to API endpoints
|
||||||
|
|
||||||
|
### Transport Security
|
||||||
|
- `TransportSecuritySettings` validates Host headers
|
||||||
|
- Configurable via `MCP_ALLOWED_HOSTS`
|
||||||
|
|
||||||
|
### Tool Strategy
|
||||||
|
|
||||||
|
**Layer 1: Curated Tools**
|
||||||
|
- `list_servers()` - Server discovery
|
||||||
|
- `list_deployments()` - Container listing
|
||||||
|
- `list_stacks()` - Stack listing
|
||||||
|
- `get_container_status(deployment)` - Container details
|
||||||
|
|
||||||
|
**Layer 2: Raw Access**
|
||||||
|
- `komodo_api_call(endpoint, request_type, params)` - Any API operation
|
||||||
|
|
||||||
|
### API Docs Resource
|
||||||
|
- URI: `komodo://api-reference`
|
||||||
|
- Provides structured API documentation for AI agents
|
||||||
|
|
||||||
|
## Komodo API
|
||||||
|
|
||||||
|
All requests use:
|
||||||
|
- **Method**: POST
|
||||||
|
- **Paths**: `/read`, `/write`, `/execute`
|
||||||
|
- **Body**: `{"type": "RequestType", "params": {...}}`
|
||||||
|
- **Auth**: `X-Api-Key` + `X-Api-Secret` headers
|
||||||
|
|
||||||
|
Full docs: https://docs.rs/komodo_client/latest/komodo_client/api/index.html
|
||||||
|
|
||||||
|
## Build & Deploy
|
||||||
|
|
||||||
|
- **Build**: `uv` + multi-stage Docker
|
||||||
|
- **Registry**: Gitea Container Registry
|
||||||
|
- **Deploy**: Docker Compose
|
||||||
36
Makefile
Normal file
36
Makefile
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
.PHONY: build dev logs stop test-sse clean rebuild
|
||||||
|
|
||||||
|
# Build the Docker image locally
|
||||||
|
build:
|
||||||
|
docker compose -f docker-compose.dev.yml build
|
||||||
|
|
||||||
|
# Start the development server
|
||||||
|
dev:
|
||||||
|
docker compose -f docker-compose.dev.yml up -d
|
||||||
|
@echo "Server starting at http://localhost:8001"
|
||||||
|
@echo "Use 'make logs' to view output"
|
||||||
|
|
||||||
|
# View container logs
|
||||||
|
logs:
|
||||||
|
docker compose -f docker-compose.dev.yml logs -f
|
||||||
|
|
||||||
|
# Stop the development server
|
||||||
|
stop:
|
||||||
|
docker compose -f docker-compose.dev.yml down
|
||||||
|
|
||||||
|
# Test SSE endpoint (5 second timeout)
|
||||||
|
test-sse:
|
||||||
|
@echo "Testing SSE endpoint (5s timeout)..."
|
||||||
|
@curl -N --max-time 5 http://localhost:8001/sse 2>/dev/null || echo "\n[Timeout - this is expected for SSE]"
|
||||||
|
|
||||||
|
# Test root endpoint
|
||||||
|
test-root:
|
||||||
|
@curl -s http://localhost:8001/ | head -20
|
||||||
|
|
||||||
|
# Full rebuild (no cache)
|
||||||
|
rebuild:
|
||||||
|
docker compose -f docker-compose.dev.yml build --no-cache
|
||||||
|
|
||||||
|
# Clean up containers and images
|
||||||
|
clean:
|
||||||
|
docker compose -f docker-compose.dev.yml down --rmi local -v
|
||||||
78
README.md
Normal file
78
README.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# Komodo MCP Server
|
||||||
|
|
||||||
|
A Model Context Protocol (MCP) server for [Komodo](https://komo.do/) Docker management.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Curated Tools**: High-level tools for common operations
|
||||||
|
- **Raw API Access**: Pass-through tool for 100% API coverage
|
||||||
|
- **API Docs Resource**: Built-in reference for AI agents
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
| Tool | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `list_servers` | Lists all periphery servers |
|
||||||
|
| `list_deployments` | Lists deployments (containers) |
|
||||||
|
| `list_stacks` | Lists stacks (docker-compose) |
|
||||||
|
| `get_container_status` | Gets container details |
|
||||||
|
| `komodo_api_call` | Raw API pass-through |
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
| Resource | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `komodo://api-reference` | API documentation |
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Required | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| `KOMODO_URL` | Yes | Komodo Core URL |
|
||||||
|
| `KOMODO_API_KEY` | Yes | API key |
|
||||||
|
| `KOMODO_API_SECRET` | Yes | API secret |
|
||||||
|
| `MCP_ALLOWED_HOSTS` | No | Allowed Host headers |
|
||||||
|
|
||||||
|
### Deploy with Docker Compose
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
komodo-mcp:
|
||||||
|
image: gitea.ext.ben.io/b3nw/komodo-mcp:latest
|
||||||
|
environment:
|
||||||
|
- KOMODO_URL=https://komodo.example.com
|
||||||
|
- KOMODO_API_KEY=your-key
|
||||||
|
- KOMODO_API_SECRET=your-secret
|
||||||
|
- MCP_ALLOWED_HOSTS=komodo-mcp.example.io,localhost:*
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Connect MCP Client
|
||||||
|
|
||||||
|
SSE endpoint: `https://your-host/sse`
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Setup
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env with your credentials
|
||||||
|
|
||||||
|
# Build and run
|
||||||
|
make build
|
||||||
|
make dev
|
||||||
|
|
||||||
|
# Test
|
||||||
|
make logs
|
||||||
|
make test-sse
|
||||||
|
make stop
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
- Python 3.11+ / FastMCP / httpx
|
||||||
|
- SSE transport / uvicorn
|
||||||
|
- Docker with multi-stage build
|
||||||
9
docker-compose.dev.yml
Normal file
9
docker-compose.dev.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
komodo-mcp:
|
||||||
|
build: .
|
||||||
|
container_name: komodo-mcp-dev
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
ports:
|
||||||
|
- "8001:8000"
|
||||||
|
restart: unless-stopped
|
||||||
12
docker-compose.yml
Normal file
12
docker-compose.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
services:
|
||||||
|
komodo-mcp:
|
||||||
|
image: gitea.ext.ben.io/b3nw/komodo-mcp:latest
|
||||||
|
container_name: komodo-mcp
|
||||||
|
environment:
|
||||||
|
- KOMODO_URL=${KOMODO_URL}
|
||||||
|
- KOMODO_API_KEY=${KOMODO_API_KEY}
|
||||||
|
- KOMODO_API_SECRET=${KOMODO_API_SECRET}
|
||||||
|
- MCP_ALLOWED_HOSTS=komodo-mcp.example.io,localhost:*,127.0.0.1:*
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
restart: unless-stopped
|
||||||
19
pyproject.toml
Normal file
19
pyproject.toml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[project]
|
||||||
|
name = "komodo-mcp"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "MCP Server for Komodo Docker Management"
|
||||||
|
dependencies = [
|
||||||
|
"mcp",
|
||||||
|
"httpx",
|
||||||
|
"uvicorn",
|
||||||
|
"fastapi",
|
||||||
|
"python-dotenv",
|
||||||
|
]
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61.0"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
python-version = "3.11"
|
||||||
230
server.py
Normal file
230
server.py
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import httpx
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
from mcp.server.transport_security import TransportSecuritySettings
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# --- Configuration ---
|
||||||
|
KOMODO_URL = os.getenv("KOMODO_URL", "").rstrip("/")
|
||||||
|
KOMODO_API_KEY = os.getenv("KOMODO_API_KEY", "")
|
||||||
|
KOMODO_API_SECRET = os.getenv("KOMODO_API_SECRET", "")
|
||||||
|
MCP_ALLOWED_HOSTS = os.getenv("MCP_ALLOWED_HOSTS", "localhost:*,127.0.0.1:*")
|
||||||
|
|
||||||
|
|
||||||
|
class KomodoClient:
|
||||||
|
"""HTTP client for Komodo Core API."""
|
||||||
|
|
||||||
|
def __init__(self, url: str, api_key: str, api_secret: str):
|
||||||
|
self.url = url
|
||||||
|
self.headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Api-Key": api_key,
|
||||||
|
"X-Api-Secret": api_secret,
|
||||||
|
}
|
||||||
|
self._client = httpx.Client(timeout=30.0)
|
||||||
|
|
||||||
|
def _request(self, endpoint: str, request_type: str, params: dict = None) -> dict:
|
||||||
|
"""Make a request to Komodo API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
endpoint: API endpoint (read, write, execute)
|
||||||
|
request_type: Request type name (e.g., 'ListServers', 'GetDeployment')
|
||||||
|
params: Request parameters
|
||||||
|
"""
|
||||||
|
url = f"{self.url}/{endpoint}"
|
||||||
|
body = {"type": request_type, "params": params or {}}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = self._client.post(url, json=body, headers=self.headers)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
except httpx.HTTPStatusError as e:
|
||||||
|
return {"error": f"HTTP {e.response.status_code}: {e.response.text}"}
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": str(e)}
|
||||||
|
|
||||||
|
def read(self, request_type: str, params: dict = None) -> dict:
|
||||||
|
"""Make a read request."""
|
||||||
|
return self._request("read", request_type, params)
|
||||||
|
|
||||||
|
def write(self, request_type: str, params: dict = None) -> dict:
|
||||||
|
"""Make a write request."""
|
||||||
|
return self._request("write", request_type, params)
|
||||||
|
|
||||||
|
def execute(self, request_type: str, params: dict = None) -> dict:
|
||||||
|
"""Make an execute request."""
|
||||||
|
return self._request("execute", request_type, params)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Initialize Client ---
|
||||||
|
def _get_client() -> tuple[KomodoClient | None, dict | None]:
|
||||||
|
"""Get Komodo client or return error dict."""
|
||||||
|
if not KOMODO_URL:
|
||||||
|
return None, {"error": "KOMODO_URL not configured"}
|
||||||
|
if not KOMODO_API_KEY or not KOMODO_API_SECRET:
|
||||||
|
return None, {"error": "KOMODO_API_KEY and KOMODO_API_SECRET required"}
|
||||||
|
return KomodoClient(KOMODO_URL, KOMODO_API_KEY, KOMODO_API_SECRET), None
|
||||||
|
|
||||||
|
|
||||||
|
# --- MCP Server ---
|
||||||
|
transport_security = TransportSecuritySettings(
|
||||||
|
enable_dns_rebinding_protection=True,
|
||||||
|
allowed_hosts=[h.strip() for h in MCP_ALLOWED_HOSTS.split(",")],
|
||||||
|
allowed_origins=[],
|
||||||
|
)
|
||||||
|
mcp = FastMCP("Komodo MCP", transport_security=transport_security)
|
||||||
|
|
||||||
|
|
||||||
|
# --- API Documentation Resource ---
|
||||||
|
API_DOCS = """# Komodo Core API Reference
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
All requests use POST method with JSON body: `{"type": "RequestType", "params": {...}}`
|
||||||
|
|
||||||
|
### /read - Get Data
|
||||||
|
| Request Type | Description | Params |
|
||||||
|
|-------------|-------------|--------|
|
||||||
|
| `ListServers` | List all servers | `{}` |
|
||||||
|
| `GetServer` | Get server details | `{"server": "name_or_id"}` |
|
||||||
|
| `ListDeployments` | List deployments | `{}` |
|
||||||
|
| `GetDeployment` | Get deployment details | `{"deployment": "name_or_id"}` |
|
||||||
|
| `GetDeploymentContainer` | Get container info | `{"deployment": "name_or_id"}` |
|
||||||
|
| `GetDeploymentLog` | Get container logs | `{"deployment": "name_or_id", "tail": 100}` |
|
||||||
|
| `ListStacks` | List stacks | `{}` |
|
||||||
|
| `GetStack` | Get stack details | `{"stack": "name_or_id"}` |
|
||||||
|
| `GetDockerContainersSummary` | Container summary for server | `{"server": "name_or_id"}` |
|
||||||
|
| `ListBuilds` | List builds | `{}` |
|
||||||
|
| `ListRepos` | List repositories | `{}` |
|
||||||
|
| `ListProcedures` | List procedures | `{}` |
|
||||||
|
| `GetCoreInfo` | Get Komodo Core info | `{}` |
|
||||||
|
|
||||||
|
### /execute - Run Actions
|
||||||
|
| Request Type | Description | Params |
|
||||||
|
|-------------|-------------|--------|
|
||||||
|
| `Deploy` | Deploy a deployment | `{"deployment": "name_or_id"}` |
|
||||||
|
| `StartContainer` | Start container | `{"deployment": "name_or_id"}` |
|
||||||
|
| `StopContainer` | Stop container | `{"deployment": "name_or_id"}` |
|
||||||
|
| `PauseContainer` | Pause container | `{"deployment": "name_or_id"}` |
|
||||||
|
| `RestartContainer` | Restart container | `{"deployment": "name_or_id"}` |
|
||||||
|
| `DeployStack` | Deploy stack | `{"stack": "name_or_id"}` |
|
||||||
|
| `StartStack` | Start stack | `{"stack": "name_or_id"}` |
|
||||||
|
| `StopStack` | Stop stack | `{"stack": "name_or_id"}` |
|
||||||
|
| `RestartStack` | Restart stack | `{"stack": "name_or_id"}` |
|
||||||
|
| `RunBuild` | Run a build | `{"build": "name_or_id"}` |
|
||||||
|
| `RunProcedure` | Run a procedure | `{"procedure": "name_or_id"}` |
|
||||||
|
|
||||||
|
### /write - Modify Resources
|
||||||
|
| Request Type | Description | Params |
|
||||||
|
|-------------|-------------|--------|
|
||||||
|
| `CreateDeployment` | Create deployment | `{"name": "...", "config": {...}}` |
|
||||||
|
| `UpdateDeployment` | Update deployment | `{"id": "...", "config": {...}}` |
|
||||||
|
| `DeleteDeployment` | Delete deployment | `{"id": "..."}` |
|
||||||
|
| `CreateStack` | Create stack | `{"name": "...", "config": {...}}` |
|
||||||
|
| `UpdateStack` | Update stack | `{"id": "...", "config": {...}}` |
|
||||||
|
| `DeleteStack` | Delete stack | `{"id": "..."}` |
|
||||||
|
|
||||||
|
## Full Documentation
|
||||||
|
https://docs.rs/komodo_client/latest/komodo_client/api/index.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.resource("komodo://api-reference")
|
||||||
|
def get_api_reference() -> str:
|
||||||
|
"""Komodo API reference documentation."""
|
||||||
|
return API_DOCS
|
||||||
|
|
||||||
|
|
||||||
|
# --- MCP Tools ---
|
||||||
|
@mcp.tool()
|
||||||
|
def list_servers() -> dict:
|
||||||
|
"""Lists all servers (periphery nodes) connected to Komodo.
|
||||||
|
|
||||||
|
Returns server names, IDs, status, and system information.
|
||||||
|
"""
|
||||||
|
client, error = _get_client()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return client.read("ListServers")
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def list_deployments() -> dict:
|
||||||
|
"""Lists all deployments (single container applications).
|
||||||
|
|
||||||
|
Deployments are Docker containers managed by Komodo.
|
||||||
|
"""
|
||||||
|
client, error = _get_client()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return client.read("ListDeployments")
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def list_stacks() -> dict:
|
||||||
|
"""Lists all stacks (docker-compose applications).
|
||||||
|
|
||||||
|
Stacks are multi-container applications defined by docker-compose files.
|
||||||
|
"""
|
||||||
|
client, error = _get_client()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return client.read("ListStacks")
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def get_container_status(deployment: str) -> dict:
|
||||||
|
"""Gets the status of a specific container.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
deployment: Deployment name or ID
|
||||||
|
|
||||||
|
Returns container state, image, ports, and resource usage.
|
||||||
|
"""
|
||||||
|
client, error = _get_client()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return client.read("GetDeploymentContainer", {"deployment": deployment})
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def komodo_api_call(
|
||||||
|
endpoint: str,
|
||||||
|
request_type: str,
|
||||||
|
params: dict = None
|
||||||
|
) -> dict:
|
||||||
|
"""Execute a raw Komodo API call.
|
||||||
|
|
||||||
|
Use the komodo://api-reference resource for available request types.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
endpoint: API endpoint - 'read', 'write', or 'execute'
|
||||||
|
request_type: Request type name (e.g., 'GetServer', 'Deploy', 'ListBuilds')
|
||||||
|
params: Request parameters as a dictionary
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- Get server: endpoint='read', request_type='GetServer', params={'server': 'my-server'}
|
||||||
|
- Deploy: endpoint='execute', request_type='Deploy', params={'deployment': 'my-app'}
|
||||||
|
- List builds: endpoint='read', request_type='ListBuilds', params={}
|
||||||
|
"""
|
||||||
|
client, error = _get_client()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
|
||||||
|
if endpoint not in ("read", "write", "execute"):
|
||||||
|
return {"error": f"Invalid endpoint '{endpoint}'. Use 'read', 'write', or 'execute'."}
|
||||||
|
|
||||||
|
method = getattr(client, endpoint)
|
||||||
|
return method(request_type, params or {})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run(mcp.sse_app, host="0.0.0.0", port=8000)
|
||||||
Reference in New Issue
Block a user