2
0

12 Commits

Author SHA1 Message Date
94e0a27b36 docs(api): document organization and landing page MCP tools
Updates README to document newly added MCP tools for organization management and landing page configuration.

Adds Organization Tools section documenting 8 tools: list_orgs, get_org_overview, update_org, list_org_repos, get_org_profile_readme, update_org_profile_readme, pin_org_repo, unpin_org_repo.

Adds Landing Page Tools section documenting 12 tools for configuring repository landing pages: get_landing_config, list_landing_templates, enable_landing_page, and 9 update_landing_* tools for brand, hero, pricing, comparison, features, social proof, SEO, theme, stats, value props, and CTA sections.

Includes example prompts users can ask Claude to exercise the new functionality.
2026-04-19 17:35:54 -04:00
4eb7f78b6b fix(mcp): restore Content-Length framing for MCP stdio
All checks were successful
Release / build (amd64, windows) (push) Successful in 39s
Release / build (arm64, darwin) (push) Successful in 40s
Release / build (amd64, linux) (push) Successful in 52s
Release / build (amd64, darwin) (push) Successful in 1m27s
Release / build (arm64, linux) (push) Successful in 1m38s
Release / release (push) Successful in 24s
Revert to LSP-style Content-Length framing for MCP stdio transport. Testing confirmed that MCP clients (Claude Code) do expect Content-Length headers, not raw NDJSON. The earlier NDJSON change was based on incorrect assumption about the protocol.
2026-04-15 03:46:17 -04:00
c6ed87cdcf fix(mcp): suppress responses to JSON-RPC notifications
All checks were successful
Release / build (amd64, windows) (push) Successful in 39s
Release / build (amd64, linux) (push) Successful in 57s
Release / build (arm64, linux) (push) Successful in 1m4s
Release / build (amd64, darwin) (push) Successful in 1m20s
Release / build (arm64, darwin) (push) Successful in 1m21s
Release / release (push) Successful in 22s
Add JSON-RPC notification detection and response suppression per MCP spec. Notifications (requests without "id" field) must never receive responses, even if the upstream server returns an error. Prevents handshake failures when Claude Code sends notifications/initialized and receives unexpected error responses.

