Fix workflow: use setup-go@v4 for Gitea Actions compatibility
Some checks failed
Release / build (amd64, darwin) (push) Has been cancelled
Release / build (amd64, windows) (push) Has been cancelled
Release / build (amd64, linux) (push) Has been cancelled
Release / build (arm64, linux) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / build (arm64, darwin) (push) Has been cancelled

This commit is contained in:
2026-01-11 16:10:16 -05:00
commit 970c02c877
5 changed files with 387 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: linux-latest
strategy:
matrix:
include:
- goos: linux
goarch: amd64
- goos: linux
goarch: arm64
- goos: darwin
goarch: amd64
- goos: darwin
goarch: arm64
- goos: windows
goarch: amd64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: '1.21'
cache: false
- name: Build
shell: bash
run: |
VERSION="${GITHUB_REF_NAME#v}"
EXT=""
if [ "${{ matrix.goos }}" = "windows" ]; then
EXT=".exe"
fi
echo "Building for ${{ matrix.goos }}/${{ matrix.goarch }} version ${VERSION}"
CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \
go build -ldflags "-s -w -X main.version=${VERSION}" \
-o "gitea-mcp-server-${{ matrix.goos }}-${{ matrix.goarch }}${EXT}"
ls -la gitea-mcp-server-*
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: gitea-mcp-server-${{ matrix.goos }}-${{ matrix.goarch }}
path: gitea-mcp-server-*
release:
needs: build
runs-on: linux-latest
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v3
with:
path: artifacts
- name: Prepare release files
shell: bash
run: |
mkdir -p release
find artifacts -type f -name 'gitea-mcp-server-*' -exec mv {} release/ \;
cd release && sha256sum * > checksums.txt
ls -la
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: release/*
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 MarketAlly
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

133
README.md Normal file
View File

@@ -0,0 +1,133 @@
# Gitea MCP Server
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that enables AI assistants like Claude to interact directly with your Gitea instance.
## Features
- **Query Runners** - List runners, check status, view capabilities (OS, tools, disk space)
- **Monitor Workflows** - List runs, get job details, view logs
- **Manage Releases** - List releases, get assets, check download counts
- **AI-Friendly** - Structured JSON responses designed for AI consumption
## Quick Start
### 1. Download
Download the latest binary from [Releases](https://git.marketally.com/gitcaddy/mcp-server/releases).
### 2. Configure Claude Code
Add to your Claude Code settings:
**Option A: Command line arguments**
```json
{
"mcpServers": {
"gitea": {
"command": "/path/to/gitea-mcp-server",
"args": ["--url", "https://git.marketally.com", "--token", "YOUR_API_TOKEN"]
}
}
}
```
**Option B: Environment variables**
```json
{
"mcpServers": {
"gitea": {
"command": "/path/to/gitea-mcp-server",
"env": {
"GITEA_URL": "https://git.marketally.com",
"GITEA_TOKEN": "your-token-here"
}
}
}
}
```
### 3. Use It
Ask Claude things like:
- "What runners are online?"
- "Show me the latest workflow runs for gitcaddy/act_runner"
- "Why did run #77 fail?"
- "What assets are in the v0.3.6 release?"
## Available Tools
| Tool | Description |
|------|-------------|
| `list_runners` | List all runners with status, capabilities, disk space |
| `get_runner` | Get detailed runner info by ID |
| `list_workflow_runs` | List workflow runs for a repository |
| `get_workflow_run` | Get run details with all jobs |
| `get_job_logs` | Get logs from a specific job |
| `list_releases` | List releases for a repository |
| `get_release` | Get release details with all assets |
## Building from Source
```bash
git clone https://git.marketally.com/gitcaddy/mcp-server.git
cd mcp-server
go build -o gitea-mcp-server .
```
### Cross-compile for all platforms
```bash
# Linux
GOOS=linux GOARCH=amd64 go build -o gitea-mcp-server-linux-amd64 .
# macOS Intel
GOOS=darwin GOARCH=amd64 go build -o gitea-mcp-server-darwin-amd64 .
# macOS Apple Silicon
GOOS=darwin GOARCH=arm64 go build -o gitea-mcp-server-darwin-arm64 .
# Windows
GOOS=windows GOARCH=amd64 go build -o gitea-mcp-server-windows-amd64.exe .
```
## Architecture
```
┌─────────────┐ stdio ┌──────────────────┐ HTTP ┌─────────────┐
│ Claude Code │ ◄────────────► │ gitea-mcp-server │ ◄───────────► │ Gitea │
│ (AI Tool) │ JSON-RPC │ (This binary) │ /api/v2/mcp │ Server │
└─────────────┘ └──────────────────┘ └─────────────┘
```
The MCP server:
1. Receives JSON-RPC requests over stdio from Claude Code
2. Forwards them to Gitea's `/api/v2/mcp` endpoint
3. Returns responses back to Claude Code
## Configuration Options
| Flag | Env Variable | Description |
|------|-------------|-------------|
| `--url` | `GITEA_URL` | Gitea server URL (required) |
| `--token` | `GITEA_TOKEN` | API token for authentication |
| `--debug` | - | Enable debug logging to stderr |
## Obtaining an API Token
1. Go to your Gitea instance → Settings → Applications
2. Generate a new token with appropriate scopes
3. Copy the token and use it in your configuration
## Requirements
- Gitea 1.26+ with GitCaddy enhancements (includes `/api/v2/mcp` endpoint)
- Go 1.21+ (for building from source)
## License
MIT License - See [LICENSE](LICENSE) file.
## Related Projects
- [GitCaddy Gitea](https://git.marketally.com/gitcaddy/gitea) - Enhanced Gitea fork with AI-friendly APIs
- [GitCaddy act_runner](https://git.marketally.com/gitcaddy/act_runner) - Enhanced runner with capabilities detection

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module git.marketally.com/gitcaddy/mcp-server
go 1.21

153
main.go Normal file
View File

@@ -0,0 +1,153 @@
// Copyright 2026 MarketAlly. All rights reserved.
// SPDX-License-Identifier: MIT
// Gitea MCP Server - Model Context Protocol server for Gitea Actions
//
// This standalone server implements the MCP protocol over stdio,
// proxying requests to a Gitea instance's /api/v2/mcp endpoint.
//
// Usage:
//
// gitea-mcp-server --url https://git.example.com --token YOUR_API_TOKEN
//
// Configure in Claude Code's settings.json:
//
// {
// "mcpServers": {
// "gitea": {
// "command": "gitea-mcp-server",
// "args": ["--url", "https://git.example.com", "--token", "YOUR_TOKEN"]
// }
// }
// }
package main
import (
"bufio"
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"net/http"
"os"
"time"
)
var (
giteaURL string
giteaToken string
debug bool
)
func main() {
flag.StringVar(&giteaURL, "url", "", "Gitea server URL (e.g., https://git.example.com)")
flag.StringVar(&giteaToken, "token", "", "Gitea API token")
flag.BoolVar(&debug, "debug", false, "Enable debug logging to stderr")
flag.Parse()
// Also check environment variables
if giteaURL == "" {
giteaURL = os.Getenv("GITEA_URL")
}
if giteaToken == "" {
giteaToken = os.Getenv("GITEA_TOKEN")
}
if giteaURL == "" {
fmt.Fprintln(os.Stderr, "Error: --url or GITEA_URL is required")
os.Exit(1)
}
debugLog("Gitea MCP Server starting")
debugLog("Connecting to: %s", giteaURL)
// Read JSON-RPC messages from stdin, forward to Gitea, write responses to stdout
reader := bufio.NewReader(os.Stdin)
for {
line, err := reader.ReadBytes('\n')
if err != nil {
if err == io.EOF {
debugLog("EOF received, exiting")
break
}
debugLog("Read error: %v", err)
continue
}
line = bytes.TrimSpace(line)
if len(line) == 0 {
continue
}
debugLog("Received: %s", string(line))
// Forward to Gitea's MCP endpoint
response, err := forwardToGitea(line)
if err != nil {
debugLog("Forward error: %v", err)
// Send error response
errorResp := map[string]interface{}{
"jsonrpc": "2.0",
"id": nil,
"error": map[string]interface{}{
"code": -32603,
"message": "Internal error",
"data": err.Error(),
},
}
writeResponse(errorResp)
continue
}
debugLog("Response: %s", string(response))
// Write response to stdout
fmt.Println(string(response))
}
}
func forwardToGitea(request []byte) ([]byte, error) {
mcpURL := giteaURL + "/api/v2/mcp"
req, err := http.NewRequest("POST", mcpURL, bytes.NewReader(request))
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
if giteaToken != "" {
req.Header.Set("Authorization", "token "+giteaToken)
}
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("http request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("http status %d: %s", resp.StatusCode, string(body))
}
return body, nil
}
func writeResponse(resp interface{}) {
data, _ := json.Marshal(resp)
fmt.Println(string(data))
}
func debugLog(format string, args ...interface{}) {
if debug {
fmt.Fprintf(os.Stderr, "[DEBUG] "+format+"\n", args...)
}
}