fix: add missing descriptions for various tools

Fixes interoperability with vscode, Perplexity, Mistral and others.
This commit is contained in:
2026-07-19 08:40:39 +02:00
parent bbde7ee110
commit cd7c29271a
12 changed files with 54 additions and 0 deletions
+1
View File
@@ -40,6 +40,7 @@ const (
var ( var (
ListRepoIssuesTool = mcp.NewTool( ListRepoIssuesTool = mcp.NewTool(
ListRepoIssuesToolName, ListRepoIssuesToolName,
mcp.WithDescription("List issues in a repository (or pull requests, via the 'type' filter), filterable by state, labels, milestones, and update time range."),
mcp.WithToolAnnotation(annotation.ReadOnly("List repository issues")), mcp.WithToolAnnotation(annotation.ReadOnly("List repository issues")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
+28
View File
@@ -2,8 +2,36 @@ package operation
import ( import (
"testing" "testing"
"gitea.com/gitea/gitea-mcp/pkg/flag"
) )
// TestAllToolsHaveDescriptions ensures every registered tool sets a non-empty
// Tool.Description. mcp-go only serializes the "description" field of a tool
// when it is non-empty, so an omitted description makes strict MCP clients
// (e.g. mcp-probe) reject the tools/list response with "missing field
// `description`".
func TestAllToolsHaveDescriptions(t *testing.T) {
origRO, origAllow := flag.ReadOnly, flag.AllowedTools
t.Cleanup(func() {
flag.ReadOnly, flag.AllowedTools = origRO, origAllow
})
flag.ReadOnly = false
flag.AllowedTools = nil
var missing []string
for _, d := range domainTools {
for _, st := range d.Tools() {
if st.Tool.Description == "" {
missing = append(missing, st.Tool.Name)
}
}
}
if len(missing) > 0 {
t.Errorf("tools missing a description: %v", missing)
}
}
func TestParseAuthToken(t *testing.T) { func TestParseAuthToken(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
+1
View File
@@ -31,6 +31,7 @@ const (
var ( var (
ListRepoPullRequestsTool = mcp.NewTool( ListRepoPullRequestsTool = mcp.NewTool(
ListRepoPullRequestsToolName, ListRepoPullRequestsToolName,
mcp.WithDescription("List pull requests in a repository, filterable by state and milestone, with configurable sort order (e.g. recently updated, most commented)."),
mcp.WithToolAnnotation(annotation.ReadOnly("List pull requests")), mcp.WithToolAnnotation(annotation.ReadOnly("List pull requests")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
+3
View File
@@ -23,6 +23,7 @@ const (
var ( var (
CreateBranchTool = mcp.NewTool( CreateBranchTool = mcp.NewTool(
CreateBranchToolName, CreateBranchToolName,
mcp.WithDescription("Create a new branch in a repository, optionally from a specific source branch (defaults to the repository's default branch)."),
mcp.WithToolAnnotation(annotation.Write("Create a new branch")), mcp.WithToolAnnotation(annotation.Write("Create a new branch")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -32,6 +33,7 @@ var (
DeleteBranchTool = mcp.NewTool( DeleteBranchTool = mcp.NewTool(
DeleteBranchToolName, DeleteBranchToolName,
mcp.WithDescription("Permanently delete a branch from a repository. This action is destructive and cannot be undone."),
mcp.WithToolAnnotation(annotation.Destructive("Delete a branch")), mcp.WithToolAnnotation(annotation.Destructive("Delete a branch")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -40,6 +42,7 @@ var (
ListBranchesTool = mcp.NewTool( ListBranchesTool = mcp.NewTool(
ListBranchesToolName, ListBranchesToolName,
mcp.WithDescription("List all branches in a repository, paginated."),
mcp.WithToolAnnotation(annotation.ReadOnly("List repository branches")), mcp.WithToolAnnotation(annotation.ReadOnly("List repository branches")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
+2
View File
@@ -22,6 +22,7 @@ const (
var ( var (
ListRepoCommitsTool = mcp.NewTool( ListRepoCommitsTool = mcp.NewTool(
ListRepoCommitsToolName, ListRepoCommitsToolName,
mcp.WithDescription("List commits in a repository, optionally starting from a specific branch or SHA and filtered to commits touching a given file path."),
mcp.WithToolAnnotation(annotation.ReadOnly("List repository commits")), mcp.WithToolAnnotation(annotation.ReadOnly("List repository commits")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -33,6 +34,7 @@ var (
GetCommitTool = mcp.NewTool( GetCommitTool = mcp.NewTool(
GetCommitToolName, GetCommitToolName,
mcp.WithDescription("Get details for a single commit in a repository by its SHA."),
mcp.WithToolAnnotation(annotation.ReadOnly("Get commit details")), mcp.WithToolAnnotation(annotation.ReadOnly("Get commit details")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
+2
View File
@@ -39,6 +39,7 @@ var (
GetDirContentTool = mcp.NewTool( GetDirContentTool = mcp.NewTool(
GetDirToolName, GetDirToolName,
mcp.WithDescription("List the entries (files and subdirectories) in a repository directory at a given ref (branch, tag, or commit SHA)."),
mcp.WithToolAnnotation(annotation.ReadOnly("Get directory contents")), mcp.WithToolAnnotation(annotation.ReadOnly("Get directory contents")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -62,6 +63,7 @@ var (
DeleteFileTool = mcp.NewTool( DeleteFileTool = mcp.NewTool(
DeleteFileToolName, DeleteFileToolName,
mcp.WithDescription("Delete a file from a repository by committing the removal to a branch. Requires the file's current SHA and a commit message."),
mcp.WithToolAnnotation(annotation.Destructive("Delete a file")), mcp.WithToolAnnotation(annotation.Destructive("Delete a file")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
+4
View File
@@ -25,6 +25,7 @@ const (
var ( var (
CreateReleaseTool = mcp.NewTool( CreateReleaseTool = mcp.NewTool(
CreateReleaseToolName, CreateReleaseToolName,
mcp.WithDescription("Create a new release in a repository from a tag, optionally marking it as a draft or pre-release."),
mcp.WithToolAnnotation(annotation.Write("Create a release")), mcp.WithToolAnnotation(annotation.Write("Create a release")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -38,6 +39,7 @@ var (
DeleteReleaseTool = mcp.NewTool( DeleteReleaseTool = mcp.NewTool(
DeleteReleaseToolName, DeleteReleaseToolName,
mcp.WithDescription("Delete a release from a repository by its numeric ID. This action is destructive and cannot be undone."),
mcp.WithToolAnnotation(annotation.Destructive("Delete a release")), mcp.WithToolAnnotation(annotation.Destructive("Delete a release")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -55,6 +57,7 @@ var (
GetLatestReleaseTool = mcp.NewTool( GetLatestReleaseTool = mcp.NewTool(
GetLatestReleaseToolName, GetLatestReleaseToolName,
mcp.WithDescription("Get the most recent published (non-draft) release in a repository."),
mcp.WithToolAnnotation(annotation.ReadOnly("Get latest release")), mcp.WithToolAnnotation(annotation.ReadOnly("Get latest release")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -62,6 +65,7 @@ var (
ListReleasesTool = mcp.NewTool( ListReleasesTool = mcp.NewTool(
ListReleasesToolName, ListReleasesToolName,
mcp.WithDescription("List releases in a repository, optionally filtered to drafts or pre-releases."),
mcp.WithToolAnnotation(annotation.ReadOnly("List releases")), mcp.WithToolAnnotation(annotation.ReadOnly("List releases")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
+4
View File
@@ -28,6 +28,7 @@ const (
var ( var (
CreateRepoTool = mcp.NewTool( CreateRepoTool = mcp.NewTool(
CreateRepoToolName, CreateRepoToolName,
mcp.WithDescription("Create a new Git repository, optionally under an organization (defaults to the authenticated user's account), with options for visibility, template, license, .gitignore, and initial README."),
mcp.WithToolAnnotation(annotation.Write("Create a new repository")), mcp.WithToolAnnotation(annotation.Write("Create a new repository")),
mcp.WithString("name", mcp.Required()), mcp.WithString("name", mcp.Required()),
mcp.WithString("description"), mcp.WithString("description"),
@@ -46,6 +47,7 @@ var (
ForkRepoTool = mcp.NewTool( ForkRepoTool = mcp.NewTool(
ForkRepoToolName, ForkRepoToolName,
mcp.WithDescription("Fork an existing repository into the authenticated user's account or a target organization, optionally under a new name."),
mcp.WithToolAnnotation(annotation.Write("Fork a repository")), mcp.WithToolAnnotation(annotation.Write("Fork a repository")),
mcp.WithString("user", mcp.Required(), mcp.Description("owner of source repo")), mcp.WithString("user", mcp.Required(), mcp.Description("owner of source repo")),
mcp.WithString("repo", mcp.Required()), mcp.WithString("repo", mcp.Required()),
@@ -55,6 +57,7 @@ var (
ListMyReposTool = mcp.NewTool( ListMyReposTool = mcp.NewTool(
ListMyReposToolName, ListMyReposToolName,
mcp.WithDescription("List repositories owned by the authenticated user."),
mcp.WithToolAnnotation(annotation.ReadOnly("List my repositories")), mcp.WithToolAnnotation(annotation.ReadOnly("List my repositories")),
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1), mcp.Min(1)), mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1), mcp.Min(1)),
mcp.WithNumber("per_page", mcp.Description(params.PaginationDesc), mcp.DefaultNumber(30), mcp.Min(1)), mcp.WithNumber("per_page", mcp.Description(params.PaginationDesc), mcp.DefaultNumber(30), mcp.Min(1)),
@@ -62,6 +65,7 @@ var (
ListOrgReposTool = mcp.NewTool( ListOrgReposTool = mcp.NewTool(
ListOrgReposToolName, ListOrgReposToolName,
mcp.WithDescription("List repositories belonging to an organization."),
mcp.WithToolAnnotation(annotation.ReadOnly("List organization repositories")), mcp.WithToolAnnotation(annotation.ReadOnly("List organization repositories")),
mcp.WithString("org", mcp.Required()), mcp.WithString("org", mcp.Required()),
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1), mcp.Min(1)), mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1), mcp.Min(1)),
+4
View File
@@ -24,6 +24,7 @@ const (
var ( var (
CreateTagTool = mcp.NewTool( CreateTagTool = mcp.NewTool(
CreateTagToolName, CreateTagToolName,
mcp.WithDescription("Create a new Git tag in a repository at a target commit, branch, or existing tag, with an optional annotation message."),
mcp.WithToolAnnotation(annotation.Write("Create a tag")), mcp.WithToolAnnotation(annotation.Write("Create a tag")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -34,6 +35,7 @@ var (
DeleteTagTool = mcp.NewTool( DeleteTagTool = mcp.NewTool(
DeleteTagToolName, DeleteTagToolName,
mcp.WithDescription("Permanently delete a tag from a repository. This action is destructive and cannot be undone."),
mcp.WithToolAnnotation(annotation.Destructive("Delete a tag")), mcp.WithToolAnnotation(annotation.Destructive("Delete a tag")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -42,6 +44,7 @@ var (
GetTagTool = mcp.NewTool( GetTagTool = mcp.NewTool(
GetTagToolName, GetTagToolName,
mcp.WithDescription("Get details for a single tag in a repository by name."),
mcp.WithToolAnnotation(annotation.ReadOnly("Get tag details")), mcp.WithToolAnnotation(annotation.ReadOnly("Get tag details")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
@@ -50,6 +53,7 @@ var (
ListTagsTool = mcp.NewTool( ListTagsTool = mcp.NewTool(
ListTagsToolName, ListTagsToolName,
mcp.WithDescription("List all tags in a repository, paginated."),
mcp.WithToolAnnotation(annotation.ReadOnly("List tags")), mcp.WithToolAnnotation(annotation.ReadOnly("List tags")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
+1
View File
@@ -20,6 +20,7 @@ const (
var GetRepoTreeTool = mcp.NewTool( var GetRepoTreeTool = mcp.NewTool(
GetRepoTreeToolName, GetRepoTreeToolName,
mcp.WithDescription("Get the file tree of a repository at a given ref (SHA, branch, or tag), optionally recursively."),
mcp.WithToolAnnotation(annotation.ReadOnly("Get repository file tree")), mcp.WithToolAnnotation(annotation.ReadOnly("Get repository file tree")),
mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)), mcp.WithString("owner", mcp.Required(), mcp.Description(params.OwnerDesc)),
mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)), mcp.WithString("repo", mcp.Required(), mcp.Description(params.RepoDesc)),
+3
View File
@@ -29,6 +29,7 @@ const (
var ( var (
SearchUsersTool = mcp.NewTool( SearchUsersTool = mcp.NewTool(
SearchUsersToolName, SearchUsersToolName,
mcp.WithDescription("Search for Gitea users by username or full name."),
mcp.WithToolAnnotation(annotation.ReadOnly("Search users")), mcp.WithToolAnnotation(annotation.ReadOnly("Search users")),
mcp.WithString("query", mcp.Required()), mcp.WithString("query", mcp.Required()),
mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1)), mcp.WithNumber("page", mcp.Description(params.PageDesc), mcp.DefaultNumber(1)),
@@ -37,6 +38,7 @@ var (
SearOrgTeamsTool = mcp.NewTool( SearOrgTeamsTool = mcp.NewTool(
SearchOrgTeamsToolName, SearchOrgTeamsToolName,
mcp.WithDescription("Search for teams within an organization by name, optionally including each team's description in the results."),
mcp.WithToolAnnotation(annotation.ReadOnly("Search organization teams")), mcp.WithToolAnnotation(annotation.ReadOnly("Search organization teams")),
mcp.WithString("org", mcp.Required()), mcp.WithString("org", mcp.Required()),
mcp.WithString("query", mcp.Required()), mcp.WithString("query", mcp.Required()),
@@ -47,6 +49,7 @@ var (
SearchReposTool = mcp.NewTool( SearchReposTool = mcp.NewTool(
SearchReposToolName, SearchReposToolName,
mcp.WithDescription("Search for repositories by keyword, with filters for topic/description matching, owner, visibility, archived status, and sort order."),
mcp.WithToolAnnotation(annotation.ReadOnly("Search repositories")), mcp.WithToolAnnotation(annotation.ReadOnly("Search repositories")),
mcp.WithString("query", mcp.Required()), mcp.WithString("query", mcp.Required()),
mcp.WithBoolean("keywordIsTopic"), mcp.WithBoolean("keywordIsTopic"),
+1
View File
@@ -21,6 +21,7 @@ const (
var GetGiteaMCPServerVersionTool = mcp.NewTool( var GetGiteaMCPServerVersionTool = mcp.NewTool(
GetGiteaMCPServerVersion, GetGiteaMCPServerVersion,
mcp.WithDescription("Get the running version of the Gitea MCP Server itself (not the Gitea instance it connects to)."),
mcp.WithToolAnnotation(annotation.ReadOnly("Get server version")), mcp.WithToolAnnotation(annotation.ReadOnly("Get server version")),
) )