Changes:
- Add isJsonRpcNotification() to detect requests without "id" field
- Skip error responses for notifications
- Suppress upstream responses to notifications
- Add detailed comments explaining JSON-RPC 2.0 notification semantics
2026-04-15 02:27:22 -04:00
f059b6f458 fix(mcp): use NDJSON instead of LSP framing for MCP stdio
All checks were successful
Release / build (amd64, windows) (push) Successful in 43s
Release / build (arm64, linux) (push) Successful in 1m0s
Release / build (amd64, linux) (push) Successful in 1m10s
Release / build (amd64, darwin) (push) Successful in 1m19s
Release / build (arm64, darwin) (push) Successful in 1m46s
Release / release (push) Successful in 21s
Replace Content-Length framing with newline-delimited JSON (NDJSON) for MCP stdio transport. MCP clients like Claude Code expect one JSON object per line, not LSP-style Content-Length headers. The previous framing caused clients to reject responses.
2026-04-15 02:20:20 -04:00
4b350fe967 fix(mcp): use Content-Length framing for all responses
All checks were successful
Release / build (amd64, linux) (push) Successful in 38s
Release / build (amd64, windows) (push) Successful in 38s
Release / build (arm64, darwin) (push) Successful in 44s
Release / build (amd64, darwin) (push) Successful in 1m4s
Release / build (arm64, linux) (push) Successful in 1m14s
Release / release (push) Successful in 21s
Adds writeFramed helper to send responses with HTTP-style Content-Length headers instead of raw JSON lines. Ensures compatibility with Claude Code which expects framed messages. Updates both main loop and writeResponse to use consistent framing.
2026-04-05 02:48:24 -04:00
1d770b45c9 feat(mcp): add support for Content-Length framed JSON-RPC messages
All checks were successful
Release / build (amd64, windows) (push) Successful in 41s
Release / build (arm64, darwin) (push) Successful in 42s
Release / build (amd64, linux) (push) Successful in 46s
Release / build (arm64, linux) (push) Successful in 1m11s
Release / release (push) Successful in 19s
Release / build (amd64, darwin) (push) Successful in 1m4s
Implements readMessage function to handle both raw JSON lines and Content-Length framed messages. Claude Code uses HTTP-style framing (Content-Length: N\r\n\r\n{json}) while other clients may send raw JSON. Auto-detects format by peeking at first bytes. Adds .gitignore for compiled binaries.
2026-04-05 02:24:17 -04:00
fd473c298c docs: add repository and issue tools to readme
All checks were successful
Release / build (amd64, linux) (push) Successful in 30s
Release / build (amd64, windows) (push) Successful in 31s
Release / build (arm64, darwin) (push) Successful in 34s
Release / build (arm64, linux) (push) Successful in 41s
Release / build (amd64, darwin) (push) Successful in 53s
Release / release (push) Successful in 14s
2026-03-06 19:23:37 -05:00
44f75cf6e0 docs(ci): add workflow validation tool to documentation
- Document new validate_workflow tool in examples and tool table
- Update list_workflows description to mention validation status
- Add example usage for workflow validation
2026-02-01 06:46:28 -05:00
01da7b9736 docs(ci): add example query for listing repositories 2026-01-26 01:30:49 -05:00
57a46d9bf8 docs(ci): add package defaults tool to readme 2026-01-25 22:39:30 -05:00
b1709b47cd docs(api): document new workflow management and artifact tools
All checks were successful
Release / build (amd64, windows) (push) Successful in 52s
Release / build (amd64, darwin) (push) Successful in 37s
Release / build (amd64, linux) (push) Successful in 35s
Release / build (arm64, darwin) (push) Successful in 36s
Release / build (arm64, linux) (push) Successful in 43s
Release / release (push) Successful in 45s
Add documentation for new MCP tools: trigger_workflow, rerun_workflow, cancel_workflow_run, approve_workflow, list_workflows, get_workflow_file, list_artifacts, get_artifact_download_url, and get_queue_depth. Reorganize tools section into logical categories (Runner, Workflow, Artifact, Release & Package) and add usage examples.
2026-01-25 15:41:39 -05:00
2ec5ed0ff7 docs(mcp): add list_secrets and list_packages to MCP tools
All checks were successful
Release / build (amd64, darwin) (push) Successful in 40s
Release / build (amd64, linux) (push) Successful in 55s
Release / build (amd64, windows) (push) Successful in 47s
Release / build (arm64, darwin) (push) Successful in 49s
Release / build (arm64, linux) (push) Successful in 42s
Release / release (push) Successful in 17s
Updates README with documentation for new list_secrets and list_packages MCP tools. Adds example queries showing how to use these tools with Claude.
2026-01-24 15:05:32 -05:00
3 changed files with 207 additions and 8 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*.exe
*.dll
*.so
*.dylib

106
README.md
View File

