Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.
Closed
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
40 changes: 40 additions & 0 deletions packages/jumpstarter-mcp-server/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Jumpstarter MCP Server Container
FROM python:3.11-slim

# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
&& rm -rf /var/lib/apt/lists/*

# Install uv
RUN pip install uv

# Create a non-root user first
RUN useradd -m -u 1000 jumpstarter

# Set working directory
WORKDIR /app

# Set fallback versions for all packages BEFORE copying files
ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_JUMPSTARTER_MCP_SERVER=0.1.0
ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_JUMPSTARTER=0.1.0
ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_JUMPSTARTER_CLI=0.1.0
ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_JUMPSTARTER_PROTOCOL=0.1.0

# Copy the entire jumpstarter workspace including git metadata
COPY . .
# Ensure we have git metadata for version detection
RUN if [ -d .git ]; then echo "Git directory found"; else echo "No git directory, using environment versions"; fi

# Change ownership to jumpstarter user
RUN chown -R jumpstarter:jumpstarter /app

# Switch to non-root user
USER jumpstarter

# Sync dependencies for the workspace as the jumpstarter user
RUN uv sync --all-packages

# Expose the FastMCP server entry point
ENTRYPOINT ["uv", "run", "--directory", "packages/jumpstarter-mcp-server", "jumpstarter-fastmcp"]
278 changes: 278 additions & 0 deletions packages/jumpstarter-mcp-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
# Jumpstarter MCP Server

A Model Context Protocol (MCP) server built with **FastMCP** that provides access to Jumpstarter's hardware automation and testing capabilities.

## Overview

This MCP server exposes Jumpstarter's core functionality as MCP tools, allowing AI assistants like Claude to interact with hardware testing infrastructure. Built on the **FastMCP framework** for enhanced reliability and performance.

### Key Features
- 🚀 **FastMCP Framework**: Production-ready MCP implementation with improved error handling
- 🔧 **Hardware Management**: Discover and lease hardware resources
- 📊 **Real-time Status**: Monitor exporter and lease status
- ⚡ **Live Integration**: Direct integration with Jumpstarter APIs
- 🐳 **Containerized**: Ready for deployment with Podman/Docker

## Current Status (PoC)

✅ **Working Tools** (Production Ready):
- `jumpstarter_get_config` - Get Jumpstarter configuration
- `jumpstarter_list_exporters` - List available hardware exporters
- `jumpstarter_list_leases` - List active hardware leases
- `jumpstarter_create_lease` - Create new hardware leases

🚧 **Additional Tools** (PoC Implementation):
- Power control, serial console, storage flashing, SSH forwarding, and arbitrary j commands

## Architecture

### FastMCP Framework

This server uses **FastMCP** instead of the standard MCP library for several advantages:

- **Simplified Decorators**: Tools defined with simple `@mcp.tool` decorators
- **Better Error Handling**: Automatic error serialization and validation
- **Production Ready**: Designed for reliability in production environments
- **Cleaner Code**: Reduced boilerplate compared to standard MCP

```python
@mcp.tool
async def jumpstarter_list_exporters(
selector: Optional[str] = None,
include_leases: bool = False,
include_online: bool = True
) -> str:
"""List available hardware exporters and their status"""
# Implementation here...
```

### Container Deployment

The server is packaged as a container for easy deployment:

```dockerfile
FROM python:3.11-slim
# FastMCP server entry point
ENTRYPOINT ["uv", "run", "--directory", "packages/jumpstarter-mcp-server", "jumpstarter-fastmcp"]
```

## Installation & Usage

### Method 1: Container (Recommended)

```bash
# Build the container
cd /path/to/jumpstarter
podman build -t jumpstarter-mcp-server -f packages/jumpstarter-mcp-server/Containerfile .

# Run with your Jumpstarter config
podman run -it \
-v ~/.config/jumpstarter:/home/jumpstarter/.config/jumpstarter:ro \
jumpstarter-mcp-server
```

### Method 2: Development Setup

```bash
# Install from the Jumpstarter workspace
uv sync --all-packages
cd packages/jumpstarter-mcp-server

# Run FastMCP server
uv run jumpstarter-fastmcp
```

### Method 3: Claude Desktop/Cursor Integration

Add to your MCP configuration:

```json
{
"mcpServers": {
"jumpstarter": {
"command": "podman",
"args": [
"run", "-i", "--rm",
"-v", "/home/user/.config/jumpstarter:/home/jumpstarter/.config/jumpstarter:ro",
"jumpstarter-mcp-server"
]
}
}
}
```

## Working Tools

### 🔧 `jumpstarter_get_config`
Get current Jumpstarter configuration information including endpoint, driver settings, and connection status.

**Example Response:**
```json
{
"type": "ClientConfigV1Alpha1",
"is_client_config": true,
"endpoint": "grpc://jumpstarter.example.com:1234",
"driver_allow_list": ["power", "console"],
"unsafe_drivers": false
}
```

### 📋 `jumpstarter_list_exporters`
List available hardware exporters and their current status.

**Parameters:**
- `selector` (optional): Label selector to filter exporters (e.g., "board-type=j784s4evm")
- `include_leases` (bool): Include lease information (default: false)
- `include_online` (bool): Include online status (default: true)

**Example Response:**
```json
[
{
"name": "exporter-1",
"labels": {"board-type": "j784s4evm", "enabled": "true"},
"status": "online",
"online": true
}
]
```

### 📊 `jumpstarter_list_leases`
List active hardware leases with status and expiration information.

**Parameters:**
- `selector` (optional): Label selector to filter leases

**Example Response:**
```json
[
{
"id": "lease-abc123",
"name": "test-lease",
"status": "active",
"expires_at": "2024-10-24T10:30:00Z"
}
]
```

### ⚡ `jumpstarter_create_lease`
Create a new hardware lease for testing with automatic error handling for API compatibility.

**Parameters:**
- `selector`: Label selector for target hardware (required)
- `lease_name` (optional): Name for the lease
- `duration_minutes`: Lease duration in minutes (default: 30)

**Example Usage:**
```json
{
"selector": "board-type=j784s4evm,enabled=true",
"lease_name": "my-test-lease",
"duration_minutes": 60
}
```

**Features:**
- ✅ Real API integration with Jumpstarter client
- ✅ Automatic parameter compatibility handling
- ✅ Robust error handling for different API versions
- ✅ Detailed lease information in response

## Configuration Requirements

The MCP server requires Jumpstarter client configuration. Ensure you have:

1. **Authentication**: Valid Jumpstarter credentials
2. **Client Config**: Either environment variables or user config file
3. **Network Access**: Connectivity to Jumpstarter endpoint

### Environment Variables
```bash
# Option 1: Environment variables
export JUMPSTARTER_ENDPOINT="grpc://your-jumpstarter-server:1234"
export JUMPSTARTER_TOKEN="your-auth-token"

# Option 2: Use existing user config (~/.config/jumpstarter/)
# No environment variables needed
```

## Troubleshooting

### Common Issues

**"No client configuration available"**
- Run `jmp login` to set up authentication
- Or set `JUMPSTARTER_ENDPOINT` and `JUMPSTARTER_TOKEN` environment variables

**"Failed to list exporters"**
- Check network connectivity to Jumpstarter endpoint
- Verify authentication token is valid and not expired

**Container build issues**
- Ensure you're building from the root jumpstarter directory
- Check that all git metadata is available for version detection

### Debug Mode

Run with debug logging:
```bash
# Container
podman run -e LOG_LEVEL=DEBUG jumpstarter-mcp-server

# Development
LOG_LEVEL=DEBUG uv run jumpstarter-fastmcp
```

## Development

### FastMCP Benefits

Compared to standard MCP, FastMCP provides:

- **Simpler Tool Definition**: Just decorators, no complex handler registration
- **Automatic Serialization**: No manual CallToolResult construction
- **Better Error Messages**: Automatic error formatting and logging
- **Type Safety**: Full Pydantic integration for request/response validation

### Adding New Tools

```python
@mcp.tool
async def new_jumpstarter_tool(param1: str, param2: Optional[int] = None) -> str:
"""Tool description for AI assistant"""
try:
# Your implementation
result = do_something(param1, param2)
return f"Success: {result}"
except Exception as e:
raise RuntimeError(f"Tool failed: {str(e)}")
```

### Testing

```bash
# Run tests
uv run pytest

# Build and test container
podman build -t jumpstarter-mcp-server -f packages/jumpstarter-mcp-server/Containerfile .
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | podman run -i jumpstarter-mcp-server
```

## Roadmap

### Next Phase
- 🔄 **Lease Management**: Release and extend lease functionality
- 📡 **Real Command Execution**: Live shell and j command execution
- 🔌 **Driver Integration**: Hardware-specific tool implementations
- 📊 **Streaming Responses**: Real-time output for long-running operations

### Future Enhancements
- **Advanced Monitoring**: Resource usage and performance metrics
- **Test Orchestration**: Multi-device test execution workflows
- **Hardware Discovery**: Automatic device detection and labeling
- **Integration APIs**: Webhooks and event notifications

---

**Built with FastMCP** - Production-ready Model Context Protocol server for hardware automation.
17 changes: 17 additions & 0 deletions packages/jumpstarter-mcp-server/claude_desktop_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"mcpServers": {
"jumpstarter": {
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/jumpstarter/packages/jumpstarter-mcp-server",
"jumpstarter-mcp"
Comment on lines +8 to +9
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Document path customization requirement and verify entry point.

Two concerns with this configuration:

  1. The hard-coded path /path/to/jumpstarter/packages/jumpstarter-mcp-server must be customized by users. Consider adding a comment or using a more obvious placeholder like <PATH_TO_JUMPSTARTER>.

  2. This uses the jumpstarter-mcp entry point, but earlier review found that jumpstarter_mcp_server.main:main_sync may not exist. The Containerfile and README use jumpstarter-fastmcp instead. Consider aligning this configuration to use jumpstarter-fastmcp for consistency.

Verify which entry point should be used:


🏁 Script executed:

#!/bin/bash
# Check if main.py exists and which entry point is intended for desktop use
fd -t f "main.py" packages/jumpstarter-mcp-server/
echo "---"
echo "Containerfile uses:"
grep "jumpstarter-fastmcp" packages/jumpstarter-mcp-server/Containerfile
echo "---"
echo "Podman config uses:"
grep "jumpstarter-mcp-server" packages/jumpstarter-mcp-server/claude_desktop_config_podman.json

Length of output: 293


I need to check the entry points defined in the project configuration to verify which one is correct for the desktop configuration.

is not needed


🏁 Script executed:

#!/bin/bash
# Find and inspect pyproject.toml for entry points
fd -t f "pyproject.toml" | head -5
echo "---"
echo "Checking jumpstarter-mcp-server pyproject.toml for entry points:"
grep -A 15 "\[project.scripts\]" packages/jumpstarter-mcp-server/pyproject.toml 2>/dev/null || echo "Not found with grep"
echo "---"
echo "Alternative check with full file context:"
cat packages/jumpstarter-mcp-server/pyproject.toml | grep -A 15 "scripts"

Length of output: 426


🏁 Script executed:

#!/bin/bash
# Search for entry point definitions in root and packages level
echo "Root pyproject.toml entry points:"
grep -A 20 "\[project.scripts\]" pyproject.toml 2>/dev/null | head -30
echo "---"
echo "Packages pyproject.toml entry points:"
grep -A 20 "\[project.scripts\]" packages/pyproject.toml 2>/dev/null | head -30
echo "---"
echo "Search for jumpstarter-mcp and jumpstarter-fastmcp definitions:"
rg -n "jumpstarter-mcp|jumpstarter-fastmcp" --type toml -C 2 | head -50

Length of output: 1225


🏁 Script executed:

#!/bin/bash
# Verify if main.py and main_sync exist
echo "Looking for main.py in jumpstarter_mcp_server:"
find packages/jumpstarter-mcp-server/jumpstarter_mcp_server -name "main.py" -o -name "*.py" | sort
echo "---"
echo "Searching for main_sync function:"
rg -n "def main_sync" packages/jumpstarter-mcp-server/
echo "---"
echo "All Python files in jumpstarter_mcp_server:"
fd -t f "\.py$" packages/jumpstarter-mcp-server/jumpstarter_mcp_server/

Length of output: 408


Change entry point from jumpstarter-mcp to jumpstarter-fastmcp and document path customization.

Two issues with this configuration:

  1. The hard-coded path /path/to/jumpstarter/packages/jumpstarter-mcp-server must be customized by users. Add a comment documenting this or use a more obvious placeholder.

  2. Line 9 uses jumpstarter-mcp entry point, but jumpstarter_mcp_server.main:main_sync does not exist—only jumpstarter_mcp_server.fastmcp_main:main is implemented. Change this to jumpstarter-fastmcp to match the Containerfile and ensure the configuration works.

🤖 Prompt for AI Agents
In packages/jumpstarter-mcp-server/claude_desktop_config.json around lines 8 to
9, the config uses a hard-coded path and the wrong entrypoint; replace the
literal "/path/to/jumpstarter/packages/jumpstarter-mcp-server" with a clear
customizable placeholder (e.g.
"<LOCAL_JUMPSTARTER_PATH>/packages/jumpstarter-mcp-server") and add a comment or
inline note indicating users must update it to their local repo path, and change
the entrypoint token from "jumpstarter-mcp" to "jumpstarter-fastmcp" so it
matches the implemented fastmcp_main entry (and the Containerfile).

],
"env": {
"JUMPSTARTER_CLIENT_ENDPOINT": "grpc.jumpstarter.example.com:443",
"JUMPSTARTER_AUTH_TOKEN": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ..."
}
}
}
}
23 changes: 23 additions & 0 deletions packages/jumpstarter-mcp-server/claude_desktop_config_podman.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"mcpServers": {
"jumpstarter": {
"command": "podman",
"args": [
"run",
"--rm",
"-i",
"--name", "jumpstarter-mcp-server",
"-v", "${HOME}/.config/jumpstarter:/home/jumpstarter/.config/jumpstarter:ro",
"-v", "${HOME}/.local/share/jumpstarter:/home/jumpstarter/.local/share/jumpstarter:ro",
"-e", "JUMPSTARTER_CLIENT_ENDPOINT=${JUMPSTARTER_CLIENT_ENDPOINT:-}",
"-e", "JUMPSTARTER_AUTH_TOKEN=${JUMPSTARTER_AUTH_TOKEN:-}",
"jumpstarter-mcp-server"
],
"env": {
"JUMPSTARTER_CLIENT_ENDPOINT": "grpc.jumpstarter.example.com:443",
"JUMPSTARTER_AUTH_TOKEN": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ..."
}
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Jumpstarter MCP Server

Model Context Protocol server for Jumpstarter hardware automation platform.
Provides tools for hardware testing, device management, and automation workflows.
"""

__version__ = "0.1.0"

Check failure on line 7 in packages/jumpstarter-mcp-server/jumpstarter_mcp_server/__init__.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (W292)

packages/jumpstarter-mcp-server/jumpstarter_mcp_server/__init__.py:7:22: W292 No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix missing newline to resolve CI failure.

The file is missing a newline at the end, causing the Ruff linter to fail (W292). This is blocking the pipeline.

Apply this fix:

 __version__ = "0.1.0"
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
__version__ = "0.1.0"
__version__ = "0.1.0"
🧰 Tools
🪛 GitHub Actions: Lint

[warning] 7-7: W292 No newline at end of file.

🪛 GitHub Check: ruff

[failure] 7-7: Ruff (W292)
packages/jumpstarter-mcp-server/jumpstarter_mcp_server/init.py:7:22: W292 No newline at end of file

🤖 Prompt for AI Agents
In packages/jumpstarter-mcp-server/jumpstarter_mcp_server/__init__.py around
line 7, the file ends without a trailing newline causing Ruff W292; fix it by
adding a single newline character at EOF (ensure the file ends with a blank line
after the existing __version__ = "0.1.0" line) and save the file so the linter
no longer reports the missing newline.

Loading