4e8eb81dac
* PoC full flow (hello world example) * add avatar resource domain * add postmessage logic and richer UI * add create issue ui * update ui for issue creatioon * fix * ignore banner * update docs after rebase * update toolsnap for get_me * new UI changes * update docs * update workflows that need ui build * add UI diff * fix build ui step for windows runners to use git bash * fix UI diff * refactor issue creation UI * add AvatarWithFallback component and update UserCard to use it; enhance CreateIssueApp to manage existing issue data * fix formatting of button labels * add create pull request functionality with UI support and insiders * update docs * add test for insiders mode handling in ServerTool schema * remove `show_ui` param for now * make insiders mode metadata stripping generic * remove ui diff * fix CI * remove redundant mention of old app name * add node types to fix ide issues for ts code * remove unused TriangleDownIcon import * update @primer/behaviors and electron-to-chromium versions in package-lock.json * add check to ensure base and head are not the same when creating a new PR * remove old show_ui * fix gitignore for dist so builds dont break * add tests for insiders mode handling and metadata stripping in ServerTool * remove unused state and components from CreatePRApp * fix ui build * update docker build to fix npm issue * remove reference to show_ui * allow insiders to work for non-ui features * formalise insiders inventory support * update docs * fix overflow issues and replace pull request dropdown with matching UI from dotcom * fix createpullrequest test * consolidate fetching tools under `ui_get` tool to remove toolset deps * fix issue data prefill in issue_write form * fix link component when updating issue * fix avatar URL * fix broken issue update logic * remove dbg * fix for new GetFlags * revert to original required fields for create_pull_request * fix for UI form submission * Simplify MCP App UIs for basic branch Remove advanced features to be kept in mcp-ui-apps-advanced: - Strip labels, assignees, milestones, issue types, repo picker from issue-write - Strip repo picker, branch selectors from pr-write - Delete ui_get tool (ui_tools.go, ui_tools_test.go, ui_get.snap) - Remove UIGet registration from tools.go Basic forms retain: title, body, submit with _ui_submitted, draft/regular split button (PR), MarkdownEditor, and SuccessView. * Fix header spacing in issue-write and pr-write UIs Add proper spacing between icon, title text, and repo name in the header bar for both issue-write and create-pull-request forms. * fix UI spacing * Revert "Simplify MCP App UIs for basic branch" This reverts commit 24174b91e222e45b47913ff6b760db809f48660b. * Undo dependency downgrades in ui/package-lock.json * Update ui/src/apps/pr-write/App.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update ui/src/apps/issue-write/App.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Implement pagination for uiGetBranches (#2012) * Initial plan * Implement pagination for uiGetBranches function Co-authored-by: mattdholloway <918573+mattdholloway@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mattdholloway <918573+mattdholloway@users.noreply.github.com> * update to new insiders feature flag func * ensure transient state is reset on successive tool calls * Mark ui_get as app-only visibility ui_get backs only the MCP App views and has no business in the agent's tool list. Per the MCP Apps 2026-01-26 spec, omitting _meta.ui.visibility defaults to ["model","app"], which exposes the tool to the model. Declare visibility ["app"] so the host hides it from tools/list while the views can still invoke it via tools/call. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update ui_get toolsnap for app-only visibility Regenerated via UPDATE_TOOLSNAPS to capture the new _meta.ui.visibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Assert ui_get declares app-only visibility Locks in the _meta.ui.visibility ["app"] contract so a future edit can't silently re-expose the UI data tool to the model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add ui_get to insiders feature docs Regenerated docs/feature-flags.md and docs/insiders-features.md to include the ui_get tool entry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address ui_get review feedback - Paginate the labels GraphQL query (cursor-based) so repos with more than 100 labels return a complete list instead of silently truncating. - Emit an empty due_on for milestones without a due date instead of formatting the zero time as "0001-01-01". - Use NewGitHubAPIErrorResponse in uiGetIssueTypes to preserve GitHub response context, matching the other REST-backed methods. - Extend tests to cover the labels (GraphQL), milestones (including the no-due-date case) and issue_types methods, plus the issue_types error path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix repo reset and stale base-branch in MCP App views - Re-initialize selectedRepo from toolInput inside the reset-on-invocation effect instead of a separate effect. The two effects both depended on toolInput and ran in declaration order, so the reset wiped the just- initialized repo and the picker never reflected the invocation's owner/repo. - Set the default base branch with a functional update in pr-write so a base prefilled from toolInput.base (or chosen by the user) isn't overwritten by a stale baseBranch value captured before the branches request resolved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fix issue-write repo owner mapping and clear stale UI state on reset - issue-write: derive owner/name from full_name since search_repositories minimal output omits the owner object (mirrors pr-write) - pr-write/issue-write: clear available branch/label/assignee/milestone/type lists and filters in the toolInput reset effect so prefill effects can't match against the previous repo's stale data Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Merge remote-tracking branch 'origin/main' into mcp-ui-apps-advanced * feat: add pull request editing functionality with reviewers support * feat: implement interactive form handling for issue and pull request creation and updates * Close response body per page in ui_get pagination loops Avoids leaking HTTP connections when paging through assignees, milestones, branches, collaborators, and teams. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Cache pr-edit.html in build-ui action The build-ui cache only saved get-me/issue-write/pr-write HTML, so once a cache entry was stored it restored an incomplete ui_dist on later runs and skipped the rebuild, leaving pr-edit.html absent and panicking the tests. Add pr-edit.html to the cached paths and bump the cache key to v2 to evict the incomplete entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: tommaso-moro <tommaso-moro@github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
493 lines
14 KiB
Go
493 lines
14 KiB
Go
package github
|
|
|
|
import (
|
|
"context"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/github/github-mcp-server/pkg/inventory"
|
|
"github.com/github/github-mcp-server/pkg/translations"
|
|
"github.com/google/go-github/v87/github"
|
|
"github.com/shurcooL/githubv4"
|
|
)
|
|
|
|
type GetClientFn func(context.Context) (*github.Client, error)
|
|
type GetGQLClientFn func(context.Context) (*githubv4.Client, error)
|
|
|
|
// Toolset metadata constants - these define all available toolsets and their descriptions.
|
|
// Tools use these constants to declare which toolset they belong to.
|
|
// Icons are Octicon names from https://primer.style/foundations/icons
|
|
var (
|
|
ToolsetMetadataAll = inventory.ToolsetMetadata{
|
|
ID: "all",
|
|
Description: "Special toolset that enables all available toolsets",
|
|
Icon: "apps",
|
|
}
|
|
ToolsetMetadataDefault = inventory.ToolsetMetadata{
|
|
ID: "default",
|
|
Description: "Special toolset that enables the default toolset configuration. When no toolsets are specified, this is the set that is enabled",
|
|
Icon: "check-circle",
|
|
}
|
|
ToolsetMetadataContext = inventory.ToolsetMetadata{
|
|
ID: "context",
|
|
Description: "Tools that provide context about the current user and GitHub context you are operating in",
|
|
Default: true,
|
|
Icon: "person",
|
|
InstructionsFunc: generateContextToolsetInstructions,
|
|
}
|
|
ToolsetMetadataRepos = inventory.ToolsetMetadata{
|
|
ID: "repos",
|
|
Description: "GitHub Repository related tools",
|
|
Default: true,
|
|
Icon: "repo",
|
|
}
|
|
ToolsetMetadataGit = inventory.ToolsetMetadata{
|
|
ID: "git",
|
|
Description: "GitHub Git API related tools for low-level Git operations",
|
|
Icon: "git-branch",
|
|
}
|
|
ToolsetMetadataIssues = inventory.ToolsetMetadata{
|
|
ID: "issues",
|
|
Description: "GitHub Issues related tools",
|
|
Default: true,
|
|
Icon: "issue-opened",
|
|
InstructionsFunc: generateIssuesToolsetInstructions,
|
|
}
|
|
ToolsetMetadataPullRequests = inventory.ToolsetMetadata{
|
|
ID: "pull_requests",
|
|
Description: "GitHub Pull Request related tools",
|
|
Default: true,
|
|
Icon: "git-pull-request",
|
|
InstructionsFunc: generatePullRequestsToolsetInstructions,
|
|
}
|
|
ToolsetMetadataUsers = inventory.ToolsetMetadata{
|
|
ID: "users",
|
|
Description: "GitHub User related tools",
|
|
Default: true,
|
|
Icon: "people",
|
|
}
|
|
ToolsetMetadataOrgs = inventory.ToolsetMetadata{
|
|
ID: "orgs",
|
|
Description: "GitHub Organization related tools",
|
|
Icon: "organization",
|
|
}
|
|
ToolsetMetadataActions = inventory.ToolsetMetadata{
|
|
ID: "actions",
|
|
Description: "GitHub Actions workflows and CI/CD operations",
|
|
Icon: "workflow",
|
|
}
|
|
ToolsetMetadataCodeSecurity = inventory.ToolsetMetadata{
|
|
ID: "code_security",
|
|
Description: "Code security related tools, such as GitHub Code Scanning",
|
|
Icon: "codescan",
|
|
}
|
|
ToolsetMetadataSecretProtection = inventory.ToolsetMetadata{
|
|
ID: "secret_protection",
|
|
Description: "Secret protection related tools, such as GitHub Secret Scanning",
|
|
Icon: "shield-lock",
|
|
}
|
|
ToolsetMetadataDependabot = inventory.ToolsetMetadata{
|
|
ID: "dependabot",
|
|
Description: "Dependabot tools",
|
|
Icon: "dependabot",
|
|
}
|
|
ToolsetMetadataNotifications = inventory.ToolsetMetadata{
|
|
ID: "notifications",
|
|
Description: "GitHub Notifications related tools",
|
|
Icon: "bell",
|
|
}
|
|
ToolsetMetadataDiscussions = inventory.ToolsetMetadata{
|
|
ID: "discussions",
|
|
Description: "GitHub Discussions related tools",
|
|
Icon: "comment-discussion",
|
|
InstructionsFunc: generateDiscussionsToolsetInstructions,
|
|
}
|
|
ToolsetMetadataGists = inventory.ToolsetMetadata{
|
|
ID: "gists",
|
|
Description: "GitHub Gist related tools",
|
|
Icon: "logo-gist",
|
|
}
|
|
ToolsetMetadataSecurityAdvisories = inventory.ToolsetMetadata{
|
|
ID: "security_advisories",
|
|
Description: "Security advisories related tools",
|
|
Icon: "shield",
|
|
}
|
|
ToolsetMetadataProjects = inventory.ToolsetMetadata{
|
|
ID: "projects",
|
|
Description: "GitHub Projects related tools",
|
|
Icon: "project",
|
|
InstructionsFunc: generateProjectsToolsetInstructions,
|
|
}
|
|
ToolsetMetadataStargazers = inventory.ToolsetMetadata{
|
|
ID: "stargazers",
|
|
Description: "GitHub Stargazers related tools",
|
|
Icon: "star",
|
|
}
|
|
ToolsetLabels = inventory.ToolsetMetadata{
|
|
ID: "labels",
|
|
Description: "GitHub Labels related tools",
|
|
Icon: "tag",
|
|
}
|
|
|
|
ToolsetMetadataCopilot = inventory.ToolsetMetadata{
|
|
ID: "copilot",
|
|
Description: "Copilot related tools",
|
|
Default: true,
|
|
Icon: "copilot",
|
|
}
|
|
|
|
// Feature flag names for granular tool variants.
|
|
// When active, consolidated tools are replaced by single-purpose granular tools.
|
|
FeatureFlagIssuesGranular = "issues_granular"
|
|
FeatureFlagPullRequestsGranular = "pull_requests_granular"
|
|
)
|
|
|
|
// HeaderAllowedFeatureFlags returns the feature flags that clients may enable via
|
|
// the X-MCP-Features header. It delegates to AllowedFeatureFlags as the single
|
|
// source of truth.
|
|
func HeaderAllowedFeatureFlags() []string {
|
|
return slices.Clone(AllowedFeatureFlags)
|
|
}
|
|
|
|
var (
|
|
// Remote-only toolsets - these are only available in the remote MCP server
|
|
// but are documented here for consistency and to enable automated documentation.
|
|
ToolsetMetadataCopilotSpaces = inventory.ToolsetMetadata{
|
|
ID: "copilot_spaces",
|
|
Description: "Copilot Spaces tools",
|
|
Icon: "copilot",
|
|
}
|
|
ToolsetMetadataSupportSearch = inventory.ToolsetMetadata{
|
|
ID: "github_support_docs_search",
|
|
Description: "Retrieve documentation to answer GitHub product and support questions. Topics include: GitHub Actions Workflows, Authentication, ...",
|
|
Icon: "book",
|
|
}
|
|
)
|
|
|
|
// AllTools returns all tools with their embedded toolset metadata.
|
|
// Tool functions return ServerTool directly with toolset info.
|
|
func AllTools(t translations.TranslationHelperFunc) []inventory.ServerTool {
|
|
return withCSVOutput([]inventory.ServerTool{
|
|
// Context tools
|
|
GetMe(t),
|
|
GetTeams(t),
|
|
GetTeamMembers(t),
|
|
|
|
// Repository tools
|
|
SearchRepositories(t),
|
|
GetFileContents(t),
|
|
ListCommits(t),
|
|
SearchCode(t),
|
|
SearchCommits(t),
|
|
GetCommit(t),
|
|
GetFileBlame(t),
|
|
ListBranches(t),
|
|
ListTags(t),
|
|
GetTag(t),
|
|
ListReleases(t),
|
|
GetLatestRelease(t),
|
|
GetReleaseByTag(t),
|
|
CreateOrUpdateFile(t),
|
|
CreateRepository(t),
|
|
ForkRepository(t),
|
|
CreateBranch(t),
|
|
PushFiles(t),
|
|
DeleteFile(t),
|
|
ListStarredRepositories(t),
|
|
StarRepository(t),
|
|
UnstarRepository(t),
|
|
ListRepositoryCollaborators(t),
|
|
|
|
// Git tools
|
|
GetRepositoryTree(t),
|
|
|
|
// Issue tools
|
|
IssueRead(t),
|
|
SearchIssues(t),
|
|
ListIssues(t),
|
|
LegacyListIssues(t),
|
|
ListIssueTypes(t),
|
|
ListIssueFields(t),
|
|
IssueWrite(t),
|
|
LegacyIssueWrite(t),
|
|
AddIssueComment(t),
|
|
SubIssueWrite(t),
|
|
|
|
// User tools
|
|
SearchUsers(t),
|
|
|
|
// Organization tools
|
|
SearchOrgs(t),
|
|
|
|
// Pull request tools
|
|
PullRequestRead(t),
|
|
ListPullRequests(t),
|
|
SearchPullRequests(t),
|
|
MergePullRequest(t),
|
|
UpdatePullRequestBranch(t),
|
|
CreatePullRequest(t),
|
|
UpdatePullRequest(t),
|
|
PullRequestReviewWrite(t),
|
|
AddCommentToPendingReview(t),
|
|
AddReplyToPullRequestComment(t),
|
|
|
|
// Copilot tools
|
|
AssignCopilotToIssue(t),
|
|
RequestCopilotReview(t),
|
|
|
|
// Code security tools
|
|
GetCodeScanningAlert(t),
|
|
ListCodeScanningAlerts(t),
|
|
|
|
// Secret protection tools
|
|
GetSecretScanningAlert(t),
|
|
ListSecretScanningAlerts(t),
|
|
|
|
// Dependabot tools
|
|
GetDependabotAlert(t),
|
|
ListDependabotAlerts(t),
|
|
|
|
// Notification tools
|
|
ListNotifications(t),
|
|
GetNotificationDetails(t),
|
|
DismissNotification(t),
|
|
MarkAllNotificationsRead(t),
|
|
ManageNotificationSubscription(t),
|
|
ManageRepositoryNotificationSubscription(t),
|
|
|
|
// Discussion tools
|
|
ListDiscussions(t),
|
|
GetDiscussion(t),
|
|
GetDiscussionComments(t),
|
|
DiscussionCommentWrite(t),
|
|
ListDiscussionCategories(t),
|
|
|
|
// Actions tools
|
|
ActionsList(t),
|
|
ActionsGet(t),
|
|
ActionsRunTrigger(t),
|
|
ActionsGetJobLogs(t),
|
|
|
|
// Security advisories tools
|
|
ListGlobalSecurityAdvisories(t),
|
|
GetGlobalSecurityAdvisory(t),
|
|
ListRepositorySecurityAdvisories(t),
|
|
ListOrgRepositorySecurityAdvisories(t),
|
|
|
|
// Gist tools
|
|
ListGists(t),
|
|
GetGist(t),
|
|
CreateGist(t),
|
|
UpdateGist(t),
|
|
|
|
// Project tools
|
|
ProjectsList(t),
|
|
ProjectsGet(t),
|
|
ProjectsWrite(t),
|
|
|
|
// Label tools
|
|
GetLabel(t),
|
|
GetLabelForLabelsToolset(t),
|
|
ListLabels(t),
|
|
LabelWrite(t),
|
|
|
|
// UI tools (insiders only)
|
|
UIGet(t),
|
|
|
|
// Granular issue tools (feature-flagged, replace consolidated issue_write/sub_issue_write)
|
|
GranularCreateIssue(t),
|
|
GranularUpdateIssueTitle(t),
|
|
GranularUpdateIssueBody(t),
|
|
GranularUpdateIssueAssignees(t),
|
|
GranularUpdateIssueLabels(t),
|
|
GranularUpdateIssueMilestone(t),
|
|
GranularUpdateIssueType(t),
|
|
GranularUpdateIssueState(t),
|
|
GranularAddSubIssue(t),
|
|
GranularRemoveSubIssue(t),
|
|
GranularReprioritizeSubIssue(t),
|
|
GranularSetIssueFields(t),
|
|
|
|
// Granular pull request tools (feature-flagged, replace consolidated update_pull_request/pull_request_review_write)
|
|
GranularUpdatePullRequestTitle(t),
|
|
GranularUpdatePullRequestBody(t),
|
|
GranularUpdatePullRequestState(t),
|
|
GranularUpdatePullRequestDraftState(t),
|
|
GranularRequestPullRequestReviewers(t),
|
|
GranularCreatePullRequestReview(t),
|
|
GranularSubmitPendingPullRequestReview(t),
|
|
GranularDeletePendingPullRequestReview(t),
|
|
GranularAddPullRequestReviewComment(t),
|
|
GranularResolveReviewThread(t),
|
|
GranularUnresolveReviewThread(t),
|
|
})
|
|
}
|
|
|
|
// ToBoolPtr converts a bool to a *bool pointer.
|
|
func ToBoolPtr(b bool) *bool {
|
|
return &b
|
|
}
|
|
|
|
// ToStringPtr converts a string to a *string pointer.
|
|
// Returns nil if the string is empty.
|
|
func ToStringPtr(s string) *string {
|
|
if s == "" {
|
|
return nil
|
|
}
|
|
return &s
|
|
}
|
|
|
|
// GenerateToolsetsHelp generates the help text for the toolsets flag
|
|
func GenerateToolsetsHelp() string {
|
|
// Get toolset group to derive defaults and available toolsets
|
|
// Build() can only fail if WithTools specifies invalid tools - not used here
|
|
r, _ := NewInventory(stubTranslator).Build()
|
|
|
|
// Format default tools from metadata using strings.Builder
|
|
var defaultBuf strings.Builder
|
|
defaultIDs := r.DefaultToolsetIDs()
|
|
for i, id := range defaultIDs {
|
|
if i > 0 {
|
|
defaultBuf.WriteString(", ")
|
|
}
|
|
defaultBuf.WriteString(string(id))
|
|
}
|
|
|
|
// Get all available toolsets (excludes context for display)
|
|
allToolsets := r.AvailableToolsets("context")
|
|
var availableBuf strings.Builder
|
|
const maxLineLength = 70
|
|
currentLine := ""
|
|
|
|
for i, toolset := range allToolsets {
|
|
id := string(toolset.ID)
|
|
switch {
|
|
case i == 0:
|
|
currentLine = id
|
|
case len(currentLine)+len(id)+2 <= maxLineLength:
|
|
currentLine += ", " + id
|
|
default:
|
|
if availableBuf.Len() > 0 {
|
|
availableBuf.WriteString(",\n\t ")
|
|
}
|
|
availableBuf.WriteString(currentLine)
|
|
currentLine = id
|
|
}
|
|
}
|
|
if currentLine != "" {
|
|
if availableBuf.Len() > 0 {
|
|
availableBuf.WriteString(",\n\t ")
|
|
}
|
|
availableBuf.WriteString(currentLine)
|
|
}
|
|
|
|
// Build the complete help text using strings.Builder
|
|
var buf strings.Builder
|
|
buf.WriteString("Comma-separated list of tool groups to enable (no spaces).\n")
|
|
buf.WriteString("Available: ")
|
|
buf.WriteString(availableBuf.String())
|
|
buf.WriteString("\n")
|
|
buf.WriteString("Special toolset keywords:\n")
|
|
buf.WriteString(" - all: Enables all available toolsets\n")
|
|
buf.WriteString(" - default: Enables the default toolset configuration of:\n\t ")
|
|
buf.WriteString(defaultBuf.String())
|
|
buf.WriteString("\n")
|
|
buf.WriteString("Examples:\n")
|
|
buf.WriteString(" - --toolsets=actions,gists,notifications\n")
|
|
buf.WriteString(" - Default + additional: --toolsets=default,actions,gists\n")
|
|
buf.WriteString(" - All tools: --toolsets=all")
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
// stubTranslator is a passthrough translator for cases where we need an Inventory
|
|
// but don't need actual translations (e.g., getting toolset IDs for CLI help).
|
|
func stubTranslator(_, fallback string) string { return fallback }
|
|
|
|
// AddDefaultToolset removes the default toolset and expands it to the actual default toolset IDs
|
|
func AddDefaultToolset(result []string) []string {
|
|
hasDefault := false
|
|
seen := make(map[string]bool)
|
|
for _, toolset := range result {
|
|
seen[toolset] = true
|
|
if toolset == string(ToolsetMetadataDefault.ID) {
|
|
hasDefault = true
|
|
}
|
|
}
|
|
|
|
// Only expand if "default" keyword was found
|
|
if !hasDefault {
|
|
return result
|
|
}
|
|
|
|
result = RemoveToolset(result, string(ToolsetMetadataDefault.ID))
|
|
|
|
// Get default toolset IDs from the Inventory
|
|
// Build() can only fail if WithTools specifies invalid tools - not used here
|
|
r, _ := NewInventory(stubTranslator).Build()
|
|
for _, id := range r.DefaultToolsetIDs() {
|
|
if !seen[string(id)] {
|
|
result = append(result, string(id))
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func RemoveToolset(tools []string, toRemove string) []string {
|
|
result := make([]string, 0, len(tools))
|
|
for _, tool := range tools {
|
|
if tool != toRemove {
|
|
result = append(result, tool)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func ContainsToolset(tools []string, toCheck string) bool {
|
|
return slices.Contains(tools, toCheck)
|
|
}
|
|
|
|
// CleanTools cleans tool names by removing duplicates and trimming whitespace.
|
|
// Validation of tool existence is done during registration.
|
|
func CleanTools(toolNames []string) []string {
|
|
seen := make(map[string]bool)
|
|
result := make([]string, 0, len(toolNames))
|
|
|
|
// Remove duplicates and trim whitespace
|
|
for _, tool := range toolNames {
|
|
trimmed := strings.TrimSpace(tool)
|
|
if trimmed == "" {
|
|
continue
|
|
}
|
|
if !seen[trimmed] {
|
|
seen[trimmed] = true
|
|
result = append(result, trimmed)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// GetDefaultToolsetIDs returns the IDs of toolsets marked as Default.
|
|
// This is a convenience function that builds an inventory to determine defaults.
|
|
func GetDefaultToolsetIDs() []string {
|
|
// Build() can only fail if WithTools specifies invalid tools - not used here
|
|
r, _ := NewInventory(stubTranslator).Build()
|
|
ids := r.DefaultToolsetIDs()
|
|
result := make([]string, len(ids))
|
|
for i, id := range ids {
|
|
result[i] = string(id)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// RemoteOnlyToolsets returns toolset metadata for toolsets that are only
|
|
// available in the remote MCP server. These are documented but not registered
|
|
// in the local server.
|
|
func RemoteOnlyToolsets() []inventory.ToolsetMetadata {
|
|
return []inventory.ToolsetMetadata{
|
|
ToolsetMetadataCopilotSpaces,
|
|
ToolsetMetadataSupportSearch,
|
|
}
|
|
}
|