Ctrl K
ComunidadGuías…

internal/mcpgateway/catalog_view.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package mcpgateway

import "github.com/modelcontextprotocol/go-sdk/mcp"

// CatalogFeature is one listed tool or prompt in a catalog view, using the
// upstream's original (un-prefixed) name. ReadOnly and Destructive relay the
// upstream's tool annotations only when it set them explicitly; they are
// hints for operators choosing tools to exclude, not guarantees.
type CatalogFeature struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	ReadOnly    bool   `json:"read_only,omitempty"`
	Destructive bool   `json:"destructive,omitempty"`
}

// CatalogResource is one listed resource in a catalog view.
type CatalogResource struct {
	URI         string `json:"uri"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
}

// CatalogTemplate is one listed resource template in a catalog view.
type CatalogTemplate struct {
	URITemplate string `json:"uri_template"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
}

// CatalogView is the admin-facing snapshot of what one upstream currently
// exposes through the gateway. Tools are the ones the operator tool filters
// expose; ExcludedTools are discovered upstream but hidden by those filters.
type CatalogView struct {
	Server        string            `json:"server"`
	Status        ServerStatus      `json:"status"`
	Instructions  string            `json:"instructions,omitempty"`
	Tools         []CatalogFeature  `json:"tools"`
	ExcludedTools []CatalogFeature  `json:"excluded_tools"`
	Prompts       []CatalogFeature  `json:"prompts"`
	Resources     []CatalogResource `json:"resources"`
	Templates     []CatalogTemplate `json:"templates"`
}

// Catalog returns the current catalog snapshot for one server, for the admin
// API and dashboard inspector. ok is false for unknown server names; a known
// server that has never listed successfully returns empty (non-nil) lists.
func (s *Service) Catalog(name string) (CatalogView, bool) {
	u, ok := s.manager.get(name)
	if !ok {
		return CatalogView{}, false
	}
	snapshot, status := u.snapshot()
	view := CatalogView{
		Server:        name,
		Status:        status,
		Tools:         []CatalogFeature{},
		ExcludedTools: []CatalogFeature{},
		Prompts:       []CatalogFeature{},
		Resources:     []CatalogResource{},
		Templates:     []CatalogTemplate{},
	}
	if snapshot == nil {
		return view, true
	}
	view.Instructions = snapshot.instructions
	exposed := make(map[string]struct{}, len(snapshot.tools))
	for _, tool := range snapshot.tools {
		exposed[tool.Name] = struct{}{}
	}
	for _, tool := range snapshot.discovered {
		feature := catalogTool(tool)
		if _, ok := exposed[tool.Name]; ok {
			view.Tools = append(view.Tools, feature)
		} else {
			view.ExcludedTools = append(view.ExcludedTools, feature)
		}
	}
	for _, prompt := range snapshot.prompts {
		view.Prompts = append(view.Prompts, CatalogFeature{Name: prompt.Name, Description: prompt.Description})
	}
	for _, resource := range snapshot.resources {
		view.Resources = append(view.Resources, CatalogResource{URI: resource.URI, Name: resource.Name, Description: resource.Description})
	}
	for _, template := range snapshot.templates {
		view.Templates = append(view.Templates, CatalogTemplate{URITemplate: template.URITemplate, Name: template.Name, Description: template.Description})
	}
	return view, true
}

// catalogTool prefers the human-facing description, falling back to the
// annotation title so the inspector never shows a blank row for tools that
// only set display metadata.
func catalogTool(tool *mcp.Tool) CatalogFeature {
	feature := CatalogFeature{Name: tool.Name, Description: tool.Description}
	if feature.Description == "" && tool.Title != "" {
		feature.Description = tool.Title
	}
	annotations := tool.Annotations
	if annotations == nil {
		return feature
	}
	if feature.Description == "" && annotations.Title != "" {
		feature.Description = annotations.Title
	}
	// The MCP spec defaults destructiveHint to true for non-read-only tools;
	// only an explicit hint is shown, so unannotated tools stay unbadged.
	feature.ReadOnly = annotations.ReadOnlyHint
	feature.Destructive = !annotations.ReadOnlyHint && annotations.DestructiveHint != nil && *annotations.DestructiveHint
	return feature
}