6b3c375492
* Upgrade MCP Go SDK to v1.2.0-pre.1 and add Octicon icons to tools - Upgrade MCP Go SDK from v1.1.0 to v1.2.0-pre.1 for Icon support - Add Icon field to ToolsetMetadata for Octicon name assignment - Add OcticonURL() helper to generate CDN URLs for Octicon SVGs - Add Icons() method on ToolsetMetadata to generate MCP Icon objects - Apply icons automatically in RegisterFunc when tool is registered - Add icons to all 22 toolset metadata constants with appropriate Octicons - Update server.go to use new Capabilities API (fixes deprecation warnings) This demonstrates how the toolsets refactor makes adding new features simpler: icons are defined once in ToolsetMetadata and automatically applied to all tools in that toolset during registration. * Update third-party licenses for SDK upgrade * Address review feedback: enum size validation, mutation fix, tests - Replace runtime size validation with compile-time enum type (Size with SizeSM=16, SizeLG=24) - Fix RegisterFunc mutation by making shallow copy of tool before modifying Icons - Add comprehensive tests for octicons package (URL, Icons, Size constants) - Add toolsets tests for ToolsetMetadata.Icons(), RegisterFunc mutation prevention, and existing icon preservation - Improve icon choices for better visual semantics: - actions: play → workflow (more specific to GitHub Actions) - secret_protection: key → shield-lock (better represents protection) - gists: code → logo-gist (dedicated gist icon exists) * Add GitHub mark icon to server metadata Add the mark-github octicon to the server's Implementation struct so that MCP clients can display the GitHub logo for this server. The icon is provided in both 16x16 and 24x24 SVG sizes. * Fix rebase conflicts: use Registry methods and NullTranslationHelper - Remove duplicate old toolsets functions (AvailableToolsets, GetValidToolsetIDs, GetDefaultToolsetIDs) - Use Registry.AvailableToolsets() and Registry.HasToolset() instead - Replace stubTranslator with translations.NullTranslationHelper - Use new SDK Capabilities struct instead of deprecated HasTools/HasResources/HasPrompts - Add icon-related tests to registry_test.go * Use embedded data URIs for Octicon icons - Embed SVG icons using go:embed for offline use and faster loading - Convert icons to base64 data URIs at runtime - Fall back to CDN URL for non-embedded icons - Add test to verify all toolset icons are properly embedded - 44 SVG files (22 icons × 2 sizes) totaling ~27KB * Convert icons from SVG to PNG for MCP client compatibility MCP clients don't support SVG data URIs, so convert all embedded icons to PNG format using rsvg-convert. Changes: - Convert all 44 SVG icons to PNG format - Add 8 new icons: copilot, git-merge, repo-forked, star-fill - Update octicons.go to use PNG MIME type - Add script/fetch-icons for easy icon management - Update tests and toolsnaps for PNG format * Add mark-github icon for server metadata * Add light/dark theme icons for tools, resources, and prompts - Switch from size-based (16/24px) to theme-based (light/dark) icons - Use only 16x16 icons for smaller bundle size - Generate white (inverted) icons for dark theme backgrounds - Add icons to resources and prompts (auto-applied from toolset metadata) - Add 'file' icon for repository content resources - Update fetch-icons script to generate both theme variants * Use 24px icons with SVG fill modification for themes - Switch from 16px to 24px icons for better visibility - Use SVG fill attribute (#24292f for light, #ffffff for dark) instead of ImageMagick color inversion for cleaner theme variants - Remove ImageMagick dependency from fetch-icons script * Add specific icons for each repository resource type - repository_content: repo icon - repository_content_branch: git-branch icon - repository_content_commit: git-commit icon (new) - repository_content_tag: tag icon - repository_content_pr: git-pull-request icon Resources now have explicit icons set rather than relying on toolset fallback. * fix: restore Icon fields to toolset metadata and add icons to docs - Add Icon field to all ToolsetMetadata definitions (lost during rebase conflict resolution) - Update doc generator to include Octicon icons in toolsets table - Update doc generator to include icons in tool section headers - Use Primer Octicons CDN for GitHub markdown compatibility * feat: add icons to individual tools in documentation * fix: use repo-local icons with picture element for GitHub theme support - Reference icons from pkg/octicons/icons/ instead of external CDN - Use picture element with prefers-color-scheme for light/dark mode - GitHub markdown renderer will display these correctly * fix: remove redundant icons from individual tools Icons are kept on section headers and toolsets table only - having the same icon on every tool within a section was visually noisy and redundant. * Add icons to remote server toolsets documentation * Fix icon paths for docs/remote-server.md * Add remote-only toolsets with auto-generated documentation and icons guide - Add ToolsetMetadataCopilot, ToolsetMetadataCopilotSpaces, ToolsetMetadataSupportSearch - Add RemoteOnlyToolsets() function to return remote-only toolset metadata - Update doc generator to auto-generate remote-only toolsets table with icons - Create docs/toolsets-and-icons.md explaining how to add icons to toolsets - Add link to icons guide in CONTRIBUTING.md * Add icon validation tests and single source of truth for required icons - Add pkg/octicons/required_icons.txt as single source of truth for icons - Add RequiredIcons() function to read the required icons list - Update script/fetch-icons to read from required_icons.txt - Update octicons_test.go to use RequiredIcons() instead of hardcoded list - Add pkg/github/toolset_icons_test.go with: - TestAllToolsetIconsExist: validates all toolset icons are embedded - TestToolsetMetadataHasIcons: ensures all toolsets have icons set - Add 'book' icon for SupportSearch toolset - Update docs/toolsets-and-icons.md with fetch-icons and CI validation docs * fix: remove unused icon parameter from writeToolDoc - Remove unused 'icon' parameter from writeToolDoc function signature - Fix whitespace inconsistency in octicons_test.go - Fixes lint failure: unused-parameter revive error * fix: combine icon with name column in remote docs for proper table rendering - Move icon from separate column to Name column with <br> separator - Keep <picture> element for light/dark theme support - Remove empty icon column that was collapsing to zero width - Remove unused octiconSimpleImg function
135 lines
5.6 KiB
Go
135 lines
5.6 KiB
Go
package inventory
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/github/github-mcp-server/pkg/octicons"
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
)
|
|
|
|
// HandlerFunc is a function that takes dependencies and returns an MCP tool handler.
|
|
// This allows tools to be defined statically while their handlers are generated
|
|
// on-demand with the appropriate dependencies.
|
|
// The deps parameter is typed as `any` to avoid circular dependencies - callers
|
|
// should define their own typed dependencies struct and type-assert as needed.
|
|
type HandlerFunc func(deps any) mcp.ToolHandler
|
|
|
|
// ToolsetID is a unique identifier for a toolset.
|
|
// Using a distinct type provides compile-time type safety.
|
|
type ToolsetID string
|
|
|
|
// ToolsetMetadata contains metadata about the toolset a tool belongs to.
|
|
type ToolsetMetadata struct {
|
|
// ID is the unique identifier for the toolset (e.g., "repos", "issues")
|
|
ID ToolsetID
|
|
// Description provides a human-readable description of the toolset
|
|
Description string
|
|
// Default indicates this toolset should be enabled by default
|
|
Default bool
|
|
// Icon is the name of the Octicon to use for tools in this toolset.
|
|
// Use the base name without size suffix, e.g., "repo" not "repo-16".
|
|
// See https://primer.style/foundations/icons for available icons.
|
|
Icon string
|
|
}
|
|
|
|
// Icons returns MCP Icon objects for this toolset, or nil if no icon is set.
|
|
// Icons are provided in both 16x16 and 24x24 sizes.
|
|
func (tm ToolsetMetadata) Icons() []mcp.Icon {
|
|
return octicons.Icons(tm.Icon)
|
|
}
|
|
|
|
// ServerTool represents an MCP tool with metadata and a handler generator function.
|
|
// The tool definition is static, while the handler is generated on-demand
|
|
// when the tool is registered with a server.
|
|
// Tools are now self-describing with their toolset membership and read-only status
|
|
// derived from the Tool.Annotations.ReadOnlyHint field.
|
|
type ServerTool struct {
|
|
// Tool is the MCP tool definition containing name, description, schema, etc.
|
|
Tool mcp.Tool
|
|
|
|
// Toolset contains metadata about which toolset this tool belongs to.
|
|
Toolset ToolsetMetadata
|
|
|
|
// HandlerFunc generates the handler when given dependencies.
|
|
// This allows tools to be passed around without handlers being set up,
|
|
// and handlers are only created when needed.
|
|
HandlerFunc HandlerFunc
|
|
|
|
// FeatureFlagEnable specifies a feature flag that must be enabled for this tool
|
|
// to be available. If set and the flag is not enabled, the tool is omitted.
|
|
FeatureFlagEnable string
|
|
|
|
// FeatureFlagDisable specifies a feature flag that, when enabled, causes this tool
|
|
// to be omitted. Used to disable tools when a feature flag is on.
|
|
FeatureFlagDisable string
|
|
|
|
// Enabled is an optional function called at build/filter time to determine
|
|
// if this tool should be available. If nil, the tool is considered enabled
|
|
// (subject to FeatureFlagEnable/FeatureFlagDisable checks).
|
|
// The context carries request-scoped information for the consumer to use.
|
|
// Returns (enabled, error). On error, the tool should be treated as disabled.
|
|
Enabled func(ctx context.Context) (bool, error)
|
|
}
|
|
|
|
// IsReadOnly returns true if this tool is marked as read-only via annotations.
|
|
func (st *ServerTool) IsReadOnly() bool {
|
|
return st.Tool.Annotations != nil && st.Tool.Annotations.ReadOnlyHint
|
|
}
|
|
|
|
// HasHandler returns true if this tool has a handler function.
|
|
func (st *ServerTool) HasHandler() bool {
|
|
return st.HandlerFunc != nil
|
|
}
|
|
|
|
// Handler returns a tool handler by calling HandlerFunc with the given dependencies.
|
|
// Panics if HandlerFunc is nil - all tools should have handlers.
|
|
func (st *ServerTool) Handler(deps any) mcp.ToolHandler {
|
|
if st.HandlerFunc == nil {
|
|
panic("HandlerFunc is nil for tool: " + st.Tool.Name)
|
|
}
|
|
return st.HandlerFunc(deps)
|
|
}
|
|
|
|
// RegisterFunc registers the tool with the server using the provided dependencies.
|
|
// Icons are automatically applied from the toolset metadata if not already set.
|
|
// A shallow copy of the tool is made to avoid mutating the original ServerTool.
|
|
// Panics if the tool has no handler - all tools should have handlers.
|
|
func (st *ServerTool) RegisterFunc(s *mcp.Server, deps any) {
|
|
handler := st.Handler(deps) // This will panic if HandlerFunc is nil
|
|
// Make a shallow copy of the tool to avoid mutating the original
|
|
toolCopy := st.Tool
|
|
// Apply icons from toolset metadata if tool doesn't have icons set
|
|
if len(toolCopy.Icons) == 0 {
|
|
toolCopy.Icons = st.Toolset.Icons()
|
|
}
|
|
s.AddTool(&toolCopy, handler)
|
|
}
|
|
|
|
// NewServerTool creates a ServerTool from a tool definition, toolset metadata, and a typed handler function.
|
|
// The handler function takes dependencies (as any) and returns a typed handler.
|
|
// Callers should type-assert deps to their typed dependencies struct.
|
|
func NewServerTool[In any, Out any](tool mcp.Tool, toolset ToolsetMetadata, handlerFn func(deps any) mcp.ToolHandlerFor[In, Out]) ServerTool {
|
|
return ServerTool{
|
|
Tool: tool,
|
|
Toolset: toolset,
|
|
HandlerFunc: func(deps any) mcp.ToolHandler {
|
|
typedHandler := handlerFn(deps)
|
|
return func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
var arguments In
|
|
if err := json.Unmarshal(req.Params.Arguments, &arguments); err != nil {
|
|
return nil, err
|
|
}
|
|
resp, _, err := typedHandler(ctx, req, arguments)
|
|
return resp, err
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewServerToolFromHandler creates a ServerTool from a tool definition, toolset metadata, and a raw handler function.
|
|
// Use this when you have a handler that already conforms to mcp.ToolHandler.
|
|
func NewServerToolFromHandler(tool mcp.Tool, toolset ToolsetMetadata, handlerFn func(deps any) mcp.ToolHandler) ServerTool {
|
|
return ServerTool{Tool: tool, Toolset: toolset, HandlerFunc: handlerFn}
|
|
}
|