fix: add missing required attributes to search tool schemas (#135)

## Summary
- Add `mcp.Required()` to `keyword` in `search_repos` and `search_users` tool schemas
- Add `mcp.Required()` to `org` and `query` in `search_org_teams` tool schema
- Add test verifying required fields are set on all search tool schemas
- Fixes MCP clients failing with `keyword is required` because the schema didn't declare the field as required

Closes #115

---
*This PR was authored by Claude.*

Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/135
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <silverwind@noreply.gitea.com>
Co-committed-by: silverwind <silverwind@noreply.gitea.com>
This commit is contained in:
silverwind
2026-02-25 19:00:17 +00:00
committed by Lunny Xiao
parent 723a30ae23
commit 3b9236695c
2 changed files with 46 additions and 4 deletions

View File

@@ -27,7 +27,7 @@ var (
SearchUsersTool = mcp.NewTool( SearchUsersTool = mcp.NewTool(
SearchUsersToolName, SearchUsersToolName,
mcp.WithDescription("search users"), mcp.WithDescription("search users"),
mcp.WithString("keyword", mcp.Description("Keyword")), mcp.WithString("keyword", mcp.Required(), mcp.Description("Keyword")),
mcp.WithNumber("page", mcp.Description("Page"), mcp.DefaultNumber(1)), mcp.WithNumber("page", mcp.Description("Page"), mcp.DefaultNumber(1)),
mcp.WithNumber("pageSize", mcp.Description("PageSize"), mcp.DefaultNumber(100)), mcp.WithNumber("pageSize", mcp.Description("PageSize"), mcp.DefaultNumber(100)),
) )
@@ -35,8 +35,8 @@ var (
SearOrgTeamsTool = mcp.NewTool( SearOrgTeamsTool = mcp.NewTool(
SearchOrgTeamsToolName, SearchOrgTeamsToolName,
mcp.WithDescription("search organization teams"), mcp.WithDescription("search organization teams"),
mcp.WithString("org", mcp.Description("organization name")), mcp.WithString("org", mcp.Required(), mcp.Description("organization name")),
mcp.WithString("query", mcp.Description("search organization teams")), mcp.WithString("query", mcp.Required(), mcp.Description("search organization teams")),
mcp.WithBoolean("includeDescription", mcp.Description("include description?")), mcp.WithBoolean("includeDescription", mcp.Description("include description?")),
mcp.WithNumber("page", mcp.Description("Page"), mcp.DefaultNumber(1)), mcp.WithNumber("page", mcp.Description("Page"), mcp.DefaultNumber(1)),
mcp.WithNumber("pageSize", mcp.Description("PageSize"), mcp.DefaultNumber(100)), mcp.WithNumber("pageSize", mcp.Description("PageSize"), mcp.DefaultNumber(100)),
@@ -45,7 +45,7 @@ var (
SearchReposTool = mcp.NewTool( SearchReposTool = mcp.NewTool(
SearchReposToolName, SearchReposToolName,
mcp.WithDescription("search repos"), mcp.WithDescription("search repos"),
mcp.WithString("keyword", mcp.Description("Keyword")), mcp.WithString("keyword", mcp.Required(), mcp.Description("Keyword")),
mcp.WithBoolean("keywordIsTopic", mcp.Description("KeywordIsTopic")), mcp.WithBoolean("keywordIsTopic", mcp.Description("KeywordIsTopic")),
mcp.WithBoolean("keywordInDescription", mcp.Description("KeywordInDescription")), mcp.WithBoolean("keywordInDescription", mcp.Description("KeywordInDescription")),
mcp.WithNumber("ownerID", mcp.Description("OwnerID")), mcp.WithNumber("ownerID", mcp.Description("OwnerID")),

View File

@@ -0,0 +1,42 @@
package search
import (
"slices"
"testing"
"github.com/mark3labs/mcp-go/mcp"
)
func TestSearchToolsRequiredFields(t *testing.T) {
tests := []struct {
name string
tool mcp.Tool
required []string
}{
{
name: "search_users",
tool: SearchUsersTool,
required: []string{"keyword"},
},
{
name: "search_org_teams",
tool: SearOrgTeamsTool,
required: []string{"org", "query"},
},
{
name: "search_repos",
tool: SearchReposTool,
required: []string{"keyword"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for _, field := range tt.required {
if !slices.Contains(tt.tool.InputSchema.Required, field) {
t.Errorf("tool %s: expected %q to be required, got required=%v", tt.name, field, tt.tool.InputSchema.Required)
}
}
})
}
}