mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2026-10-30 02:01:54 +01:00
- Read only API keys: an Access choice when creating a key, stored in the key metadata; the middleware refuses writes and most auth calls for them with 403 API_KEY_READ_ONLY. - POST /api/mcp: stateless MCP endpoint with 8 tools that call the REST API over loopback with the caller's key. Needs x-api-key, a cookie alone gets 401. MCP_INTERNAL_URL overrides the loopback address. - mcp/: gitea-mirror-mcp, a zero dependency stdio bridge to /api/mcp for Claude Desktop and Cursor, with a CI workflow that publishes it on an mcp-v* tag. - e2e spec for keys, the endpoint and the bridge; docs for the endpoint, the bridge and read only keys.
121 lines
3.3 KiB
YAML
121 lines
3.3 KiB
YAML
name: MCP Server
|
|
|
|
# Tests the stdio bridge in mcp/ and publishes it to npm as gitea-mirror-mcp
|
|
# when an mcp-v* tag is pushed. Path filters do not apply to tag pushes. The
|
|
# tools themselves live in the app (src/lib/mcp) and are tested with it.
|
|
on:
|
|
push:
|
|
branches: ['**']
|
|
tags: ['mcp-v*']
|
|
paths:
|
|
- 'mcp/**'
|
|
- '.github/workflows/mcp.yml'
|
|
pull_request:
|
|
branches: ['**']
|
|
paths:
|
|
- 'mcp/**'
|
|
- '.github/workflows/mcp.yml'
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
BUN_VERSION: '1.3.13'
|
|
NODE_VERSION: '22'
|
|
|
|
jobs:
|
|
test:
|
|
name: Test MCP bridge
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
defaults:
|
|
run:
|
|
working-directory: mcp
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@v1
|
|
with:
|
|
bun-version: ${{ env.BUN_VERSION }}
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Typecheck
|
|
run: npm run typecheck
|
|
|
|
- name: Run tests
|
|
run: npm test
|
|
|
|
- name: Build
|
|
run: npm run build
|
|
|
|
- name: Smoke test the build on Node
|
|
# No app runs here, so the bridge must answer the request itself
|
|
# with a clear error instead of hanging or crashing.
|
|
run: |
|
|
printf '%s\n' \
|
|
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"ci","version":"0"}}}' \
|
|
| GITEA_MIRROR_URL=http://127.0.0.1:9 GITEA_MIRROR_API_KEY=gm_smoke timeout 20 node dist/index.js > smoke.jsonl
|
|
node -e '
|
|
const lines = require("fs").readFileSync("smoke.jsonl", "utf8").trim().split("\n").map(JSON.parse);
|
|
const answer = lines.find((m) => m.id === 1);
|
|
if (!answer?.error?.message?.includes("Could not reach Gitea Mirror")) { console.error(lines); process.exit(1); }
|
|
console.log(answer.error.message);
|
|
'
|
|
|
|
- name: Show package contents
|
|
run: npm pack --dry-run
|
|
|
|
publish:
|
|
name: Publish to npm
|
|
needs: test
|
|
if: startsWith(github.ref, 'refs/tags/mcp-v')
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
defaults:
|
|
run:
|
|
working-directory: mcp
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@v1
|
|
with:
|
|
bun-version: ${{ env.BUN_VERSION }}
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
registry-url: 'https://registry.npmjs.org'
|
|
|
|
- name: Check the tag matches the package version
|
|
run: |
|
|
version=$(node -p 'require("./package.json").version')
|
|
if [ "mcp-v${version}" != "${GITHUB_REF_NAME}" ]; then
|
|
echo "::error::Tag ${GITHUB_REF_NAME} does not match mcp/package.json version ${version}"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Publish
|
|
run: npm publish --provenance --access public
|
|
env:
|
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|