Skip to content

Commit ca141fa

Browse files
committed
Add Docker support
1 parent 4b176a8 commit ca141fa

File tree

7 files changed

+194
-5
lines changed

7 files changed

+194
-5
lines changed

.dockerignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# OS specific files
2+
Thumbs.db
3+
.DS_Store
4+
._*
5+
6+
# --- Don't track Python cache & virtual environments
7+
__pycache__/
8+
*.pyc
9+
env/
10+
venv/
11+
.venv/
12+
13+
# --- Debugpy logs, WinMerge Backups etc.
14+
*.log
15+
*.bak
16+
*.hex
17+
18+
# --- Skip the Doorstop working dir
19+
test/

.github/workflows/deploy-image.yml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#
2+
name: Create and publish a Docker image
3+
4+
# Configures this workflow to run every time a change is pushed to the branch called
5+
# `main` or `dev`.
6+
on:
7+
push:
8+
branches: ['main', 'dev']
9+
tags: ['*']
10+
11+
# Defines two custom environment variables for the workflow. These are used for the
12+
# Container registry domain, and a name for the Docker image that this workflow builds.
13+
env:
14+
REGISTRY: ghcr.io
15+
IMAGE_NAME: ${{ github.repository }}
16+
17+
# There is a single job in this workflow. It's configured to run on the latest available
18+
# version of Ubuntu.
19+
jobs:
20+
build-and-push-image:
21+
runs-on: ubuntu-latest
22+
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
23+
permissions:
24+
contents: read
25+
packages: write
26+
attestations: write
27+
id-token: write
28+
29+
steps:
30+
- name: Checkout repository
31+
uses: actions/checkout@v6
32+
with:
33+
submodules: true
34+
35+
# Uses the `docker/login-action` action to log in to the Container registry registry
36+
# using the account and password that will publish the packages. Once published, the
37+
# packages are scoped to the account defined here.
38+
- name: Log in to the Container registry
39+
uses: docker/login-action@v3
40+
with:
41+
registry: ${{ env.REGISTRY }}
42+
username: ${{ github.actor }}
43+
password: ${{ secrets.GITHUB_TOKEN }}
44+
45+
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about)
46+
# to extract tags and labels that will be applied to the specified image.
47+
# The `id` "meta" allows the output of this step to be referenced in a subsequent
48+
# step. The `images` value provides the base name for the tags and labels.
49+
# It will automatically create the latest Docker tag, if a git tag is found: https://github.com/docker/metadata-action?tab=readme-ov-file#latest-tag
50+
- name: Extract metadata (tags, labels) for Docker
51+
id: meta
52+
uses: docker/metadata-action@v5
53+
with:
54+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
55+
56+
# This step gets the short git commit hash
57+
# https://dev.to/hectorleiva/github-actions-and-creating-a-short-sha-hash-8b7
58+
- name: Set short git commit SHA
59+
id: vars
60+
run: |
61+
calculatedSha=$(git rev-parse --short ${{ github.sha }})
62+
echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
63+
64+
# This step uses the `docker/build-push-action` action to build the image, based on
65+
# your repository's `Dockerfile`. If the build succeeds, it pushes the image to
66+
# GitHub Packages.
67+
# It uses the `context` parameter to define the build's context as the set of files
68+
# located in the specified path. For more information, see [Usage](https://github.com/docker/build-push-action#usage)
69+
# in the README of the `docker/build-push-action` repository.
70+
# It uses the `tags` and `labels` parameters to tag and label the image with the
71+
# output from the "meta" step.
72+
- name: Build and push Docker image
73+
id: push
74+
uses: docker/build-push-action@v6
75+
with:
76+
context: .
77+
push: true
78+
tags: ${{ steps.meta.outputs.tags }}
79+
labels: ${{ steps.meta.outputs.labels }}
80+
build-args: |
81+
GIT_HASH=${{ github.sha }}
82+
GIT_HASH_SHORT=${{ env.COMMIT_SHORT_SHA }}
83+
84+
# This step generates an artifact attestation for the image, which is an unforgeable
85+
# statement about where and how it was built. It increases supply chain security for
86+
# people who consume the image. For more information, see [Using artifact attestations
87+
# to establish provenance for builds](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds).
88+
- name: Generate artifact attestation
89+
uses: actions/attest-build-provenance@v3
90+
with:
91+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
92+
subject-digest: ${{ steps.push.outputs.digest }}
93+
push-to-registry: true

