GitHub Actions 자동 게시

GitHub Actions 자동 게시

GitHub Actions를 사용해 MCP 서버 게시를 자동화하는 워크플로를 구성합니다.

학습 목표

이 튜토리얼을 완료하면 다음을 갖추게 됩니다:

  • 서버를 자동 게시하는 GitHub Actions 워크플로
  • GitHub OIDC 인증 방식에 대한 이해
  • 자동 게시 모범 사례
  • Node.js, Python, Docker, .NET 프로젝트 예시

사전 준비

  • 패키지 검증 등 기본 게시 요구사항을 이해하고 있어야 합니다(게시 가이드 참고).
  • MCP 서버 코드가 있는 GitHub 저장소

GitHub Actions 설정

단계 1: 워크플로 파일 생성

.github/workflows/publish-mcp.yml를 생성하세요. 아래 예시는 NPM 패키지 기준이지만, MCP Registry 게시 단계는 모든 패키지 타입에서 동일합니다.

name: Publish to MCP Registry

on:
  push:
    tags: ["v*"]  # Trigger on version tags (e.g. v1.0.0)

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      id-token: write  # Required for OIDC authentication
      contents: read

    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Setup Node.js  # Adjust for your language/runtime
        uses: actions/setup-node@v5
        with:
          node-version: "lts/*"

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm run test --if-present

      - name: Build package
        run: npm run build --if-present

      - name: Publish to npm
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Install MCP Publisher
        run: |
          curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.0.0/mcp-publisher_1.0.0_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher

      - name: Login to MCP Registry
        run: ./mcp-publisher login github-oidc

      - name: Publish to MCP Registry
        run: ./mcp-publisher publish

단계 2: 시크릿(secrets) 설정

GitHub OIDC로 MCP Registry에 게시할 때는 별도의 MCP Registry용 시크릿이 필요하지 않습니다.

다만, 패키지 레지스트리 게시에는 시크릿이 필요할 수 있습니다. 예를 들어 위 워크플로에서는 NPM_TOKEN이 필요합니다(GitHub 저장소 Settings → Secrets and variables → Actions에서 추가).

단계 3: 태그 생성 및 게시

워크플로를 트리거하려면 버전 태그를 생성하세요:

git tag v1.0.0
git push origin v1.0.0

워크플로는 테스트/빌드 후 npm에 게시하고, 이어서 MCP Registry에 게시합니다.

인증 방법

GitHub Actions OIDC(권장)

- name: Login to MCP Registry
  run: mcp-publisher login github-oidc

권장하는 이유:

  • 시크릿을 저장할 필요가 없음
  • GitHub 내장 인증 사용
  • GitHub 네임스페이스에 자동으로 접근

GitHub 개인 액세스 토큰(PAT)

- name: Login to MCP Registry
  run: mcp-publisher login github --token ${{ secrets.GITHUB_TOKEN }}
  env:
    GITHUB_TOKEN: ${{ secrets.MCP_GITHUB_TOKEN }}

저장소 접근 권한이 있는 GitHub PAT를 MCP_GITHUB_TOKEN 시크릿으로 추가하세요.

DNS 인증

