forgejo-mcp/docs/plans/wiki-support.md
Christoph Görn 7b7536a10d
fix: add build tag to wiki package for Nix build compatibility
The wiki package uses forgejo-sdk methods that don't exist in the
released SDK (v2.0.0), causing builds to fail when compiling all
subpackages (go build ./...).

Add //go:build wiki tag to exclude the wiki package from default builds.
This fixes Nix buildGoModule without requiring subPackages workarounds.

Closes #47
2025-12-30 12:04:37 +01:00

10 KiB

Wiki Support Implementation Plan for forgejo-mcp

Summary

Complete wiki support in forgejo-mcp requires wiki API methods in the upstream forgejo-sdk. This plan outlines the upstream contribution strategy and downstream integration.

Current State

forgejo-mcp (operation/wiki/wiki.go) defines 3 wiki tools but uses SDK methods that don't exist:

  • ListWikiPages(), CreateWikiPage(), EditWikiPage() - undefined
  • CreateWikiPageOption, EditWikiPageOption - undefined
  • Build fails with undefined method errors

forgejo-sdk v2.0.0-v2.2.0 has no wiki page API methods.

Target State

forgejo-sdk (upstream)

Add wiki page methods matching the Forgejo/Gitea API:

  • ListWikiPages(owner, repo string, opts ListWikiPagesOptions) ([]*WikiPageMeta, *Response, error)
  • GetWikiPage(owner, repo, pageName string) (*WikiPage, *Response, error)
  • GetWikiPageRevisions(owner, repo, pageName string, opts ListOptions) ([]*WikiCommit, *Response, error)
  • CreateWikiPage(owner, repo string, opt CreateWikiPageOption) (*WikiPage, *Response, error)
  • EditWikiPage(owner, repo, pageName string, opt EditWikiPageOption) (*WikiPage, *Response, error)
  • DeleteWikiPage(owner, repo, pageName string) (*Response, error)

forgejo-mcp (downstream)

Once SDK is updated, complete wiki support with 6 tools:

Tool Description
list_wiki_pages List all wiki pages in a repository
get_wiki_page Get a wiki page content and metadata
get_wiki_revisions Get revisions history of a wiki page
create_wiki_page Create a new wiki page
update_wiki_page Update an existing wiki page
delete_wiki_page Delete a wiki page

Part 1: Upstream Contribution to forgejo-sdk

Repository

Files to Create/Modify

1. forgejo/wiki.go (NEW FILE)

// Copyright 2024 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package forgejo

import (
    "fmt"
    "net/url"
    "time"
)

// WikiPage represents a wiki page
type WikiPage struct {
    Title      string      `json:"title"`
    PageName   string      `json:"page_name"`
    SubURL     string      `json:"sub_url"`
    Content    string      `json:"content_base64"` // base64 encoded
    CommitSHA  string      `json:"commit_sha"`
    Sidebar    string      `json:"sidebar"`
    Footer     string      `json:"footer"`
    LastCommit *WikiCommit `json:"last_commit,omitempty"`
}

// WikiPageMeta represents wiki page metadata (for list operations)
type WikiPageMeta struct {
    Title      string      `json:"title"`
    PageName   string      `json:"page_name"`
    SubURL     string      `json:"sub_url"`
    LastCommit *WikiCommit `json:"last_commit,omitempty"`
}

// WikiCommit represents a wiki commit
type WikiCommit struct {
    SHA       string         `json:"sha"`
    Author    *WikiAuthor    `json:"author"`
    Committer *WikiCommitter `json:"committer"`
    Message   string         `json:"message"`
}

// WikiAuthor represents a wiki commit author
type WikiAuthor struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

// WikiCommitter represents a wiki commit committer
type WikiCommitter struct {
    Name  string `json:"name"`
    Email string `json:"email"`
}

// CreateWikiPageOption options for creating a wiki page
type CreateWikiPageOption struct {
    Title   string `json:"title"`
    Content string `json:"content_base64"` // base64 encoded
    Message string `json:"message,omitempty"`
}

// EditWikiPageOption options for editing a wiki page
type EditWikiPageOption struct {
    Title   string `json:"title,omitempty"`
    Content string `json:"content_base64,omitempty"` // base64 encoded
    Message string `json:"message,omitempty"`
}

// ListWikiPages lists all wiki pages in a repository
func (c *Client) ListWikiPages(owner, repo string, opts ListOptions) ([]*WikiPageMeta, *Response, error) {
    opt := newListOptions(opts)
    pages := make([]*WikiPageMeta, 0)
    resp, err := c.getParsedResponse("GET",
        fmt.Sprintf("/repos/%s/%s/wiki/pages?%s",
            url.PathEscape(owner), url.PathEscape(repo), opt.toQuery()),
        nil, nil, &pages)
    return pages, resp, err
}

// GetWikiPage gets a wiki page
func (c *Client) GetWikiPage(owner, repo, pageName string) (*WikiPage, *Response, error) {
    page := new(WikiPage)
    resp, err := c.getParsedResponse("GET",
        fmt.Sprintf("/repos/%s/%s/wiki/page/%s",
            url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(pageName)),
        nil, nil, page)
    return page, resp, err
}

// GetWikiPageRevisions gets the revision history of a wiki page
func (c *Client) GetWikiPageRevisions(owner, repo, pageName string, opts ListOptions) ([]*WikiCommit, *Response, error) {
    opt := newListOptions(opts)
    commits := make([]*WikiCommit, 0)
    resp, err := c.getParsedResponse("GET",
        fmt.Sprintf("/repos/%s/%s/wiki/revisions/%s?%s",
            url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(pageName), opt.toQuery()),
        nil, nil, &commits)
    return commits, resp, err
}

