chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:37:57 +08:00
commit e30f8ba47c
533 changed files with 115926 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

+84
View File
@@ -0,0 +1,84 @@
// Package octicons provides helpers for working with GitHub Octicon icons.
// See https://primer.style/foundations/icons for available icons.
package octicons
import (
"bufio"
"embed"
"encoding/base64"
"fmt"
"strings"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
//go:embed icons/*.png
var iconsFS embed.FS
//go:embed required_icons.txt
var requiredIconsTxt string
// RequiredIcons returns the list of icon names from required_icons.txt.
// This is the single source of truth for which icons should be embedded.
func RequiredIcons() []string {
var icons []string
scanner := bufio.NewScanner(strings.NewReader(requiredIconsTxt))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
// Skip empty lines and comments
if line == "" || strings.HasPrefix(line, "#") {
continue
}
icons = append(icons, line)
}
return icons
}
// Theme represents the color theme of an icon.
type Theme string
const (
// ThemeLight is for light backgrounds (dark/black icons).
ThemeLight Theme = "light"
// ThemeDark is for dark backgrounds (light/white icons).
ThemeDark Theme = "dark"
)
// DataURI returns a data URI for the embedded Octicon PNG.
// The theme parameter specifies which variant to use:
// - ThemeLight: dark icons for light backgrounds
// - ThemeDark: light icons for dark backgrounds
// If the icon is not found in the embedded filesystem, it returns an empty string.
func DataURI(name string, theme Theme) string {
filename := fmt.Sprintf("icons/%s-%s.png", name, theme)
data, err := iconsFS.ReadFile(filename)
if err != nil {
return ""
}
return "data:image/png;base64," + base64.StdEncoding.EncodeToString(data)
}
// Icons returns MCP Icon objects for the given octicon name in light and dark themes.
// Icons are embedded as 24x24 PNG data URIs for offline use and faster loading.
// The name should be the base octicon name without size suffix (e.g., "repo" not "repo-16").
// See https://primer.style/foundations/icons for available icons.
//
// Note: The Sizes field is omitted for backward compatibility with older MCP clients
// that expect it to be a string rather than an array per the 2025-11-25 MCP spec.
func Icons(name string) []mcp.Icon {
if name == "" {
return nil
}
return []mcp.Icon{
{
Source: DataURI(name, ThemeLight),
MIMEType: "image/png",
Theme: mcp.IconThemeLight,
},
{
Source: DataURI(name, ThemeDark),
MIMEType: "image/png",
Theme: mcp.IconThemeDark,
},
}
}
+119
View File
@@ -0,0 +1,119 @@
package octicons
import (
"strings"
"testing"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/stretchr/testify/assert"
)
func TestDataURI(t *testing.T) {
tests := []struct {
name string
icon string
theme Theme
wantDataURI bool
wantEmpty bool
}{
{
name: "light theme icon returns data URI",
icon: "repo",
theme: ThemeLight,
wantDataURI: true,
wantEmpty: false,
},
{
name: "dark theme icon returns data URI",
icon: "repo",
theme: ThemeDark,
wantDataURI: true,
wantEmpty: false,
},
{
name: "non-embedded icon returns empty string",
icon: "nonexistent-icon",
theme: ThemeLight,
wantDataURI: false,
wantEmpty: true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result := DataURI(tc.icon, tc.theme)
if tc.wantDataURI {
assert.True(t, strings.HasPrefix(result, "data:image/png;base64,"), "expected data URI prefix")
assert.NotContains(t, result, "https://")
}
if tc.wantEmpty {
assert.Empty(t, result, "expected empty string for non-embedded icon")
}
})
}
}
func TestIcons(t *testing.T) {
tests := []struct {
name string
icon string
wantNil bool
wantCount int
}{
{
name: "valid embedded icon returns light and dark variants",
icon: "repo",
wantNil: false,
wantCount: 2,
},
{
name: "empty name returns nil",
icon: "",
wantNil: true,
wantCount: 0,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result := Icons(tc.icon)
if tc.wantNil {
assert.Nil(t, result)
return
}
assert.NotNil(t, result)
assert.Len(t, result, tc.wantCount)
// Verify first icon is light theme
assert.Equal(t, DataURI(tc.icon, ThemeLight), result[0].Source)
assert.Equal(t, "image/png", result[0].MIMEType)
assert.Empty(t, result[0].Sizes) // Sizes field omitted for backward compatibility
assert.Equal(t, mcp.IconThemeLight, result[0].Theme)
// Verify second icon is dark theme
assert.Equal(t, DataURI(tc.icon, ThemeDark), result[1].Source)
assert.Equal(t, "image/png", result[1].MIMEType)
assert.Empty(t, result[1].Sizes) // Sizes field omitted for backward compatibility
assert.Equal(t, mcp.IconThemeDark, result[1].Theme)
})
}
}
func TestThemeConstants(t *testing.T) {
assert.Equal(t, Theme("light"), ThemeLight)
assert.Equal(t, Theme("dark"), ThemeDark)
}
func TestEmbeddedIconsExist(t *testing.T) {
// Test that all required icons from required_icons.txt are properly embedded
// This is the single source of truth for which icons should be available
expectedIcons := RequiredIcons()
for _, icon := range expectedIcons {
t.Run(icon, func(t *testing.T) {
lightURI := DataURI(icon, ThemeLight)
darkURI := DataURI(icon, ThemeDark)
assert.True(t, strings.HasPrefix(lightURI, "data:image/png;base64,"), "light theme icon %s should be embedded", icon)
assert.True(t, strings.HasPrefix(darkURI, "data:image/png;base64,"), "dark theme icon %s should be embedded", icon)
})
}
}
+46
View File
@@ -0,0 +1,46 @@
# Required Octicons for the GitHub MCP Server
# This file is the source of truth for icon requirements.
# Used by:
# - script/fetch-icons (to download icons)
# - pkg/octicons/octicons_test.go (to validate icons are embedded)
# - pkg/github/toolset_icons_test.go (to validate toolset icons exist)
#
# Add new icons here when:
# - Adding a new toolset with an icon
# - Adding a new tool that needs a custom icon
#
# Format: one icon name per line (without -24.svg suffix)
# Lines starting with # are comments
# Empty lines are ignored
apps
beaker
bell
book
check-circle
codescan
code-square
comment-discussion
copilot
dependabot
file
git-branch
git-commit
git-merge
git-pull-request
issue-opened
logo-gist
mark-github
organization
people
person
project
repo
repo-forked
shield
shield-lock
star
star-fill
tag
tools
workflow