Documentation
¶
Overview ¶
Package actioncatalog provides the canonical GitLab action catalog shared by catalog-backed MCP tool surfaces.
The catalog is the intermediate action core between typed GitLab handlers and the public meta and dynamic tool surfaces. It stores executable actions as deterministic groups, preserving route metadata such as input schemas, output schemas, destructive flags, action aliases, tags, icons, descriptions, and formatter hooks.
Action IDs use the stable domain.action form derived from the backing meta-tool name and action name. For example, gitlab_project/create becomes project.create, and gitlab_merge_request/list becomes merge_request.list. Dynamic mode uses these IDs directly, while meta-tools expose the same routes through action dispatch inside domain tools.
This package is not the registry for individual MCP tools. Individual tools are still registered directly by internal/tools.RegisterAll for compatibility. Meta-tools and dynamic tools consume this catalog through adapters such as internal/tools.RegisterMetaCatalog and internal/tools/dynamic.NewRegistryFromCatalog.
Invariants ¶
Catalog construction must be deterministic. Groups preserve explicit action order for user-facing descriptions, cloning avoids mutable alias/schema sharing between surfaces, and validation rejects duplicate action IDs or ambiguous aliases before tools are registered.
Index ¶
- func DomainFromToolName(toolName string) string
- func ToActionMaps(catalog *Catalog) map[string]toolutil.ActionMap
- type Action
- type ActionID
- type Catalog
- func (c *Catalog) Action(id ActionID) (Action, bool)
- func (c *Catalog) ActionMaps() map[string]toolutil.ActionMap
- func (c *Catalog) Actions() []Action
- func (c *Catalog) AddAction(toolName string, action Action, groupOptions ...GroupOptions) error
- func (c *Catalog) AddGroup(group Group) error
- func (c *Catalog) BindTo(client *gitlabclient.Client) *Catalog
- func (c *Catalog) Clone() *Catalog
- func (c *Catalog) CountActions() int
- func (c *Catalog) CountGroups() int
- func (c *Catalog) ExcludedActionIDs(excludeTools []string) []string
- func (c *Catalog) Filter(opts FilterOptions) *Catalog
- func (c *Catalog) FilterAllowedToolNames(toolNames []string) *Catalog
- func (c *Catalog) FilterExcludedToolNames(excludeTools []string) (filtered *Catalog, unmatched []string)
- func (c *Catalog) FilterExcludedTools(excludeTools []string) *Catalog
- func (c *Catalog) FilterReadOnlyActions() *Catalog
- func (c *Catalog) FilterReadOnlyGroups() *Catalog
- func (c *Catalog) Group(toolName string) (Group, bool)
- func (c *Catalog) Groups() []Group
- func (c *Catalog) MarkShared()
- func (c *Catalog) SharedOrigin() *Catalog
- func (c *Catalog) Validate() error
- func (c *Catalog) WithSafeModePreviews() *Catalog
- type CatalogGroupSpec
- type FilterOptions
- type Group
- type GroupOptions
- type SurfaceKind
- type SurfaceToolSpec
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DomainFromToolName ¶
DomainFromToolName returns the canonical dynamic domain for a meta-tool name.
Types ¶
type Action ¶
type Action struct {
ID ActionID
ToolName string
Domain string
Name string
Route toolutil.ActionRoute
SchemaURI string
Aliases []string
Tags []string
Usage string
RelatedActions []string
Compatibility toolutil.CompatibilityPolicy
ReadOnly bool
Edition string
GitLabDotComOnly bool
OwnerPackage string
IndividualTool toolutil.IndividualToolSpec
ContentKind string
NotFoundPolicy string
EmbeddedResourcePolicy string
EmbeddedResource string
RichResultPolicy string
SchemaValidationNotes []string
RuntimeValidationNotes []string
SpecBacked bool
Destructive bool
Idempotent bool
OpenWorld bool
}
Action describes one executable GitLab action in the canonical catalog.
func ActionsFromSpecs ¶
func ActionsFromSpecs(specs []toolutil.ActionSpec) ([]Action, error)
ActionsFromSpecs projects canonical action specs into catalog actions.
type ActionID ¶
type ActionID string
ActionID is the stable dynamic identifier for one GitLab action.
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog stores deterministic groups and action lookup indexes. A Catalog is intended to be mutated during single-threaded initialization and then shared read-only; concurrent mutation is not supported.
What a catalog shares ¶
Every accessor returns copies of the Group and Action values, so a caller may set fields and append to slices without reaching the catalog. What the copies do not include is the route metadata: the InputSchema, OutputSchema and ParameterGuidance maps of every route are frozen and shared, between the copies, the catalog, and every other catalog derived from it by filtering or binding. The accessors used to deep-copy them, and in the HTTP pool, where a catalog is consulted several times for each of a thousand credentials, those copies were half of the process's heap. A consumer that must change a schema derives its own through toolutil.DeriveSchema.
Shared and bound catalogs ¶
A catalog built once per configuration and cached for the process is marked with Catalog.MarkShared; its handlers are bound to no credential. Each server gets Catalog.BindTo of it: the same groups and actions, with the handlers rebuilt for that server's client. A bound catalog remembers the shared one it came from as its origin, and consumers that build something client-independent from a catalog (the dynamic search index, the tool manifest, the telemetry identifier) key it on Catalog.SharedOrigin so every server of one configuration shares one.
func FromActionMaps ¶
FromActionMaps converts legacy route maps into a canonical catalog.
func FromActionMapsWithError ¶
FromActionMapsWithError converts legacy route maps into a canonical catalog and reports invalid groups instead of panicking.
func (*Catalog) Action ¶
Action returns a copy of one action by canonical ID, sharing the route schemas as described on Catalog.
func (*Catalog) ActionMaps ¶
ActionMaps returns a legacy route snapshot keyed by tool and action. The maps are the caller's; the routes share their schemas with the catalog.
func (*Catalog) Actions ¶
Actions returns copies of all actions sorted by canonical ID, sharing the route schemas as described on Catalog.
func (*Catalog) AddAction ¶
func (c *Catalog) AddAction(toolName string, action Action, groupOptions ...GroupOptions) error
AddAction adds one action to an existing or newly-created group. When the group does not exist, callers may provide GroupOptions so the synthesized group carries the same metadata as a normal catalog group.
func (*Catalog) BindTo ¶
func (c *Catalog) BindTo(client *gitlabclient.Client) *Catalog
BindTo returns this catalog with every handler rebuilt for client, through toolutil.ActionRoute.BindTo. The groups, the actions and the route metadata are the same; only the handlers are new, which is the whole per-credential cost of a surface built from a shared catalog. The result remembers this catalog's Catalog.SharedOrigin as its own.
func (*Catalog) Clone ¶
Clone returns a copy of the catalog that may be added to and filtered without reaching the original, sharing the route schemas as described on Catalog. The copy is a new catalog with no shared origin: what is added to it afterwards makes it a different action set.
func (*Catalog) CountActions ¶
CountActions returns the number of actions in the catalog.
func (*Catalog) CountGroups ¶
CountGroups returns the number of groups in the catalog.
func (*Catalog) ExcludedActionIDs ¶
ExcludedActionIDs returns the canonical action IDs excludeTools removes from this catalog, sorted.
The tool surface is not the only request path to a GitLab object: a resource template returns the same data through the same credential, and its registration knows nothing about tool names. Resolving the operator's entries — group name, individual tool name or action ID alike — to canonical IDs here is what lets that other surface apply the same narrowing from one table keyed by one kind of name, instead of repeating this matcher.
func (*Catalog) Filter ¶
func (c *Catalog) Filter(opts FilterOptions) *Catalog
Filter applies all catalog-level filters in a deterministic order.
func (*Catalog) FilterAllowedToolNames ¶
FilterAllowedToolNames returns a cloned catalog with only explicitly allowed tools.
func (*Catalog) FilterExcludedToolNames ¶
func (c *Catalog) FilterExcludedToolNames(excludeTools []string) (filtered *Catalog, unmatched []string)
FilterExcludedToolNames returns a cloned catalog without the tools and actions named by excludeTools, together with the entries that matched nothing in this catalog.
An entry is matched against three names, because three names reach the same action depending on which surface is registered:
- a group's meta-tool name ("gitlab_issue"), which removes the group and every action in it;
- an action's individual tool name ("gitlab_issue_delete"), which removes that one action;
- the canonical action ID ("issue.delete"), which the dynamic surface takes directly, likewise.
Only the group name matched before. The default surface is dynamic, where the two visible tools reach every action by canonical ID, so an operator who hardened a deployment with EXCLUDE_TOOLS=gitlab_issue_delete got a server that still executed it and a startup log that said nothing was excluded.
Aliases are deliberately not matched. Alias resolution is fuzzy by design, and an exclusion that removes more than the operator named is a different defect rather than a fix for this one.
A group whose every action was excluded is dropped: a dispatcher that can only refuse is worse than no tool at all. A group that was already empty is left alone so catalog validation can still report it.
func (*Catalog) FilterExcludedTools ¶
FilterExcludedTools returns a cloned catalog without the tools and actions named by excludeTools.
Entries that name nothing on this surface are logged at WARN rather than refused: one configuration is routinely reused across Free, Premium and Ultimate instances, and a lower-tier catalog legitimately lacks tools the same file names. The warning is deliberately operator-facing only — the excluded actions must stay out of the client-facing withheld list, or the dynamic registry would name back the very actions the operator removed.
Standalone utility tools (gitlab_discover_project, gitlab_interactive_*) are not in this catalog; they are filtered where they are added, so the warning names them too. Use Catalog.FilterExcludedToolNames when the caller can account for those before reporting.
func (*Catalog) FilterReadOnlyActions ¶
FilterReadOnlyActions returns a cloned catalog containing only read-only actions, filtered at action granularity rather than group granularity.
A group that mixes reads and writes keeps its read-only actions instead of disappearing entirely, which is what read-only mode promises: mutating operations are removed, reads keep working. Groups left without a single read-only action are dropped, and every surviving group is marked ReadOnly so derived tool annotations agree with the actions the group actually exposes (otherwise read-only tool pruning would remove the very tools this filter just built).
func (*Catalog) FilterReadOnlyGroups ¶
FilterReadOnlyGroups returns a cloned catalog containing only read-only groups.
func (*Catalog) Group ¶
Group returns a copy of one group by tool name, sharing the route schemas as described on Catalog.
func (*Catalog) Groups ¶
Groups returns copies of all groups sorted by tool name, sharing the route schemas as described on Catalog.
func (*Catalog) MarkShared ¶
func (c *Catalog) MarkShared()
MarkShared records that this catalog is the process-lived copy of its configuration and registers every route schema in it with toolutil.ShareSchema, so the transforms every server derives from them are built once. Call it only from a cache that keeps the catalog for the rest of the process: a registered schema is never collected, and a catalog's identity may key other caches from then on.
func (*Catalog) SharedOrigin ¶
SharedOrigin returns the shared catalog this one is, or was bound from, and nil for a catalog that is neither. It is the identity to key a client-independent derivation on: every server of one configuration binds the same shared catalog, and a catalog nobody shared has no identity worth caching under.
func (*Catalog) Validate ¶
Validate verifies that the catalog has a consistent, executable action index.
func (*Catalog) WithSafeModePreviews ¶
WithSafeModePreviews returns a cloned catalog in which every mutating action is replaced by a handler returning a toolutil.SafeModePreview naming that action, leaving read-only actions untouched.
Safe Mode is a per-action policy, but dispatcher surfaces (meta-tools and the dynamic execute tool) expose one tool covering many actions, so intercepting at the tool level would block that tool's reads too. Rewriting the catalog instead keeps the interception exactly as granular as the policy: reads execute, writes preview, and the preview names the action rather than the dispatcher. Destructive is cleared on rewritten actions because nothing is executed, so there is nothing to confirm.
type CatalogGroupSpec ¶
type CatalogGroupSpec struct {
ToolName string
Title string
Description string
ReadOnly bool
Icons []mcp.Icon
BaseDomain string
EnterpriseOnly bool
GitLabDotComOnly bool
CapabilityRequirements []string
FormatResult toolutil.FormatResultFunc
Actions []toolutil.ActionSpec
OwnerPackage string
SurfaceKind SurfaceKind
}
CatalogGroupSpec is the canonical metadata contract for one catalog group.
func CloneCatalogGroupSpec ¶
func CloneCatalogGroupSpec(spec CatalogGroupSpec) CatalogGroupSpec
CloneCatalogGroupSpec returns a defensive copy of group metadata.
func (CatalogGroupSpec) GroupOptions ¶
func (spec CatalogGroupSpec) GroupOptions() GroupOptions
GroupOptions returns catalog group options projected from the group spec.
func (CatalogGroupSpec) Validate ¶
func (spec CatalogGroupSpec) Validate() error
Validate verifies group-level catalog invariants before runtime projection.
type FilterOptions ¶
FilterOptions describes catalog-level filtering inputs.
type Group ¶
type Group struct {
ToolName string
Title string
Description string
Icons []mcp.Icon
ReadOnly bool
FormatResult toolutil.FormatResultFunc
BaseDomain string
EnterpriseOnly bool
GitLabDotComOnly bool
CapabilityRequirements []string
OwnerPackage string
SurfaceKind SurfaceKind
Actions map[string]Action
ActionOrder []string
}
Group describes all actions exposed through one logical meta-tool group.
func GroupFromSpecs ¶
func GroupFromSpecs(opts GroupOptions, specs []toolutil.ActionSpec) (Group, error)
GroupFromSpecs builds a catalog group from canonical action specs.
func NewGroup ¶
func NewGroup(opts GroupOptions) Group
NewGroup creates an action group with initialized maps.
func (*Group) ActionMap ¶
ActionMap returns a legacy route map for this group. The map is the caller's; the routes in it share their schemas with the group, as every accessor of this package does (see Catalog).
func (*Group) ActionsInOrder ¶
ActionsInOrder returns group actions in deterministic action-name order.
type GroupOptions ¶
type GroupOptions struct {
ToolName string
Title string
Description string
Icons []mcp.Icon
ReadOnly bool
FormatResult toolutil.FormatResultFunc
BaseDomain string
EnterpriseOnly bool
GitLabDotComOnly bool
CapabilityRequirements []string
OwnerPackage string
SurfaceKind SurfaceKind
}
GroupOptions contains metadata for creating a catalog group.
type SurfaceKind ¶
type SurfaceKind string
SurfaceKind classifies the runtime surface represented by a catalog group.
const ( // SurfaceKindGitLabAction identifies ordinary GitLab API actions. SurfaceKindGitLabAction SurfaceKind = "gitlab-action" // SurfaceKindMetaGroup identifies visible domain meta-tool dispatchers. SurfaceKindMetaGroup SurfaceKind = "meta-group" // SurfaceKindDynamicController identifies Dynamic controller tools. SurfaceKindDynamicController SurfaceKind = "dynamic-controller" // SurfaceKindRuntimeUtility identifies non-GitLab runtime helper tools. SurfaceKindRuntimeUtility SurfaceKind = "runtime-utility" // SurfaceKindInteractiveUtility identifies tools that require MCP elicitation. SurfaceKindInteractiveUtility SurfaceKind = "interactive-utility" )
type SurfaceToolSpec ¶
type SurfaceToolSpec struct {
Name string
Title string
Description string
GroupToolName string
BaseDomain string
ActionName string
SurfaceKind SurfaceKind
Route toolutil.ActionRoute
Aliases []string
Tags []string
RelatedActions []string
Compatibility toolutil.CompatibilityPolicy
Icons []mcp.Icon
CapabilityRequirements []string
FormatResult toolutil.FormatResultFunc
SafeModePolicy string
ReadOnlyPolicy string
OwnerPackage string
ReadOnly bool
Destructive bool
Idempotent bool
OpenWorld bool
}
SurfaceToolSpec is the canonical metadata contract for visible MCP tools that are not ordinary GitLab API meta-tool groups.
func CloneSurfaceToolSpec ¶
func CloneSurfaceToolSpec(spec SurfaceToolSpec) SurfaceToolSpec
CloneSurfaceToolSpec returns a defensive copy of surface tool metadata.
func (SurfaceToolSpec) ActionSpec ¶
func (spec SurfaceToolSpec) ActionSpec() (toolutil.ActionSpec, error)
ActionSpec projects a surface tool spec into the shared ActionSpec model.
func (SurfaceToolSpec) Validate ¶
func (spec SurfaceToolSpec) Validate() error
Validate verifies that the surface spec has enough metadata for runtime registration and catalog projection.