Skip to content

Generate Windmill MCP Server Version #14

Generate Windmill MCP Server Version

Generate Windmill MCP Server Version #14

name: Generate Windmill MCP Server Version
on:
workflow_dispatch:
inputs:
windmill_version:
description: 'Windmill version (e.g., 1.520.1 or "latest")'
required: true
default: "latest"
type: string
schedule:
- cron: "0 0 * * 1" # Run weekly on Mondays at midnight UTC (generates latest)
permissions:
contents: write
jobs:
generate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "18"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Start Windmill instance
run: |
echo "🚀 Starting Windmill instance..."
npm run docker:up
- name: Wait for Windmill to be ready
run: |
echo "⏳ Waiting for Windmill to be ready..."
npm run docker:wait
timeout-minutes: 5
- name: Fetch OpenAPI spec from Windmill
id: fetch-spec
run: |
echo "📥 Fetching OpenAPI spec from running Windmill instance..."
# Ensure cache directory exists
mkdir -p cache
# Fetch from local Windmill instance
curl -f http://localhost:8000/api/openapi.json -o cache/openapi-spec.json
# Extract version from spec
SPEC_VERSION=$(node -p "JSON.parse(require('fs').readFileSync('cache/openapi-spec.json', 'utf8')).info.version")
echo "spec_version=$SPEC_VERSION" >> $GITHUB_OUTPUT
echo "✅ Fetched OpenAPI spec version: $SPEC_VERSION"
- name: Generate and build MCP server
id: generate
run: |
echo "🔧 Generating and building MCP server from OpenAPI spec..."
npm run generate
# Verify generation succeeded
if [ ! -f "build/src/index.ts" ]; then
echo "❌ Generation failed - index.ts not found"
exit 1
fi
# Verify build succeeded (postgenerate hook builds automatically)
if [ ! -f "build/dist/index.js" ]; then
echo "❌ Build failed - build/dist/index.js not found"
exit 1
fi
echo "✅ MCP server generated and built successfully"
- name: Run unit tests
id: unit-test
run: |
echo "🧪 Running unit tests..."
npm run test:unit 2>&1 | tee unit-test-output.txt
TEST_EXIT_CODE=${PIPESTATUS[0]}
echo "exit_code=$TEST_EXIT_CODE" >> $GITHUB_OUTPUT
if [ "$TEST_EXIT_CODE" -eq 0 ]; then
echo "✅ Unit tests passed"
else
echo "❌ Unit tests failed"
fi
exit $TEST_EXIT_CODE
continue-on-error: true
- name: Run E2E tests
id: e2e-test
env:
E2E_WINDMILL_URL: http://localhost:8000
E2E_WINDMILL_TOKEN: test-super-secret
E2E_WORKSPACE: admins
WINDMILL_BASE_URL: http://localhost:8000
run: |
echo "🧪 Running E2E tests..."
npm run test:e2e 2>&1 | tee e2e-test-output.txt
TEST_EXIT_CODE=${PIPESTATUS[0]}
echo "exit_code=$TEST_EXIT_CODE" >> $GITHUB_OUTPUT
if [ "$TEST_EXIT_CODE" -eq 0 ]; then
echo "✅ E2E tests passed"
else
echo "⚠️ E2E tests completed with warnings"
fi
exit $TEST_EXIT_CODE
continue-on-error: true
- name: Stop Windmill
if: always()
run: |
echo "🛑 Stopping Windmill instance..."
npm run docker:down
- name: Determine test status
id: test-status
run: |
UNIT_EXIT=${{ steps.unit-test.outputs.exit_code || '1' }}
E2E_EXIT=${{ steps.e2e-test.outputs.exit_code || '1' }}
# STRICT: Both unit AND E2E tests must pass for release
if [ "$UNIT_EXIT" = "0" ] && [ "$E2E_EXIT" = "0" ]; then
echo "passed=true" >> $GITHUB_OUTPUT
echo "✅ All tests passed - ready for release"
else
echo "passed=false" >> $GITHUB_OUTPUT
echo "❌ Tests failed - no release will be created"
if [ "$UNIT_EXIT" != "0" ]; then
echo " - Unit tests: FAILED"
fi
if [ "$E2E_EXIT" != "0" ]; then
echo " - E2E tests: FAILED"
fi
exit 1
fi
- name: Get package version
id: package-version
if: steps.test-status.outputs.passed == 'true'
run: |
PKG_VERSION=$(node -p "require('./package.json').version")
echo "version=$PKG_VERSION" >> $GITHUB_OUTPUT
echo "📦 Package version: $PKG_VERSION"
- name: Create tarball of generated code
if: steps.test-status.outputs.passed == 'true'
run: |
echo "📦 Creating tarball of generated code..."
cd build
tar --exclude='./runtime' -czf ../generated-mcp-server.tar.gz .
cd ..
echo "✅ Tarball created"
- name: Determine release tag
id: release-tag
if: steps.test-status.outputs.passed == 'true'
run: |
SPEC_VERSION="${{ steps.fetch-spec.outputs.spec_version }}"
PKG_VERSION="${{ steps.package-version.outputs.version }}"
INPUT_VERSION="${{ github.event.inputs.windmill_version || 'latest' }}"
if [ "$INPUT_VERSION" = "latest" ]; then
TAG="windmill-latest"
else
TAG="windmill-v${SPEC_VERSION}-mcp-${PKG_VERSION}"
fi
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "🏷️ Release tag: $TAG"
- name: Create or update release
if: steps.test-status.outputs.passed == 'true'
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.release-tag.outputs.tag }}
name: Windmill ${{ steps.fetch-spec.outputs.spec_version }} MCP Server
body: |
## Windmill MCP Server
**Windmill API Version**: ${{ steps.fetch-spec.outputs.spec_version }}
**MCP Package Version**: ${{ steps.package-version.outputs.version }}
**Generated**: ${{ github.event.repository.updated_at }}
### Test Results
- ✅ Unit tests passed
- ✅ E2E tests passed
### Installation
This is a pre-generated MCP server artifact. The main package will automatically download this when you specify:
```bash
WINDMILL_VERSION=${{ steps.fetch-spec.outputs.spec_version }} npx windmill-mcp
```
Or use latest:
```bash
npx windmill-mcp
```
### Files
- `generated-mcp-server.tar.gz` - Generated MCP server code
- `openapi-spec.json` - OpenAPI specification used for generation
---
Generated by workflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
files: |
generated-mcp-server.tar.gz
cache/openapi-spec.json
draft: false
prerelease: false
make_latest: ${{ github.event.inputs.windmill_version == 'latest' || github.event_name == 'schedule' }}
- name: Upload test results as artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ steps.fetch-spec.outputs.spec_version }}
path: |
unit-test-output.txt
e2e-test-output.txt
retention-days: 30
- name: Workflow Summary
if: always()
run: |
echo "## Workflow Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Windmill API Version**: ${{ steps.fetch-spec.outputs.spec_version }}" >> $GITHUB_STEP_SUMMARY
echo "- **MCP Package Version**: ${{ steps.package-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Release Tag**: \`${{ steps.release-tag.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY
echo "- **Tests Passed**: ${{ steps.test-status.outputs.passed == 'true' && '✅ Yes' || '❌ No' }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.test-status.outputs.passed }}" = "true" ]; then
echo "### ✅ Success!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The MCP server was generated, tested, and released successfully." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Installation:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "# Use this version" >> $GITHUB_STEP_SUMMARY
echo "WINDMILL_VERSION=${{ steps.fetch-spec.outputs.spec_version }} npx windmill-mcp" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
else
echo "### ❌ Tests Failed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The MCP server was generated but tests failed. No release was created." >> $GITHUB_STEP_SUMMARY
fi