커스텀 도메인 네임스페이스(com.yourcompany/*)의 경우:

- name: Login to MCP Registry
  run: |
    echo "${{ secrets.MCP_PRIVATE_KEY }}" > key.pem
    mcp-publisher login dns --domain yourcompany.com --private-key-file key.pem

Ed25519 개인키를 MCP_PRIVATE_KEY 시크릿으로 추가하세요.

언어별 예시

Node.js/NPM 프로젝트

name: Publish NPM MCP Server

on:
  push:
    tags: ["v*"]

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v5
      
      - uses: actions/setup-node@v5
        with:
          node-version: "lts/*"
          registry-url: "https://registry.npmjs.org"

      - run: npm ci
      - run: npm test
      - run: npm run build --if-present
      
      - name: Publish to NPM
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Install MCP Publisher
        run: |
          curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.0.0/mcp-publisher_1.0.0_linux_amd64.tar.gz" | tar xz mcp-publisher

      - name: Publish to MCP Registry
        run: |
          ./mcp-publisher login github-oidc
          ./mcp-publisher publish

Python/PyPI 프로젝트

name: Publish Python MCP Server

on:
  push:
    tags: ["v*"]

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v5
      
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install build twine

      - name: Build package
        run: python -m build

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}

      - name: Install MCP Publisher
        run: |
          curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.0.0/mcp-publisher_1.0.0_linux_amd64.tar.gz" | tar xz mcp-publisher

      - name: Publish to MCP Registry
        run: |
          ./mcp-publisher login github-oidc
          ./mcp-publisher publish

Docker/OCI 프로젝트

name: Publish Docker MCP Server

on:
  push:
    tags: ["v*"]

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v5

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

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${{ github.repository }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: |
            ${{ steps.meta.outputs.labels }}
            io.modelcontextprotocol.server.name=io.github.${{ github.repository_owner }}/my-server

      - name: Install MCP Publisher
        run: |
          curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.0.0/mcp-publisher_1.0.0_linux_amd64.tar.gz" | tar xz mcp-publisher

      - name: Publish to MCP Registry
        run: |
          ./mcp-publisher login github-oidc
          ./mcp-publisher publish

NuGet/.NET 프로젝트

name: Publish NuGet MCP Server

on:
  push:
    tags: ["v*"]

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
      - uses: actions/checkout@v5
      
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "8.0.x"

      - name: Restore dependencies
        run: dotnet restore

      - name: Build
        run: dotnet build --configuration Release --no-restore

      - name: Test
        run: dotnet test --no-restore --verbosity normal

      - name: Pack
        run: dotnet pack --configuration Release --no-build --output ./artifacts

      - name: Publish to NuGet
        run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json

      - name: Install MCP Publisher
        run: |
          curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.0.0/mcp-publisher_1.0.0_linux_amd64.tar.gz" | tar xz mcp-publisher

      - name: Publish to MCP Registry
        run: |
          ./mcp-publisher login github-oidc
          ./mcp-publisher publish

버전 동기화 팁

패키지 버전과 server.json 버전을 자동으로 동기화하려면 다음처럼 구성할 수 있습니다:

- name: Update server.json version
  run: |
    VERSION=${GITHUB_REF#refs/tags/v}
    jq --arg v "$VERSION" '.version = $v' server.json > tmp && mv tmp server.json

고급 설정

조건부 게시

특정 조건일 때만 Registry에 게시합니다:

- name: Publish to MCP Registry
  if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-')
  run: |
    ./mcp-publisher login github-oidc
    ./mcp-publisher publish

다중 환경 게시

환경별로 서로 다른 설정 파일을 사용합니다:

- name: Publish to MCP Registry
  run: |
    ./mcp-publisher login github-oidc
    if [[ "${{ github.ref }}" == *"-alpha"* ]]; then
      ./mcp-publisher publish --file=server-alpha.json
    else
      ./mcp-publisher publish
    fi

실패 알림

실패 시 알림을 추가합니다:

- name: Notify on failure
  if: failure()
  uses: actions/github-script@v7
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '❌ MCP Registry publish failed. Please check Actions logs.'
      })

모범 사례

1) 릴리스 태그 기반 게시

on:
  push:
    tags: ["v*"]

2) 검증 후 게시

- name: Validate before publish
  run: |
    ./mcp-publisher publish --dry-run

3) 의존성 캐시

- name: Cache dependencies
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

4) 매트릭스 빌드

여러 버전에서 테스트합니다:

strategy:
  matrix:
    node-version: [18, 20, 22]

문제 해결

“Authentication failed”(인증 실패)

  • OIDC를 사용하는 경우 id-token: write 권한이 설정되어 있는지 확인하세요.
  • 시크릿 설정을 점검하세요.

“Package validation failed”(패키지 검증 실패)

  • 패키지가 먼저 레지스트리(NPM, PyPI 등)에 정상적으로 게시되었는지 확인하세요.
  • 게시 가이드의 검증 단계를 모두 수행했는지 확인하세요.

“Version mismatch”(버전 불일치)

  • server.json 버전과 패키지 버전이 일치하는지 확인하세요.
  • 위의 버전 동기화 스크립트를 사용하세요.

“Rate limiting”(요청 제한)

  • 짧은 시간에 반복 게시하지 마세요.
  • 필요하다면 적절한 재시도 로직을 추가하세요.

실제 예시

자동 게시 워크플로의 실제 예시:

다음 단계

수동 게시 흐름을 학습하세요. `mcp-publisher` 명령어를 익히세요. 버전 관리 모범 사례를 확인하세요. 네임스페이스와 보안 모델을 이해하세요.
자동화의 장점: GitHub Actions를 사용하면 매 릴리스가 테스트, 빌드, 검증을 거치게 되어 휴먼 에러를 줄이고 게시 품질을 높일 수 있습니다.