Skip to main content
Glama
list.go16.1 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 repo 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" ) // SearchRepositoriesParams defines the parameters for the search_repositories tool. // It includes the search query and various options for filtering and sorting. type SearchRepositoriesParams struct { // Q is the search query string. Q string `json:"q"` // Topic indicates whether to search in repository topics. Topic bool `json:"topic,omitempty"` // IncludeDesc indicates whether to include repository descriptions in the search. IncludeDesc bool `json:"include_desc,omitempty"` // Sort specifies the sort order for the results. Sort string `json:"sort,omitempty"` // Order specifies the sort direction (asc or desc). Order string `json:"order,omitempty"` // Page is the page number for pagination. Page int `json:"page,omitempty"` // Limit is the number of repositories to return per page. Limit int `json:"limit,omitempty"` } // SearchRepositoriesImpl implements the read-only MCP tool for searching repositories. // This operation is safe, idempotent, and uses the Forgejo SDK to find repositories // across the entire Forgejo instance based on a query string. type SearchRepositoriesImpl struct { Client *tools.Client } // Definition describes the `search_repositories` tool. It requires a search query `q` // and supports various optional parameters for sorting and pagination. It is // marked as a safe, read-only operation. func (SearchRepositoriesImpl) Definition() *mcp.Tool { return &mcp.Tool{ Name: "search_repositories", Title: "Search Repositories", Description: "Search for repositories across the Forgejo instance. Returns repository information including name, description, and metadata.", Annotations: &mcp.ToolAnnotations{ ReadOnlyHint: true, IdempotentHint: true, }, InputSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "q": { Type: "string", Description: "Search query string", }, "topic": { Type: "boolean", Description: "Whether to search in repository topics (optional, defaults to true)", }, "include_desc": { Type: "boolean", Description: "Whether to include repository descriptions in search (optional, defaults to true)", }, "sort": { Type: "string", Description: "Sort order: 'alpha', 'created', 'updated', 'size', 'id' (optional, defaults to 'alpha')", Enum: []any{"alpha", "created", "updated", "size", "id"}, }, "order": { Type: "string", Description: "Sort direction: 'asc' or 'desc' (optional, defaults to 'asc')", Enum: []any{"asc", "desc"}, }, "page": { Type: "integer", Description: "Page number for pagination (optional, defaults to 1)", Minimum: tools.Float64Ptr(1), }, "limit": { Type: "integer", Description: "Number of repositories per page (optional, defaults to 10, max 50)", Minimum: tools.Float64Ptr(1), Maximum: tools.Float64Ptr(50), }, }, Required: []string{"q"}, }, } } // Handler implements the logic for searching repositories. It calls the Forgejo SDK's // `SearchRepos` function and formats the results into a markdown list. func (impl SearchRepositoriesImpl) Handler() mcp.ToolHandlerFor[SearchRepositoriesParams, any] { return func(ctx context.Context, req *mcp.CallToolRequest, args SearchRepositoriesParams) (*mcp.CallToolResult, any, error) { p := args // Build options for SDK call opt := forgejo.SearchRepoOptions{ Keyword: p.Q, } if p.Topic { opt.KeywordIsTopic = p.Topic } if p.IncludeDesc { opt.KeywordInDescription = p.IncludeDesc } if p.Sort != "" { opt.Sort = p.Sort } if p.Order != "" { opt.Order = p.Order } if p.Page > 0 { opt.Page = p.Page } if p.Limit > 0 { opt.PageSize = p.Limit } // Call SDK repos, _, err := impl.Client.SearchRepos(opt) if err != nil { return nil, nil, fmt.Errorf("failed to search repositories: %w", err) } // Convert to our types and format var content string if len(repos) == 0 { content = "No repositories found matching the search criteria." } else { // Convert repos to our type repoList := make(types.RepositoryList, len(repos)) for i, repo := range repos { repoList[i] = &types.Repository{Repository: repo} } content = fmt.Sprintf("Found %d repositories\n\n%s", len(repos), repoList.ToMarkdown()) } return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{ Text: content, }, }, }, nil, nil } } // ListMyRepositoriesParams defines the parameters for the list_my_repositories tool. // It allows filtering and sorting of the authenticated user's repositories. type ListMyRepositoriesParams struct { // Affiliation filters repositories by the user's role. Affiliation string `json:"affiliation,omitempty"` // Visibility filters repositories by their public or private status. Visibility string `json:"visibility,omitempty"` // Sort specifies the sort order for the results. Sort string `json:"sort,omitempty"` // Direction specifies the sort direction (asc or desc). Direction string `json:"direction,omitempty"` // Page is the page number for pagination. Page int `json:"page,omitempty"` // Limit is the number of repositories to return per page. Limit int `json:"limit,omitempty"` } // ListMyRepositoriesImpl implements the read-only MCP tool for listing the // authenticated user's repositories. This is a safe, idempotent operation that // uses the Forgejo SDK. type ListMyRepositoriesImpl struct { Client *tools.Client } // Definition describes the `list_my_repositories` tool. It supports optional // parameters for filtering and sorting, and is marked as a safe, read-only operation. func (ListMyRepositoriesImpl) Definition() *mcp.Tool { return &mcp.Tool{ Name: "list_my_repositories", Title: "List My Repositories", Description: "List repositories owned by the authenticated user. Returns repository information including name, description, and metadata.", Annotations: &mcp.ToolAnnotations{ ReadOnlyHint: true, IdempotentHint: true, }, InputSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "affiliation": { Type: "string", Description: "Repository affiliation filter: 'owner', 'collaborator', 'organization_member', or 'all' (optional, defaults to 'all')", Enum: []any{"owner", "collaborator", "organization_member", "all"}, }, "visibility": { Type: "string", Description: "Repository visibility filter: 'all', 'public', 'private' (optional, defaults to 'all')", Enum: []any{"all", "public", "private"}, }, "sort": { Type: "string", Description: "Sort order: 'created', 'updated', 'pushed', 'full_name' (optional, defaults to 'full_name')", Enum: []any{"created", "updated", "pushed", "full_name"}, }, "direction": { Type: "string", Description: "Sort direction: 'asc' or 'desc' (optional, defaults to 'asc')", Enum: []any{"asc", "desc"}, }, "page": { Type: "integer", Description: "Page number for pagination (optional, defaults to 1)", Minimum: tools.Float64Ptr(1), }, "limit": { Type: "integer", Description: "Number of repositories per page (optional, defaults to 20, max 50)", Minimum: tools.Float64Ptr(1), Maximum: tools.Float64Ptr(50), }, }, Required: []string{}, }, } } // Handler implements the logic for listing the user's repositories. It calls the // Forgejo SDK's `ListMyRepos` function and formats the results into a markdown list. func (impl ListMyRepositoriesImpl) Handler() mcp.ToolHandlerFor[ListMyRepositoriesParams, any] { return func(ctx context.Context, req *mcp.CallToolRequest, args ListMyRepositoriesParams) (*mcp.CallToolResult, any, error) { p := args // Build options for SDK call opt := forgejo.ListReposOptions{} // Note: ListReposOptions is quite limited in the SDK // Many filtering options are not available if p.Page > 0 { opt.Page = p.Page } if p.Limit > 0 { opt.PageSize = p.Limit } // Call SDK repos, _, err := impl.Client.ListMyRepos(opt) if err != nil { return nil, nil, fmt.Errorf("failed to list my repositories: %w", err) } // Convert to our types and format var content string if len(repos) == 0 { content = "No repositories found for the authenticated user." } else { // Convert repos to our type repoList := make(types.RepositoryList, len(repos)) for i, repo := range repos { repoList[i] = &types.Repository{Repository: repo} } content = fmt.Sprintf("Found %d repositories\n\n%s", len(repos), repoList.ToMarkdown()) } return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{ Text: content, }, }, }, nil, nil } } // ListOrgRepositoriesParams defines the parameters for the list_org_repositories tool. // It specifies the organization and allows for filtering and sorting. type ListOrgRepositoriesParams struct { // Org is the name of the organization. Org string `json:"org"` // Type filters repositories by their type (e.g., forks, sources). Type string `json:"type,omitempty"` // Sort specifies the sort order for the results. Sort string `json:"sort,omitempty"` // Direction specifies the sort direction (asc or desc). Direction string `json:"direction,omitempty"` // Page is the page number for pagination. Page int `json:"page,omitempty"` // Limit is the number of repositories to return per page. Limit int `json:"limit,omitempty"` } // ListOrgRepositoriesImpl implements the read-only MCP tool for listing an // organization's repositories. This is a safe, idempotent operation that uses // the Forgejo SDK. type ListOrgRepositoriesImpl struct { Client *tools.Client } // Definition describes the `list_org_repositories` tool. It requires an `org` name // and supports optional parameters for filtering and sorting. It is marked as a // safe, read-only operation. func (ListOrgRepositoriesImpl) Definition() *mcp.Tool { return &mcp.Tool{ Name: "list_org_repositories", Title: "List Organization Repositories", Description: "List repositories owned by a specific organization. Returns repository information including name, description, and metadata.", Annotations: &mcp.ToolAnnotations{ ReadOnlyHint: true, IdempotentHint: true, }, InputSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "org": { Type: "string", Description: "Organization name", }, "type": { Type: "string", Description: "Repository type filter: 'all', 'public', 'private', 'forks', 'sources', 'member' (optional, defaults to 'all')", Enum: []any{"all", "public", "private", "forks", "sources", "member"}, }, "sort": { Type: "string", Description: "Sort order: 'created', 'updated', 'pushed', 'full_name' (optional, defaults to 'created')", Enum: []any{"created", "updated", "pushed", "full_name"}, }, "direction": { Type: "string", Description: "Sort direction: 'asc' or 'desc' (optional, defaults to 'desc')", Enum: []any{"asc", "desc"}, }, "page": { Type: "integer", Description: "Page number for pagination (optional, defaults to 1)", Minimum: tools.Float64Ptr(1), }, "limit": { Type: "integer", Description: "Number of repositories per page (optional, defaults to 20, max 50)", Minimum: tools.Float64Ptr(1), Maximum: tools.Float64Ptr(50), }, }, Required: []string{"org"}, }, } } // Handler implements the logic for listing organization repositories. It calls the // Forgejo SDK's `ListOrgRepos` function and formats the results into a markdown list. func (impl ListOrgRepositoriesImpl) Handler() mcp.ToolHandlerFor[ListOrgRepositoriesParams, any] { return func(ctx context.Context, req *mcp.CallToolRequest, args ListOrgRepositoriesParams) (*mcp.CallToolResult, any, error) { p := args // Build options for SDK call opt := forgejo.ListOrgReposOptions{} // Note: ListOrgReposOptions is quite limited in the SDK // Type filtering is not available if p.Page > 0 { opt.Page = p.Page } if p.Limit > 0 { opt.PageSize = p.Limit } // Call SDK repos, _, err := impl.Client.ListOrgRepos(p.Org, opt) if err != nil { return nil, nil, fmt.Errorf("failed to list organization repositories: %w", err) } // Convert to our types and format var content string if len(repos) == 0 { content = fmt.Sprintf("No repositories found for organization '%s'.", p.Org) } else { // Convert repos to our type repoList := make(types.RepositoryList, len(repos)) for i, repo := range repos { repoList[i] = &types.Repository{Repository: repo} } content = fmt.Sprintf("Found %d repositories for organization '%s'\n\n%s", len(repos), p.Org, repoList.ToMarkdown()) } return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{ Text: content, }, }, }, nil, nil } } // GetRepositoryParams defines the parameters for the get_repository tool. // It specifies the owner and repository name to retrieve. type GetRepositoryParams 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"` } // GetRepositoryImpl implements the read-only MCP tool for fetching detailed // information about a single repository. This is a safe, idempotent operation // that uses the Forgejo SDK. type GetRepositoryImpl struct { Client *tools.Client } // Definition describes the `get_repository` tool. It requires `owner` and `repo` // as parameters and is marked as a safe, read-only operation. func (GetRepositoryImpl) Definition() *mcp.Tool { return &mcp.Tool{ Name: "get_repository", Title: "Get Repository Information", Description: "Get detailed information about a specific repository, including description, stats, permissions, and metadata.", 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", }, }, Required: []string{"owner", "repo"}, }, } } // Handler implements the logic for fetching repository details. It calls the // Forgejo SDK's `GetRepo` function and formats the full repository object into // a detailed markdown view. func (impl GetRepositoryImpl) Handler() mcp.ToolHandlerFor[GetRepositoryParams, any] { return func(ctx context.Context, req *mcp.CallToolRequest, args GetRepositoryParams) (*mcp.CallToolResult, any, error) { p := args // Call SDK repo, _, err := impl.Client.GetRepo(p.Owner, p.Repo) if err != nil { return nil, nil, fmt.Errorf("failed to get repository: %w", err) } // Convert to our type and format repoWrapper := &types.Repository{Repository: repo} return &mcp.CallToolResult{ Content: []mcp.Content{ &mcp.TextContent{ Text: repoWrapper.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