Skip to main content
Glama
attach.go9.64 kB
// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. // // Copyright © 2025 Ronmi Ren <ronmi.ren@gmail.com> package release import ( "context" "fmt" "codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2" "github.com/google/jsonschema-go/jsonschema" "github.com/modelcontextprotocol/go-sdk/mcp" "github.com/raohwork/forgejo-mcp/tools" "github.com/raohwork/forgejo-mcp/types" ) // ListReleaseAttachmentsParams defines the parameters for the list_release_attachments tool. // It specifies the release to list attachments from. type ListReleaseAttachmentsParams struct { // Owner is the username or organization name that owns the repository. Owner string `json:"owner"` // Repo is the name of the repository. Repo string `json:"repo"` // ReleaseID is the unique identifier of the release. ReleaseID int `json:"release_id"` } // ListReleaseAttachmentsImpl implements the read-only MCP tool for listing release attachments. // This is a safe, idempotent operation that uses the Forgejo SDK to fetch a list // of all attachments for a specific release. type ListReleaseAttachmentsImpl struct { Client *tools.Client } // Definition describes the `list_release_attachments` tool. It requires `owner`, // `repo`, and `release_id`. It is marked as a safe, read-only operation. func (ListReleaseAttachmentsImpl) Definition() *mcp.Tool { return &mcp.Tool{ Name: "list_release_attachments", Title: "List Release Attachments", Description: "List all attachments for a specific release.", Annotations: &mcp.ToolAnnotations{ ReadOnlyHint: true, IdempotentHint: true, }, InputSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "owner": { Type: "string", Description: "Repository owner (username or organization name)", }, "repo": { Type: "string", Description: "Repository name", }, "release_id": { Type: "integer", Description: "Release ID", }, }, Required: []string{"owner", "repo", "release_id"}, }, } } // Handler implements the logic for listing release attachments. It calls the Forgejo // SDK's `ListReleaseAttachments` function and formats the results into a markdown list. func (impl ListReleaseAttachmentsImpl) Handler() mcp.ToolHandlerFor[ListReleaseAttachmentsParams, any] { return func(ctx context.Context, req *mcp.CallToolRequest, args ListReleaseAttachmentsParams) (*mcp.CallToolResult, any, error) { p := args // Call SDK attachments, _, err := impl.Client.ListReleaseAttachments(p.Owner, p.Repo, int64(p.ReleaseID), forgejo.ListReleaseAttachmentsOptions{}) if err != nil { return nil, nil, fmt.Errorf("failed to list release attachments: %w", err) } // Convert to our types and format var content string if len(attachments) == 0 { content = "No attachments found for this release." } else { // Convert attachments to our type attachmentList := make(types.AttachmentList, len(attachments)) for i, attachment := range attachments { attachmentList[i] = &types.Attachment{Attachment: attachment} } content = fmt.Sprintf("Found %d attachments\n\n%s", len(attachments), attachmentList.ToMarkdown()) } return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{ Text: content, }, }, }, nil, nil } } // EditReleaseAttachmentParams defines the parameters for editing a release attachment. // It specifies the attachment to edit and its new name. type EditReleaseAttachmentParams struct { // Owner is the username or organization name that owns the repository. Owner string `json:"owner"` // Repo is the name of the repository. Repo string `json:"repo"` // ReleaseID is the unique identifier of the release containing the attachment. ReleaseID int `json:"release_id"` // AttachmentID is the unique identifier of the attachment to edit. AttachmentID int `json:"attachment_id"` // Name is the new display name for the attachment. Name string `json:"name"` } // EditReleaseAttachmentImpl implements the MCP tool for editing a release attachment. // This is an idempotent operation that renames an existing attachment using the // Forgejo SDK. type EditReleaseAttachmentImpl struct { Client *tools.Client } // Definition describes the `edit_release_attachment` tool. It requires `release_id`, // `attachment_id`, and a new `name`. It is marked as idempotent. func (EditReleaseAttachmentImpl) Definition() *mcp.Tool { return &mcp.Tool{ Name: "edit_release_attachment", Title: "Edit Release Attachment", Description: "Edit a release attachment's metadata (like display name).", Annotations: &mcp.ToolAnnotations{ ReadOnlyHint: false, DestructiveHint: tools.BoolPtr(false), IdempotentHint: true, }, InputSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "owner": { Type: "string", Description: "Repository owner (username or organization name)", }, "repo": { Type: "string", Description: "Repository name", }, "release_id": { Type: "integer", Description: "Release ID", }, "attachment_id": { Type: "integer", Description: "Attachment ID to edit", }, "name": { Type: "string", Description: "New display name for the attachment", }, }, Required: []string{"owner", "repo", "release_id", "attachment_id", "name"}, }, } } // Handler implements the logic for editing a release attachment. It calls the Forgejo // SDK's `EditReleaseAttachment` function. It will return an error if the attachment // ID is not found. func (impl EditReleaseAttachmentImpl) Handler() mcp.ToolHandlerFor[EditReleaseAttachmentParams, any] { return func(ctx context.Context, req *mcp.CallToolRequest, args EditReleaseAttachmentParams) (*mcp.CallToolResult, any, error) { p := args // Build options for SDK call opt := forgejo.EditAttachmentOptions{ Name: p.Name, } // Call SDK attachment, _, err := impl.Client.EditReleaseAttachment(p.Owner, p.Repo, int64(p.ReleaseID), int64(p.AttachmentID), opt) if err != nil { return nil, nil, fmt.Errorf("failed to edit release attachment: %w", err) } // Convert to our type and format attachmentWrapper := &types.Attachment{Attachment: attachment} return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{ Text: attachmentWrapper.ToMarkdown(), }, }, }, nil, nil } } // DeleteReleaseAttachmentParams defines the parameters for deleting a release attachment. // It specifies the attachment to be deleted by its ID. type DeleteReleaseAttachmentParams struct { // Owner is the username or organization name that owns the repository. Owner string `json:"owner"` // Repo is the name of the repository. Repo string `json:"repo"` // ReleaseID is the unique identifier of the release containing the attachment. ReleaseID int `json:"release_id"` // AttachmentID is the unique identifier of the attachment to delete. AttachmentID int `json:"attachment_id"` } // DeleteReleaseAttachmentImpl implements the destructive MCP tool for deleting a release attachment. // This is an idempotent but irreversible operation that removes an attachment from a // release using the Forgejo SDK. type DeleteReleaseAttachmentImpl struct { Client *tools.Client } // Definition describes the `delete_release_attachment` tool. It requires `release_id` // and `attachment_id`. It is marked as a destructive operation to ensure clients // can warn the user before execution. func (DeleteReleaseAttachmentImpl) Definition() *mcp.Tool { return &mcp.Tool{ Name: "delete_release_attachment", Title: "Delete Release Attachment", Description: "Delete an attachment from a release.", Annotations: &mcp.ToolAnnotations{ ReadOnlyHint: false, DestructiveHint: tools.BoolPtr(true), IdempotentHint: true, }, InputSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "owner": { Type: "string", Description: "Repository owner (username or organization name)", }, "repo": { Type: "string", Description: "Repository name", }, "release_id": { Type: "integer", Description: "Release ID", }, "attachment_id": { Type: "integer", Description: "Attachment ID to delete", }, }, Required: []string{"owner", "repo", "release_id", "attachment_id"}, }, } } // Handler implements the logic for deleting a release attachment. It calls the Forgejo // SDK's `DeleteReleaseAttachment` function. On success, it returns a simple text // confirmation. It will return an error if the attachment does not exist. func (impl DeleteReleaseAttachmentImpl) Handler() mcp.ToolHandlerFor[DeleteReleaseAttachmentParams, any] { return func(ctx context.Context, req *mcp.CallToolRequest, args DeleteReleaseAttachmentParams) (*mcp.CallToolResult, any, error) { p := args // Call SDK _, err := impl.Client.DeleteReleaseAttachment(p.Owner, p.Repo, int64(p.ReleaseID), int64(p.AttachmentID)) if err != nil { return nil, nil, fmt.Errorf("failed to delete release attachment: %w", err) } // Return success message emptyResponse := types.EmptyResponse{} return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{ Text: emptyResponse.ToMarkdown(), }, }, }, nil, nil } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/raohwork/forgejo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server