Skip to content
Merged
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
76 changes: 76 additions & 0 deletions .github/workflows/build-deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: build-deploy flux-mcp

on:
pull_request: {}
release:
types: [published]
push:
branches:
- main

jobs:
build-arm:
if: (github.event_name != 'pull_request')
runs-on: ubuntu-latest
name: make and build arm
env:
container: ghcr.io/converged-computing/flux-mcp
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: GHCR Login
if: (github.event_name != 'pull_request')
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Add custom buildx ARM builder
run: |
docker buildx create --name armbuilder
docker buildx use armbuilder
docker buildx inspect --bootstrap

- name: Build Container
run: make arm

- name: Tag Release Image
if: (github.event_name == 'release')
run: |
tag=${GITHUB_REF#refs/tags/}
echo "Tagging and releasing ${{ env.container }}:${tag}"
docker tag ${{ env.container }}:latest ${{ env.container }}:${tag}

- name: Deploy Container
run: make push

build:
permissions:
packages: write
runs-on: ubuntu-latest
name: build
env:
container: ghcr.io/converged-computing/flux-mcp
steps:
- uses: actions/checkout@v4
- name: Build Container
run: make
- name: Tag Release Image
if: (github.event_name == 'release')
run: |
tag=${GITHUB_REF#refs/tags/}
echo "Tagging and releasing ${{ env.container }}:${tag}"
docker tag ${{ env.container }}:latest ${{ env.container }}:${tag}

- name: GHCR Login
if: (github.event_name != 'pull_request')
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Deploy Container
if: (github.event_name != 'pull_request')
run: make push
23 changes: 23 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM fluxrm/flux-sched:noble

# docker build -t ghcr.io/converged-computing/flux-mcp:latest .
# Install system-level dependencies for HPC introspection
USER root
RUN apt-get update && apt-get install -y --no-install-recommends python3-pip python3-venv && \
apt remove -y python3-zipp && apt remove -y python3-typing-extensions \
&& rm -rf /var/lib/apt/lists/*

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONPATH=/code

WORKDIR /code
COPY . /code
RUN python3 -m pip install mcp-serve --no-cache-dir --break-system-packages && python3 -m pip install . --no-cache-dir --break-system-packages
EXPOSE 8089
ENTRYPOINT ["mcpserver", "start"]

# Default command if no arguments are provided.
# We bind to 0.0.0.0 so the server is reachable outside the container.
CMD ["-t", "http", "--host", "0.0.0.0", "--port", "8089", "--config", "/code/examples/servers/flux-mcp.yaml"]
40 changes: 40 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
IMAGE_NAME ?= ghcr.io/converged-computing/flux-mcp
IMAGE_TAG ?= latest
FULL_IMAGE_NAME = $(IMAGE_NAME):$(IMAGE_TAG)
FULL_ARM_IMAGE = $(IMAGE_NAME):arm
DOCKERFILE_PATH = Dockerfile
BUILD_CONTEXT = .

# Default target: builds the Docker image
all: build

# Build the Docker image
build:
@echo "Building Docker image $(FULL_IMAGE_NAME)..."
docker build \
-f $(DOCKERFILE_PATH) \
-t $(FULL_IMAGE_NAME) \
.
@echo "Docker image $(FULL_IMAGE_NAME) built successfully."

# Push the docker image
push:
@echo "Pushing image $(FULL_IMAGE_NAME)..."
docker push $(IMAGE_NAME) --all-tags

# Remove the image (clean with rmi)
clean:
@echo "Removing Docker image $(FULL_IMAGE_NAME)..."
docker rmi $(FULL_IMAGE_NAME) || true
@echo "Docker image $(FULL_IMAGE_NAME) removed (if it existed)."

arm:
@echo "Building arm Docker image $(FULL_IMAGE_NAME)..."
docker buildx build \
--platform linux/arm64 \
-f $(DOCKERFILE_PATH) \
-t $(FULL_ARM_IMAGE) \
--load .
@echo "Docker image $(FULL_ARM_IMAGE) built successfully."

.PHONY: all build push clean arm
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVe
python3 -m flux_mcp.server.fastmcp
```

### Docker

We have a provided [Dockerfile](Dockerfile) that builds and includes [mcp-server](https://github.com/converged-computing/mcp-server) to provide the basic set of Flux endpoints (submit, info, cancel, etc) via the configuration file [flux-mcp.yaml](examples/servers/flux-mcp.yaml). You can tweak that file and build, or just use from our GitHub packages registry.

```bash
docker build -t ghcr.io/converged-computing/flux-mcp:latest .
docker run -it -p 8089:8089 ghcr.io/converged-computing/flux-mcp:latest
```

### Testing

I will add tools to git as I write tests for them. To test, start the fastmcp server in one terminal:
Expand Down
3 changes: 2 additions & 1 deletion flux_mcp/validate/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ def flux_validate_batch_jobspec(content: Annotated[str, "Loaded jobspec"]):
except Exception as e:
display_error(content, str(e))
errors.append(str(e))
return {"jobspec": None, "errors": errors, "valid": not errors}
# Return the original jobspec so there is a record
return {"jobspec": content, "errors": errors, "valid": not errors}


def flux_validate_jobspec(content: Annotated[str, "Loaded jobspec"]):
Expand Down
2 changes: 1 addition & 1 deletion flux_mcp/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.0.16"
__version__ = "0.0.17"
AUTHOR = "Vanessa Sochat"
AUTHOR_EMAIL = "vsoch@users.noreply.github.com"
NAME = "flux-mcp"
Expand Down