@@ -4,9 +4,14 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that e
## Features
- **Query Runners** - List runners, check status, view capabilities (OS, tools, disk space)
- **Monitor Workflows** - List runs, get job details, view logs
- **Organization Management** - List orgs, view overviews, update settings, manage profile READMEs
- **Repository Organization** - List repos with group support, pin/unpin featured repos
- **Query Runners** - List runners, check status, view capabilities, monitor queue depth
- **Manage Workflows** - List, trigger, rerun, cancel, and approve workflow runs
- **View Logs** - Get job logs with automatic error extraction for failed jobs
- **Access Artifacts** - List and download workflow artifacts
- **Manage Releases** - List releases, get assets, check download counts
- **Landing Pages** - Configure and customize repository landing pages
- **AI Learning** - Query error patterns, report solutions, help other AIs learn
- **AI-Friendly** - Structured JSON responses designed for AI consumption
@@ -50,26 +55,100 @@ Add to your Claude Code settings:
### 3. Use It
Ask Claude things like:
- "What organizations do I have access to?"
- "Show me the overview for myorg"
- "List all repos in myorg grouped by category"
- "Update myorg's description and website"
- "Show me the profile README for myorg"
- "Update the profile README for myorg"
- "Pin the 'flagship-app' repo to the myorg overview"
- "Unpin 'old-project' from myorg"
- "What runners are online?"
- "Show me the latest workflow runs for gitcaddy/act_runner"
- "Why did run #77 fail?"
- "Rerun the failed jobs in run #77"
- "Cancel run #80"
- "Trigger the build.yml workflow on the main branch"
- "What workflows are available in myorg/myrepo?"
- "Show me the build.yml workflow file"
- "Validate the build.yml workflow in myorg/myrepo"
- "What artifacts were produced by run #77?"
- "What's the queue depth for each runner label?"
- "Approve the workflow run from the fork PR"
- "What assets are in the v0.3.6 release?"
- "Are there any known solutions for NETSDK1147?"
- "Diagnose why job 456 failed"
- "What secrets are available for myorg/myrepo?"
- "List all NuGet packages for myorg"
- "What are the package defaults for myorg?"
- "List all repos for myorg"
- "List open issues for gitcaddy/server"
- "Show me issue #42 in myorg/myrepo"
- "Set up a landing page for myorg/myrepo"
- "Update the hero section on the landing page"
## Available Tools
### Runner & Workflow Tools
### Organization Tools
| Tool | Description |
|------|-------------|
| `list_orgs` | List all organizations the authenticated user belongs to |
| `get_org_overview` | Get comprehensive org overview: pinned repos, groups, members, stats, profile README, recent activity |
| `update_org` | Update org info (full name, email, description, website, location, group header) |
| `list_org_repos` | List repos for an org with optional `group_by=group_header` grouping |
| `get_org_profile_readme` | Get the raw markdown of an org's profile README from its `.profile` repo |
| `update_org_profile_readme` | Update (or create) the org's profile README; creates the `.profile` repo if needed |
| `pin_org_repo` | Pin a repository to the org's overview page, optionally into a group |
| `unpin_org_repo` | Unpin a repository from the org's overview page |
### Runner Tools
| Tool | Description |
|------|-------------|
| `list_runners` | List all runners with status, capabilities, disk space |
| `get_runner` | Get detailed runner info by ID |
| `get_queue_depth` | Get waiting jobs per runner label (capacity insight) |
### Workflow Tools
| Tool | Description |
|------|-------------|
| `list_workflows` | List available workflow files in a repository (includes validation status) |
| `get_workflow_file` | Get the YAML content of a workflow file |
| `validate_workflow` | Validate a workflow YAML file for parse errors (from repo or raw content) |
| `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 |
| `get_job_logs` | Get logs from a specific job (auto-extracts errors for failed jobs) |
| `trigger_workflow` | Manually trigger a workflow_dispatch workflow with inputs |
| `rerun_workflow` | Rerun a completed workflow or specific failed job |
| `cancel_workflow_run` | Cancel a running workflow and all its jobs |
| `approve_workflow` | Approve a workflow run that requires approval (fork PRs) |
### Artifact Tools
| Tool | Description |
|------|-------------|
| `list_artifacts` | List artifacts from a workflow run |
| `get_artifact_download_url` | Get the download URL for a specific artifact |
### Repository & Issue Tools
| Tool | Description |
|------|-------------|
| `list_repos` | List repositories for an owner (org or user) |
| `list_issues` | List issues for a repository with pagination and state filtering |
| `get_issue` | Get issue details including body content and comments |
### Release & Package Tools
| Tool | Description |
|------|-------------|
| `list_releases` | List releases for a repository |
| `get_release` | Get release details with all assets |
| `list_secrets` | List secret names and descriptions (not values) for global, org, and repo scopes |
| `list_packages` | List packages for an owner or globally with version and visibility info |
| `get_package_defaults` | Get preconfigured package defaults (authors, company, copyright, icon, URLs) for an org |
### AI Learning Tools
@@ -81,6 +160,25 @@ Ask Claude things like:
| `get_compatibility_matrix` | See what project types work on which runners |
| `diagnose_job_failure` | Auto-analyze failed job logs and suggest solutions |
### Landing Page Tools
| Tool | Description |
|------|-------------|
| `get_landing_config` | Get the full landing page configuration for a repository |
| `list_landing_templates` | List available landing page templates |
| `enable_landing_page` | Enable or disable a repository's landing page |
| `update_landing_brand` | Update the brand section (name, logo, colors) |
| `update_landing_hero` | Update the hero section (headline, description, CTA) |
| `update_landing_pricing` | Update the pricing section |
| `update_landing_comparison` | Update the feature comparison table |
| `update_landing_features` | Update the features list |
| `update_landing_social_proof` | Update testimonials and social proof |
| `update_landing_seo` | Update SEO metadata (title, description, keywords) |
| `update_landing_theme` | Update the visual theme (colors, fonts, layout) |
| `update_landing_stats` | Update stat counters |
| `update_landing_value_props` | Update value propositions |
| `update_landing_cta` | Update the call-to-action section |
## AI Learning System
GitCaddy includes a collaborative AI learning system. When you encounter and fix CI/CD errors, you can report your solutions to help other AI assistants:

105
main.go
View File

@@ -69,10 +69,11 @@ func main() {
debugLog("Connecting to: %s", giteaURL)
// Read JSON-RPC messages from stdin, forward to Gitea, write responses to stdout
// Supports both raw JSON lines and Content-Length framed messages (Claude Code uses framing)
reader := bufio.NewReader(os.Stdin)
for {
line, err := reader.ReadBytes('\n')
line, err := readMessage(reader)
if err != nil {
if err == io.EOF {
debugLog("EOF received, exiting")
@@ -89,10 +90,22 @@ func main() {
debugLog("Received: %s", string(line))
// JSON-RPC notifications (no "id" field) must NEVER receive a response.
// The MCP spec defines notifications/initialized, notifications/cancelled,
// notifications/progress, etc. — these are fire-and-forget. Even if the
// remote gitcaddy server returns an error for an unknown notification, we
// must suppress it on the way back to the client (Claude Code), otherwise
// the client sees an unexpected response and fails the handshake.
isNotification := isJsonRpcNotification(line)
// Forward to Gitea's MCP endpoint
response, err := forwardToGitea(line)
if err != nil {
debugLog("Forward error: %v", err)
if isNotification {
// Notification — no response allowed, just swallow.
continue
}
// Send error response
errorResp := map[string]interface{}{
"jsonrpc": "2.0",
@@ -109,11 +122,30 @@ func main() {
debugLog("Response: %s", string(response))
// Write response to stdout
fmt.Println(string(response))
if isNotification {
// Notification — never respond, even if the remote sent something.
debugLog("Suppressing response to notification")
continue
}
// Write response to stdout as newline-delimited JSON
writeFramed(response)
}
}
// isJsonRpcNotification reports whether a raw JSON-RPC message is a notification
// (a request without an "id" field). Per JSON-RPC 2.0, servers MUST NOT reply to
// notifications.
func isJsonRpcNotification(raw []byte) bool {
var probe map[string]json.RawMessage
if err := json.Unmarshal(raw, &probe); err != nil {
return false
}
_, hasId := probe["id"]
_, hasMethod := probe["method"]
return hasMethod && !hasId
}
func forwardToGitea(request []byte) ([]byte, error) {
mcpURL := giteaURL + "/api/v2/mcp"
@@ -147,9 +179,74 @@ func forwardToGitea(request []byte) ([]byte, error) {
return body, nil
}
// readMessage reads a JSON-RPC message from stdin.
// Handles both raw JSON lines and Content-Length framed messages.
// Claude Code sends: Content-Length: N\r\n\r\n{json}
func readMessage(reader *bufio.Reader) ([]byte, error) {
// Peek at first bytes to detect format
for {
line, err := reader.ReadBytes('\n')
if err != nil {
return nil, err
}
trimmed := bytes.TrimSpace(line)
if len(trimmed) == 0 {
continue
}
// If it starts with '{', it's a raw JSON line
if trimmed[0] == '{' {
return trimmed, nil
}
// If it starts with "Content-Length:", read the framed message
if bytes.HasPrefix(bytes.ToLower(trimmed), []byte("content-length:")) {
// Parse content length
parts := bytes.SplitN(trimmed, []byte(":"), 2)
if len(parts) != 2 {
continue
}
lengthStr := bytes.TrimSpace(parts[1])
var contentLength int
fmt.Sscanf(string(lengthStr), "%d", &contentLength)
if contentLength <= 0 {
continue
}
// Read until empty line (end of headers)
for {
headerLine, err := reader.ReadBytes('\n')
if err != nil {
return nil, err
}
if len(bytes.TrimSpace(headerLine)) == 0 {
break
}
}
// Read exactly contentLength bytes
body := make([]byte, contentLength)
_, err := io.ReadFull(reader, body)
if err != nil {
return nil, fmt.Errorf("read body: %w", err)
}
return body, nil
}
// Unknown line, skip
debugLog("Skipping unknown line: %s", string(trimmed))
}
}
func writeResponse(resp interface{}) {
data, _ := json.Marshal(resp)
fmt.Println(string(data))
writeFramed(data)
}
func writeFramed(data []byte) {
fmt.Fprintf(os.Stdout, "Content-Length: %d\r\n\r\n%s", len(data), data)
}
func debugLog(format string, args ...interface{}) {