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
47 changes: 47 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# .NET build artifacts
**/bin/
**/obj/
**/out/
**/TestResults/

# Visual Studio / VS Code
.vs/
.vscode/
*.user
*.suo
*.userprefs

# Git
.git/
.gitignore
.gitattributes

# Docker
Dockerfile
.dockerignore

# Documentation
*.md
LICENSE

# CI/CD
.github/

# Development containers
.devcontainer/

# Environment files
*.env
appsettings.Development.json

# Logs
*.log

# Test artifacts
coverage*.json
coverage*.xml
*.trx

# OS files
.DS_Store
Thumbs.db
68 changes: 68 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Docker Build and Publish

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix=${{ github.ref_name }}-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable={{is_default_branch}}
# Note: semver tags require Git tags in the format v1.2.3

- name: Build Docker image
uses: docker/build-push-action@v6
with:
context: .
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Push Docker image to GitHub Container Registry
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
54 changes: 54 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS build
WORKDIR /src

# Copy solution and project files
COPY ["AbeckDev.DbTimetable.sln", "./"]
COPY ["AbeckDev.DbTimetable.Mcp/AbeckDev.DbTimetable.Mcp.csproj", "AbeckDev.DbTimetable.Mcp/"]
COPY ["AbeckDev.DbTimetable.Mcp.Test/AbeckDev.DbTimetable.Mcp.Test.csproj", "AbeckDev.DbTimetable.Mcp.Test/"]

# Restore dependencies
RUN dotnet restore "AbeckDev.DbTimetable.Mcp/AbeckDev.DbTimetable.Mcp.csproj"

# Copy the rest of the source code
COPY . .

# Build the application
WORKDIR "/src/AbeckDev.DbTimetable.Mcp"
RUN dotnet build "AbeckDev.DbTimetable.Mcp.csproj" -c Release -o /app/build

# Publish stage
FROM build AS publish
RUN dotnet publish "AbeckDev.DbTimetable.Mcp.csproj" -c Release -o /app/publish /p:UseAppHost=false

# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:9.0-bookworm-slim AS final
WORKDIR /app

# Install curl for healthcheck
RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*

# Create a non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser

# Copy published files
COPY --from=publish /app/publish .

# Change ownership to non-root user
RUN chown -R appuser:appuser /app

# Switch to non-root user
USER appuser

# Expose port
EXPOSE 3001

# Set environment variables
ENV ASPNETCORE_URLS=http://0.0.0.0:3001

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3001/ || exit 1

# Entry point
ENTRYPOINT ["dotnet", "AbeckDev.DbTimetable.Mcp.dll"]
101 changes: 101 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# DB-TimetableAPI-MCPServer

[![.NET CI with Code Coverage](https://github.com/abeckDev/DB-TimetableAPI-MCPServer/actions/workflows/dotnet-ci.yml/badge.svg)](https://github.com/abeckDev/DB-TimetableAPI-MCPServer/actions/workflows/dotnet-ci.yml)
[![Docker Build and Publish](https://github.com/abeckDev/DB-TimetableAPI-MCPServer/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/abeckDev/DB-TimetableAPI-MCPServer/actions/workflows/docker-publish.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![codecov](https://codecov.io/github/abeckDev/DB-TimetableAPI-MCPServer/graph/badge.svg?token=RJR3H1JRPW)](https://codecov.io/github/abeckDev/DB-TimetableAPI-MCPServer)

Expand Down Expand Up @@ -187,6 +188,90 @@ dotnet build

The project should build successfully. If you encounter any issues, ensure you have .NET 9.0 SDK installed.

### Using Docker (Recommended for Production)

The easiest way to run the MCP server is using Docker. Pre-built images are automatically published to the GitHub Container Registry.

#### Pull and Run the Latest Image

```bash
# Pull the latest image from GitHub Container Registry
docker pull ghcr.io/abeckdev/db-timetableapi-mcpserver:latest

# Run the container with your API credentials
docker run -d \
--name db-timetable-mcp \
-p 3001:3001 \
-e DeutscheBahnApi__ClientId="your-actual-client-id" \
-e DeutscheBahnApi__ApiKey="your-actual-api-key" \
-e DeutscheBahnApi__BaseUrl="https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/" \
ghcr.io/abeckdev/db-timetableapi-mcpserver:latest

# Check if the container is running
docker ps

# View logs
docker logs db-timetable-mcp
```

The MCP server will be accessible at `http://localhost:3001/mcp`.

#### Build Your Own Docker Image

If you prefer to build the Docker image locally:

```bash
# Build the image
docker build -t db-timetableapi-mcpserver:local .

# Run the container
docker run -d \
--name db-timetable-mcp \
-p 3001:3001 \
-e DeutscheBahnApi__ClientId="your-actual-client-id" \
-e DeutscheBahnApi__ApiKey="your-actual-api-key" \
-e DeutscheBahnApi__BaseUrl="https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/" \
db-timetableapi-mcpserver:local
```

#### Docker Compose

You can also use Docker Compose for easier management. Create a `docker-compose.yml` file:

```yaml
services:
mcp-server:
image: ghcr.io/abeckdev/db-timetableapi-mcpserver:latest
container_name: db-timetable-mcp
ports:
- "3001:3001"
environment:
- DeutscheBahnApi__ClientId=your-actual-client-id
- DeutscheBahnApi__ApiKey=your-actual-api-key
- DeutscheBahnApi__BaseUrl=https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/
restart: unless-stopped
```

Then run:

```bash
docker compose up -d
```

#### Docker Image Tags

Images are tagged with multiple identifiers for flexibility:

- `latest` - The most recent build from the main branch
- `main` - Same as latest, tracks the main branch
- `main-<sha>` - Specific commit SHA from the main branch (e.g., `main-abc1234`)

Example pulling a specific version:

```bash
docker pull ghcr.io/abeckdev/db-timetableapi-mcpserver:main-a1b2c3d
```

---

## βš™οΈ Configuration
Expand Down Expand Up @@ -680,9 +765,25 @@ All pull requests automatically run:
- βœ… All unit tests
- βœ… Code coverage analysis
- βœ… Coverage threshold checks (70% minimum)
- βœ… Docker image build verification

Coverage reports are available as workflow artifacts.

### Continuous Deployment

When changes are pushed to the `main` branch:
- βœ… Docker images are automatically built
- βœ… Images are tagged with multiple identifiers (latest, main, commit SHA)
- βœ… Images are published to GitHub Container Registry (ghcr.io)
- βœ… Images are publicly accessible at `ghcr.io/abeckdev/db-timetableapi-mcpserver`

The Docker image includes:
- Multi-stage build for optimized size
- .NET 9.0 runtime on Debian Bookworm (slim variant)
- Non-root user for enhanced security
- Health check endpoint
- Proper port exposure (3001)

---

## 🀝 Contributing
Expand Down