// CreateWikiPage creates a new wiki page
func (c *Client) CreateWikiPage(owner, repo string, opt CreateWikiPageOption) (*WikiPage, *Response, error) {
    page := new(WikiPage)
    resp, err := c.getParsedResponse("POST",
        fmt.Sprintf("/repos/%s/%s/wiki/new",
            url.PathEscape(owner), url.PathEscape(repo)),
        jsonHeader, opt, page)
    return page, resp, err
}

// EditWikiPage edits a wiki page
func (c *Client) EditWikiPage(owner, repo, pageName string, opt EditWikiPageOption) (*WikiPage, *Response, error) {
    page := new(WikiPage)
    resp, err := c.getParsedResponse("PATCH",
        fmt.Sprintf("/repos/%s/%s/wiki/page/%s",
            url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(pageName)),
        jsonHeader, opt, page)
    return page, resp, err
}

// DeleteWikiPage deletes a wiki page
func (c *Client) DeleteWikiPage(owner, repo, pageName string) (*Response, error) {
    resp, err := c.getResponse("DELETE",
        fmt.Sprintf("/repos/%s/%s/wiki/page/%s",
            url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(pageName)),
        nil, nil)
    return resp, err
}

2. forgejo/wiki_test.go (NEW FILE)

Add tests for all wiki operations following the SDK's testing patterns.

API Reference

Forgejo/Gitea Wiki API endpoints:

Method Endpoint Description
GET /repos/{owner}/{repo}/wiki/pages List all wiki pages
GET /repos/{owner}/{repo}/wiki/page/{pageName} Get a wiki page
GET /repos/{owner}/{repo}/wiki/revisions/{pageName} Get wiki page revisions
POST /repos/{owner}/{repo}/wiki/new Create a wiki page
PATCH /repos/{owner}/{repo}/wiki/page/{pageName} Edit a wiki page
DELETE /repos/{owner}/{repo}/wiki/page/{pageName} Delete a wiki page

Pull Request Checklist

  • Add wiki.go with types and methods
  • Add wiki_test.go with tests
  • Update CHANGELOG if required
  • Ensure CI passes
  • Follow SDK coding conventions

Part 2: Downstream Integration in forgejo-mcp

After forgejo-sdk releases with wiki support:

1. Update go.mod

go get codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2@latest

2. Update operation/wiki/wiki.go

Add 3 new tools:

  • get_wiki_page - Get wiki page content and metadata
  • get_wiki_revisions - Get revision history
  • delete_wiki_page - Delete a wiki page

Fix 3 existing tools to use correct SDK methods.

3. Add to params if needed

// Wiki parameters (already exist)
WikiTitle   = "Wiki page title"
WikiContent = "Wiki page content"
WikiPage    = "Wiki page name"

Timeline Estimate

  1. SDK Contribution: 1-2 weeks (including review cycles)
  2. forgejo-mcp Integration: 1 day (after SDK release)

Feature Request Comment for forgejo-sdk

Copy the following comment to submit to the Codeberg feature request:


Wiki API Support for forgejo-sdk

Summary: Add wiki page management methods to the forgejo-sdk.

Background: The forgejo-mcp project provides an MCP (Model Context Protocol) server for Forgejo integration. We're implementing wiki support but discovered that the forgejo-sdk (v2.0.0-v2.2.0) doesn't include wiki page API methods.

Forgejo/Gitea Wiki API endpoints exist and are documented:

  • GET /repos/{owner}/{repo}/wiki/pages - List wiki pages
  • GET /repos/{owner}/{repo}/wiki/page/{pageName} - Get a wiki page
  • GET /repos/{owner}/{repo}/wiki/revisions/{pageName} - Get page revisions
  • POST /repos/{owner}/{repo}/wiki/new - Create a wiki page
  • PATCH /repos/{owner}/{repo}/wiki/page/{pageName} - Edit a wiki page
  • DELETE /repos/{owner}/{repo}/wiki/page/{pageName} - Delete a wiki page

Requested SDK methods:

// Types
type WikiPage struct { ... }
type WikiPageMeta struct { ... }
type WikiCommit struct { ... }
type CreateWikiPageOption struct { ... }
type EditWikiPageOption struct { ... }

// Methods on Client
func (c *Client) ListWikiPages(owner, repo string, opts ListOptions) ([]*WikiPageMeta, *Response, error)
func (c *Client) GetWikiPage(owner, repo, pageName string) (*WikiPage, *Response, error)
func (c *Client) GetWikiPageRevisions(owner, repo, pageName string, opts ListOptions) ([]*WikiCommit, *Response, error)
func (c *Client) CreateWikiPage(owner, repo string, opt CreateWikiPageOption) (*WikiPage, *Response, error)
func (c *Client) EditWikiPage(owner, repo, pageName string, opt EditWikiPageOption) (*WikiPage, *Response, error)
func (c *Client) DeleteWikiPage(owner, repo, pageName string) (*Response, error)

Reference implementation: The gitea-mcp project implements wiki support using raw HTTP calls. We'd prefer to use proper SDK methods for consistency and maintainability.

Willingness to contribute: We're happy to submit a PR adding these methods if the maintainers are open to it.


Current Workaround

The operation/wiki/wiki.go file uses a Go build tag to exclude it from default builds:

//go:build wiki

This means:

  • Default builds (go build ./...) skip the wiki package entirely
  • Nix builds work without special configuration
  • Wiki-enabled builds require explicit tag: go build -tags wiki ./...

When the upstream forgejo-sdk adds wiki support, remove the build tag and register wiki tools in operation/operation.go.