.vscode/settings.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@
4343
"Jannled",
4444
"modelcontextprotocol",
4545
"pycache",
46+
"reqs",
4647
"streamable",
4748
"unreviewed",
48-
"venv"
49+
"venv",
50+
"Yeet"
4951
]
5052
}

Dockerfile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Using an official Python Debian image as a baseline
2+
# https://hub.docker.com/_/python
3+
# https://www.debian.org/releases/
4+
FROM python:3.13-slim
5+
6+
# Labels as per:
7+
# https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
8+
LABEL org.opencontainers.image.authors="Jannled"
9+
LABEL org.opencontainers.image.version="0.0.1"
10+
LABEL org.opencontainers.image.licenses="MIT"
11+
LABEL org.opencontainers.image.description="Doorstop with MCP"
12+
LABEL org.opencontainers.image.source="https://github.com/Jannled/DoorstopMCP"
13+
14+
# Yeet the apt-cache afterwards, since it is no longer needed
15+
RUN apt-get update && apt-get install -y nano htop git less && rm -rf /var/lib/apt/lists/*
16+
17+
# Create a non root user for enhanced security
18+
RUN groupadd -r door && useradd -r -g door door
19+
20+
# Change workdir to folder where doorstop will be installed (affects COPY, RUN etc.)
21+
WORKDIR /usr/src/doorstop
22+
23+
# Install all Python libs that are required (installing under the root user, since the other user has no home)
24+
COPY requirements.txt .
25+
RUN pip install --no-cache-dir -r requirements.txt
26+
27+
# Set the ownership and permissions for the application files, switch to this user for the rest of the script
28+
RUN chown -R door:door /usr/src/doorstop
29+
USER door
30+
31+
# Copy the MCP code
32+
COPY . .
33+
RUN mkdir reqs && cd reqs && git init
34+
RUN doorstop create REQ ./reqs/req
35+
RUN doorstop create LLR ./reqs/llr --parent REQ
36+
RUN doorstop create TST ./reqs/tests --parent REQ
37+
38+
VOLUME [ "/usr/src/doorstop/reqs" ]
39+
40+
# Exposes the port that FastMCP is listening to
41+
EXPOSE 3001
42+
43+
# Run the FastMCP server when the container launches
44+
CMD ["python", "-m", "DoorstopMCP"]

DoorstopMCP.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22

33
import doorstop # type: ignore
4-
from doorstop import Document, Item, DoorstopError # type: ignore
4+
from doorstop import Document, DoorstopError # type: ignore
55
from mcp.server.fastmcp import FastMCP
66

77
from utils import CUSTOM_ATTRIB_TYPE, CUSTOM_ATTRIB_VERIFICATION_METHOD, add_custom_attribs, get_tree

Readme.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ Options:
1515

1616
## Custom Attributes
1717
Some attributes commonly used in requirements engineering such as Functional / Non-Functional
18-
requirements are an afterthought in Doorstop and have to be added manually by the user of the
19-
framework. Here is the list of attributes that where extended by this MCP server. They are
20-
automatically added to every document and when creating an item they can be populated.
18+
requirements are an afterthought in Doorstop and have to be
19+
[added manually](https://doorstop.readthedocs.io/en/latest/reference/item.html#extended-item-attributes)
20+
by the user of the framework. Here is the list of attributes that where extended by this
21+
MCP server. They are automatically added to every document and when creating an item they can
22+
be populated.
2123

2224
| Attribute | Examples |
2325
| --------------- | ----------------------------------------------------------- |

docker-compose.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: doorstop-mcp
2+
3+
volumes:
4+
doorstop_data:
5+
6+
services:
7+
doorstop-mcp-server:
8+
image: doorstop-mcp
9+
pull_policy: build
10+
build: .
11+
restart: unless-stopped
12+
13+
ports:
14+
- "3001:3001"
15+
16+
volumes:
17+
- doorstop_data:/usr/src/doorstop/reqs
18+
19+
deploy:
20+
# prevent malfunction of this container from affecting the host
21+
resources:
22+
limits:
23+
cpus: '2'
24+
memory: 4G
25+
pids: 48
26+
restart_policy:
27+
condition: on-failure
28+
delay: 10s
29+
max_attempts: 3

0 commit comments

Comments
 (0)