Documentation
¶
Overview ¶
Package toolutil provides shared utilities for MCP tool handler sub-packages. It contains error handling, pagination, logging, text processing, Markdown formatting helpers, and meta-tool infrastructure used across all domain sub-packages under internal/tools/.
The package centralizes cross-cutting behavior for:
- MCP response construction, annotations, icons, embedded resources, and Markdown formatter registration.
- GitLab API support types for pagination, GraphQL cursors, access levels, diff positions, file validation, and flexible string-or-integer IDs.
- Operational helpers for structured errors, not-found results, logging, rate limiting, polling, destructive-action confirmation, and identity resolution.
- Schema middleware that hardens generated tool schemas and enriches common pagination parameters with numeric bounds.
This package must never import from domain sub-packages to prevent circular dependencies. The dependency direction is: domain sub-packages -> toolutil.
Common Entry Points ¶
Handlers usually use WrapErr, WrapErrWithMessage, or WrapErrWithHint for errors; PaginationInput and PaginationOutput for paginated endpoints; StringOrInt for GitLab IDs that may be numeric or path-based; and RegisterMarkdown or RegisterMarkdownResult to publish type-specific Markdown renderers.
Destructive tools use ConfirmAction when they need an MCP elicitation step, and list/detail outputs commonly embed HintableOutput so meta-tools can add next-step guidance.
Markdown and Structured Output ¶
Domain packages register Markdown renderers with RegisterMarkdown and RegisterMarkdownResult. The registry lets handlers return typed structured output for MCP clients while still producing compact human-readable Markdown. Shared helpers such as MarkdownTableHeader, MarkdownTableSeparator, and MarkdownTableRow keep table formatting consistent across domains.
Dependency Direction ¶
The package dependency shape is intentionally one-way:
internal/tools/{domain}
|
v
toolutil
|
v
MCP SDK and GitLab client primitives
Index ¶
- Constants
- Variables
- func AccessLevelDescription(level gl.AccessLevelValue) string
- func ActionDispatchOutputSchema() map[string]any
- func ActionTimeout() time.Duration
- func AddMetaTool(server *mcp.Server, name, desc string, routes ActionMap, icons []mcp.Icon, ...)
- func AddReadOnlyMetaTool(server *mcp.Server, name, desc string, routes ActionMap, icons []mcp.Icon, ...)
- func AdjustPagination(p *PaginationOutput, itemCount int)
- func AppendResourceLink(_ *mcp.CallToolResult, _, _, _ string)deprecated
- func ApplyActionMeta(options *ActionSpecOptions, meta ActionMetaEntry)
- func ApplyListOptions(opts *gl.ListOptions, page PaginationInput, keyset KeysetPaginationInput)
- func AttachArgumentLimits(server *mcp.Server, maxDepth int)
- func AttachRateLimit(server *mcp.Server, limiter *RateLimiter)
- func AttachRateLimitFunc(server *mcp.Server, resolve func(context.Context) *RateLimiter)
- func BoolEmoji(v bool) string
- func BoolPtr(b bool) *bool
- func BuildMetaToolSchema(routes ActionMap, mode string) map[string]any
- func BuildPipelineInputs(raw map[string]any) (gl.PipelineInputsOption, error)
- func BuildTargetURL(projectWebURL, targetType string, targetIID int64) string
- func CancelledResult(message string) *mcp.CallToolResult
- func CanonicalDownloadOutputPath(path string) (string, error)
- func CanonicalImportArchivePath(path string) (string, error)
- func CanonicalLocalDirPath(path string) (string, error)
- func CanonicalLocalFilePath(path string) (string, error)
- func CatalogListingRPS(rps float64) float64
- func ClampPollInterval(v int) int
- func ClampPollTimeout(v int) int
- func ClassifyError(err error) string
- func ClassifyHTTPStatus(code int) string
- func CloneMetaSchemaRoutes(routes map[string]ActionMap) map[string]ActionMap
- func CloneSchemaMap(schema map[string]any) map[string]any
- func CompileToolSchemas(tool *mcp.Tool, cacheKey string)
- func ComputeSHA256(path string) (string, error)
- func ComputeSHA256Reader(r io.Reader) (string, error)
- func ConfirmAction(ctx context.Context, req *mcp.CallToolRequest, message string) (*mcp.CallToolResult, error)
- func ConfirmDestructiveAction(ctx context.Context, req *mcp.CallToolRequest, params map[string]any, ...) (*mcp.CallToolResult, error)
- func ContainsAny(err error, substrs ...string) bool
- func ContextWithRequest(ctx context.Context, req *mcp.CallToolRequest) context.Context
- func CopyReadOnlyMetaAnnotations() *mcp.ToolAnnotations
- func CreateDownloadOutputFile(path string) (*os.File, error)
- func DefuseHintsHeading(s string) string
- func DeriveAnnotations(routes ActionMap) *mcp.ToolAnnotations
- func DeriveSchema(schema any, transform string, derive func() any) any
- func DetectRichContent(body string) string
- func EmbedCanonicalResource(result *mcp.CallToolResult, template string, params map[string]any, value any)
- func EmbedResource(result *mcp.CallToolResult, uri, mimeType, text string)
- func EmbedResourceJSON(result *mcp.CallToolResult, uri string, value any)
- func EmbeddedResourcesEnabled() bool
- func EnableEmbeddedResources(enabled bool)
- func EnrichPaginationConstraints(server *mcp.Server)
- func ErrFieldRequired(field string) error
- func ErrInvalidEnum(field, value string, validValues []string) error
- func ErrRequiredInt64(operation, field string) error
- func ErrRequiredString(operation, field string) error
- func ErrorResult(message string) *mcp.CallToolResult
- func ErrorResultMarkdown(domain, action string, err error) *mcp.CallToolResult
- func EscapeConsentValue(s string) string
- func EscapeMdHeading(s string) string
- func EscapeMdLinkDestination(url string) string
- func EscapeMdLinkLabel(s string) string
- func EscapeMdTableCell(s string) string
- func ExceedsJSONDepth(raw []byte, limit int) bool
- func ExecGraphQLDestroyNote(ctx context.Context, gql gl.GraphQLInterface, op, hint, query, noteGID string) error
- func ExecGraphQLNoteMutation[N any](ctx context.Context, gql gl.GraphQLInterface, m GraphQLNoteMutation) (*N, error)
- func ExpandResourceURI(template string, params map[string]any) (string, bool)
- func ExplicitConfirmFromRequest(req *mcp.CallToolRequest) bool
- func ExtractGitLabMessage(err error) string
- func ExtractHints(md string) []string
- func FieldTiers(rt reflect.Type) map[string]string
- func FormatCICDVariableCollectionMarkdown[T any](variables []T, pagination PaginationOutput, ...) string
- func FormatCICDVariableDetailMarkdown(v CICDVariableMarkdown, title string, includeEnvironmentScope bool) string
- func FormatCICDVariableListMarkdown(variables []CICDVariableMarkdown, pagination PaginationOutput, ...) string
- func FormatCICDVariableMarkdown(v CICDVariableMarkdown, opts CICDVariableMarkdownOptions) string
- func FormatDiscussionListMarkdown(discussions []DiscussionMarkdown, opts DiscussionListMarkdownOptions) string
- func FormatDiscussionMarkdown(discussion DiscussionMarkdown, hints ...string) string
- func FormatDiscussionNoteMarkdown(note DiscussionNoteMarkdown, hints ...string) string
- func FormatGID(typeName string, id int64) string
- func FormatGraphQLDiscussionListMarkdown[T any](discussions []T, pagination GraphQLPaginationOutput, ...) string
- func FormatGraphQLForwardPagination(p GraphQLForwardPaginationOutput, shown int) string
- func FormatGraphQLPagination(p GraphQLPaginationOutput, shown int) string
- func FormatISOTimePtr(t *gl.ISOTime) string
- func FormatLabelListMarkdown(labels []LabelMarkdown, pagination PaginationOutput, opts LabelMarkdownOptions) string
- func FormatLabelListMarkdownFunc[T any](labels []T, pagination PaginationOutput, opts LabelMarkdownOptions, ...) string
- func FormatLabelMarkdown(label LabelMarkdown, opts LabelMarkdownOptions) string
- func FormatNoteListMarkdown(notes []NoteMarkdown, pagination PaginationOutput, ...) string
- func FormatNoteMarkdown(note NoteMarkdown, opts NoteMarkdownOptions) string
- func FormatPagination(p PaginationOutput) string
- func FormatRESTDiscussionListMarkdown[T any](discussions []T, pagination PaginationOutput, ...) string
- func FormatStorageMoveCollectionMarkdown[T any](moves []T, pagination PaginationOutput, convert func(T) StorageMoveMarkdown, ...) string
- func FormatStorageMoveDetailMarkdown(move StorageMoveMarkdown, title string, hints ...string) string
- func FormatStorageMoveListMarkdown(moves []StorageMoveMarkdown, opts StorageMoveListMarkdownOptions) string
- func FormatTarget(targetType string, targetIID int64, targetTitle, targetURL string) string
- func FormatTemplateAttributeListMarkdown(items []TemplateAttributeListMarkdownItem, ...) string
- func FormatTemplateCollectionMarkdown[T any](templates []T, pagination PaginationOutput, convert func(T) TemplateMarkdown, ...) string
- func FormatTemplateContentMarkdown(title, name, language, content string, hints ...string) string
- func FormatTemplateDetailMarkdown(detail TemplateDetailMarkdown) string
- func FormatTemplateListMarkdown(templates []TemplateMarkdown, pagination PaginationOutput, ...) string
- func FormatTime(s string) string
- func FormatTimePtr(t *time.Time) string
- func GraphQLMutationError(operation string, payloadErrors []string) error
- func GraphQLTopLevelError(operation string, responseErrors []GraphQLError) error
- func HasRegisteredMarkdownFormatter(v any) bool
- func IdentityToContext(ctx context.Context, id UserIdentity) context.Context
- func ImageMIMEType(filename string) string
- func IndividualToolFromActionSpec(spec ActionSpec, opts IndividualToolProjectionOptions) (*mcp.Tool, error)
- func IndividualToolFromSpecs(specs []ActionSpec, individualName string, ...) (*mcp.Tool, error)
- func InputRequiredResultFromError(err error) (*mcp.CallToolResult, bool)
- func InternalError(err error) error
- func InvalidParams(err error) error
- func IsBinaryFile(filename string) bool
- func IsDeleteToolName(name string) bool
- func IsHTTPStatus(err error, code int) bool
- func IsImageFile(filename string) bool
- func IsNotFound(err error) bool
- func IsReadToolName(name string) bool
- func IsTerminalStatus(status string) bool
- func IsYOLOMode() bool
- func IssueStateEmoji(state string) string
- func ListHints(hints ...string) []string
- func ListRegisteredTools(ctx context.Context, server *mcp.Server, clientName string) ([]*mcp.Tool, error)
- func LocalFilesystemAccessAllowed() bool
- func LockdownInputSchemas(server *mcp.Server)
- func LogToolCallAll(ctx context.Context, req *mcp.CallToolRequest, tool string, start time.Time, ...)
- func LogToolRefusal(ctx context.Context, req *mcp.CallToolRequest, tool, reason string)
- func LookupMetaActionSchema(routes map[string]ActionMap, tool, action string) (map[string]any, bool)
- func MRStateEmoji(state string) string
- func MakeMetaHandler(toolName string, routes ActionMap, formatResult FormatResultFunc) ...
- func MarkdownCodeFence(content string) string
- func MarkdownFencedBlock(language, content string) string
- func MarkdownForResult(result any) *mcp.CallToolResult
- func MarkdownFormatterCount() int
- func MarkdownTableHeader(columns ...string) string
- func MarkdownTableRow(cells ...string) string
- func MarkdownTableSeparator(columns int) string
- func MdTitleLink(title, url string) string
- func MergeVariables(sources ...map[string]any) map[string]any
- func MetaActionSchema(route ActionRoute) map[string]any
- func MetaParamSchemaMode() string
- func MetaSchemaURI(tool, action string) string
- func MetaToolDescriptionPrefix(toolName string, routes ActionMap) string
- func MetaToolOutputSchema() map[string]any
- func MetaToolSchema(routes ActionMap) map[string]any
- func MustIndividualToolFromSpecs(specs []ActionSpec, individualName string, ...) *mcp.Tool
- func NormalizeActionAlias(action string, routes ActionMap) string
- func NormalizeActionAliasForParams(toolName, action string, params map[string]any, routes ActionMap) string
- func NormalizeParamAliasesForSchema(params, schema map[string]any) map[string]any
- func NormalizeText(s string) string
- func NotFoundResult(resource, identifier string, hints ...string) *mcp.CallToolResult
- func OpenAndValidateFile(path string, maxSize int64) (*os.File, os.FileInfo, error)
- func OpenFileOrBase64Source(op, filePath, contentBase64 string) (reader io.Reader, size int64, cleanup func(), err error)
- func ParameterGuidanceIdentity(guidance map[string]ParameterGuidance) string
- func ParseGID(gid string) (typeName string, id int64, err error)
- func ParseMetaSchemaURI(uri string) (tool, action string)
- func ParseOptionalTime(s string) *time.Time
- func PipelineInputsSchema[T any](property string) map[string]any
- func PipelineStatusEmoji(status string) string
- func PopulateHints(result *mcp.CallToolResult, setter HintSetter)
- func ProgressReportInterval(total int64) int64
- func ReadFileOrBase64(op, filePath, contentBase64 string) (*bytes.Reader, error)
- func RegisterMarkdown[T any](fn func(T) string)
- func RegisterMarkdownPair[A, B any](first func(A) string, second func(B) string)
- func RegisterMarkdownResult[T any](fn func(T) *mcp.CallToolResult)
- func RegisterMarkdownTriple[A, B, C any](first func(A) string, second func(B) string, third func(C) string)
- func RegisterSurfaceToolFromSpec(server *mcp.Server, spec ActionSpec, opts SurfaceToolRegisterOptions)
- func RegisteredMarkdownTypeNames() []string
- func RequestFromContext(ctx context.Context) *mcp.CallToolRequest
- func ResolveProjectWebURLs(ctx context.Context, projects gl.ProjectsServiceInterface, projectIDs []int64) map[int64]string
- func ResourceTemplateVariables(template string) ([]string, error)
- func RichContentHint(features, webURL string) string
- func SanitizeError(err error) error
- func SchemaForRoute[R any]() map[string]any
- func SchemaShared(schema any) bool
- func SetActionTimeout(d time.Duration)
- func SetLocalFilesystemAccess(allowed bool)
- func SetMetaParamSchemaMode(mode string)
- func SetMetaParamSchemaModeScoped(mode string) func()
- func SetUploadConfig(maxFileSize int64)
- func ShareSchema(schema any)
- func SharedSchemaIdentity(schema any) (string, bool)
- func StripControlBytes(s string) string
- func StripMetaToolDescriptionPrefix(description string) string
- func SuccessResult(markdown string) *mcp.CallToolResult
- func TitleFromName(name string) string
- func ToolResultAnnotated(md string, ann *mcp.Annotations) *mcp.CallToolResult
- func ToolResultWithImage(md string, ann *mcp.Annotations, imageData []byte, mimeType string) *mcp.CallToolResult
- func ToolResultWithMarkdown(md string) *mcp.CallToolResult
- func TypeIdentity(rt reflect.Type) string
- func UnattributedRequestError() error
- func UnattributedRequestErrorFor(ctx context.Context) error
- func UnmarshalParams[T any](params map[string]any) (T, error)
- func ValidActionsString(routes ActionMap) string
- func ValidateDiffPosition(diffLines []DiffLine, newLine, oldLine int) error
- func ValidatePackageFileName(filename string) error
- func ValidatePackageName(name string) error
- func ValidateRateLimit(rps float64, burst int) error
- func ValidateRouteBinding(route ActionRoute) error
- func WithActionDeadline(ctx context.Context) (context.Context, context.CancelFunc)
- func WithHints[O any](result *mcp.CallToolResult, out O, err error) (*mcp.CallToolResult, O, error)
- func WithInternalInspection(ctx context.Context) context.Context
- func WrapErr(operation string, err error) error
- func WrapErrWithHint(operation string, err error, hint string) error
- func WrapErrWithMessage(operation string, err error) error
- func WrapErrWithStatusHint(operation string, err error, code int, hint string) error
- func WrapGFMBody(body string) string
- func WriteDescription(b *strings.Builder, description string)
- func WriteEmpty(b *strings.Builder, resource string)
- func WriteHints(b *strings.Builder, hints ...string)
- func WriteListSummary(b *strings.Builder, shown int, p PaginationOutput)
- func WriteMdURL(b *strings.Builder, url string)
- func WriteMdURLNewline(b *strings.Builder, url string)
- func WritePagination(b *strings.Builder, p PaginationOutput)
- type AccessRequestExtra
- type ActionAliasSpec
- type ActionFunc
- func SafeModeActionFunc(name string) ActionFunc
- func WrapAction[T, R any](client *gitlabclient.Client, ...) ActionFunc
- func WrapActionWithRequest[T, R any](client *gitlabclient.Client, ...) ActionFunc
- func WrapVoidAction[T any](client *gitlabclient.Client, ...) ActionFunc
- func WrapVoidActionWithRequest[T any](client *gitlabclient.Client, ...) ActionFunc
- type ActionMap
- type ActionMetaEntry
- type ActionRoute
- func CloneActionRoute(route ActionRoute) ActionRoute
- func DestructiveAction[T, R any](client *gitlabclient.Client, ...) ActionRoute
- func DestructiveActionWithRequest[T, R any](client *gitlabclient.Client, ...) ActionRoute
- func DestructiveFunc[T, R any](fn func(ctx context.Context, input T) (R, error)) ActionRoute
- func DestructiveRoute(fn ActionFunc) ActionRoute
- func DestructiveVoidAction[T any](client *gitlabclient.Client, ...) ActionRoute
- func DestructiveVoidActionWithRequest[T any](client *gitlabclient.Client, ...) ActionRoute
- func Route(fn ActionFunc) ActionRoute
- func RouteAction[T, R any](client *gitlabclient.Client, ...) ActionRoute
- func RouteActionWithRequest[T, R any](client *gitlabclient.Client, ...) ActionRoute
- func RouteFunc[T, R any](fn func(ctx context.Context, input T) (R, error)) ActionRoute
- func RouteRequestFunc[T, R any](fn func(ctx context.Context, req *mcp.CallToolRequest, input T) (R, error)) ActionRoute
- func RouteVoidAction[T any](client *gitlabclient.Client, ...) ActionRoute
- func (route ActionRoute) BindTo(client *gitlabclient.Client) ActionRoute
- func (route ActionRoute) WithAliases(aliases ...string) ActionRoute
- func (route ActionRoute) WithBoundHandler(client *gitlabclient.Client, bind func(*gitlabclient.Client) ActionFunc) ActionRoute
- func (route ActionRoute) WithParameterGuidance(guidance map[string]ParameterGuidance) ActionRoute
- func (route ActionRoute) WithRelatedActions(actions ...string) ActionRoute
- func (route ActionRoute) WithTags(tags ...string) ActionRoute
- func (route ActionRoute) WithUsage(usage string) ActionRoute
- func (route ActionRoute) WrapHandler(wrap func(next ActionFunc) ActionFunc) ActionRoute
- type ActionSpec
- func CloneActionSpec(spec ActionSpec) ActionSpec
- func CloneActionSpecs(specs []ActionSpec) []ActionSpec
- func FillScopeParameterGuidance(specs []ActionSpec) []ActionSpec
- func FillScopeParameterGuidanceSingle(spec ActionSpec) ActionSpec
- func NewActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
- func NewAdditiveActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
- func NewCreateActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
- func NewDeleteActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
- func NewReadActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
- func NewUpdateActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
- type ActionSpecOptions
- type AppearanceExtra
- type ApproverIDsFilter
- type AssetLinkOutput
- type AssetSourceOutput
- type AssetsOutput
- type AuthorOutput
- type BasicGroupDetailsOutput
- type BasicUserOutput
- type BillableMemberExtra
- type BoardExtra
- type BoardLabelDetailsOutput
- type BoardLabelOutput
- type BoardListAssigneeOutput
- type BoardListExtra
- type BoardUserOutput
- type BridgeExtra
- type BridgeProjectOutput
- type BroadcastMessageExtra
- type CICDVariableFlags
- type CICDVariableListMarkdownOptions
- type CICDVariableMarkdown
- type CICDVariableMarkdownOptions
- type CIVariableExtra
- type ClusterAgentExtra
- type CodedError
- type CommitCommentExtra
- type CommitOutput
- type CompatibilityPolicy
- type CustomAttributeOutput
- type DeleteOutput
- type DependencyExtra
- type DeployKeyExtra
- type DeployKeyProjectOutput
- type DeploymentApprovalOutput
- type DeploymentApprovalRuleOutput
- type DeploymentApprovalSummaryOutput
- type DeploymentExtra
- type DetailedError
- type DiffLine
- type DiffOutput
- type DiffRefsOutput
- type DiscussionExtra
- type DiscussionListMarkdownOptions
- type DiscussionMarkdown
- type DiscussionNoteMarkdown
- type DiscussionRenderer
- func (r DiscussionRenderer) FormatDiscussion(discussion DiscussionMarkdown) string
- func (r DiscussionRenderer) FormatGraphQLForwardList(discussions []DiscussionMarkdown, pagination GraphQLForwardPaginationOutput) string
- func (r DiscussionRenderer) FormatGraphQLList(discussions []DiscussionMarkdown, pagination GraphQLPaginationOutput) string
- func (r DiscussionRenderer) FormatNote(note DiscussionNoteMarkdown) string
- func (r DiscussionRenderer) FormatRESTList(discussions []DiscussionMarkdown, pagination PaginationOutput) string
- type DiscussionThreadNoteOutput
- type DiscussionThreadOutput
- func CapturedThread(op string, d *gl.Discussion, capture *gitlabclient.ResponseCapture) (DiscussionThreadOutput, error)
- func CapturedThreads(op string, ds []*gl.Discussion, capture *gitlabclient.ResponseCapture) ([]DiscussionThreadOutput, error)
- func DiscussionThreadOutputFromGitLab(d *gl.Discussion, extra DiscussionExtra) DiscussionThreadOutput
- func DiscussionThreadOutputsFromGitLab(discussions []*gl.Discussion, extras []DiscussionExtra) []DiscussionThreadOutput
- type EpicOutput
- type EventExtra
- type EventWikiPageOutput
- type EvidenceOutput
- type FeatureDefinitionExtra
- type FeatureExtra
- type FeatureFlagUserListExtra
- type FormatResultFunc
- type GraphQLCursor
- type GraphQLCursorPaginationInput
- type GraphQLError
- type GraphQLForwardPaginationOutput
- type GraphQLNoteMutation
- type GraphQLPageInfo
- type GraphQLPaginationInput
- type GraphQLPaginationOutput
- type GraphQLRawForwardPageInfo
- type GraphQLRawPageInfo
- type HintSetter
- type HintableOutput
- type HookHeaderOutput
- type ImpersonationTokenExtra
- type IndividualToolAnnotationOverrides
- type IndividualToolProjectionOptions
- type IndividualToolSpec
- type InputSchemaOverride
- func FilterOverridesForSchema(schema map[string]any, overrides []InputSchemaOverride) []InputSchemaOverride
- func SchemaAnyOfRequired(propertyNames ...string) InputSchemaOverride
- func SchemaApproverIDsOverride(propertyPath string) InputSchemaOverride
- func SchemaEnumOverride(propertyPath string, values ...string) InputSchemaOverride
- func SchemaFormatOverride(propertyPath, format string) InputSchemaOverride
- func SchemaPropertyOverride(propertyPath string, values map[string]any) InputSchemaOverride
- func SchemaRootOverride(values map[string]any) InputSchemaOverride
- type InstanceUserExtra
- type InvitationExtra
- type IssueLinksOutput
- type IssueUserOutput
- func NewIssueUserOutputFromBasicUser(u gl.BasicUser) IssueUserOutput
- func NewIssueUserOutputFromEpicAuthor(u *gl.EpicAuthor) *IssueUserOutput
- func NewIssueUserOutputFromIssueAssignee(a *gl.IssueAssignee) *IssueUserOutput
- func NewIssueUserOutputFromIssueAuthor(u *gl.IssueAuthor) *IssueUserOutput
- func NewIssueUserOutputFromIssueCloser(u *gl.IssueCloser) *IssueUserOutput
- func NewIssueUserOutputFromPointer(u *gl.BasicUser) *IssueUserOutput
- func NewIssueUserOutputsFromIssueAssignees(as []*gl.IssueAssignee) []*IssueUserOutput
- type IterationOutput
- type JSONDepthScanner
- type KeyExtra
- type KeysetPaginationInput
- type LabelDetailsOutput
- type LabelExtra
- type LabelMarkdown
- type LabelMarkdownOptions
- type LastPipelineOutput
- type LicenseTemplateExtra
- type LinePositionOutput
- type LineRangeOutput
- type LineType
- type LinksOutput
- type LintExtra
- type LintJobOutput
- type MRMilestoneOutput
- type MemberExtra
- type MemberRoleOutput
- type MemberUserOutput
- type MergeRequestDiffExtra
- type MergeRequestExtra
- type MergeRequestOutput
- type MergeRequestUserOutput
- type MetaSchemaActionEntry
- type MetaSchemaDiscoveryIndex
- type MetaSchemaIndex
- type MetaSchemaIndexEntry
- type MetaSchemaRegistry
- type MetaSchemaToolEntry
- type MetaToolInput
- type MilestoneExtra
- type MilestoneIssueStatsOutput
- type MilestoneOutput
- type NamespaceBasicOutput
- type NamespaceExtra
- type NoteExtra
- type NoteListMarkdownOptions
- type NoteMarkdown
- type NoteMarkdownFlags
- type NoteMarkdownOptions
- type NoteOutput
- type NotePositionOutput
- type NoteUserExtra
- type NoteUserOutput
- type OnceMap
- type PackageExtra
- type PackagePipelineOutput
- type PackageTagOutput
- type PackageVersionOutput
- type PagesCertificateExpirationOutput
- type PagesDomainExtra
- type PaginationInput
- type PaginationOutput
- type ParamAliasExplanation
- type ParamValidationError
- type ParameterAliasSpec
- type ParameterGuidance
- type PersonalTokenOutput
- type PipelineDetailedStatusIllustrationOutput
- type PipelineDetailedStatusOutput
- type PipelineExtra
- type PipelineInfoOutput
- type PipelineOutput
- type PipelineTriggerExtra
- type ProgressReader
- type ProgressWriter
- type ProtectedBranchExtra
- type RateLimiter
- type ReferencesOutput
- type RegistryRepositoryExtra
- type ResourceMilestoneEventExtra
- type ResourceStateEventExtra
- type ResourceTokenExtra
- type RunnerExtra
- type RunnerManagerExtra
- type SAMLIdentityOutput
- type SCIMIdentityExtra
- type SCIMIdentityOutput
- type SafeModePreview
- type SecureFileExtra
- type ServiceAccountExtra
- type SnippetExtra
- type StorageMoveEntityMarkdown
- type StorageMoveExtra
- type StorageMoveListMarkdownOptions
- type StorageMoveMarkdown
- type StringOrInt
- type SuggestionOutput
- type SurfaceToolRegisterOptions
- type SystemHookExtra
- type TaskCompletionStatusOutput
- type TemplateAttributeListMarkdownItem
- type TemplateAttributeListMarkdownOptions
- type TemplateDetailMarkdown
- type TemplateListMarkdownOptions
- type TemplateMarkdown
- type TemplateRenderer
- type TimeStatsOutput
- type TodoExtra
- type TokenExtra
- type TokenGranularScopeOutput
- type ToolError
- type TopicExtra
- type UploadConfig
- type UserBasicOutput
- type UserExtra
- type UserIdentity
- type UserRefOutput
- type VoidOutput
- type WikiExtra
Constants ¶
const ( ActionSpecContentList = "list" ActionSpecContentDetail = "detail" ActionSpecContentMutate = "mutate" ActionSpecContentAssistant = "assistant" ActionSpecContentImage = "image" ActionSpecNotFoundNone = "none" ActionSpecNotFoundResult = "not_found_result" ActionSpecNotFoundPropagate = "propagate_error" ActionSpecEmbeddedNone = "none" ActionSpecEmbeddedOptional = "optional" ActionSpecEmbeddedAlways = "always" ActionSpecRichStandard = "standard" ActionSpecRichImage = "image" ActionSpecRichResourceLink = "resource_link" ActionSpecRichMixed = "mixed" )
const ( // ApproverAny matches merge requests with at least one approver. ApproverAny = "Any" // ApproverNone matches merge requests with no approvers. ApproverNone = "None" )
Approver filter literals accepted in place of a list of user IDs.
const ( DefaultMaxFileSize = config.DefaultMaxFileSize // ImportArchiveAllowlistEnv names extra directories allowed for local // GitLab project/group import archives, separated by the OS path-list separator. ImportArchiveAllowlistEnv = "GITLAB_MCP_ALLOWED_IMPORT_DIRS" // UploadDirAllowlistEnv names extra directories a tool may READ a local // file from (every file_path input), separated by the OS path-list // separator. The working directory and the OS temp directory are always // allowed. UploadDirAllowlistEnv = "GITLAB_MCP_ALLOWED_UPLOAD_DIRS" // DownloadDirAllowlistEnv names extra directories a tool may WRITE a // downloaded file into (output_path), separated by the OS path-list // separator. The working directory and the OS temp directory are always // allowed. DownloadDirAllowlistEnv = "GITLAB_MCP_ALLOWED_DOWNLOAD_DIRS" )
DefaultMaxFileSize re-exports the upload size limit from config as the single source of truth for tool utilities.
const ( GraphQLDefaultFirst = 20 GraphQLMaxFirst = 100 )
GraphQL pagination defaults.
const ( RefusalSafeMode = "safe_mode" RefusalNeedsConfirmation = "needs_confirmation" RefusalInvalidParams = "invalid_params" RefusalUnknownAction = "unknown_action" RefusalRateLimited = "rate_limited" )
Reasons a call was declined before its handler ran, recorded as the reason attribute of LogToolRefusal.
They are a closed set on purpose: an operator computing a refusal rate needs to group by something, and free text does not group.
const ( DateFormatISO = "2006-01-02" DateTimeFormat = "2006-01-02T15:04:05Z" )
Common date format constants used across tool sub-packages.
const ( TblRowID = "| ID | %d |\n" TblRowStatus = "| Status | %s |\n" TblRowCreatedAt = "| Created At | %s |\n" TblRowUpdatedAt = "| Updated At | %s |\n" TblRowHasFailures = "| Has Failures | %v |\n" )
Table row format constants for common detail-table fields. Each pairs with TblFieldValue and is shared across sub-packages to avoid duplicated literals.
const ( FmtMdH1 = "# %s\n\n" FmtMdH2 = "## %s\n\n" FmtMdH3 = "### %s\n\n" FmtMdH4 = "#### %s\n\n" FmtMdH5 = "##### %s\n\n" FmtMdH6 = "###### %s\n\n" )
Headings format string with trailing blank line.
const ( FmtMdID = "- **ID**: %d\n" FmtMdName = "- **Name**: %s\n" FmtMdTitle = "- **Title**: %s\n" FmtMdState = "- **State**: %s\n" FmtMdStatus = "- **Status**: %s\n" FmtMdDescription = "- **Description**: %s\n" FmtMdPath = "- **Path**: %s\n" FmtMdVisibility = "- **Visibility**: %s\n" FmtMdEmail = "- **Email**: %s\n" FmtMdUsername = "- **Username**: %s\n" FmtMdTarget = "- **Target**: %s\n" FmtMdCreated = "- **Created**: %s\n" FmtMdUpdated = "- **Updated**: %s\n" FmtMdAuthorAt = "- **Author**: @%s\n" FmtMdAuthor = "- **Author**: %s\n" FmtMdSectionText = "\n%s\n" FmtMdH2Count = "## %s (%d)\n\n" TblSep1Col = "| --- |\n" TblSep2Col = "| --- | --- |\n" TblSep3Col = "| --- | --- | --- |\n" TblSep4Col = "| --- | --- | --- | --- |\n" TblSep5Col = "| --- | --- | --- | --- | --- |\n" TblSep6Col = "| --- | --- | --- | --- | --- | --- |\n" TblSep7Col = "| --- | --- | --- | --- | --- | --- | --- |\n" TblSep8Col = "| --- | --- | --- | --- | --- | --- | --- | --- |\n" TblSep9Col = "| --- | --- | --- | --- | --- | --- | --- | --- | --- |\n" TblSep10Col = "| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n" FmtRow1Str = "| %s |\n" FmtRow2Str = "| %s | %s |\n" FmtRow3Str = "| %s | %s | %s |\n" FmtRow4Str = "| %s | %s | %s | %s |\n" FmtRow5Str = "| %s | %s | %s | %s | %s |\n" FmtRow6Str = "| %s | %s | %s | %s | %s | %s |\n" FmtRow7Str = "| %s | %s | %s | %s | %s | %s | %s |\n" FmtRow8Str = "| %s | %s | %s | %s | %s | %s | %s | %s |\n" FmtRow9Str = "| %s | %s | %s | %s | %s | %s | %s | %s | %s |\n" FmtRow10Str = "| %s | %s | %s | %s | %s | %s | %s | %s | %s | %s |\n" )
Markdown format constants for repeated table separators and field patterns.
const ( EmojiDraft = "\U0001F4DD" // 📝 EmojiWarning = "\u26A0\uFE0F" // ⚠️ EmojiConfidential = "\U0001F512" // 🔒 EmojiArchived = "\U0001F4E6" // 📦 EmojiStar = "\u2B50" // ⭐ EmojiSuccess = "\u2705" // ✅ EmojiCross = "\u274C" // ❌ EmojiRefresh = "\U0001F504" // 🔄 EmojiFile = "\U0001F4C4" // 📄 EmojiFolder = "\U0001F4C1" // 📁 EmojiCalendar = "\U0001F4C5" // 📅 EmojiUpArrow = "\u2B06\uFE0F" // ⬆️ EmojiDownArrow = "\u2B07\uFE0F" // ⬇️ EmojiInfo = "\u2139\uFE0F" // ℹ️ EmojiQuestion = "\u2753" // ❓ EmojiLink = "\U0001F517" // 🔗 EmojiUser = "\U0001F464" // 👤 EmojiGroup = "\U0001F465" // 👥 EmojiPipeline = "\U0001F6A7" // 🚧 EmojiMergeRequest = "\U0001F5C3" // 🗃️ EmojiIssue = "\U0001F4A1" // 💡 EmojiRed = "\U0001F534" // 🔴 EmojiYellow = "\U0001F7E1" // 🟡 EmojiGreen = "\U0001F7E2" // 🟢 EmojiProhibited = "\U0001F6AB" // 🚫 EmojiWhiteCircle = "\u26AA" // ⚪ EmojiParty = "\U0001F389" // 🎉 EmojiPurple = "\U0001F7E3" // 🟣 EmojiBlue = "\U0001F535" // 🔵 EmojiStop = "\u26D4" // ⛔ EmojiSkip = "\u23ED\uFE0F" // ⏭️ EmojiNew = "\U0001F195" // 🆕 EmojiHand = "\u270B" // ✋ )
Contextual emoji constants for consistent visual indicators across formatters.
const ( MetaParamSchemaOpaque = "opaque" MetaParamSchemaCompact = "compact" MetaParamSchemaFull = "full" )
Meta-tool param schema mode constants. Mirrors the values accepted by the META_PARAM_SCHEMA env var and --meta-param-schema CLI flag in package config. Duplicated here to avoid an import cycle (config → toolutil → mcp).
const ( PollMinInterval = 5 PollMaxInterval = 60 PollDefaultInterval = 10 PollMinTimeout = 1 PollMaxTimeout = 3600 PollDefaultTimeout = 300 )
Polling bounds and defaults (all values in seconds) for tools that wait on a GitLab resource to reach a terminal state (pipelines, jobs, deployments).
const DefaultMaxArgumentDepth = 64
DefaultMaxArgumentDepth is the nesting ceiling applied to a tools/call arguments object.
No schema this server registers nests anywhere near it — the deepest is a few objects inside a few arrays — so it is a ceiling on shapes nothing legitimate produces rather than a budget a caller could plausibly spend.
const DestinationRefusedMessage = "this server refused to connect to that address, so the request never left the process"
DestinationRefusedMessage is what a caller is told when this server declined to open the connection an action needed.
It says the request never left the process, because that is the fact every other reading of the symptom gets wrong: nothing was sent, nothing answered, and no credential was disclosed to the address named in the cause. Retrying changes nothing, which is why the sentence does not suggest it and the hint names a flag instead.
const ErrMsgContextCanceled = "context canceled"
ErrMsgContextCanceled is the operation label passed to WrapErr when a tool handler detects context cancellation before calling the GitLab API.
const HintPreserveLinks = "" /* 127-byte string literal not displayed */
HintPreserveLinks reminds the LLM to keep the clickable [text](url) markdown links when presenting list results to the user.
const MetaSchemaIndexURI = "gitlab://schema/meta/"
MetaSchemaIndexURI is the static URI returning the full meta-tool action catalog.
const MetaSchemaTemplateURI = "gitlab://schema/meta/{tool}/{action}"
MetaSchemaTemplateURI is the URI template for per-action params schemas.
const (
RateLimitRefusalPrefix = "rate limit exceeded for "
)
RateLimitRefusalPrefix and rateLimitRetrySuffix are how every refusal this limiter writes begins and ends, whichever of the two wire shapes carries it.
The prefix is exported because a refused tools/call arrives as a successful JSON-RPC result whose only distinguishing mark is this text: there is no code and no _meta on that shape, so anything that has to tell a refusal from a handler failure matches the wording. cmd/bench_resources' fairness scenario does exactly that, and reading the constant rather than a copy of the sentence makes a change of wording a compile-visible edit here instead of a silent reclassification of every refusal as a failure there.
const RedactedSecretValue = "REDACTED"
RedactedSecretValue is the standard placeholder for sensitive values that must not be exposed through structured output or Markdown renderers.
const SafeModeHint = "Set GITLAB_MCP_SAFE_MODE=false to execute this operation"
SafeModeHint is the operator-facing hint attached to every safe-mode preview.
const StepFormattingResponse = "Formatting response..."
StepFormattingResponse is a standard progress step label for response formatting.
const TblFieldValue = "| Field | Value |\n| --- | --- |\n"
TblFieldValue is the standard "| Field | Value |" detail table header+separator.
const UnattributedRequestMessage = "this request could not be attributed to a credential and was not sent to GitLab; " +
"retry, and report it if it persists"
UnattributedRequestMessage is what a caller is told when this server could not decide which credential a request belongs to.
It says what happened and asks for a report, because nothing the caller sent is wrong and nothing they can change will help: on a server shared by a configuration shape every handler resolves the caller's client from the request, and a handler that resolved none has run without one. The wording matches the refusal the subscription path already gives for the same cause, so an operator meeting both sees one fact rather than two symptoms.
What it deliberately does not say is "not found" or "your token lacks access". Both were what a caller used to see, and both send someone to check permissions that are perfectly fine.
Variables ¶
var ( ReadAnnotations = &mcp.ToolAnnotations{ ReadOnlyHint: true, DestructiveHint: new(false), IdempotentHint: true, OpenWorldHint: new(true), } CreateAnnotations = &mcp.ToolAnnotations{ DestructiveHint: new(false), OpenWorldHint: new(true), } UpdateAnnotations = &mcp.ToolAnnotations{ DestructiveHint: new(false), IdempotentHint: true, OpenWorldHint: new(true), } DeleteAnnotations = &mcp.ToolAnnotations{ DestructiveHint: new(true), IdempotentHint: true, OpenWorldHint: new(true), } // NonDestructiveMetaAnnotations are for meta-tools that include // create/update operations but no delete actions. NonDestructiveMetaAnnotations = &mcp.ToolAnnotations{ DestructiveHint: new(false), OpenWorldHint: new(true), } // MetaAnnotations are annotations for meta-tools that combine read/write/delete. // Since a single meta-tool may include destructive actions, annotations reflect // the most cautious combination. MetaAnnotations = &mcp.ToolAnnotations{ DestructiveHint: new(true), OpenWorldHint: new(true), } // ReadOnlyMetaAnnotations are for meta-tools with only list/get/search actions. ReadOnlyMetaAnnotations = &mcp.ToolAnnotations{ ReadOnlyHint: true, DestructiveHint: new(false), IdempotentHint: true, OpenWorldHint: new(true), } )
Tool annotation presets for different operation categories. Each preset configures MCP hints that help LLMs understand whether a tool is read-only, destructive, or idempotent.
var ( // ContentBoth marks content for both user display and LLM processing (default). ContentBoth = &mcp.Annotations{ Audience: []mcp.Role{"user", "assistant"}, Priority: 0.5, } // ContentUser marks content primarily for user display (uploads, visualizations). ContentUser = &mcp.Annotations{ Audience: []mcp.Role{"user"}, Priority: 0.8, } // ContentAssistant marks content primarily for LLM processing (search, raw data). ContentAssistant = &mcp.Annotations{ Audience: []mcp.Role{"assistant"}, Priority: 0.7, } )
Content annotation presets for TextContent responses. These guide MCP clients on who the content is intended for and its importance.
var ( // ContentList marks list/search results for LLM processing with lower priority. ContentList = &mcp.Annotations{ Audience: []mcp.Role{"assistant"}, Priority: 0.4, } // ContentDetail marks single-entity details for LLM processing with medium priority. ContentDetail = &mcp.Annotations{ Audience: []mcp.Role{"assistant"}, Priority: 0.6, } // ContentMutate marks create/update/delete results for LLM processing with high priority. ContentMutate = &mcp.Annotations{ Audience: []mcp.Role{"assistant"}, Priority: 0.8, } )
Operation-based content annotation presets. All use audience ["assistant"] so the Markdown content is available to the LLM for reasoning, while StructuredContent (JSON) serves programmatic clients. This avoids redundant display when clients show both Content and StructuredContent.
var ( // ResourceList marks list-shaped resources, readable by user and model. ResourceList = &mcp.Annotations{ Audience: []mcp.Role{"user", "assistant"}, Priority: 0.4, } // ResourceDetail marks single-entity resources, readable by user and model. ResourceDetail = &mcp.Annotations{ Audience: []mcp.Role{"user", "assistant"}, Priority: 0.6, } // ResourceMachineList and ResourceMachineDetail are for machine-facing // resources — call shapes, entry IDs, input schemas. Their intended // customer is the assistant deciding what to call (and programmatic // clients); the raw JSON has near-zero display value for a person, so // this is the one resource family that drops the "user" role. Every // other resource keeps both roles per the rationale above — and keeping // the split real is what makes the audience field carry information at // all: a value uniform across every resource tells a consumer nothing. ResourceMachineList = &mcp.Annotations{ Audience: []mcp.Role{"assistant"}, Priority: 0.4, } ResourceMachineDetail = &mcp.Annotations{ Audience: []mcp.Role{"assistant"}, Priority: 0.6, } )
Resource-facing annotation presets.
These mirror the priorities of the operation presets above but add the "user" role, and the difference is deliberate. The assistant-only audience exists to stop a client rendering a tool result twice, once from Content and once from StructuredContent. A resource has no such duality: it is content a person asks for by URI — a workflow guide, a project's issues — so telling the client not to show it to that person describes it wrongly.
var ( IconBranch = icon("branch", svgBranch) IconCommit = icon("commit", svgCommit) IconIssue = icon("issue", svgIssue) IconMR = icon("mr", svgMR) IconPipeline = icon("pipeline", svgPipeline) IconJob = icon("job", svgJob) IconRelease = icon("release", svgRelease) IconTag = icon("tag", svgTag) IconProject = icon("project", svgProject) IconGroup = icon("group", svgGroup) IconUser = icon("user", svgUser) IconWiki = icon("wiki", svgWiki) IconFile = icon("file", svgFile) IconPackage = icon("package", svgPackage) IconSearch = icon("search", svgSearch) IconLabel = icon("label", svgLabel) IconMilestone = icon("milestone", svgMilestone) IconEnvironment = icon("environment", svgEnvironment) IconDeploy = icon("deploy", svgDeploy) IconSchedule = icon("schedule", svgSchedule) IconVariable = icon("variable", svgVariable) IconRunner = icon("runner", svgRunner) IconTodo = icon("todo", svgTodo) IconHealth = icon("health", svgHealth) IconUpload = icon("upload", svgUpload) IconBoard = icon("board", svgBoard) IconSnippet = icon("snippet", svgSnippet) IconToken = icon("token", svgToken) IconIntegration = icon("integration", svgIntegration) IconNotify = icon("notify", svgNotify) IconServer = icon("server", svgServer) IconSecurity = icon("security", svgSecurity) IconConfig = icon("config", svgConfig) IconAnalytics = icon("analytics", svgAnalytics) IconKey = icon("key", svgKey) IconLink = icon("link", svgLink) IconDiscussion = icon("discussion", svgDiscussion) IconEvent = icon("event", svgEvent) IconContainer = icon("container", svgContainer) IconImport = icon("import", svgImport) IconAlert = icon("alert", svgAlert) IconTemplate = icon("template", svgTemplate) IconInfra = icon("infra", svgInfra) IconEpic = icon("epic", svgEpic) IconShield = icon("shield", svgShield) IconAudit = icon("audit", svgAudit) IconQueue = icon("queue", svgQueue) IconBot = icon("bot", svgBot) IconVulnerability = icon("vulnerability", svgVulnerability) IconCompliance = icon("compliance", svgCompliance) IconBrand = icon("brand", svgBrand) )
Domain icons — each returns a three-element []mcp.Icon (SVG + light/dark WebP fallback) ready for the Icons field.
var ErrInvalidRateLimit = errors.New("invalid rate limit configuration")
ErrInvalidRateLimit is returned by ValidateRateLimit when the parameters are inconsistent (e.g. burst < 1 with rps > 0).
var ReadOnlyNameSuffixes = []string{
"_list", "_lists", "_get", "_search",
"_latest", "_blame", "_raw", "_diff", "_refs",
"_statuses", "_signature", "_languages", "_statistics",
}
ReadOnlyNameSuffixes lists tool-name suffixes that imply a read-only operation. Shared between annotation derivation and surface-quality audits so both agree on what "looks read-only".
Functions ¶
func AccessLevelDescription ¶
func AccessLevelDescription(level gl.AccessLevelValue) string
AccessLevelDescription maps GitLab access level integers to human-readable labels.
func ActionDispatchOutputSchema ¶
ActionDispatchOutputSchema returns a permissive JSON Schema for tools whose exact structured result depends on the selected catalog action.
func ActionTimeout ¶
ActionTimeout reports the deadline every action runs under, 0 for none.
func AddMetaTool ¶
func AddMetaTool(server *mcp.Server, name, desc string, routes ActionMap, icons []mcp.Icon, formatResult FormatResultFunc)
AddMetaTool registers an action-dispatched meta-tool with route-derived annotations. Use it for meta-tools that may include mutating or destructive actions; if any route is destructive, the tool receives DestructiveHint=true.
func AddReadOnlyMetaTool ¶
func AddReadOnlyMetaTool(server *mcp.Server, name, desc string, routes ActionMap, icons []mcp.Icon, formatResult FormatResultFunc)
AddReadOnlyMetaTool registers an action-dispatched meta-tool whose actions are all read-only list/get/search-style operations.
func AdjustPagination ¶
func AdjustPagination(p *PaginationOutput, itemCount int)
AdjustPagination corrects pagination metadata when the GitLab API does not return X-Total and X-Total-Pages headers (e.g., the Search API). It infers TotalItems and TotalPages from the actual item count received and the presence of a NextPage indicator.
func AppendResourceLink
deprecated
func AppendResourceLink(_ *mcp.CallToolResult, _, _, _ string)
AppendResourceLink preserves the legacy resource-link hook as a no-op.
Deprecated: AppendResourceLink is intentionally a no-op. It previously emitted mcp.ResourceLink content blocks with external HTTP URLs (GitLab WebURL), but ResourceLink is reserved for MCP-registered resources (gitlab:// URIs). Clients that received an https:// ResourceLink attempted to resolve it via resources/read, triggering JSON-RPC -32002 "Resource not found" errors. External web links are already included in the Markdown text output. Callers will be removed in a future major version.
func ApplyActionMeta ¶
func ApplyActionMeta(options *ActionSpecOptions, meta ActionMetaEntry)
ApplyActionMeta overlays the non-zero fields of meta onto options. Aliases and RelatedActions are copied defensively so callers may share a metadata table across actions without aliasing the underlying slices. It is a no-op for a zero-value entry, so a missing metadata row leaves the option defaults untouched.
func ApplyListOptions ¶
func ApplyListOptions(opts *gl.ListOptions, page PaginationInput, keyset KeysetPaginationInput)
ApplyListOptions copies offset (PaginationInput) and keyset (KeysetPaginationInput) parameters onto a gl.ListOptions, setting only the values the caller supplied. Pass a zero KeysetPaginationInput for endpoints that only support offset pagination.
func AttachArgumentLimits ¶
AttachArgumentLimits registers a receiving middleware that refuses a tools/call whose arguments nest deeper than maxDepth, before the SDK decodes them.
Why this is not the HTTP body cap ¶
The SDK hands tools/call arguments to middleware as raw bytes and unmarshals them into a map[string]any only when it applies the tool's schema. That decoder (github.com/segmentio/encoding/json, through the SDK's internal json package) has no maximum-nesting guard, where the standard library refuses past 10000, and it is quadratic in nesting depth: measured on v0.5.4, an 18 KB value nested 9000 deep costs over a second of CPU, and a 4 MiB body admits depth in the millions. The decode runs ahead of additionalProperties validation and ahead of the handler, so read-only mode, safe mode and the tool's own logic are all downstream of the burn, and the per-second rate limiter counts requests rather than cycles.
A body-size cap alone only narrows the window: 256 KiB still admits depth 128000. The bound that closes it is on the shape, and it belongs in a receiving middleware rather than in the HTTP front door so that stdio — the transport with no body cap at all — is covered by the same check.
The scan is a single linear pass over bytes the SDK has already framed, so the guard costs about a microsecond on an ordinary call. A non-positive maxDepth disables it; a nil server is a no-op.
func AttachRateLimit ¶
func AttachRateLimit(server *mcp.Server, limiter *RateLimiter)
AttachRateLimit registers a receiving middleware that gates every method that reaches GitLab with the caller's credential, plus `completion/complete` and `tools/list`, when their buckets are empty.
`tools/call`, `resources/read`, `resources/subscribe`, `subscriptions/listen` and `prompts/get` draw on one bucket: each is a request to GitLab on the caller's behalf, and a limit that metered tool calls alone left the other doors open to the same upstream. They are refused differently because they fail differently. A refused tool call is reported as an MCP tool error result (IsError: true) rather than a JSON-RPC error, so the model receives a structured, retryable diagnostic and the agent loop can back off. A refused resource or prompt request is a JSON-RPC error carrying the code that mirrors HTTP 429, since those results have no error flag of their own. A refused completion returns an empty completion instead: the documented contract for this surface is that autocomplete is never blocked, and an error in a completion popup is worse than no suggestions.
`tools/list` draws on a third bucket, refilled a tenth as fast as the tool-call one and holding the same burst (see [catalogDivisor]), and it is metered for a reason none of the others share: it reaches no upstream, it spends the processor of a process many tenants share. On the individual surface one listing marshals about 3.2 MB and is the majority of that surface's processor time, so a client listing in a loop takes the processor its co-tenants are waiting for while the shared bucket, which counts requests to GitLab, sees nothing at all. Keeping the two apart is also what preserves the property the old exemption provided: draining the tool-call bucket never refuses a client's discovery. It is refused like the flagless methods above, with the code that mirrors HTTP 429, because ListToolsResult carries no error flag either. One token is one JSON-RPC request, so a catalog split over several pages costs one per page; the server keeps its whole catalog in one page, for a different reason recorded where PageSize is set.
Every other method (initialize, resources/list, prompts/list) bypasses the limiter: they reach no upstream and cost little to answer, and metering something cheap buys nothing and costs a concept. If limiter is nil, this function is a no-op.
func AttachRateLimitFunc ¶
func AttachRateLimitFunc(server *mcp.Server, resolve func(context.Context) *RateLimiter)
AttachRateLimitFunc is AttachRateLimit for a server whose bucket depends on the request.
It exists because one server now answers for every credential of a configuration shape, while the limit is per credential: a bucket captured at registration would be one budget shared by every tenant, so the noisiest of them would refuse everybody else's calls. The resolver reads the bucket the request's own pool entry owns, and returning nil means this request is not limited, which is what an unbound request on a shape server and the stdio default both want.
func BuildMetaToolSchema ¶
BuildMetaToolSchema returns the input schema for a meta-tool given the chosen mode. Unknown modes silently fall back to MetaParamSchemaOpaque so that callers cannot break the tools/list payload by passing a typo.
- opaque: legacy {action, params:any} envelope (default).
- full: discriminated oneOf with full per-action params schemas.
- compact: discriminated oneOf with descriptions and $defs stripped.
func BuildPipelineInputs ¶
func BuildPipelineInputs(raw map[string]any) (gl.PipelineInputsOption, error)
BuildPipelineInputs converts a JSON-decoded inputs map into the SDK's type-safe gl.PipelineInputsOption. JSON numbers decode to float64 and JSON arrays to []any; both are normalized to the SDK's supported value types (string, float64, bool, []string). An unsupported value type returns an error.
Shared by pipeline creation and manual-job play, which take the same spec:inputs value shapes.
func BuildTargetURL ¶
BuildTargetURL constructs a GitLab web URL for a target resource. Returns "" when the project web URL is empty, the IID is zero, or the target type has no known URL segment.
Supported target types: Issue, MergeRequest, Milestone.
func CancelledResult ¶
func CancelledResult(message string) *mcp.CallToolResult
CancelledResult returns an error tool result indicating the user canceled.
func CanonicalDownloadOutputPath ¶
CanonicalDownloadOutputPath resolves a caller-supplied destination for a file the server is about to write and returns it canonicalized, provided it lies under the working directory, the OS temporary directory, or a directory listed in GITLAB_MCP_ALLOWED_DOWNLOAD_DIRS. It refuses every path when the server is reached over HTTP.
The destination does not exist yet and neither may its parents, so the deepest existing ancestor is what gets resolved through symlinks; the segments below it cannot be symlinks because they do not exist. A leaf that does exist must be a regular file: a symlink there would redirect the write to whatever it names, which is how an "output path" becomes a way to overwrite an SSH key.
Call it again after creating the parent directories. The second call resolves a parent that now exists, which is what turns the check from a promise about the path into a check on the directory being written to.
An existing regular file is overwritten, deliberately, and there is no caller opt-in to refuse it. The audit that produced the symlink check asked for one, and the trade is not worth taking: an opt-in is a new field on DownloadInput, which is a served input schema, so it lands in the tool snapshots, all three llms artifacts, the token-footprint tables and the per-domain docs. What it buys is bounded by two things that are already true. The destination can only be inside the working directory, the OS temporary directory or a directory the operator allow-listed, so the file at risk is one in the workspace rather than one belonging to the system; and under stdio, which is the only transport where a caller-supplied path is honored at all, whatever is driving this server holds its own filesystem write and can overwrite that same file directly. The opt-in would be one bool plus a regeneration pass if the calculus ever changes, but the residual risk it removes is smaller than the surface it adds.
func CanonicalImportArchivePath ¶
CanonicalImportArchivePath validates a local GitLab export archive path and returns the canonical path resolved through symlinks. Archives must be regular .tar.gz files under the current working directory, the OS temporary directory, or a directory listed in GITLAB_MCP_ALLOWED_IMPORT_DIRS.
func CanonicalLocalDirPath ¶
CanonicalLocalDirPath resolves a caller-supplied path to an existing local directory and returns it canonicalized, subject to the same roots and the same HTTP refusal as CanonicalLocalFilePath.
func CanonicalLocalFilePath ¶
CanonicalLocalFilePath resolves a caller-supplied path to an existing local file and returns it canonicalized, provided the resolved path lies under the working directory, the OS temporary directory, or a directory listed in GITLAB_MCP_ALLOWED_UPLOAD_DIRS. It refuses every path when the server is reached over HTTP.
func CatalogListingRPS ¶
CatalogListingRPS is the refill rate a listing draws on when the tool-call bucket is configured at rps.
Exported so the entrypoint can announce both figures at startup: the listing rate is the other number an operator can meet in a refusal, and the divisor that produces it belongs here rather than copied into a log statement. The burst is the configured one, unchanged; [catalogDivisor] records why.
func ClampPollInterval ¶
ClampPollInterval constrains a polling interval to [PollMinInterval, PollMaxInterval], returning PollDefaultInterval when the value is below the minimum.
func ClampPollTimeout ¶
ClampPollTimeout constrains a polling timeout to [PollMinTimeout, PollMaxTimeout], returning PollDefaultTimeout when the value is below the minimum.
func ClassifyError ¶
ClassifyError inspects the error chain and returns a short, human-friendly diagnostic message explaining what went wrong at a high level.
func ClassifyHTTPStatus ¶
ClassifyHTTPStatus returns a semantic description for common HTTP status codes.
func CloneMetaSchemaRoutes ¶
CloneMetaSchemaRoutes returns a snapshot of the route maps: the two map levels are new, so later insertions and deletions in routes do not reach the snapshot, and every route in it is a CloneActionRoute copy.
The schemas are not copied. A route's InputSchema, OutputSchema and ParameterGuidance are frozen and shared by every consumer in the process, which is what lets a catalog cached per configuration serve every server without a copy per server; the copies this function used to make were half of the heap at a hundred pooled credentials. A consumer that must change a schema derives its own through DeriveSchema.
func CloneSchemaMap ¶
CloneSchemaMap returns a deep copy of a JSON Schema map, for a caller that has a reason to mutate one: every schema reachable from a shared catalog is shared with every server in the process and must be copied before it is changed.
func CompileToolSchemas ¶
CompileToolSchemas replaces a projected tool's map-based input and output schemas with process-cached *jsonschema.Schema equivalents. Passing the SDK a stable schema pointer instead of a map removes the per-registration JSON remarshal inside mcp.AddTool and lets a shared mcp.SchemaCache (keyed by pointer identity) skip schema resolution on subsequent registrations — the dominant cost when the HTTP server pool builds a new MCP server per token.
The conversion is a faithful roundtrip: the maps are produced by marshaling jsonschema output, and jsonschema.Schema preserves non-standard keys such as x_destructive. On any marshal error the original map is kept, preserving current behavior. An empty cacheKey disables compilation, so callers that cannot guarantee a content-stable key keep the map path.
func ComputeSHA256 ¶
ComputeSHA256 computes the SHA-256 checksum of a file at the given path and returns the lowercase hex-encoded hash string.
func ComputeSHA256Reader ¶
ComputeSHA256Reader computes the SHA-256 checksum from an arbitrary io.Reader and returns the lowercase hex-encoded hash string.
func ConfirmAction ¶
func ConfirmAction(ctx context.Context, req *mcp.CallToolRequest, message string) (*mcp.CallToolResult, error)
ConfirmAction uses MCP elicitation to ask the user for confirmation before a destructive action. Returns nil if the user confirmed or elicitation is unsupported (fallback: action proceeds — destructive callers must go through ConfirmDestructiveAction, which fails closed in that case). Returns an error tool result if the user declined or canceled. On sessions negotiated at protocol >= 2026-07-28 the confirmation travels as a multi round-trip input request (SEP-2322): the first pass returns an input-required result and the client retries the call with the user's answer attached.
func ConfirmDestructiveAction ¶
func ConfirmDestructiveAction(ctx context.Context, req *mcp.CallToolRequest, params map[string]any, message string) (*mcp.CallToolResult, error)
ConfirmDestructiveAction checks whether a destructive action should proceed. The confirmation flow is:
- GITLAB_MCP_YOLO_MODE / AUTOPILOT env var → skip confirmation entirely
- Explicit "confirm": true in params → skip confirmation
- MCP elicitation supported → ask user interactively
- Elicitation unsupported and no confirm param → fail closed: return an error result prompting the caller to re-send with confirm: true
Returns nil, nil if the action should proceed. Returns a non-nil *mcp.CallToolResult if the action was canceled or requires explicit confirmation.
The error return is for protocol faults rather than tool outcomes: a requestState this server did not issue, one carrying a version it does not know, or an inputResponses value of the wrong type. "Protocol errors (malformed JSON, invalid schema, internal server errors) SHOULD return a JSON-RPC error response with an appropriate error code and message", and none of those three is something the model wrote or can correct — putting them in a tool result asks it to fix a field its client mangled. Everything a caller can act on (declined, cancelled, a client that cannot prompt) stays in the result, which is where MCP wants tool-level failure.
func ContainsAny ¶
ContainsAny returns true if err.Error() contains any of the substrings.
func ContextWithRequest ¶
ContextWithRequest returns a derived context carrying the MCP request.
func CopyReadOnlyMetaAnnotations ¶
func CopyReadOnlyMetaAnnotations() *mcp.ToolAnnotations
CopyReadOnlyMetaAnnotations returns a copy of ReadOnlyMetaAnnotations so callers never alias the shared singleton.
Note on ToolAnnotations.Title: it is deliberately left unset here and in DeriveAnnotations. Since MCP 2025-06-18 a Tool carries its own top-level Title, and the display-name precedence is Title → Annotations.Title → Name, so setting both only duplicates the string in every tools/list response. The individual-tool projection has always relied on the top-level Title alone; the meta surface now matches it.
func CreateDownloadOutputFile ¶
CreateDownloadOutputFile creates the destination a download writes to, refusing a symlink at the leaf where the platform can.
CanonicalDownloadOutputPath refuses a destination that is already a symlink, but it refuses a path, and the file is created by a later syscall: a local principal who can write in an allowed root can put a symlink there in between and redirect the write to whatever the server may overwrite. The creation is the only place that race can be closed, so it happens here rather than at the call site.
func DefuseHintsHeading ¶
DefuseHintsHeading rewrites every copy of the server's guidance heading in s so it can no longer pass for one. Text with no such heading is returned unchanged.
func DeriveAnnotations ¶
func DeriveAnnotations(routes ActionMap) *mcp.ToolAnnotations
DeriveAnnotations computes tool-level MCP annotations from the route map. If any route is destructive, returns a copy of MetaAnnotations (DestructiveHint: true). If all routes are non-destructive, returns a copy of NonDestructiveMetaAnnotations. Each call returns a fresh copy to avoid aliasing the shared singletons.
func DeriveSchema ¶
DeriveSchema returns transform applied to schema, where derive builds the result and transform names the rewrite it performs. The name must identify the rewrite completely: two calls with the same name on the same schema are assumed to want the same output, so any parameter the rewrite depends on belongs in the name.
For a schema registered with ShareSchema the result is built once per process, registered as shared in turn, and returned to every later caller; derive must therefore never mutate its input. For any other schema the result is built privately on every call, exactly as before this memo existed. A transform reapplied to its own output returns that output.
func DetectRichContent ¶
DetectRichContent scans a GFM body for non-portable features that may not render correctly outside GitLab (mermaid diagrams, math blocks, raw HTML). Returns a comma-separated list of detected features or an empty string.
func EmbedCanonicalResource ¶
func EmbedCanonicalResource(result *mcp.CallToolResult, template string, params map[string]any, value any)
EmbedCanonicalResource appends the canonical resource of a successful action result: the template is the one the action's spec declares, expanded from the parameters the call carried, and the payload is the JSON form of the output. It is a no-op without a template, on an error result, when a variable is missing, or when embedding is disabled, so every dispatcher can call it unconditionally after formatting.
func EmbedResource ¶
func EmbedResource(result *mcp.CallToolResult, uri, mimeType, text string)
EmbedResource appends an EmbeddedResource content block to result that references the canonical MCP resource URI for the entity returned by the tool. mimeType should typically be "application/json" with text containing a compact JSON serialization of the entity (or empty if the resource is addressable but the body is large).
When result is nil, the URI is empty, or the global toggle is disabled, EmbedResource is a no-op. No further URI validation is performed; callers are responsible for passing well-formed URIs that match an MCP resource template registered with the server.
func EmbedResourceJSON ¶
func EmbedResourceJSON(result *mcp.CallToolResult, uri string, value any)
EmbedResourceJSON marshals value as JSON and embeds the result with MIME type application/json. Marshaling errors are dropped silently — the tool result is still returned with text and StructuredContent so the LLM has a usable response.
func EmbeddedResourcesEnabled ¶
func EmbeddedResourcesEnabled() bool
EmbeddedResourcesEnabled reports the current state of the global toggle. Exposed for tests; production code should call EmbedResource directly.
func EnableEmbeddedResources ¶
func EnableEmbeddedResources(enabled bool)
EnableEmbeddedResources toggles the global EmbedResource behavior. When false, EmbedResource is a no-op, preserving the legacy two-block (text + structuredContent) tool result shape.
func EnrichPaginationConstraints ¶
EnrichPaginationConstraints registers a receiving middleware that walks every tools/list response and injects JSON Schema numeric constraints on the standard pagination property names so LLM clients see the bounds directly in tools/list rather than only through prose in the description.
The middleware operates per property name:
- `page` gets `minimum: 1`
- `per_page` gets `minimum: 1` and `maximum: 100`
Existing constraints are preserved: if a schema already declares `minimum` or `maximum` on these properties the middleware leaves them untouched so domain-specific overrides remain authoritative. Only nodes whose `type` is `integer` or `number` (or unset, defaulting to integer per the Go SDK's int-typed pagination input) are modified, so unrelated properties named `page` on a custom schema cannot be silently mutated.
The transformation runs after LockdownInputSchemas so it sees the same fully-populated schema set every list/tools response carries.
Concurrency. As with LockdownInputSchemas, the mutation runs through [onFirstToolsList], whose `sync.Once` guard prevents concurrent `tools/list` calls from racing on the shared *Tool.InputSchema maps.
Sharing. Like the lockdown, this derives the enriched schema instead of changing the one in place (see DeriveSchema): the lockdown's output is shared across servers, and so is this one.
func ErrFieldRequired ¶
ErrFieldRequired returns a validation error indicating that a required field is missing or empty. It produces the message "<field> is required", which is the standard validation pattern used across all tool handlers.
func ErrInvalidEnum ¶
ErrInvalidEnum returns a validation error indicating that a field value is not one of the allowed options. The error message lists the valid values to guide LLMs toward correct parameter usage.
func ErrRequiredInt64 ¶
ErrRequiredInt64 returns a formatted error when a required int64 field is missing or has its zero value. This catches silent deserialization failures in meta-tool dispatch, where a misnamed JSON parameter (e.g. "mr_iid" instead of "merge_request_iid") is silently ignored and the field defaults to 0.
func ErrRequiredString ¶
ErrRequiredString returns a formatted error when a required string field is missing or empty. Like ErrRequiredInt64, this guides LLMs to use the exact parameter name when silent deserialization failures occur.
func ErrorResult ¶
func ErrorResult(message string) *mcp.CallToolResult
ErrorResult builds a standard error mcp.CallToolResult with IsError set. It returns the error message as Markdown content for display.
func ErrorResultMarkdown ¶
func ErrorResultMarkdown(domain, action string, err error) *mcp.CallToolResult
ErrorResultMarkdown creates an MCP tool error result with Markdown formatting. The result has IsError = true for MCP clients that distinguish error results.
func EscapeConsentValue ¶
EscapeConsentValue renders caller-controlled text for a consent dialog.
"MCP servers requesting elicitation SHOULD NOT include URLs intended to be clickable in any field of a form mode elicitation request." The dialog is where a person decides whether to allow an action, so what it shows has to be the server's own words plus data that cannot pass for them. Interpolating raw values did not meet that: a project path of
demo/proj\n\n**SECURITY NOTICE** Verify at https://evil.example/verify
reached the user as bold text and a link inside the question they were being asked, all of it attacker-supplied by way of the model.
Three things happen here. Line breaks collapse, so a value cannot add paragraphs to the dialog's structure. URL schemes are defanged to https[:]//, which stays legible while leaving nothing for a client to linkify. And the result is fenced in backticks, so emphasis, headings and link syntax inside it are shown rather than rendered — using a fence longer than any run of backticks in the value, the same rule Markdown itself uses for nesting code.
This is escaping, not sanitizing: the text still reaches the user, and should, since a project path they cannot read is no use to them deciding. What it can no longer do is impersonate the server asking the question.
func EscapeMdHeading ¶
EscapeMdHeading sanitizes a user-controlled string that will be interpolated into a Markdown heading (e.g. `## Project: {name}`). It strips leading '#' characters that could promote/demote the heading level and collapses newlines into spaces so the heading stays on one line.
The opening angle bracket is escaped for the reason EscapeMdTableCell gives, and in the same entity form: a heading is the other place a formatter puts a GitLab-authored name, all 44 call sites interpolate one value into a heading the server wrote, and the same name should not turn into a live tag in a heading after being neutralized in a cell.
func EscapeMdLinkDestination ¶
EscapeMdLinkDestination renders url as the destination of a Markdown link.
func EscapeMdLinkLabel ¶
EscapeMdLinkLabel renders s as the visible text of a Markdown link.
A label is not a cell: escaping the pipe keeps the row intact and does nothing about the bracket. An issue titled
Fix login](http://attacker.invalid/x)
closed the label after "Fix login" and opened a destination of its own, so a reader saw the issue's title linking to a host that is not GitLab — on this server's own instruction, since HintPreserveLinks tells the model to keep the clickable links so the user can navigate to GitLab.
func EscapeMdTableCell ¶
EscapeMdTableCell escapes characters in s that would break a Markdown table row. Pipes are replaced with the HTML entity | and newlines/carriage-returns are replaced with a space so the cell stays on a single row. Control characters are dropped by StripControlBytes.
The opening angle bracket is an entity too, for the reason [mdLinkLabelEscaper] gives: a renderer takes raw HTML ahead of whatever surrounds it, so a title of
<a href="http://attacker.invalid/x">Fix login</a>
arrives as a working link to a host that is not GitLab. MdTitleLink closed that for the link case and returns this escaper's output untouched when the item has no URL, which is the ordinary shape for something with no page of its own, and around 266 formatters call this one directly.
An entity rather than the backslash the label escaper uses, because MdTitleLink pipes a cell through that escaper: a backslash arriving there is escaped again into a visible one, where < passes through untouched and renders as the character it always was.
Only '<' is escaped. Everything a renderer obeys instead of reading opens with it (a tag, a comment, an autolink), so that is the whole of the containment, and '>' is left alone because callers compose cells of their own: a merge request's branch cell reads "feature/fix -> develop", and entity-encoding the arrow the server itself wrote damages output that no untrusted text ever touched.
func ExceedsJSONDepth ¶
ExceedsJSONDepth reports whether raw nests containers deeper than limit.
Convenience wrapper over JSONDepthScanner for a value that is already whole in memory.
func ExecGraphQLDestroyNote ¶
func ExecGraphQLDestroyNote(ctx context.Context, gql gl.GraphQLInterface, op, hint, query, noteGID string) error
ExecGraphQLDestroyNote runs the destroyNote work item mutation, applying the shared error conventions: transport errors are wrapped with op + hint and the first mutation payload error becomes "op: message".
func ExecGraphQLNoteMutation ¶
func ExecGraphQLNoteMutation[N any](ctx context.Context, gql gl.GraphQLInterface, m GraphQLNoteMutation) (*N, error)
ExecGraphQLNoteMutation runs a work item note mutation and returns the mutated note node decoded as N, applying the shared error conventions described on GraphQLNoteMutation.
func ExpandResourceURI ¶
ExpandResourceURI fills a canonical resource URI template from an action's parameters. Each {name} is replaced by the path-escaped value of the parameter of that name, so a project given as "group/project" lands in the URI as group%2Fproject, which is the form the resource templates accept; {+name} keeps the slashes of a path-valued parameter, escaping each segment. It reports false when the template is empty or any variable is absent or empty, so a result whose identifier the caller never supplied gets no resource block instead of a URI with a hole in it.
func ExplicitConfirmFromRequest ¶
func ExplicitConfirmFromRequest(req *mcp.CallToolRequest) bool
ExplicitConfirmFromRequest reports whether the caller set the reserved confirm key on this tool call.
The key never reaches a typed action input: [stripReservedKeys] removes it before strict unmarshalling so it cannot trip the unknown-field rejection. A handler that needs to know whether the caller confirmed — because its destructiveness depends on runtime state and cannot be declared on the route — must therefore read it from the raw arguments, which this does for both call shapes: flat on individual tools, and nested under params on the dispatcher surfaces.
func ExtractGitLabMessage ¶
ExtractGitLabMessage extracts the specific error message from a GitLab ErrorResponse in the error chain. Returns empty string if not found, if the message only repeats the HTTP status text (e.g. "405 Method Not Allowed"), or if it is an unparsed upstream response body rather than a GitLab message.
What survives is flattened onto one line and truncated to 300 characters. GitLab's messages routinely quote input an attacker chose — a branch name, a path, a title — so the span has to stay a span: with its newlines intact it could add structure to the error text a model reads.
func ExtractHints ¶
ExtractHints parses the "💡 Next steps" section from a Markdown tool response and returns the individual hint strings. Returns nil when the section is absent.
Only a section in a position the server could have written it is read, and there are exactly two: WriteHints is called either on an empty builder, so the section opens the response (nineteen list formatters do this), or after the body, so it closes it. A section anywhere in between is content that happens to look like guidance — a README, a job log, a project description — and content does not get to speak as the server. This used to be the first match anywhere in the response, which is what let a file's contents fill next_steps.
func FieldTiers ¶
FieldTiers returns a map from top-level JSON field name to the minimum licensing tier declared via the `tier:"premium"` / `tier:"ultimate"` struct tag on the input/output type rt. Fields without a tier tag (the common case, Free) are omitted. Anonymous embedded structs are flattened, mirroring the JSON field promotion used by [secretJSONFieldNames]. The result drives per-instance-tier schema pruning so Free/Premium instances never see fields that require a higher tier.
func FormatCICDVariableCollectionMarkdown ¶
func FormatCICDVariableCollectionMarkdown[T any](variables []T, pagination PaginationOutput, convert func(T) CICDVariableMarkdown, title, emptyMessage string, includeEnvironmentScope bool, hints ...string) string
FormatCICDVariableCollectionMarkdown maps package-specific CI/CD variable outputs and renders them as a shared Markdown list.
func FormatCICDVariableDetailMarkdown ¶
func FormatCICDVariableDetailMarkdown(v CICDVariableMarkdown, title string, includeEnvironmentScope bool) string
FormatCICDVariableDetailMarkdown renders a CI/CD variable with standard update/delete next-step hints shared by project and group variables.
func FormatCICDVariableListMarkdown ¶
func FormatCICDVariableListMarkdown(variables []CICDVariableMarkdown, pagination PaginationOutput, opts CICDVariableListMarkdownOptions) string
FormatCICDVariableListMarkdown renders CI/CD variables as a Markdown table.
func FormatCICDVariableMarkdown ¶
func FormatCICDVariableMarkdown(v CICDVariableMarkdown, opts CICDVariableMarkdownOptions) string
FormatCICDVariableMarkdown renders a single CI/CD variable as a Markdown detail table.
func FormatDiscussionListMarkdown ¶
func FormatDiscussionListMarkdown(discussions []DiscussionMarkdown, opts DiscussionListMarkdownOptions) string
FormatDiscussionListMarkdown renders discussion threads as Markdown.
func FormatDiscussionMarkdown ¶
func FormatDiscussionMarkdown(discussion DiscussionMarkdown, hints ...string) string
FormatDiscussionMarkdown renders a single discussion thread as Markdown.
func FormatDiscussionNoteMarkdown ¶
func FormatDiscussionNoteMarkdown(note DiscussionNoteMarkdown, hints ...string) string
FormatDiscussionNoteMarkdown renders a single discussion note as Markdown.
func FormatGID ¶
FormatGID builds a GitLab Global ID string from a type name and numeric ID.
FormatGID("Vulnerability", 42) → "gid://gitlab/Vulnerability/42"
func FormatGraphQLDiscussionListMarkdown ¶
func FormatGraphQLDiscussionListMarkdown[T any](discussions []T, pagination GraphQLPaginationOutput, convert func(T) DiscussionMarkdown, title, emptyMessage string, hints ...string) string
FormatGraphQLDiscussionListMarkdown maps GraphQL discussion outputs and renders them with cursor pagination metadata.
func FormatGraphQLForwardPagination ¶
func FormatGraphQLForwardPagination(p GraphQLForwardPaginationOutput, shown int) string
FormatGraphQLForwardPagination renders the pagination metadata of a forward-only connection, which never names a previous page.
func FormatGraphQLPagination ¶
func FormatGraphQLPagination(p GraphQLPaginationOutput, shown int) string
FormatGraphQLPagination renders cursor-based pagination metadata as a Markdown summary line, suitable for appending to list tool responses.
func FormatISOTimePtr ¶
FormatISOTimePtr renders an optional *gl.ISOTime as YYYY-MM-DD, or "" when nil.
func FormatLabelListMarkdown ¶
func FormatLabelListMarkdown(labels []LabelMarkdown, pagination PaginationOutput, opts LabelMarkdownOptions) string
FormatLabelListMarkdown renders project or group labels as a paginated table.
func FormatLabelListMarkdownFunc ¶
func FormatLabelListMarkdownFunc[T any](labels []T, pagination PaginationOutput, opts LabelMarkdownOptions, convert func(T) LabelMarkdown) string
FormatLabelListMarkdownFunc renders labels after mapping domain-specific outputs to the shared Markdown view.
func FormatLabelMarkdown ¶
func FormatLabelMarkdown(label LabelMarkdown, opts LabelMarkdownOptions) string
FormatLabelMarkdown renders a project or group label as a Markdown summary.
func FormatNoteListMarkdown ¶
func FormatNoteListMarkdown(notes []NoteMarkdown, pagination PaginationOutput, opts NoteListMarkdownOptions) string
FormatNoteListMarkdown renders a list of GitLab notes as Markdown.
func FormatNoteMarkdown ¶
func FormatNoteMarkdown(note NoteMarkdown, opts NoteMarkdownOptions) string
FormatNoteMarkdown renders a single GitLab note as Markdown.
func FormatPagination ¶
func FormatPagination(p PaginationOutput) string
FormatPagination renders pagination metadata as a compact Markdown line.
func FormatRESTDiscussionListMarkdown ¶
func FormatRESTDiscussionListMarkdown[T any](discussions []T, pagination PaginationOutput, convert func(T) DiscussionMarkdown, title, emptyMessage string, hints ...string) string
FormatRESTDiscussionListMarkdown maps REST discussion outputs and renders them with offset pagination metadata.
func FormatStorageMoveCollectionMarkdown ¶
func FormatStorageMoveCollectionMarkdown[T any](moves []T, pagination PaginationOutput, convert func(T) StorageMoveMarkdown, title, emptyMessage, entityColumn string) string
FormatStorageMoveCollectionMarkdown maps package-specific storage moves and renders them as a shared Markdown list.
func FormatStorageMoveDetailMarkdown ¶
func FormatStorageMoveDetailMarkdown(move StorageMoveMarkdown, title string, hints ...string) string
FormatStorageMoveDetailMarkdown renders one repository storage move as a Markdown detail table.
func FormatStorageMoveListMarkdown ¶
func FormatStorageMoveListMarkdown(moves []StorageMoveMarkdown, opts StorageMoveListMarkdownOptions) string
FormatStorageMoveListMarkdown renders repository storage moves as a Markdown table with the domain-specific entity column supplied by the caller.
func FormatTarget ¶
FormatTarget builds a Markdown table cell for a typed target resource. When targetURL is non-empty, the result is a clickable link like [Issue #42](url). When empty, the label is returned as plain text. Returns "" if there is nothing to display.
func FormatTemplateAttributeListMarkdown ¶
func FormatTemplateAttributeListMarkdown(items []TemplateAttributeListMarkdownItem, opts TemplateAttributeListMarkdownOptions) string
FormatTemplateAttributeListMarkdown renders a common Key/Name/Attribute template list without changing the JSON schema used by existing template tools.
func FormatTemplateCollectionMarkdown ¶
func FormatTemplateCollectionMarkdown[T any](templates []T, pagination PaginationOutput, convert func(T) TemplateMarkdown, title, emptyMessage string, hints ...string) string
FormatTemplateCollectionMarkdown maps package-specific template outputs and renders them as a shared Markdown list.
func FormatTemplateContentMarkdown ¶
FormatTemplateContentMarkdown renders a GitLab template body inside a fenced code block.
func FormatTemplateDetailMarkdown ¶
func FormatTemplateDetailMarkdown(detail TemplateDetailMarkdown) string
FormatTemplateDetailMarkdown renders a shared template detail layout.
func FormatTemplateListMarkdown ¶
func FormatTemplateListMarkdown(templates []TemplateMarkdown, pagination PaginationOutput, opts TemplateListMarkdownOptions) string
FormatTemplateListMarkdown renders GitLab template list entries as Markdown.
func FormatTime ¶
FormatTime converts an RFC3339 timestamp string to a human-readable format ("2 Jan 2006 15:04 UTC"), falling back to the date-only layout and then to the string it was given.
Every one of this function's callers writes the result straight into Markdown, so the fallback runs it through EscapeMdTableCell rather than returning it as it arrived. A value that reaches the fallback is by definition not a timestamp, which leaves only two ways to get there: a field this server formatted itself and a field carrying whatever GitLab put in it. Returning the second verbatim put a pipe, a newline and a '<' into a table cell from 155 call sites, and telling each of those call sites to escape a timestamp would have taught the next reader that a date needs escaping. Escaping here costs nothing that renders: neither layout's output contains any character the escaper touches.
func FormatTimePtr ¶
FormatTimePtr renders an optional *time.Time as RFC 3339, or "" when nil.
func GraphQLMutationError ¶
GraphQLMutationError formats mutation payload errors, if any.
func GraphQLTopLevelError ¶
func GraphQLTopLevelError(operation string, responseErrors []GraphQLError) error
GraphQLTopLevelError formats top-level GraphQL response errors, if any.
func HasRegisteredMarkdownFormatter ¶
HasRegisteredMarkdownFormatter reports whether a Markdown formatter has been registered for the given Go type. Accepts either a reflect.Type (the canonical lookup path — matches spec.Route.OutputType) or a value of any kind (used by tests). Pointer types are dereferenced to their element type for the registry lookup. Returns false for nil, for the special "interface" reflect.Type returned by reflect.TypeOf on a nil/untyped interface, and for unregistered types.
This is the authoritative source for "is there a Markdown formatter for this output type?" queries from external tools (e.g. cmd/audit_discovery_completeness uses it to gate the `missing_next_steps` check).
func IdentityToContext ¶
func IdentityToContext(ctx context.Context, id UserIdentity) context.Context
IdentityToContext stores a UserIdentity in the context. Used at startup in stdio mode to make the identity available to all tool handlers.
func ImageMIMEType ¶
ImageMIMEType returns the MIME type for image file extensions. Returns an empty string for non-image files.
func IndividualToolFromActionSpec ¶
func IndividualToolFromActionSpec(spec ActionSpec, opts IndividualToolProjectionOptions) (*mcp.Tool, error)
IndividualToolFromActionSpec projects canonical action metadata into an MCP tool definition for the individual-tool surface.
func IndividualToolFromSpecs ¶
func IndividualToolFromSpecs(specs []ActionSpec, individualName string, opts IndividualToolProjectionOptions) (*mcp.Tool, error)
IndividualToolFromSpecs projects the spec that owns an individual tool name.
func InputRequiredResultFromError ¶
func InputRequiredResultFromError(err error) (*mcp.CallToolResult, bool)
InputRequiredResultFromError extracts the input-required tool result from a handler error produced by elicitation.Flow.PendingError. Surface dispatchers call this before logging so a pending multi round-trip exchange is returned to the client instead of being reported as a handler failure.
func InternalError ¶
InternalError marks an error as JSON-RPC -32603: an upstream call failed or a response would not decode, and there is nothing the caller can change.
func InvalidParams ¶
InvalidParams marks an error as JSON-RPC -32602: the caller sent something missing, empty or unparseable, and has to change it.
func IsBinaryFile ¶
IsBinaryFile returns true when the filename has a known binary extension that is not an image. Returns false for text and image files.
func IsDeleteToolName ¶
IsDeleteToolName reports whether name contains or ends with "delete".
func IsHTTPStatus ¶
IsHTTPStatus reports whether err wraps a GitLab ErrorResponse with the given HTTP status code. Useful for handling specific API responses like 404 (feature not available on CE) or 403 (insufficient permissions).
func IsImageFile ¶
IsImageFile returns true when the filename has an image extension. Comparison is case-insensitive. Returns false for empty strings.
func IsNotFound ¶
IsNotFound reports whether err represents a 404 Not Found, either via a structured GitLab ErrorResponse status code or via a plain-text error message from client-go (which may contain "404 Not Found" as text).
func IsReadToolName ¶
IsReadToolName reports whether name ends with a read-only suffix.
func IsTerminalStatus ¶
IsTerminalStatus reports whether a CI/CD status represents a finished state.
func IsYOLOMode ¶
func IsYOLOMode() bool
IsYOLOMode returns true when destructive action confirmation should be skipped entirely. It reads GITLAB_MCP_YOLO_MODE (or its old spelling YOLO_MODE, warned about at startup like every other renamed setting) and falls back to AUTOPILOT, a convention other agent tooling sets. Any truthy value (1, true, yes — case-insensitive) enables the mode.
func IssueStateEmoji ¶
IssueStateEmoji returns the Markdown emoji for an issue state.
func ListRegisteredTools ¶
func ListRegisteredTools(ctx context.Context, server *mcp.Server, clientName string) ([]*mcp.Tool, error)
ListRegisteredTools lists tools registered on a server through an ephemeral in-memory MCP client session.
func LocalFilesystemAccessAllowed ¶
func LocalFilesystemAccessAllowed() bool
LocalFilesystemAccessAllowed reports whether caller-supplied local paths are honored in this process.
func LockdownInputSchemas ¶
LockdownInputSchemas registers a receiving middleware that rewrites tools/list responses so every tool's inputSchema declares `additionalProperties: false` at the root and on any nested object schema reachable through "properties", "items", "anyOf", "oneOf", or "allOf". It also strips jsonschema tag metadata such as ",required" from property descriptions after the SDK generates schemas. Schemas converted from SDK types are stored back as map[string]any values, so callers inspecting tools after this middleware runs should not expect the original concrete schema type.
Background. The MCP specification (2025-11-25 §server/tools) requires inputSchema to be a valid JSON Schema object but does not mandate `additionalProperties`. JSON Schema 2020-12 default semantics treat an unspecified `additionalProperties` as `true`, which silently accepts unknown fields. When an LLM mistypes an argument name (e.g. "projetc_id" instead of "project_id"), the server forwards an empty value to the handler, which then fails with a confusing "missing parameter" error rather than the actionable "unknown property" diagnostic the LLM needs to self-correct.
Schemas that already declare `additionalProperties` (true or false) at a given level are left untouched, so meta-tool router branches that intentionally permit unknown fields for forward compatibility remain intact.
Concurrency. The MCP Go SDK does not expose a public API to enumerate registered tools at startup, so the transformation runs inside a `tools/list` middleware via [onFirstToolsList], which guards the mutation with a `sync.Once`.
Sharing. The schema a tool carries at that point is never changed in place: a compiled schema is shared by every server in the process through the compile cache, and a map may be shared through a catalog. The locked down form is derived from it, once per process for a shared schema (see DeriveSchema), so a thousand pooled servers list one set of maps.
func LogToolCallAll ¶
func LogToolCallAll(ctx context.Context, req *mcp.CallToolRequest, tool string, start time.Time, result any, err error)
LogToolCallAll logs a tool call to stderr (slog). It is the standard logging function for all tool handlers. When the request contains authenticated user identity (any mode), it includes the user in the log output for audit trail purposes.
result is what the handler returned, taken so the record can say whether the call actually succeeded. A handler that reports failure in its result rather than as a Go error, which NotFoundResult does in every get handler that uses it, used to be logged as "tool call completed" with nothing distinguishing it from a call that worked. An operator could not compute an error rate from this stream, because the stream did not contain one.
func LogToolRefusal ¶
func LogToolRefusal(ctx context.Context, req *mcp.CallToolRequest, tool, reason string)
LogToolRefusal records a call the server declined to run.
These paths returned an error result to the model and wrote nothing at all: safe-mode previews, unknown actions, missing parameters and unconfirmed destructive actions each returned before reaching LogToolCallAll. They are refusals rather than failures, so they are INFO, and they are exactly the events an operator most wants to count: a deployment refusing every third call because its clients have not learned the parameter shape looks identical to a healthy one from the logs.
It is the second half of the observability item ADR-0011 already accepted: "add observability for find query, selected action, validation failure, policy block, and destructive confirmation events". Only the destructive one was delivered.
func LookupMetaActionSchema ¶
func LookupMetaActionSchema(routes map[string]ActionMap, tool, action string) (map[string]any, bool)
LookupMetaActionSchema returns the per-action params schema for a tool/action pair.
func MRStateEmoji ¶
MRStateEmoji returns the Markdown emoji for a merge request state.
func MakeMetaHandler ¶
func MakeMetaHandler(toolName string, routes ActionMap, formatResult FormatResultFunc) func(ctx context.Context, req *mcp.CallToolRequest, input MetaToolInput) (*mcp.CallToolResult, any, error)
MakeMetaHandler creates a generic MCP tool handler that dispatches to action routes. The formatResult function converts the action result into an MCP response. If formatResult is nil, a default JSON formatter is used.
Destructive actions (delete, remove, revoke, unprotect, etc.) are automatically intercepted with a user confirmation prompt via MCP elicitation before execution. Confirmation can be bypassed with GITLAB_MCP_YOLO_MODE/AUTOPILOT env vars or by passing "confirm": true in the action params.
func MarkdownCodeFence ¶
MarkdownCodeFence returns a backtick fence long enough to contain content: three backticks, or one more than the longest run inside it.
A fixed three-backtick fence is closed by any content that contains one, and the content here is a repository file, a job log, a snippet or a diff — written by whoever can push a branch or run a pipeline. Everything after the run they wrote renders as live Markdown at the top level of the response: headings, links, and the server's own guidance section. Sizing the fence to the body is the rule Markdown itself uses for nesting code, and it is why this helper exists rather than a literal.
func MarkdownFencedBlock ¶
MarkdownFencedBlock renders content as a complete fenced code block: a fence sized by MarkdownCodeFence, the info string, the body, and the matching closing fence on its own line. Pass an empty language for a bare fence.
Prefer it over writing a fence by hand wherever the body is GitLab-authored.
func MarkdownForResult ¶
func MarkdownForResult(result any) *mcp.CallToolResult
MarkdownForResult resolves a tool output to its Markdown mcp.CallToolResult. Returns nil for nil input (caller should handle), returns nil when no formatter is registered for the concrete type.
func MarkdownFormatterCount ¶
func MarkdownFormatterCount() int
MarkdownFormatterCount returns the number of registered Markdown formatters (string + result variants). Useful for sanity checks in tests and tools that need to know "are formatters even loaded?".
func MarkdownTableHeader ¶
MarkdownTableHeader returns a Markdown table header followed by a standard separator row for the supplied column labels.
func MarkdownTableRow ¶
MarkdownTableRow returns a Markdown table row for the supplied cell values.
func MarkdownTableSeparator ¶
MarkdownTableSeparator returns a standard left-aligned Markdown separator row for the requested number of columns.
func MdTitleLink ¶
MdTitleLink returns the title as a Markdown link if url is non-empty, otherwise returns the escaped title. Suitable for table cells. Both halves are escaped, so neither the title nor the URL can end the link they are in.
func MergeVariables ¶
MergeVariables merges multiple variable maps into a single map. Later maps override earlier ones for duplicate keys.
func MetaActionSchema ¶
func MetaActionSchema(route ActionRoute) map[string]any
MetaActionSchema returns the params schema served for one meta-tool action: the route's input schema with the destructive confirmation property and the parameter guidance added, or a permissive placeholder when the route captured no schema. For a route of a shared catalog the result is built once per process and shared; the caller must not mutate it.
func MetaParamSchemaMode ¶
func MetaParamSchemaMode() string
MetaParamSchemaMode reports the meta-tool input schema strategy currently selected by SetMetaParamSchemaMode: "opaque", "compact" or "full". Callers that memoize a registered surface must key on it, because the same registration produces different input schemas under each mode.
func MetaSchemaURI ¶
MetaSchemaURI returns the resource URI for a tool/action schema.
func MetaToolDescriptionPrefix ¶
MetaToolDescriptionPrefix builds a fixed-format header that should be prepended to a meta-tool's user-supplied description. The header gives LLMs a literal JSON usage example based on a representative action and points at the gitlab://tools resource for per-action params schemas. Returns an empty string when routes is empty so callers degrade gracefully rather than emit a malformed header.
func MetaToolOutputSchema ¶
MetaToolOutputSchema returns the shared action-dispatch output schema used by meta-tools.
func MetaToolSchema ¶
MetaToolSchema builds a JSON Schema for a meta-tool with the action field constrained to an enum of valid action names extracted from the routes map. Setting this as Tool.InputSchema ensures the LLM sees the exact list of valid actions in the schema, enabling first-try action selection.
The strategy used (opaque, compact, full) is read from the package-level mode set via SetMetaParamSchemaMode. Default is opaque. Callers that always want the opaque envelope regardless of global configuration should invoke BuildMetaToolSchema directly.
The opaque envelope is small and is compiled and cached by name downstream (see CompileToolSchemas). The compact and full envelopes embed every action's params schema and are served as maps, so they are shared as maps, one per distinct routes map (see [metaEnvelopeFor]).
func MustIndividualToolFromSpecs ¶
func MustIndividualToolFromSpecs(specs []ActionSpec, individualName string, opts IndividualToolProjectionOptions) *mcp.Tool
MustIndividualToolFromSpecs projects an individual tool or panics on invalid registration metadata. Use it from catalog-backed startup paths where a missing spec is a programming error.
func NormalizeActionAlias ¶
NormalizeActionAlias returns the canonical action name for common shortened action spellings when the canonical action exists on the target meta-tool.
func NormalizeActionAliasForParams ¶
func NormalizeActionAliasForParams(toolName, action string, params map[string]any, routes ActionMap) string
NormalizeActionAliasForParams returns the canonical action name for aliases that depend on the submitted parameter shape.
func NormalizeParamAliasesForSchema ¶
NormalizeParamAliasesForSchema applies the same compatibility aliases used by UnmarshalParams, driven by a JSON Schema properties map instead of a Go struct type. It is used by evaluation code that validates simulated calls.
func NormalizeText ¶
NormalizeText replaces literal escape sequences with real characters. MCP clients may send text with literal backslash-n instead of real newlines when the JSON transport double-escapes the input.
Replacement order matters to avoid cascading conversions:
- `\\` -> `\` (double-escaped backslash first, so `\\n` becomes `\` + literal n, not a newline)
- `\r\n` -> `\n` (CRLF before individual CR/LF to avoid double-replacement)
- `\r` -> `\n` (standalone carriage return)
- `\n` -> newline (the most common case)
- `\t` -> tab
func NotFoundResult ¶
func NotFoundResult(resource, identifier string, hints ...string) *mcp.CallToolResult
NotFoundResult creates an informational MCP tool result for resources that do not exist or are not accessible. Instead of returning a Go error (which would be logged as ERROR and produce an opaque error message for the LLM), this returns a structured Markdown result with actionable next steps.
The result has IsError=true to signal the tool could not fulfill the request, but the content is rich and helpful — the LLM can act on the suggestions.
Use this in register.go handler closures when IsHTTPStatus(err, 404) is true for "get" operations. Pass nil error back to the SDK so the call is logged at INFO level instead of ERROR.
func OpenAndValidateFile ¶
OpenAndValidateFile opens a caller-supplied local file for reading after confining it to the allowed upload directories, resolving it through every symlink on the way, and validating that what the resolved path names is a regular file of at most maxSize bytes. Returns the open file handle and its FileInfo.
The containment is the point: file_path names a path on the machine the server runs on, and the caller — a model following an instruction that may have come from an issue description or a job log — is not the person whose files these are. See CanonicalLocalFilePath for the roots.
func OpenFileOrBase64Source ¶
func OpenFileOrBase64Source(op, filePath, contentBase64 string) (reader io.Reader, size int64, cleanup func(), err error)
OpenFileOrBase64Source resolves the mutually-exclusive file_path / content_base64 upload input pair into a streaming reader plus the source size and a cleanup func the caller must defer. file_path is opened and validated against the configured upload size limit and streamed without buffering; content_base64 is decoded in memory. All errors are prefixed with op, matching the per-tool error convention.
func ParameterGuidanceIdentity ¶
func ParameterGuidanceIdentity(guidance map[string]ParameterGuidance) string
ParameterGuidanceIdentity names a guidance map by its content, for a transform key whose output depends on the guidance as well as on the schema. Nil and empty maps name the same thing, since a transform treats them alike.
By content and not by address, which was the other way to close the same hole. DeriveSchema memoizes on the identity of the input schema, and every typed route's input schema is shared, so a route from a catalog nobody retained still writes a memo entry that lives for the process. An address in that key would be the address of a guidance map that does not: once the catalog is collected the allocator may hand the address out again, and the next map at it would be served the previous route's guidance. Pinning the guidance of every catalog marked shared would close it for the routes somebody remembered to pin and leave the rest keyed on a transient address; a digest cannot be forgotten, holds nothing alive, and lets two routes that spell the same guidance share one derivation.
The cost is a hash of a few short strings per lookup, against the schema clone the memo saves.
func ParseGID ¶
ParseGID extracts the type name and numeric ID from a GitLab Global ID. It returns an error if the format is invalid.
ParseGID("gid://gitlab/Vulnerability/42") → ("Vulnerability", 42, nil)
func ParseMetaSchemaURI ¶
ParseMetaSchemaURI extracts the tool and action segments from a schema URI.
func ParseOptionalTime ¶
ParseOptionalTime parses an RFC3339 string and returns a *time.Time. Returns nil if the string is empty or unparseable.
func PipelineInputsSchema ¶
PipelineInputsSchema builds the JSON Schema for the typed input T and constrains the named map property's values to exactly the shapes BuildPipelineInputs accepts (string, number, boolean, array of strings). The generic map[string]any field alone would advertise additionalProperties:true, promising value shapes the converter rejects.
func PipelineStatusEmoji ¶
PipelineStatusEmoji returns the Markdown emoji for a pipeline status.
func PopulateHints ¶
func PopulateHints(result *mcp.CallToolResult, setter HintSetter)
PopulateHints extracts next-step hints from the Markdown content of a CallToolResult and sets them on the output struct. It is a no-op when result is nil, contains no TextContent, or has no hints section.
func ProgressReportInterval ¶
ProgressReportInterval returns the byte interval between progress reports. It is the smaller of 1 MB or 5% of total, with a minimum of 64 KB.
func ReadFileOrBase64 ¶
ReadFileOrBase64 resolves the mutually-exclusive file_path / content_base64 upload input pair into an in-memory bytes.Reader, for endpoints that need a seekable or length-aware body. All errors are prefixed with op.
func RegisterMarkdown ¶
RegisterMarkdown registers a Markdown string formatter for type T. Subsequent calls to MarkdownForResult with a value of type T will invoke fn and wrap the returned string in a mcp.CallToolResult.
func RegisterMarkdownPair ¶
RegisterMarkdownPair registers two Markdown string formatters.
func RegisterMarkdownResult ¶
func RegisterMarkdownResult[T any](fn func(T) *mcp.CallToolResult)
RegisterMarkdownResult registers a result formatter for type T. Use this for types that need custom mcp.CallToolResult construction (e.g. uploads with image content).
func RegisterMarkdownTriple ¶
func RegisterMarkdownTriple[A, B, C any](first func(A) string, second func(B) string, third func(C) string)
RegisterMarkdownTriple registers three Markdown string formatters.
func RegisterSurfaceToolFromSpec ¶
func RegisterSurfaceToolFromSpec(server *mcp.Server, spec ActionSpec, opts SurfaceToolRegisterOptions)
RegisterSurfaceToolFromSpec registers one visible MCP tool by projecting an ActionSpec and executing its route handler directly.
func RegisteredMarkdownTypeNames ¶
func RegisteredMarkdownTypeNames() []string
RegisteredMarkdownTypeNames returns the type names of all registered Markdown formatters (both string and result variants). Used by validation tests to verify sub-packages self-register their formatters.
func RequestFromContext ¶
func RequestFromContext(ctx context.Context) *mcp.CallToolRequest
RequestFromContext extracts the MCP request from a context, or nil if absent.
func ResolveProjectWebURLs ¶
func ResolveProjectWebURLs(ctx context.Context, projects gl.ProjectsServiceInterface, projectIDs []int64) map[int64]string
ResolveProjectWebURLs fetches the web URL for each unique project ID. Failures are silently ignored — missing URLs simply produce no links.
func ResourceTemplateVariables ¶
ResourceTemplateVariables returns the names of the {variables} in a URI template, in order of appearance, without the RFC 6570 "+" reserved-expansion prefix. A brace that never closes, or a pair with nothing between them, is an error rather than the end of the scan: ExpandResourceURI answers such a template by embedding nothing, and a declaration that validation had let through would fail that quietly on every call.
func RichContentHint ¶
RichContentHint returns an informational note directing users to the GitLab web URL for full rendering when non-portable GFM features are detected. Returns an empty string when features or webURL is empty.
func SanitizeError ¶
SanitizeError returns err with a rendering that reflects no upstream response body, leaving the chain intact for errors.As and errors.Is.
The four wrapping helpers in this file already do this to what they wrap, but a handler is free to wrap a client-go error itself with %w, and a good many do, so for those actions nothing between the handler and the SDK ever bounded the body. Calling this at the dispatchers, where every action's error passes on its way to the model and to the "tool call failed" log line, makes the wrapping helpers defense in depth rather than the only gate.
func SchemaForRoute ¶
SchemaForRoute returns the cached output schema for type R. Exported for use by gen_llms and audit tools.
func SchemaShared ¶
SchemaShared reports whether schema was registered with ShareSchema, or produced by DeriveSchema from a registered schema.
func SetActionTimeout ¶
SetActionTimeout sets the deadline every action runs under. Zero or a negative value disables it.
func SetLocalFilesystemAccess ¶
func SetLocalFilesystemAccess(allowed bool)
SetLocalFilesystemAccess overrides the transport inference for this process: pass false to refuse every caller-supplied local path, true to allow the allow-listed roots. Call it before any tool handler runs.
The default is inferred from the process arguments rather than configured, so a deployment that never heard of this policy still gets the right answer: an operator who forgets a flag would otherwise be the one running the exposed server. An explicit call always wins over the inference.
func SetMetaParamSchemaMode ¶
func SetMetaParamSchemaMode(mode string)
SetMetaParamSchemaMode selects the meta-tool input schema strategy used by MetaToolSchema. Accepts "opaque" (default), "compact", or "full". Any other value is coerced to opaque so that misconfiguration cannot break the tools/list payload. Must be called before meta-tools are registered; later calls only affect schemas built after the call returns.
func SetMetaParamSchemaModeScoped ¶
func SetMetaParamSchemaModeScoped(mode string) func()
SetMetaParamSchemaModeScoped selects the meta-tool input schema strategy and returns a restore function for tests that temporarily override the global mode.
func SetUploadConfig ¶
func SetUploadConfig(maxFileSize int64)
SetUploadConfig overrides the default upload thresholds. Call before RegisterAll to propagate values into tool handler closures.
func ShareSchema ¶
func ShareSchema(schema any)
ShareSchema registers a schema as process-lived so that transforms of it are memoized by DeriveSchema. Registering keeps the schema reachable for the rest of the process, which is the point: only a schema that can never be collected has an address that can serve as its identity.
Register what the process builds once and serves from then on: the reflected type schemas, the compiled tool schemas, and the routes of a catalog cached per configuration. Never register a per-server map.
func SharedSchemaIdentity ¶
SharedSchemaIdentity returns a string naming a registered schema's identity, for callers that build a composite cache key out of several schemas. It reports false for a schema that is not shared, because the address of a map that can be collected names nothing durable.
func StripControlBytes ¶
StripControlBytes removes the C0 and C1 control ranges and DEL from s, keeping the three controls Markdown actually uses: tab, newline and carriage return.
Everything this package renders is GitLab-authored: an issue title, a file, a job log, a note somebody left on a merge request. None of it is written by the caller, and a good deal of it is written by whoever can open an issue or push a branch, which on a public project is anybody. It reaches the model as text and frequently reaches a person's terminal unchanged, where an escape sequence is not text but an instruction: ESC[2J clears the screen, ESC]0;…BEL renames the window. Nothing downstream filters them, so they are dropped here, at the point the text becomes part of a response.
Dropping rather than escaping is deliberate. A rendered escape would still have to be un-rendered by something to be read, and the sequences that matter carry no information a reader loses by not seeing them: what survives of ESC[2J is "[2J", which says plainly that the content tried something.
This covers the text channel and not structuredContent, and that is a decision rather than an oversight. structuredContent is marshaled by the SDK from the typed value each handler returns, so there is no funnel in this package to apply it at: closing it means either a sweep over every output struct in the 175 handler packages, or a result middleware in the server that walks each value reflectively on the way out. The second is the tempting one and it is the wrong trade. encoding/json already escapes every byte in these ranges, so what reaches a client is the six characters of a \u001b sequence, which no terminal acts on: a viewer would have to parse the JSON and print a string field raw to be affected, and such a client is showing the text channel too, which is sanitized here. Paying a reflective walk of every result for that is not worth it. If the shape of the risk changes, the place to add it is one middleware at the server boundary, not this function.
func StripMetaToolDescriptionPrefix ¶
StripMetaToolDescriptionPrefix removes the generated meta-tool usage header added by MetaToolDescriptionPrefix while preserving standalone descriptions that happen to start with an example.
func SuccessResult ¶
func SuccessResult(markdown string) *mcp.CallToolResult
SuccessResult builds a standard success mcp.CallToolResult with Markdown and the structured output for both human-readable and programmatic consumption. If markdown is empty, the result contains only a structured JSON annotation.
func TitleFromName ¶
TitleFromName generates a human-readable UI title from a snake_case MCP tool name by stripping the "gitlab_" prefix and converting to Title Case.
TitleFromName("gitlab_list_projects") // returns "List Projects"
TitleFromName("my_open_mrs") // returns "My Open MRs"
func ToolResultAnnotated ¶
func ToolResultAnnotated(md string, ann *mcp.Annotations) *mcp.CallToolResult
ToolResultAnnotated wraps a Markdown string into a CallToolResult with content annotations that guide MCP clients on audience and priority. Pass nil annotations to get the same behavior as ToolResultWithMarkdown.
func ToolResultWithImage ¶
func ToolResultWithImage(md string, ann *mcp.Annotations, imageData []byte, mimeType string) *mcp.CallToolResult
ToolResultWithImage creates a CallToolResult containing both a text description (metadata) and an ImageContent block with the raw image bytes. Multimodal LLMs can "see" the image; text-only LLMs get the metadata.
func ToolResultWithMarkdown ¶
func ToolResultWithMarkdown(md string) *mcp.CallToolResult
ToolResultWithMarkdown wraps a Markdown string into a CallToolResult with a single TextContent entry annotated for assistant-only audience. This prevents MCP clients (e.g. VS Code) from displaying raw Markdown inline — the LLM processes it and presents formatted output to the user.
Control characters are dropped here as well as in the helpers that build the Markdown, because this is the last point every rendered response passes through and a formatter that writes a GitLab field straight into its builder would otherwise deliver an escape sequence to whatever prints the text. See StripControlBytes.
func TypeIdentity ¶
TypeIdentity names a reflected type unambiguously, package path included, since two packages may declare input types with the same name. It is the form a transform name embeds when the transform depends on a type.
func UnattributedRequestError ¶
func UnattributedRequestError() error
UnattributedRequestError is UnattributedRequestMessage as a JSON-RPC internal error, for the surfaces that answer with an error value rather than a classified string.
Internal rather than invalid-request for the reason the message gives: the request was well formed and this server failed to route it.
func UnattributedRequestErrorFor ¶
UnattributedRequestErrorFor is UnattributedRequestError for a request that is still live, and the reason it ended for one that is not.
Not every unattributed request is a wiring defect, which is what the message says it is. A POST the client abandoned takes its carrier with it, and the carrier is where the credential is read from, so the binding finds nothing and the handler resolves the credential-less client: a legitimate cause, answered with a sentence asking the caller to report a bug. The tools path never had this problem, because ClassifyError checks cancellation first and that check is what it hits.
Consulting the context is what tells them apart. A cancelled request is over and nobody is reading the answer, so what matters is only that it is not blamed on the wiring in a log an operator does read.
One cause it cannot distinguish, and does not claim to: the pool evicting the entry between the gate resolving it and the gate looking up its state. The request is alive and unattributable, and the honest thing to tell that caller is exactly what the message already says, since retrying rebuilds the entry.
func UnmarshalParams ¶
UnmarshalParams re-serializes params map to JSON and deserializes into T. LLMs frequently send numeric values as JSON strings (e.g. "17" instead of 17). When standard unmarshalling fails, this function retries after coercing string values that look like integers or floats into actual numbers.
Unknown keys in params (i.e. fields that do not exist on T) are rejected with an actionable error so that LLMs receive a clear diagnostic when they mistype a parameter name (e.g. "iid" instead of "snippet_id"). This mirrors the JSON Schema lockdown applied to tools/list responses (see LockdownInputSchemas) and the MCP guidance to surface validation errors as recoverable tool results so the model can self-correct. Meta-protocol keys (see [reservedParamKeys]) are stripped before unmarshalling.
func ValidActionsString ¶
ValidActionsString returns a sorted, comma-separated list of action names.
func ValidateDiffPosition ¶
ValidateDiffPosition checks whether a (newLine, oldLine) combination corresponds to a valid commentable position in the parsed diff lines.
Rules enforced (per GitLab API):
- new_line only → line must be an added (+) line
- old_line only → line must be a removed (-) line
- both set → line must be an unchanged context line
Returns nil when the position is valid, or a descriptive error explaining exactly why the position is invalid and what the caller should do instead.
func ValidatePackageFileName ¶
ValidatePackageFileName validates a filename for GitLab generic package upload. Filenames must not be empty, must not contain spaces, and must not start with a tilde or at-sign.
func ValidatePackageName ¶
ValidatePackageName validates a GitLab generic package name against allowed characters. Names must start with a letter or digit and may contain A-Z a-z 0-9 . _ - + ~ / @.
func ValidateRateLimit ¶
ValidateRateLimit reports whether the given rps/burst pair forms a well-defined limiter configuration. Used by the server entrypoint to fail fast on bad CLI input rather than silently disabling the limiter.
func ValidateRouteBinding ¶
func ValidateRouteBinding(route ActionRoute) error
ValidateRouteBinding reports a route whose handler was replaced without its binder being replaced with it. Such a route serves the replacement on the server it was built for and the constructor's plain handler on every server a shared catalog rebinds it to, which is a defect no test of the domain package can see, since the package tests the route as it built it. The check is exact: the handler in place must be the very closure the binder installed, compared by identity rather than by the code it runs, because the compiler gives an inlined copy of a function literal a closure of its own.
A route with no binder at all passes here, because this compares the two halves against each other and there is nothing to compare. Whether a route is allowed to have no binder is a question about where the route lives, and is answered where that is known: the catalog requires one of every action but the dynamic controllers, which close over a registry rather than a client.
func WithActionDeadline ¶
WithActionDeadline derives the context an action runs under: the caller's, bounded by the configured deadline when there is one. The cancel function is always safe to call.
Exported for the one model-facing handler that is not a catalog action and so passes through none of the WrapAction functions: the dynamic surface's gitlab_find_action, whose cost is the catalog rather than a GitLab call and which was therefore the only registered tool with no deadline at all.
func WithHints ¶
func WithHints[O any](result *mcp.CallToolResult, out O, err error) (*mcp.CallToolResult, O, error)
WithHints extracts hints from a CallToolResult and populates them on the typed output struct, returning all three handler values in one call. This avoids evaluation-order ambiguity in multi-value return statements.
For value Out types (the common case), &out is used internally to satisfy the HintSetter pointer receiver. For pointer Out types (*T), the pointer itself implements HintSetter. If neither case applies, WithHints is a no-op.
return toolutil.WithHints(toolutil.ToolResultWithMarkdown(md), out, err)
func WithInternalInspection ¶
WithInternalInspection marks ctx as belonging to a session the server opens against itself, so what it asks for is not charged to a caller's bucket.
The server lists its own tools several times while it starts: to count them, to drop the excluded ones, to learn which survived the read-only and safe-mode passes, to build the gitlab://tools manifest, and to write the server card. Those requests travel the same receiving middlewares a client's do, so metering tools/list charged them to the deployment's own bucket, and on a server started with --rate-limit-burst=1 the second one was refused and the tool manifest resource failed to build. Pass this to the server's mcp.Server.Connect: the handler context descends from that one, and no header or parameter a caller controls reaches it.
Only the catalog bucket consults the mark, because only listings are asked for this way. A method that reached GitLab would be spending the credential whether the server or a client asked for it, and should still be charged.
func WrapErr ¶
WrapErr classifies the error, enriches it with a semantic message, and wraps it with the operation name. All tool handlers funnel through here so connectivity and auth problems are reported consistently.
func WrapErrWithHint ¶
WrapErrWithHint works like WrapErrWithMessage but appends an actionable hint that tells the LLM what to do next. Example:
"branchDelete: bad request (Cannot delete: protected branch). Suggestion: use gitlab_branch_unprotect first, then retry deletion: <original>"
The hint should be a concise suggestion starting with a verb (e.g., "use gitlab_branch_list to verify the branch name").
func WrapErrWithMessage ¶
WrapErrWithMessage works like WrapErr but also includes the specific GitLab error message (from ErrorResponse.Message) when available. This produces richer errors like:
"fileCreate: bad request (A file with this name already exists): POST .../files: 400"
Use WrapErrWithMessage for mutating operations where the specific GitLab error detail helps the LLM understand what went wrong. Use WrapErr for read-only operations where the generic classification suffices.
func WrapErrWithStatusHint ¶
WrapErrWithStatusHint returns WrapErrWithHint(operation, err, hint) when err matches the given HTTP status code, otherwise falls back to WrapErrWithMessage(operation, err). It compresses the common pattern:
if toolutil.IsHTTPStatus(err, 404) {
return ..., toolutil.WrapErrWithHint(op, err, hint)
}
return ..., toolutil.WrapErrWithMessage(op, err)
into a single call. For handlers that need different hints per status, use a switch over IsHTTPStatus checks; this helper covers the dominant single- status case.
func WrapGFMBody ¶
WrapGFMBody wraps user-generated GFM content in a Markdown blockquote to prevent heading hierarchy conflicts and structural breaks in the formatted output. Empty bodies return an empty string.
The quote is the containment: every line of the body is a line of a quote, so the body cannot add a heading, a list item or a section to the document it sits in. Two things happen before it. Control characters are dropped, and the server's own guidance heading is defused, so a body carrying that heading is shown as the text it is rather than parsed back out as the server's suggestions. See DefuseHintsHeading.
func WriteDescription ¶
WriteDescription writes a GitLab-authored description field.
A description is prose somebody typed into GitLab, and the "- **Description**: %s" line it used to be interpolated into puts it at column zero after a list bullet: its second line is no longer part of the item, so an embedded heading is a heading of the response and an embedded bullet is an item of the server's own list. A one-line description keeps the compact form with the cell escaping applied; anything longer becomes a blockquote, which is what the merge request, wiki and release renderers already do.
func WriteEmpty ¶
WriteEmpty writes a standardized empty-result message to the builder. The resource parameter should be a clear, specific plural noun (e.g. "merge requests", "pipeline variables", "protected branches").
func WriteHints ¶
WriteHints appends a "💡 Next steps" section to the Markdown builder. Each hint is a short string describing a related action the LLM can take (e.g. "Use action 'delete' to remove this package"). If no hints are provided, no section is written.
Whether or not there are hints, any guidance heading already in the builder is defused first. This is the one place every formatter passes through on its way to a response — including the raw file, job trace, snippet and discussion renderers that embed GitLab bytes verbatim — so doing it here covers them all without each renderer having to remember, and covers the ones added later.
func WriteListSummary ¶
func WriteListSummary(b *strings.Builder, shown int, p PaginationOutput)
WriteListSummary appends a brief "Showing N of M results (page X of Y)" line between the heading and the table body. It is a no-op when there is only a single page, because the heading count already conveys everything.
func WriteMdURL ¶
WriteMdURL appends the "- **URL**: ..." line, rendering url as a link whose label and destination are the same address.
It replaces a pair of format constants that read "- **URL**: [%[1]s](%[1]s)" and were used at 31 call sites. One value filling both halves of a link is a shape no argument can be escaped into safely, so each of those call sites hand-wrote a link with nothing in front of it, and the audit flagged every one of them twice. Escaping belongs here, once, rather than in a decision each of 22 packages makes for itself.
func WriteMdURLNewline ¶
WriteMdURLNewline appends the same line as WriteMdURL, preceded by a blank line, for a formatter that closes a section with it.
func WritePagination ¶
func WritePagination(b *strings.Builder, p PaginationOutput)
WritePagination appends a newline-wrapped pagination summary to the builder.
Types ¶
type AccessRequestExtra ¶
type AccessRequestExtra struct {
MemberExtra
AvatarURL string `json:"avatar_url"`
WebURL string `json:"web_url"`
CreatedBy *MemberUserOutput `json:"created_by"`
// ExpiresAt is a date and not a timestamp, which is how GitLab spells a
// membership expiry, so it is read as the string it arrives as.
ExpiresAt string `json:"expires_at"`
Email string `json:"email"`
MemberRole *MemberRoleOutput `json:"member_role"`
}
AccessRequestExtra is what lib/api/entities/access_requester.rb sends on an access request that client-go's AccessRequest does not carry. The entity inherits Member and merges UserBasic into it, so everything MemberExtra reads arrives here too; these are the keys beside them. The two URLs are unconditional; the address, the creator and the custom role each wait on their own condition, and the expiry is sent on every member.
Three keys the entity can send are deliberately not read: is_using_seat, avatar_path and custom_attributes wait on presenter options the caller has to ask for, and no access-request route declares show_seat_info, only_path or with_custom_attributes, so GitLab never sends them here. The first is absent from this shape and the other two arrive through the embed unread.
func CapturedAccessRequest ¶
func CapturedAccessRequest(capture *gitlabclient.ResponseCapture) (AccessRequestExtra, error)
CapturedAccessRequest reads them off the captured answer to a request that returned one access request.
func CapturedAccessRequests ¶
func CapturedAccessRequests(capture *gitlabclient.ResponseCapture, decoded int) ([]AccessRequestExtra, error)
CapturedAccessRequests reads the same off a list answer, one extra per request in order, the count held to what the SDK decoded.
type ActionAliasSpec ¶
type ActionAliasSpec struct {
Alias string
Target string
Source string
Searchable bool
Deprecated bool
RemovalVersion string
Reason string
}
ActionAliasSpec describes a compatibility alias that resolves to a canonical action owned by an ActionSpec.
type ActionFunc ¶
ActionFunc is a handler that receives raw params and returns a result or error.
func SafeModeActionFunc ¶
func SafeModeActionFunc(name string) ActionFunc
SafeModeActionFunc returns an ActionFunc that returns a SafeModePreview for name instead of executing anything. It is used to neutralize mutating catalog actions at registration time, so dispatcher surfaces (meta-tools and the dynamic execute tool) preview each mutating action individually while their read-only actions keep executing.
func WrapAction ¶
func WrapAction[T, R any](client *gitlabclient.Client, fn func(ctx context.Context, client *gitlabclient.Client, input T) (R, error)) ActionFunc
WrapAction wraps a typed handler (input T -> output R) into a generic ActionFunc.
The client the handler runs under is the one bound to the request context, falling back to the one this route was built for. That is the seam a server shared by several credentials needs: its routes are bound to the unbound client, which refuses every request, and the per-request binding is what makes a call reach the caller's own instance. On stdio, and everywhere a catalog is built for one real client, no context carries a binding and the captured client is returned unchanged.
func WrapActionWithRequest ¶
func WrapActionWithRequest[T, R any](client *gitlabclient.Client, fn func(ctx context.Context, req *mcp.CallToolRequest, client *gitlabclient.Client, input T) (R, error)) ActionFunc
WrapActionWithRequest wraps a handler that also requires the MCP request (e.g., for progress tracking). The request is extracted from context via RequestFromContext; if absent, nil is passed.
func WrapVoidAction ¶
func WrapVoidAction[T any](client *gitlabclient.Client, fn func(ctx context.Context, client *gitlabclient.Client, input T) error) ActionFunc
WrapVoidAction wraps a typed handler that returns only error.
It carries the same deadline as WrapAction, and for a stronger reason: an action that returns nothing is a delete, a cancel or a retry, which is exactly the call an operator wants bounded. The deadline was missing here while the setting's own documentation said every action passed through it.
func WrapVoidActionWithRequest ¶
func WrapVoidActionWithRequest[T any](client *gitlabclient.Client, fn func(ctx context.Context, req *mcp.CallToolRequest, client *gitlabclient.Client, input T) error) ActionFunc
WrapVoidActionWithRequest wraps a void handler that also requires the MCP request. The request is extracted from context via RequestFromContext; if absent, nil is passed.
type ActionMap ¶
type ActionMap map[string]ActionRoute
ActionMap maps action names to their route definitions (handler + metadata).
func ActionSpecsToMap ¶
func ActionSpecsToMap(specs []ActionSpec) ActionMap
ActionSpecsToMap converts canonical action specs to a legacy ActionMap.
func ActionSpecsToMapWithError ¶
func ActionSpecsToMapWithError(specs []ActionSpec) (ActionMap, error)
ActionSpecsToMapWithError converts canonical action specs to a legacy ActionMap.
type ActionMetaEntry ¶
type ActionMetaEntry struct {
// Usage replaces the generic action Usage line when non-empty.
Usage string
// Aliases replaces the default tool-name alias list when non-empty.
Aliases []string
// Related replaces RelatedActions when non-empty.
Related []string
// Guidance replaces ParameterGuidance when non-empty.
Guidance map[string]ParameterGuidance
// Description sets the individual-tool description when non-empty.
Description string
}
ActionMetaEntry holds the per-action discovery metadata that domains overlay on top of their shared ActionSpecOptions defaults: a non-generic Usage line, distinctive natural-language Aliases, canonical RelatedActions, per-parameter Guidance, and the "Returns: … See also: …" individual-tool Description (1:1 audit R-META). Every GitLab domain that carries an action metadata table uses this single type instead of a domain-local struct, and applies it with ApplyActionMeta, so the overlay logic lives in one place.
Zero-value fields are skipped by ApplyActionMeta; only fields a domain actually populates override the option defaults.
type ActionRoute ¶
type ActionRoute struct {
Handler ActionFunc
// Bind builds the handler for a client. Nil means the handler depends on
// no client and is shared as it is.
Bind func(*gitlabclient.Client) ActionFunc
Destructive bool
InputType reflect.Type
OutputType reflect.Type
InputSchema map[string]any
OutputSchema map[string]any
ParameterGuidance map[string]ParameterGuidance
Aliases []string
Tags []string
Usage string
RelatedActions []string
// EmbeddedResource is the canonical resource URI template the dispatchers
// expand from the call's parameters and embed in a successful result. The
// catalog sets it from the action's spec when the spec's policy embeds.
EmbeddedResource string
// contains filtered or unexported fields
}
ActionRoute pairs an action handler with metadata about its behavior. Used by meta-tools to carry per-route destructive classification without string parsing. OutputSchema holds the JSON Schema for the action's typed output. InputSchema holds the JSON Schema for the action's typed params (nil for routes constructed via the untyped Route and DestructiveRoute constructors).
A route is two things with different lifetimes. Its metadata (the schemas, the guidance, the aliases) depends on nothing but the action, and a catalog cached per configuration shares it between every server in the process; the schema maps are frozen, and a consumer that needs to change one copies it first (see DeriveSchema). Its Handler is bound to one GitLab client, and so to one credential. Bind is what joins the two: the RouteAction family sets it to rebuild the handler for any client, and ActionRoute.BindTo pairs the shared metadata with a handler for the client at hand. A route with no Bind has a handler that captured no client and is served as is.
Replacing Handler directly breaks that pairing silently: the shared catalog would rebind to the constructor's plain handler and drop whatever the replacement added. ActionRoute.WrapHandler and ActionRoute.WithBoundHandler change the handler and its binder together, and ValidateRouteBinding refuses a route whose two halves disagree.
func CloneActionRoute ¶
func CloneActionRoute(route ActionRoute) ActionRoute
CloneActionRoute returns a copy of the route that owns its string slices and shares everything else. The handler, the types and the frozen schema and guidance maps describe the same action and are not copied; the Aliases, Tags and RelatedActions slices are, so a caller may append to them without reaching the original.
func DestructiveAction ¶
func DestructiveAction[T, R any](client *gitlabclient.Client, fn func(ctx context.Context, client *gitlabclient.Client, input T) (R, error)) ActionRoute
DestructiveAction wraps a typed function as a destructive ActionRoute and attaches input/output schemas.
func DestructiveActionWithRequest ¶
func DestructiveActionWithRequest[T, R any](client *gitlabclient.Client, fn func(ctx context.Context, req *mcp.CallToolRequest, client *gitlabclient.Client, input T) (R, error)) ActionRoute
DestructiveActionWithRequest wraps a typed function that needs the MCP request as a destructive ActionRoute and attaches input/output schemas.
func DestructiveFunc ¶
func DestructiveFunc[T, R any](fn func(ctx context.Context, input T) (R, error)) ActionRoute
DestructiveFunc wraps a typed function as a destructive ActionRoute without a GitLab client dependency and attaches input and output schemas.
func DestructiveRoute ¶
func DestructiveRoute(fn ActionFunc) ActionRoute
DestructiveRoute creates a destructive ActionRoute without an output schema.
func DestructiveVoidAction ¶
func DestructiveVoidAction[T any](client *gitlabclient.Client, fn func(ctx context.Context, client *gitlabclient.Client, input T) error) ActionRoute
DestructiveVoidAction wraps a typed void function as a destructive ActionRoute. The handler returns a typed DeleteOutput confirmation so meta-tool routes expose structured output instead of nil content.
func DestructiveVoidActionWithRequest ¶
func DestructiveVoidActionWithRequest[T any](client *gitlabclient.Client, fn func(ctx context.Context, req *mcp.CallToolRequest, client *gitlabclient.Client, input T) error) ActionRoute
DestructiveVoidActionWithRequest wraps a request-aware void function as a destructive ActionRoute with typed DeleteOutput confirmation, reusing WrapVoidActionWithRequest so the request-extraction logic is not duplicated.
func Route ¶
func Route(fn ActionFunc) ActionRoute
Route creates a non-destructive ActionRoute without an output schema.
func RouteAction ¶
func RouteAction[T, R any](client *gitlabclient.Client, fn func(ctx context.Context, client *gitlabclient.Client, input T) (R, error)) ActionRoute
RouteAction wraps a typed function as a non-destructive ActionRoute and attaches the JSON Schema for the input type T and output type R.
func RouteActionWithRequest ¶
func RouteActionWithRequest[T, R any](client *gitlabclient.Client, fn func(ctx context.Context, req *mcp.CallToolRequest, client *gitlabclient.Client, input T) (R, error)) ActionRoute
RouteActionWithRequest wraps a typed function that needs the MCP request as a non-destructive ActionRoute and attaches input/output schemas.
func RouteFunc ¶
func RouteFunc[T, R any](fn func(ctx context.Context, input T) (R, error)) ActionRoute
RouteFunc wraps a typed function as a non-destructive ActionRoute without a GitLab client dependency and attaches input and output schemas.
func RouteRequestFunc ¶
func RouteRequestFunc[T, R any](fn func(ctx context.Context, req *mcp.CallToolRequest, input T) (R, error)) ActionRoute
RouteRequestFunc wraps a typed request-aware function as a non-destructive ActionRoute without a GitLab client dependency and attaches schemas.
func RouteVoidAction ¶
func RouteVoidAction[T any](client *gitlabclient.Client, fn func(ctx context.Context, client *gitlabclient.Client, input T) error) ActionRoute
RouteVoidAction wraps a typed void function as a non-destructive ActionRoute. The handler returns a typed VoidOutput confirmation so meta-tool routes expose structured output instead of nil content.
func (ActionRoute) BindTo ¶
func (route ActionRoute) BindTo(client *gitlabclient.Client) ActionRoute
BindTo returns the route with its handler rebuilt for client. A route whose Bind is nil captured no client and is returned unchanged. The metadata is shared with the receiver, not copied: it is the same action.
func (ActionRoute) WithAliases ¶
func (route ActionRoute) WithAliases(aliases ...string) ActionRoute
WithAliases returns a copy of route with additional search aliases.
func (ActionRoute) WithBoundHandler ¶
func (route ActionRoute) WithBoundHandler(client *gitlabclient.Client, bind func(*gitlabclient.Client) ActionFunc) ActionRoute
WithBoundHandler returns the route with a handler that bind builds for client, and with bind recorded so a shared catalog can build the same handler for any other client. Use it where the replacement handler needs the client itself rather than only the handler it replaces.
func (ActionRoute) WithParameterGuidance ¶
func (route ActionRoute) WithParameterGuidance(guidance map[string]ParameterGuidance) ActionRoute
WithParameterGuidance returns a copy of route with merged parameter guidance.
func (ActionRoute) WithRelatedActions ¶
func (route ActionRoute) WithRelatedActions(actions ...string) ActionRoute
WithRelatedActions returns a copy of route with related canonical action IDs.
func (ActionRoute) WithTags ¶
func (route ActionRoute) WithTags(tags ...string) ActionRoute
WithTags returns a copy of route with additional search tags.
func (ActionRoute) WithUsage ¶
func (route ActionRoute) WithUsage(usage string) ActionRoute
WithUsage returns a copy of route with a short model-facing usage hint.
func (ActionRoute) WrapHandler ¶
func (route ActionRoute) WrapHandler(wrap func(next ActionFunc) ActionFunc) ActionRoute
WrapHandler returns the route with wrap applied to its handler, now and on every later rebinding. Use it where a domain decorates the constructor's handler, such as turning a 404 into a structured not-found result: wrap receives the handler to decorate and returns the decorated one.
type ActionSpec ¶
type ActionSpec struct {
Name string
Route ActionRoute
Aliases []string
Tags []string
Usage string
RelatedActions []string
Compatibility CompatibilityPolicy
ParameterGuidance map[string]ParameterGuidance
InputSchemaOverrides []InputSchemaOverride
ReadOnly bool
Destructive bool
Idempotent bool
OpenWorld bool
Edition string
GitLabDotComOnly bool
OwnerPackage string
IndividualTool IndividualToolSpec
ContentKind string
NotFoundPolicy string
EmbeddedResourcePolicy string
// EmbeddedResource is the canonical gitlab:// URI template of the entity a
// get-style action returns, expanded from the call's parameters and
// embedded in the result under the embedded-resource policy.
EmbeddedResource string
RichResultPolicy string
SchemaValidationNotes []string
RuntimeValidationNotes []string
}
ActionSpec is the canonical metadata contract for one GitLab action.
func CloneActionSpec ¶
func CloneActionSpec(spec ActionSpec) ActionSpec
CloneActionSpec returns a defensive copy of spec and all mutable metadata it owns.
func CloneActionSpecs ¶
func CloneActionSpecs(specs []ActionSpec) []ActionSpec
CloneActionSpecs returns defensive copies of specs in their original order.
func FillScopeParameterGuidance ¶
func FillScopeParameterGuidance(specs []ActionSpec) []ActionSpec
FillScopeParameterGuidance returns a copy of specs with default ParameterGuidance entries added for every scope-suggestive parameter (project_id, group_id, user_id, instance_id, namespace_id, milestone_id, epic_id, ref, branch, tag, sha, path, iid) present in each spec's input schema that lacks an explicit guidance entry. The defaults use the canonical SemanticRole for each scope name and the standard "Project ID or URL-encoded path…" / "Branch or tag name…" ValueSource text.
Packages call this from their ActionSpecs() function before returning so that the discovery auditor's missing_parameter_guidance check is satisfied without each action having to hand-write guidance for every common scope parameter. Explicit guidance entries on a spec are preserved unchanged (they take precedence over the defaults).
func FillScopeParameterGuidanceSingle ¶
func FillScopeParameterGuidanceSingle(spec ActionSpec) ActionSpec
FillScopeParameterGuidanceSingle is the single-spec form of FillScopeParameterGuidance. The central tier filter calls this after pruning tier-restricted fields from the input schema so that the default guidance set never references a field the filter has stripped. Existing guidance entries whose parameter has been removed from the schema are dropped, while guidance for scope-suggestive parameters still present in the schema is added when missing. Explicit guidance entries written by package authors are preserved unchanged.
func NewActionSpec ¶
func NewActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
NewActionSpec creates a defensive canonical action specification.
The route's input schema is not changed in place: the overrides and the canonical enums, formats and ranges are applied to a derived schema, built once per process for a shared input (see DeriveSchema) and privately otherwise. The transform is idempotent, so a spec cloned through this constructor keeps the schema it already had.
func NewAdditiveActionSpec ¶
func NewAdditiveActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
NewAdditiveActionSpec creates a mutating action whose repetition changes the result, so idempotentHint stays false.
It exists because "update" is the wrong shape for some endpoints that look like one. Logging spent time is the example: GitLab's add_spent_time is additive, so two calls of "1h" leave two hours logged, and an idempotentHint of true would invite a model to retry a call whose outcome it could not observe — leaving the user's timesheet wrong in a way nobody notices for a while.
The hint is advisory, which is exactly why it has to be accurate: nothing enforces it, so its only effect is on what a model decides to do.
func NewCreateActionSpec ¶
func NewCreateActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
NewCreateActionSpec creates a mutating, non-idempotent action specification.
func NewDeleteActionSpec ¶
func NewDeleteActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
NewDeleteActionSpec creates a destructive, idempotent action specification.
func NewReadActionSpec ¶
func NewReadActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
NewReadActionSpec creates a read-only, idempotent action specification.
func NewUpdateActionSpec ¶
func NewUpdateActionSpec(name string, route ActionRoute, opts ActionSpecOptions) ActionSpec
NewUpdateActionSpec creates a mutating, idempotent action specification.
func (ActionSpec) Validate ¶
func (spec ActionSpec) Validate() error
Validate verifies invariants that must hold before projecting a spec.
func (ActionSpec) WithEmbeddedResource ¶
func (spec ActionSpec) WithEmbeddedResource(template string) ActionSpec
WithEmbeddedResource returns the spec with its canonical resource declared: the given gitlab:// URI template, expanded from the call's parameters, is embedded in every successful result. Declared at the spec site so the action's owner package states which resource a get returns, and the catalog validator holds the template to the action's parameters.
type ActionSpecOptions ¶
type ActionSpecOptions struct {
Aliases []string
Tags []string
Usage string
RelatedActions []string
Compatibility CompatibilityPolicy
ParameterGuidance map[string]ParameterGuidance
InputSchemaOverrides []InputSchemaOverride
ReadOnly bool
Destructive bool
Idempotent bool
OpenWorld bool
Edition string
GitLabDotComOnly bool
OwnerPackage string
IndividualTool IndividualToolSpec
ContentKind string
NotFoundPolicy string
EmbeddedResourcePolicy string
EmbeddedResource string
RichResultPolicy string
SchemaValidationNotes []string
RuntimeValidationNotes []string
}
ActionSpecOptions contains optional metadata for NewActionSpec.
type AppearanceExtra ¶
type AppearanceExtra struct {
SiteName string `json:"site_name"`
}
AppearanceExtra is the instance's site name, which GitLab's appearance entity exposes under no condition.
func CapturedAppearance ¶
func CapturedAppearance(capture *gitlabclient.ResponseCapture) (AppearanceExtra, error)
CapturedAppearance reads it off the captured answer to an appearance request.
type ApproverIDsFilter ¶
type ApproverIDsFilter []StringOrInt
ApproverIDsFilter mirrors GitLab's approver_ids and approved_by_ids merge request filters, which accept either a list of numeric user IDs or exactly one of the literals "Any" and "None".
Elements are StringOrInt, so both JSON numbers and JSON strings unmarshal cleanly. Actions exposing this filter must widen the published item type with SchemaApproverIDsOverride, otherwise input validation rejects the literals before the handler ever sees them.
func (ApproverIDsFilter) ApproverIDsValue ¶
func (f ApproverIDsFilter) ApproverIDsValue() (*gl.ApproverIDsValue, error)
ApproverIDsValue converts the filter into the SDK value expected by the merge request list options. It returns nil for an empty filter, so callers can assign the result unconditionally.
The literals are only meaningful on their own: GitLab has no notion of "None plus these IDs", so mixing them with user IDs is rejected rather than silently dropped, which would return a differently-filtered result set than the caller asked for.
type AssetLinkOutput ¶
type AssetLinkOutput struct {
ID int64 `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
DirectAssetURL string `json:"direct_asset_url,omitempty"`
External bool `json:"external"`
LinkType string `json:"link_type"`
}
AssetLinkOutput mirrors gl.ReleaseLink (the per-link object inside release.assets.links). The DirectAssetURL field is omitempty because the official assets-by-link endpoint only populates it for package-link types.
type AssetSourceOutput ¶
AssetSourceOutput mirrors gl.ReleaseAssetsSource (the per-source object inside release.assets.sources). Format is a short string (e.g. "package", "image", "url", "other").
type AssetsOutput ¶
type AssetsOutput struct {
Count int64 `json:"count"`
Sources []AssetSourceOutput `json:"sources,omitempty"`
Links []AssetLinkOutput `json:"links,omitempty"`
EvidenceFilePath string `json:"evidence_file_path,omitempty"`
}
AssetsOutput mirrors gl.ReleaseAssets (the count / sources / links / evidence_file_path object).
func NewAssetsOutput ¶
func NewAssetsOutput(a gl.ReleaseAssets) *AssetsOutput
NewAssetsOutput converts a gl.ReleaseAssets into the canonical-key assets object, returning nil when the SDK value has every field zero.
type AuthorOutput ¶
type AuthorOutput struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
State string `json:"state,omitempty"`
AvatarURL string `json:"avatar_url"`
WebURL string `json:"web_url"`
}
AuthorOutput mirrors gl.BasicUser for the release author (per the documented release-by-tag response; the author object is the compact BasicUser shape, not the full User shape).
func NewAuthorOutputFromBasicUser ¶
func NewAuthorOutputFromBasicUser(u gl.BasicUser) AuthorOutput
NewAuthorOutputFromBasicUser converts a gl.BasicUser into the canonical-key author object.
type BasicGroupDetailsOutput ¶
type BasicGroupDetailsOutput struct {
ID int64 `json:"id"`
Name string `json:"name"`
WebURL string `json:"web_url,omitempty"`
}
BasicGroupDetailsOutput is the group reference GitLab renders on a board, which carries three keys and not a whole group.
type BasicUserOutput ¶
type BasicUserOutput struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
State string `json:"state"`
AvatarURL string `json:"avatar_url"`
WebURL string `json:"web_url"`
CreatedAt string `json:"created_at,omitempty"`
}
BasicUserOutput mirrors gl.BasicUser (the user shape returned in many pipeline / merge-train / deployment-MR sub-objects: head_pipeline.user, merge_train.pipeline.user, etc.).
func NewBasicUserOutput ¶
func NewBasicUserOutput(u *gl.BasicUser) *BasicUserOutput
NewBasicUserOutput converts a *gl.BasicUser into the canonical-key basic user object, returning nil when the SDK value is nil.
func NewBasicUserOutputs ¶
func NewBasicUserOutputs(users []*gl.BasicUser) []*BasicUserOutput
NewBasicUserOutputs converts a []*gl.BasicUser slice, skipping nil elements and returning nil for an empty input.
type BillableMemberExtra ¶
type BillableMemberExtra struct {
Locked bool `json:"locked"`
PublicEmail string `json:"public_email"`
}
BillableMemberExtra is what ee/lib/api/entities/billable_member.rb sends on a billable member that client-go's BillableGroupMember does not carry: whether the account is locked and the address the user publishes, both of them from the UserBasic the entity inherits and both on every member.
The same UserBasic exposes avatar_path and custom_attributes, and neither is read: both wait on a presenter option, and the billable members route declares neither only_path nor with_custom_attributes, so GitLab has never sent either on this response.
It is deliberately not MemberExtra. A billable member is a user who counts against the seat total and not a membership record, so it carries no access level, no expiry and no role. The endpoint's own desc annotates Entities::Member while its handler presents this entity, which is why the audit reads nine membership keys against a response that has never carried one of them.
func CapturedBillableMembers ¶
func CapturedBillableMembers(capture *gitlabclient.ResponseCapture, decoded int) ([]BillableMemberExtra, error)
CapturedBillableMembers reads them off the captured answer to a list of billable members, one extra per member in order, the count held to what the SDK decoded.
type BoardExtra ¶
type BoardExtra struct {
Group *BasicGroupDetailsOutput `json:"group"`
}
BoardExtra is that reference on the board, which GitLab exposes under no condition and leaves null on a board that belongs to a project.
func CapturedBoard ¶
func CapturedBoard(capture *gitlabclient.ResponseCapture) (BoardExtra, error)
CapturedBoard reads it off the captured answer to a request for one board.
func CapturedBoards ¶
func CapturedBoards(capture *gitlabclient.ResponseCapture, decoded int) ([]BoardExtra, error)
CapturedBoards reads the same off a list answer, one extra per board in order, the count held to what the SDK decoded.
type BoardLabelDetailsOutput ¶
type BoardLabelDetailsOutput struct {
ID int64 `json:"id"`
Name string `json:"name"`
Color string `json:"color"`
Description string `json:"description"`
}
BoardLabelDetailsOutput is the documented board `labels[]` entry. The documented update-board responses show only id, name, color, and description for each label; the SDK label types' remaining fields are not part of the documented board labels shape.
func NewBoardLabelDetailsOutputs ¶
func NewBoardLabelDetailsOutputs(details []*gl.LabelDetails) []*BoardLabelDetailsOutput
NewBoardLabelDetailsOutputs converts a slice of gl.LabelDetails into the documented board label subset, skipping nil elements and returning nil when no labels remain (consistent with NewCustomAttributeOutputs, so callers never serialize an empty array for an effectively-empty input).
type BoardLabelOutput ¶
type BoardLabelOutput struct {
Name string `json:"name"`
Color string `json:"color"`
Description string `json:"description"`
}
BoardLabelOutput is the documented board-list label object. Every documented board-list response shows the list's `label` object with only name, color, and description; gl.Label's remaining fields are not part of the documented board-list label shape.
func NewBoardLabelOutput ¶
func NewBoardLabelOutput(l *gl.Label) *BoardLabelOutput
NewBoardLabelOutput converts a gl.Label into the documented board-list label subset, returning nil when the SDK value is nil.
type BoardListAssigneeOutput ¶
type BoardListAssigneeOutput struct {
ID int64 `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
}
BoardListAssigneeOutput is the compact assignee object on a board list (Premium/Ultimate assignee list type), matching gl.BoardListAssignee. The documented response examples cover only label and milestone lists, so this premium list-type sub-object has no fuller documented shape to trim against.
func NewBoardListAssigneeOutput ¶
func NewBoardListAssigneeOutput(a *gl.BoardListAssignee) *BoardListAssigneeOutput
NewBoardListAssigneeOutput converts a gl.BoardListAssignee into the shared output shape, returning nil when the SDK value is nil.
type BoardListExtra ¶
type BoardListExtra struct {
LimitMetric string `json:"limit_metric"`
}
BoardListExtra is the metric a board list limits its work in progress by, which GitLab exposes only on a list whose board has work-in-progress limits available, so it is empty everywhere else.
func CapturedBoardList ¶
func CapturedBoardList(capture *gitlabclient.ResponseCapture) (BoardListExtra, error)
CapturedBoardList reads it off the captured answer to a request for one board list.
func CapturedBoardLists ¶
func CapturedBoardLists(capture *gitlabclient.ResponseCapture, decoded int) ([]BoardListExtra, error)
CapturedBoardLists reads the same off a list answer, one extra per board list in order, the count held to what the SDK decoded.
type BoardUserOutput ¶
type BoardUserOutput struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
State string `json:"state"`
AvatarURL string `json:"avatar_url"`
WebURL string `json:"web_url"`
}
BoardUserOutput is the documented 6-field board assignee object shared by the project boards and group boards APIs (doc/api/boards.md and doc/api/group_boards.md). The documented update-board responses show only id, name, username, state, avatar_url, and web_url; gl.BasicUser's created_at is not part of the documented board assignee shape.
func NewBoardUserOutput ¶
func NewBoardUserOutput(u *gl.BasicUser) *BoardUserOutput
NewBoardUserOutput converts a gl.BasicUser into the documented board assignee subset, returning nil when the SDK value is nil.
type BridgeExtra ¶
type BridgeExtra struct {
Project *BridgeProjectOutput `json:"project"`
}
BridgeExtra is that object on a bridge job, exposed under no condition.
func CapturedBridges ¶
func CapturedBridges(capture *gitlabclient.ResponseCapture, decoded int) ([]BridgeExtra, error)
CapturedBridges reads it off the captured answer to a list of bridges, one extra per bridge in order, the count held to what the SDK decoded.
type BridgeProjectOutput ¶
type BridgeProjectOutput struct {
CIJobTokenScopeEnabled bool `json:"ci_job_token_scope_enabled"`
}
BridgeProjectOutput is the project object GitLab renders on a job, which carries one key: whether the job token can reach outside this project.
type BroadcastMessageExtra ¶
type BroadcastMessageExtra struct {
Color string `json:"color"`
}
BroadcastMessageExtra is the color a broadcast message is drawn in, which GitLab's broadcast message entity exposes under no condition.
func CapturedBroadcastMessage ¶
func CapturedBroadcastMessage(capture *gitlabclient.ResponseCapture) (BroadcastMessageExtra, error)
CapturedBroadcastMessage reads it off the captured answer to a request for one message.
func CapturedBroadcastMessages ¶
func CapturedBroadcastMessages(capture *gitlabclient.ResponseCapture, decoded int) ([]BroadcastMessageExtra, error)
CapturedBroadcastMessages reads the same off a list answer, one extra per message in order, the count held to what the SDK decoded.
type CICDVariableFlags ¶
CICDVariableFlags groups boolean CI/CD variable attributes for Markdown view-model construction.
type CICDVariableListMarkdownOptions ¶
type CICDVariableListMarkdownOptions struct {
Title string
EmptyMessage string
IncludeEnvironmentScope bool
Hints []string
}
CICDVariableListMarkdownOptions configures the shared CI/CD variable list renderer.
type CICDVariableMarkdown ¶
type CICDVariableMarkdown struct {
Key string
Value string
VariableType string
Protected bool
Masked bool
Hidden bool
Raw bool
EnvironmentScope string
Description string
}
CICDVariableMarkdown carries the common fields rendered by GitLab CI/CD variable tools at project, group, and instance scopes.
func CICDVariableMarkdowns ¶
func CICDVariableMarkdowns[T any](variables []T, convert func(T) CICDVariableMarkdown) []CICDVariableMarkdown
CICDVariableMarkdowns maps package-specific variable outputs to the shared CI/CD variable Markdown view model.
func NewCICDVariableMarkdown ¶
func NewCICDVariableMarkdown(key, value, variableType string, flags CICDVariableFlags, environmentScope, description string) CICDVariableMarkdown
NewCICDVariableMarkdown builds a shared Markdown view model for CI/CD variables without forcing tool packages to duplicate composite literals.
type CICDVariableMarkdownOptions ¶
type CICDVariableMarkdownOptions struct {
Title string
IncludeEnvironmentScope bool
Hints []string
}
CICDVariableMarkdownOptions configures the shared CI/CD variable detail renderer.
type CIVariableExtra ¶
type CIVariableExtra struct {
EnvironmentScope string `json:"environment_scope"`
Hidden bool `json:"hidden"`
}
CIVariableExtra is what GitLab's CI variable entity sends that the instance variable struct does not carry: the environments the value applies to, and whether the value is hidden from every reader once set. Both are exposed only where the variable's own model answers to them.
func CapturedCIVariable ¶
func CapturedCIVariable(capture *gitlabclient.ResponseCapture) (CIVariableExtra, error)
CapturedCIVariable reads them off the captured answer to a request for one variable.
func CapturedCIVariables ¶
func CapturedCIVariables(capture *gitlabclient.ResponseCapture, decoded int) ([]CIVariableExtra, error)
CapturedCIVariables reads the same off a list answer, one extra per variable in order, the count held to what the SDK decoded.
type ClusterAgentExtra ¶
type ClusterAgentExtra struct {
IsReceptive bool `json:"is_receptive"`
}
ClusterAgentExtra is whether an agent is receptive, meaning GitLab connects out to it rather than waiting for it to connect in. The agent entity exposes it under no condition.
func CapturedClusterAgent ¶
func CapturedClusterAgent(capture *gitlabclient.ResponseCapture) (ClusterAgentExtra, error)
CapturedClusterAgent reads it off the captured answer to a request for one agent.
func CapturedClusterAgents ¶
func CapturedClusterAgents(capture *gitlabclient.ResponseCapture, decoded int) ([]ClusterAgentExtra, error)
CapturedClusterAgents reads the same off a list answer, one extra per agent in order, the count held to what the SDK decoded.
type CodedError ¶
type CodedError struct {
// contains filtered or unexported fields
}
CodedError carries a JSON-RPC code alongside the original error.
It exists because the go-sdk derives the wire code from the error value: its toWireError leaves Code at 0 unless the error is, or wraps, a *jsonrpc.Error. An unclassified error therefore reaches the client as code 0, which is not a JSON-RPC error code at all, and a client cannot tell "you sent the wrong arguments" from "the upstream is down" — the two failures it would act on differently.
Unwrap lists the cause before the code, so errors.As finds the innermost code first. That ordering is deliberate in both directions: a handler that wraps an argument failure in its own context still reports the argument code, and a cause that already carries a specific code (a not-found, say) keeps it rather than being flattened into the generic one.
func (*CodedError) Error ¶
func (e *CodedError) Error() string
Error renders the cause alone: the code is for the transport, not the reader.
func (*CodedError) Unwrap ¶
func (e *CodedError) Unwrap() []error
Unwrap exposes the cause first and the code second, in the order the type documentation explains.
type CommitCommentExtra ¶
CommitCommentExtra is when a commit comment was written, which GitLab's commit note entity exposes under no condition.
func CapturedCommitComment ¶
func CapturedCommitComment(capture *gitlabclient.ResponseCapture) (CommitCommentExtra, error)
CapturedCommitComment reads it off the captured answer to a request that returned one comment.
func CapturedCommitComments ¶
func CapturedCommitComments(capture *gitlabclient.ResponseCapture, decoded int) ([]CommitCommentExtra, error)
CapturedCommitComments reads the same off a list answer, one extra per comment in order, the count held to what the SDK decoded.
type CommitOutput ¶
type CommitOutput struct {
ID string `json:"id"`
ShortID string `json:"short_id"`
Title string `json:"title"`
AuthorName string `json:"author_name"`
AuthorEmail string `json:"author_email"`
AuthoredDate string `json:"authored_date,omitempty"`
CommitterName string `json:"committer_name"`
CommitterEmail string `json:"committer_email"`
CommittedDate string `json:"committed_date,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
Message string `json:"message"`
ParentIDs []string `json:"parent_ids,omitempty"`
}
CommitOutput is the documented reference subset of the commit object surfaced on a release (per doc/api/releases/_index.md). The documented release commit JSON surfaces id, short_id, title, created_at, parent_ids, message, author_name, author_email, authored_date, committer_name, committer_email, committed_date. SDK-only commit fields (stats, status, project_id, web_url) are not part of the documented project-release commit subset and are intentionally omitted from this base type. The group-releases endpoint adds web_url; consumers that need it embed this type and add the extra field.
func NewCommitOutput ¶
func NewCommitOutput(c gl.Commit) *CommitOutput
NewCommitOutput converts a gl.Commit into the canonical-key commit object, returning nil when the commit ID is empty (no commit associated with the release). Timestamps are formatted as RFC 3339 strings via FormatTimePtr.
type CompatibilityPolicy ¶
type CompatibilityPolicy struct {
ActionAliases []ActionAliasSpec
ParameterAliases []ParameterAliasSpec
}
CompatibilityPolicy carries compatibility aliases and their ownership policy.
func CloneCompatibilityPolicy ¶
func CloneCompatibilityPolicy(policy CompatibilityPolicy) CompatibilityPolicy
CloneCompatibilityPolicy returns a defensive copy of compatibility metadata.
type CustomAttributeOutput ¶
CustomAttributeOutput mirrors gl.CustomAttribute, a key/value custom attribute attached to a user.
func NewCustomAttributeOutputs ¶
func NewCustomAttributeOutputs(attrs []*gl.CustomAttribute) []CustomAttributeOutput
NewCustomAttributeOutputs converts a []*gl.CustomAttribute slice, skipping nil elements and returning nil when no attributes remain.
type DeleteOutput ¶
type DeleteOutput struct {
HintableOutput
Status string `json:"status"`
Message string `json:"message"`
}
DeleteOutput is a confirmation message returned by destructive tool handlers (delete, unprotect, unapprove) so the LLM receives explicit feedback instead of empty content when the operation succeeds.
func DeleteResult ¶
func DeleteResult(resource string) (*mcp.CallToolResult, DeleteOutput, error)
DeleteResult builds a DeleteOutput and its Markdown representation for a successful destructive operation. The resource parameter describes what was affected (e.g., "project 42", "branch feature/x").
type DependencyExtra ¶
type DependencyExtra struct {
Malware *bool `json:"malware"`
}
DependencyExtra is whether a dependency is known malware, which GitLab exposes to a caller allowed to read the project's vulnerabilities and only while the instance has the feature enabled.
The pointer carries the third state: true is a detection, false is a package the scan cleared, and absent is a scan that did not run. Read into a bool the last two would both arrive as false.
func CapturedDependencies ¶
func CapturedDependencies(capture *gitlabclient.ResponseCapture, decoded int) ([]DependencyExtra, error)
CapturedDependencies reads it off the captured answer to a list of dependencies, one extra per dependency in order, the count held to what the SDK decoded.
type DeployKeyExtra ¶
type DeployKeyExtra struct {
LastUsedAt *time.Time `json:"last_used_at"`
UsageType string `json:"usage_type"`
ProjectsWithWriteAccess []DeployKeyProjectOutput `json:"projects_with_write_access"`
ProjectsWithReadonlyAccess []DeployKeyProjectOutput `json:"projects_with_readonly_access"`
}
DeployKeyExtra is what GitLab's deploy key entity sends that the key itself does not say: when the key was last used to reach the instance and what it may be used for, both unconditional, and the projects it can write to or only read from, which are sent when the request asks for them.
func CapturedDeployKey ¶
func CapturedDeployKey(capture *gitlabclient.ResponseCapture) (DeployKeyExtra, error)
CapturedDeployKey reads them off the captured answer to a request for one deploy key.
func CapturedDeployKeys ¶
func CapturedDeployKeys(capture *gitlabclient.ResponseCapture, decoded int) ([]DeployKeyExtra, error)
CapturedDeployKeys reads the same off a list answer, one extra per key in order, the count held to what the SDK decoded.
type DeployKeyProjectOutput ¶
type DeployKeyProjectOutput struct {
ID int64 `json:"id"`
Description string `json:"description"`
Name string `json:"name"`
NameWithNamespace string `json:"name_with_namespace"`
Path string `json:"path"`
PathWithNamespace string `json:"path_with_namespace"`
CreatedAt *time.Time `json:"created_at"`
}
DeployKeyProjectOutput is one project a deploy key reaches, rendered as the project identity entity: the naming and the creation date, without the settings a full project carries.
type DeploymentApprovalOutput ¶
type DeploymentApprovalOutput struct {
User *UserBasicOutput `json:"user,omitempty"`
Status string `json:"status"`
CreatedAt *time.Time `json:"created_at"`
Comment string `json:"comment,omitempty"`
}
DeploymentApprovalOutput is one approval or rejection recorded against a deployment, as lib/api/entities/deployments/approval.rb renders it.
type DeploymentApprovalRuleOutput ¶
type DeploymentApprovalRuleOutput struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id,omitempty"`
GroupID int64 `json:"group_id,omitempty"`
AccessLevel int64 `json:"access_level,omitempty"`
AccessLevelDescription string `json:"access_level_description,omitempty"`
RequiredApprovals int64 `json:"required_approvals"`
GroupInheritanceType int64 `json:"group_inheritance_type,omitempty"`
DeploymentApprovals []DeploymentApprovalOutput `json:"deployment_approvals,omitempty"`
}
DeploymentApprovalRuleOutput is one rule of the approval summary: who may approve, how many approvals it needs, and what has been recorded against it.
type DeploymentApprovalSummaryOutput ¶
type DeploymentApprovalSummaryOutput struct {
Rules []DeploymentApprovalRuleOutput `json:"rules,omitempty"`
}
DeploymentApprovalSummaryOutput is the rules a deployment must satisfy before it may run.
type DeploymentExtra ¶
type DeploymentExtra struct {
Approvals []DeploymentApprovalOutput `json:"approvals"`
ApprovalSummary *DeploymentApprovalSummaryOutput `json:"approval_summary"`
PendingApprovalCount int64 `json:"pending_approval_count"`
}
DeploymentExtra is what GitLab's extended deployment entity sends that client-go's Deployment does not carry: the approvals recorded so far, how many are still outstanding, and the rules they are counted against. All three are exposed under no condition, so a deployment that needs no approval carries them empty rather than not at all.
func CapturedDeployment ¶
func CapturedDeployment(capture *gitlabclient.ResponseCapture) (DeploymentExtra, error)
CapturedDeployment reads them off the captured answer to a request for one deployment.
func CapturedDeployments ¶
func CapturedDeployments(capture *gitlabclient.ResponseCapture, decoded int) ([]DeploymentExtra, error)
CapturedDeployments reads the same off a list answer, one extra per deployment in order, the count held to what the SDK decoded.
type DetailedError ¶
type DetailedError struct {
Domain string `json:"domain"`
Action string `json:"action"`
Message string `json:"message"`
Details string `json:"details,omitempty"`
GitLabStatus int `json:"gitlab_status,omitempty"`
RequestID string `json:"request_id,omitempty"`
}
DetailedError represents a rich, structured error with domain context for diagnostic output. It extends ToolError with additional fields useful for automated issue creation and Markdown error reporting.
func NewDetailedError ¶
func NewDetailedError(domain, action string, err error) *DetailedError
NewDetailedError creates a DetailedError from a GitLab API error, extracting HTTP status and request ID when available.
func (*DetailedError) Error ¶
func (e *DetailedError) Error() string
Error returns a concise representation: "domain/action: message".
func (*DetailedError) Markdown ¶
func (e *DetailedError) Markdown() string
Markdown renders the error as a Markdown block suitable for display in MCP tool results. Includes all available context for diagnostics.
type DiffLine ¶
type DiffLine struct {
OldLine int // Line number in old file (0 for added lines)
NewLine int // Line number in new file (0 for removed lines)
Type LineType // Whether the line was added, removed, or unchanged
}
DiffLine represents a single line in a parsed unified diff with its old/new line numbers and type (added, removed, or context).
func ParseDiffLines ¶
ParseDiffLines parses a unified diff string and returns metadata for each line, including old/new line numbers and whether it is added, removed, or context. Only lines inside @@ hunk headers are returned.
type DiffOutput ¶
type DiffOutput struct {
OldPath string `json:"old_path"`
NewPath string `json:"new_path"`
AMode string `json:"a_mode,omitempty"`
BMode string `json:"b_mode,omitempty"`
Diff string `json:"diff"`
NewFile bool `json:"new_file"`
RenamedFile bool `json:"renamed_file"`
DeletedFile bool `json:"deleted_file"`
}
DiffOutput represents a single file diff from the GitLab API. It is used by both commit diff and repository compare operations.
func DiffToOutput ¶
func DiffToOutput(d *gl.Diff) DiffOutput
DiffToOutput converts a GitLab API gl.Diff to the MCP tool output format.
type DiffRefsOutput ¶
type DiffRefsOutput struct {
BaseSHA string `json:"base_sha"`
HeadSHA string `json:"head_sha"`
StartSHA string `json:"start_sha"`
}
DiffRefsOutput mirrors the diff_refs object on a merge request, carrying the base, head, and start SHAs of the diff. It is byte-identical across the mergerequests and deploymentmergerequests domains; the canonical copy lives here so both packages can alias it without introducing import cycles (ADR-0004).
type DiscussionExtra ¶
type DiscussionExtra struct {
Resolvable bool `json:"resolvable"`
Resolved bool `json:"resolved"`
Notes []NoteExtra `json:"notes"`
}
DiscussionExtra is what GitLab's Discussion entity sends that client-go's Discussion does not model, the thread's own resolution state, read from the captured response beside the notes' own extras (see CapturedDiscussion).
func CapturedDiscussion ¶
func CapturedDiscussion(capture *gitlabclient.ResponseCapture) (DiscussionExtra, error)
CapturedDiscussion reads, from the captured answer of a call that returned one discussion, what GitLab sends that client-go's Discussion and its notes do not model.
func CapturedDiscussions ¶
func CapturedDiscussions(capture *gitlabclient.ResponseCapture, decoded int) ([]DiscussionExtra, error)
CapturedDiscussions reads the same from the captured answer of a call that returned a list of discussions, one extra per discussion in the list's order, the count held to what the SDK decoded as CapturedNotes holds it.
type DiscussionListMarkdownOptions ¶
type DiscussionListMarkdownOptions struct {
Title string
EmptyMessage string
Pagination PaginationOutput
GraphQLPagination *GraphQLPaginationOutput
Hints []string
}
DiscussionListMarkdownOptions configures shared discussion list rendering.
type DiscussionMarkdown ¶
type DiscussionMarkdown struct {
ID string
Notes []DiscussionNoteMarkdown
}
DiscussionMarkdown carries common discussion fields for Markdown responses.
func DiscussionMarkdowns ¶
func DiscussionMarkdowns[T any](discussions []T, convert func(T) DiscussionMarkdown) []DiscussionMarkdown
DiscussionMarkdowns maps package-specific discussion outputs to the shared discussion Markdown view model.
func DiscussionThreadOutputMarkdowns ¶
func DiscussionThreadOutputMarkdowns(discussions []DiscussionThreadOutput) []DiscussionMarkdown
DiscussionThreadOutputMarkdowns maps thread outputs to Markdown view models.
func NewDiscussionMarkdown ¶
func NewDiscussionMarkdown(id string, notes []DiscussionNoteMarkdown) DiscussionMarkdown
NewDiscussionMarkdown builds a shared Markdown view model for discussion threads.
type DiscussionNoteMarkdown ¶
DiscussionNoteMarkdown carries common note fields rendered inside discussion Markdown responses.
func DiscussionNoteMarkdowns ¶
func DiscussionNoteMarkdowns[T any](notes []T, convert func(T) DiscussionNoteMarkdown) []DiscussionNoteMarkdown
DiscussionNoteMarkdowns maps package-specific note outputs to the shared discussion note Markdown view model.
func NewDiscussionNoteMarkdown ¶
func NewDiscussionNoteMarkdown(id int64, body, author, createdAt string) DiscussionNoteMarkdown
NewDiscussionNoteMarkdown builds a shared Markdown view model for discussion notes.
type DiscussionRenderer ¶
type DiscussionRenderer struct {
ListTitle string
EmptyMessage string
ListHints []string
DiscussionHints []string
NoteHints []string
}
DiscussionRenderer stores stable labels and hints for a discussion family so package formatters can avoid repeating identical rendering glue.
func NewDiscussionRenderer ¶
func NewDiscussionRenderer(listTitle, emptyMessage, listHint, discussionHint, noteHint string) DiscussionRenderer
NewDiscussionRenderer builds a renderer for discussion tool families that use one hint for each list, discussion, and note view.
func (DiscussionRenderer) FormatDiscussion ¶
func (r DiscussionRenderer) FormatDiscussion(discussion DiscussionMarkdown) string
FormatDiscussion renders a single discussion using the renderer hints.
func (DiscussionRenderer) FormatGraphQLForwardList ¶
func (r DiscussionRenderer) FormatGraphQLForwardList(discussions []DiscussionMarkdown, pagination GraphQLForwardPaginationOutput) string
FormatGraphQLForwardList renders GraphQL discussion threads from a connection that only pages forward, so the summary line names no previous page.
func (DiscussionRenderer) FormatGraphQLList ¶
func (r DiscussionRenderer) FormatGraphQLList(discussions []DiscussionMarkdown, pagination GraphQLPaginationOutput) string
FormatGraphQLList renders GraphQL discussion threads with cursor pagination.
func (DiscussionRenderer) FormatNote ¶
func (r DiscussionRenderer) FormatNote(note DiscussionNoteMarkdown) string
FormatNote renders a single discussion note using the renderer hints.
func (DiscussionRenderer) FormatRESTList ¶
func (r DiscussionRenderer) FormatRESTList(discussions []DiscussionMarkdown, pagination PaginationOutput) string
FormatRESTList renders REST discussion threads with offset pagination.
type DiscussionThreadNoteOutput ¶
type DiscussionThreadNoteOutput struct {
HintableOutput
ID int64 `json:"id"`
Body string `json:"body"`
Author *NoteUserOutput `json:"author,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at,omitempty"`
Resolved bool `json:"resolved"`
Resolvable bool `json:"resolvable"`
ResolvedAt string `json:"resolved_at,omitempty"`
ResolvedBy *NoteUserOutput `json:"resolved_by,omitempty"`
System bool `json:"system"`
Internal bool `json:"internal"`
Confidential bool `json:"confidential"`
Type string `json:"type,omitempty"`
NoteableType string `json:"noteable_type,omitempty"`
NoteableID int64 `json:"noteable_id,omitempty"`
NoteableIID int64 `json:"noteable_iid,omitempty"`
CommitID string `json:"commit_id,omitempty"`
Position *NotePositionOutput `json:"position,omitempty"`
ProjectID int64 `json:"project_id,omitempty"`
Imported bool `json:"imported"`
ImportedFrom string `json:"imported_from,omitempty"`
CommandsChanges map[string]any `json:"commands_changes,omitempty"`
Suggestions []SuggestionOutput `json:"suggestions,omitempty"`
}
DiscussionThreadNoteOutput mirrors every field of GitLab's Note entity as it appears within a REST discussion thread (mrdiscussions, commitdiscussions, issuediscussions, snippetdiscussions). The shape differs from NoteOutput in omitempty semantics: UpdatedAt carries omitempty (absent on notes created without an update), while Resolved and Resolvable are always emitted (never omitted) because thread resolution state is always meaningful. Field order and JSON tags are locked.
func CapturedThreadNote ¶
func CapturedThreadNote(op string, n *gl.Note, capture *gitlabclient.ResponseCapture) (DiscussionThreadNoteOutput, error)
CapturedThreadNote converts one note of a thread the same way.
func DiscussionThreadNoteOutputFromGitLab ¶
func DiscussionThreadNoteOutputFromGitLab(n *gl.Note, extra NoteExtra) DiscussionThreadNoteOutput
DiscussionThreadNoteOutputFromGitLab converts a gl.Note within a discussion thread, and what the captured response adds to it, into the thread note shape. A nil note converts to the zero value, since the SDK returns []*gl.Note and an element may be nil.
func (DiscussionThreadNoteOutput) MarkdownNote ¶
func (n DiscussionThreadNoteOutput) MarkdownNote() DiscussionNoteMarkdown
MarkdownNote returns the shared Markdown view model for a thread note, naming the author by username.
type DiscussionThreadOutput ¶
type DiscussionThreadOutput struct {
HintableOutput
ID string `json:"id"`
IndividualNote bool `json:"individual_note"`
Resolvable bool `json:"resolvable"`
Resolved bool `json:"resolved,omitempty"`
Notes []*DiscussionThreadNoteOutput `json:"notes"`
}
DiscussionThreadOutput mirrors GitLab's Discussion entity with its full note payloads as returned by the REST Discussions API. Notes are pointer elements because the SDK returns []*gl.Note and individual notes may be nil in edge cases. `resolvable` and `resolved` are the thread's own, which client-go does not model; `resolved` is sent only for a resolvable thread.
func CapturedThread ¶
func CapturedThread(op string, d *gl.Discussion, capture *gitlabclient.ResponseCapture) (DiscussionThreadOutput, error)
CapturedThread converts one discussion with what its captured answer carries beside the SDK's decode, or reports under op the answer the type cannot hold. It is the whole tail of a handler that returns one thread.
func CapturedThreads ¶
func CapturedThreads(op string, ds []*gl.Discussion, capture *gitlabclient.ResponseCapture) ([]DiscussionThreadOutput, error)
CapturedThreads does the same for a list of discussions, pairing each with its own extra by position.
func DiscussionThreadOutputFromGitLab ¶
func DiscussionThreadOutputFromGitLab(d *gl.Discussion, extra DiscussionExtra) DiscussionThreadOutput
DiscussionThreadOutputFromGitLab converts a gl.Discussion and what the captured response adds to it into the thread shape, every note included. A note the capture holds no extra for, which cannot happen for an answer the SDK decoded, converts with none; a nil discussion converts to the zero value.
func DiscussionThreadOutputsFromGitLab ¶
func DiscussionThreadOutputsFromGitLab(discussions []*gl.Discussion, extras []DiscussionExtra) []DiscussionThreadOutput
DiscussionThreadOutputsFromGitLab converts a list of discussions with the extras the captured list answer holds for each, by position.
func (DiscussionThreadOutput) MarkdownDiscussion ¶
func (d DiscussionThreadOutput) MarkdownDiscussion() DiscussionMarkdown
MarkdownDiscussion returns the shared Markdown view model for a thread.
type EpicOutput ¶
type EpicOutput struct {
ID int64 `json:"id"`
IID int64 `json:"iid"`
GroupID int64 `json:"group_id"`
ParentID int64 `json:"parent_id"`
Title string `json:"title"`
Description string `json:"description"`
State string `json:"state"`
Confidential bool `json:"confidential"`
WebURL string `json:"web_url"`
URL string `json:"url"`
Author *IssueUserOutput `json:"author,omitempty"`
Labels []string `json:"labels,omitempty"`
Upvotes int64 `json:"upvotes,omitempty"`
Downvotes int64 `json:"downvotes,omitempty"`
UserNotesCount int64 `json:"user_notes_count,omitempty"`
StartDate string `json:"start_date,omitempty"`
StartDateIsFixed bool `json:"start_date_is_fixed,omitempty"`
StartDateFixed string `json:"start_date_fixed,omitempty"`
StartDateFromMilestones string `json:"start_date_from_milestones,omitempty"`
DueDate string `json:"due_date,omitempty"`
DueDateIsFixed bool `json:"due_date_is_fixed,omitempty"`
DueDateFixed string `json:"due_date_fixed,omitempty"`
DueDateFromMilestones string `json:"due_date_from_milestones,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
ClosedAt string `json:"closed_at,omitempty"`
}
EpicOutput mirrors gl.Epic (the nested epic object surfaced on issue.epic). The nested EpicAuthorOutput is the same IssueUserOutput shape used elsewhere in the issues package.
func NewEpicOutput ¶
func NewEpicOutput(e *gl.Epic) *EpicOutput
NewEpicOutput converts a gl.Epic pointer into the canonical epic object, returning nil for a nil source.
type EventExtra ¶
type EventExtra struct {
Imported bool `json:"imported"`
ImportedFrom string `json:"imported_from"`
WikiPage *EventWikiPageOutput `json:"wiki_page"`
}
EventExtra is what GitLab's event entity sends that the event itself does not say: whether the event arrived with an import rather than happening here and which platform it came from, both unconditional, and the wiki page an event about a wiki names.
func CapturedEvents ¶
func CapturedEvents(capture *gitlabclient.ResponseCapture, decoded int) ([]EventExtra, error)
CapturedEvents reads them off the captured answer to a list of events, one extra per event in order, the count held to what the SDK decoded.
type EventWikiPageOutput ¶
type EventWikiPageOutput struct {
Format string `json:"format"`
Slug string `json:"slug"`
Title string `json:"title"`
WikiPageMetaID int64 `json:"wiki_page_meta_id"`
}
EventWikiPageOutput is the wiki page an event happened to, as the basic wiki page entity renders it: how the page is written, where it lives, its title, and the identifier of the record that survives a rename.
type EvidenceOutput ¶
type EvidenceOutput struct {
SHA string `json:"sha,omitempty"`
Filepath string `json:"filepath,omitempty"`
CollectedAt string `json:"collected_at,omitempty"`
}
EvidenceOutput mirrors gl.ReleaseEvidence (the per-evidence object surfaced on the release's evidences array).
func NewEvidenceOutputs ¶
func NewEvidenceOutputs(evs []*gl.ReleaseEvidence) []*EvidenceOutput
NewEvidenceOutputs converts a slice of gl.ReleaseEvidence, skipping nil elements and returning nil for an empty input.
type FeatureDefinitionExtra ¶
type FeatureDefinitionExtra struct {
FeatureIssueURL string `json:"feature_issue_url"`
IntendedToRolloutBy string `json:"intended_to_rollout_by"`
}
FeatureDefinitionExtra is where a feature flag's definition points a reader: the issue that tracks it and the milestone it is meant to roll out by. The definition entity exposes both under no condition.
func CapturedFeatureDefinitions ¶
func CapturedFeatureDefinitions(capture *gitlabclient.ResponseCapture, decoded int) ([]FeatureDefinitionExtra, error)
CapturedFeatureDefinitions reads them off the captured answer to a list of definitions, one extra per definition in order, the count held to what the SDK decoded.
type FeatureExtra ¶
type FeatureExtra struct {
Definition FeatureDefinitionExtra `json:"definition"`
}
FeatureExtra reaches the same two keys where a feature carries its definition under a key of its own, which is the shape the feature list answers with.
func CapturedFeature ¶
func CapturedFeature(capture *gitlabclient.ResponseCapture) (FeatureExtra, error)
CapturedFeature reads them off the captured answer to a request that set one feature flag.
func CapturedFeatures ¶
func CapturedFeatures(capture *gitlabclient.ResponseCapture, decoded int) ([]FeatureExtra, error)
CapturedFeatures reads them off the captured answer to a list of features, one extra per feature in order, the count held to what the SDK decoded.
type FeatureFlagUserListExtra ¶
type FeatureFlagUserListExtra struct {
Path string `json:"path"`
EditPath string `json:"edit_path"`
}
FeatureFlagUserListExtra is where a user list lives in GitLab's own web interface, both exposed under no condition.
func CapturedFeatureFlagUserList ¶
func CapturedFeatureFlagUserList(capture *gitlabclient.ResponseCapture) (FeatureFlagUserListExtra, error)
CapturedFeatureFlagUserList reads them off the captured answer to a request for one user list.
func CapturedFeatureFlagUserLists ¶
func CapturedFeatureFlagUserLists(capture *gitlabclient.ResponseCapture, decoded int) ([]FeatureFlagUserListExtra, error)
CapturedFeatureFlagUserLists reads the same off a list answer, one extra per user list in order, the count held to what the SDK decoded.
type FormatResultFunc ¶
type FormatResultFunc func(any) *mcp.CallToolResult
FormatResultFunc converts an action result into an MCP call tool result.
type GraphQLCursor ¶
GraphQLCursor is one resolved cursor request. At most one of First and Last is set, which is what makes the direction the caller asked for the direction they get.
type GraphQLCursorPaginationInput ¶
type GraphQLCursorPaginationInput struct {
GraphQLPaginationInput
Last *int `` /* 141-byte string literal not displayed */
Before string `` /* 172-byte string literal not displayed */
}
GraphQLCursorPaginationInput adds backward pagination to GraphQLPaginationInput, for the connections GitLab lets a caller walk in both directions. Embed it only when the operation declares all four variables: GraphQLCursorPaginationInput.Variables refuses a document that does not.
func (GraphQLCursorPaginationInput) Resolve ¶
func (p GraphQLCursorPaginationInput) Resolve() (GraphQLCursor, error)
Resolve turns the four requested parameters into the pair GitLab accepts.
The cursor picks the direction and the count only sizes the page. A before cursor sent beside first is not backward pagination on any GitLab connection: the keyset ones answer it with the head of the list and the array-backed ones intersect first with last, so a caller following start_cursor back through a list would loop on the page they were already on. Sending both counts is refused rather than reinterpreted, because GitLab refuses it too and there is no reading of the pair that is not a guess.
func (GraphQLCursorPaginationInput) Variables ¶
func (p GraphQLCursorPaginationInput) Variables(document string) (map[string]any, error)
Variables returns the variable map for document, refusing a document that declares fewer variables than this input can send. See GraphQLPaginationInput.Variables for why the document is a parameter.
type GraphQLError ¶
type GraphQLError struct {
Message string `json:"message"`
}
GraphQLError is one top-level GraphQL error returned in a successful HTTP response body.
type GraphQLForwardPaginationOutput ¶
type GraphQLForwardPaginationOutput struct {
HasNextPage bool `json:"has_next_page"`
EndCursor string `json:"end_cursor,omitempty"`
}
GraphQLForwardPaginationOutput is the pagination metadata of a connection that only pages forward: whether another page follows, and the cursor that asks for it.
It exists so that a tool taking GraphQLPaginationInput cannot report a previous page. GitLab's keyset connections fill in hasPreviousPage and startCursor from their second page on whether or not the field accepts before, so a forward-only tool reporting the whole of pageInfo hands a model a cursor and no parameter to spend it on, which reads as a capability the tool withdrew rather than as the dead end it is.
func ForwardPageInfoToOutput ¶
func ForwardPageInfoToOutput(pi GraphQLRawForwardPageInfo) GraphQLForwardPaginationOutput
ForwardPageInfoToOutput converts the forward half of pageInfo, as a forward-only document selects it, to the forward-only output struct.
type GraphQLNoteMutation ¶
type GraphQLNoteMutation struct {
// Op is the operation name used in wrapped errors (e.g. "epicNoteCreate").
Op string
// Hint is the corrective hint attached to transport errors.
Hint string
// PayloadKey is the mutation payload key in the response data object
// ("createNote" or "updateNote").
PayloadKey string
// Query is the GraphQL mutation document.
Query string
// Variables holds the mutation variables.
Variables map[string]any
}
GraphQLNoteMutation describes one work item note mutation call (createNote/updateNote) so the shared executor can apply the error conventions used by every GraphQL note domain (epic notes, epic discussions): transport errors are wrapped with the operation name and corrective hint, the first mutation payload error becomes "op: message", and a missing note node becomes "op: no note returned".
type GraphQLPageInfo ¶
type GraphQLPageInfo struct {
HasNextPage bool `json:"has_next_page"`
HasPreviousPage bool `json:"has_previous_page"`
EndCursor string `json:"end_cursor,omitempty"`
StartCursor string `json:"start_cursor,omitempty"`
}
GraphQLPageInfo holds cursor-based pagination metadata returned by GraphQL connection responses. It maps directly to GitLab's PageInfo type.
type GraphQLPaginationInput ¶
type GraphQLPaginationInput struct {
First *int `json:"first,omitempty" jsonschema:"Number of items to return (default 20, max 100)"`
After string `json:"after,omitempty" jsonschema:"Cursor for forward pagination (from previous response end_cursor)"`
}
GraphQLPaginationInput holds forward cursor pagination parameters for a GraphQL list query: first and after, and nothing else.
Forward only is the safe default rather than a limitation of the helper. A connection paginates backwards only where GitLab's own field accepts before and last, and several fields this server queries refuse them: Project's branchRules and the work item notes widget's discussions both answer those arguments with argumentNotAccepted. What the two do with the backward half of pageInfo differs, which is why the promise is withdrawn in the output as well as in the input: branchRules reports no previous page and no start cursor, while the discussions widget is keyset-paginated and reports both from its second page on, offering a cursor no argument could ever spend. A domain whose field does accept the pair embeds GraphQLCursorPaginationInput, which is the only type that can put it on the wire, and reports the whole of pageInfo through GraphQLPaginationOutput; a forward-only domain reports GraphQLForwardPaginationOutput instead.
func (GraphQLPaginationInput) EffectiveFirst ¶
func (p GraphQLPaginationInput) EffectiveFirst() int
EffectiveFirst returns the requested page size, clamped to [1, GraphQLMaxFirst] with GraphQLDefaultFirst as fallback.
func (GraphQLPaginationInput) Variables ¶
func (p GraphQLPaginationInput) Variables(document string) (map[string]any, error)
Variables returns the variable map for document, which must be the operation the caller is about to execute.
The document is a parameter because a variable an operation does not declare is ignored rather than rejected: a page request carrying one is answered with somebody else's page and no error. Taking the document here is what makes that impossible, since the only way to obtain the map is to name the operation it is going to.
type GraphQLPaginationOutput ¶
type GraphQLPaginationOutput struct {
HasNextPage bool `json:"has_next_page"`
HasPreviousPage bool `json:"has_previous_page"`
EndCursor string `json:"end_cursor,omitempty"`
StartCursor string `json:"start_cursor,omitempty"`
}
GraphQLPaginationOutput holds pagination metadata for GraphQL list tool responses, presented in a consistent format for LLM consumers.
func PageInfoToOutput ¶
func PageInfoToOutput(pi GraphQLRawPageInfo) GraphQLPaginationOutput
PageInfoToOutput converts a raw GraphQL PageInfo response struct (with camelCase JSON keys from the API) to the snake_case output struct.
type GraphQLRawForwardPageInfo ¶
type GraphQLRawForwardPageInfo struct {
HasNextPage bool `json:"hasNextPage"`
EndCursor string `json:"endCursor"`
}
GraphQLRawForwardPageInfo is the half of pageInfo a forward-only document selects. A forward-only tool decodes into this rather than into GraphQLRawPageInfo, so its decoder declares exactly what its document asks for: a decoder carrying the backward half beside a document that never selects it holds two fields that are always empty, which is what make check-graphql-shapes refuses.
type GraphQLRawPageInfo ¶
type GraphQLRawPageInfo struct {
HasNextPage bool `json:"hasNextPage"`
HasPreviousPage bool `json:"hasPreviousPage"`
EndCursor string `json:"endCursor"`
StartCursor string `json:"startCursor"`
}
GraphQLRawPageInfo matches the camelCase JSON shape returned by the GitLab GraphQL API before conversion to our snake_case output.
type HintSetter ¶
type HintSetter interface {
// SetNextSteps stores the extracted next-step hints on the output struct.
SetNextSteps(hints []string)
}
HintSetter is implemented by any Output struct that embeds HintableOutput. PopulateHints uses this interface to set extracted hints on the output.
type HintableOutput ¶
type HintableOutput struct {
NextSteps []string `json:"next_steps,omitempty"`
}
HintableOutput is an embeddable struct that adds a next_steps field to any Output type. Embed it as the FIRST field of an Output struct so that next_steps appears first in the serialized JSON, giving LLMs immediate guidance before reading the rest of the payload.
type Output struct {
toolutil.HintableOutput
Name string `json:"name"`
}
func (*HintableOutput) SetNextSteps ¶
func (h *HintableOutput) SetNextSteps(hints []string)
SetNextSteps stores the given hints in the NextSteps field.
type HookHeaderOutput ¶
type HookHeaderOutput struct {
Key string `json:"key"`
}
HookHeaderOutput is one custom header a webhook sends with every delivery. Only the name is read: GitLab masks the value on the way out, and a header value is secret-bearing.
type ImpersonationTokenExtra ¶
type ImpersonationTokenExtra struct {
TokenExtra
Impersonation bool `json:"impersonation"`
Description string `json:"description"`
UserID int64 `json:"user_id"`
}
ImpersonationTokenExtra is what lib/api/entities/impersonation_token.rb sends beyond TokenExtra that client-go's ImpersonationToken does not carry. Its impersonation flag is its own; description and user_id come from the personal access token entity it inherits, which the SDK models on PersonalAccessToken and not on ImpersonationToken.
func CapturedImpersonationToken ¶
func CapturedImpersonationToken(capture *gitlabclient.ResponseCapture) (ImpersonationTokenExtra, error)
CapturedImpersonationToken reads, off the captured answer to a request for one impersonation token, the fields client-go's ImpersonationToken does not model.
func CapturedImpersonationTokens ¶
func CapturedImpersonationTokens(capture *gitlabclient.ResponseCapture, decoded int) ([]ImpersonationTokenExtra, error)
CapturedImpersonationTokens reads the same off a list answer, one extra per token in order, the count held to what the SDK decoded.
type IndividualToolAnnotationOverrides ¶
type IndividualToolAnnotationOverrides struct {
ReadOnly *bool
Destructive *bool
Idempotent *bool
OpenWorld *bool
}
IndividualToolAnnotationOverrides carries compatibility overrides for historical individual-tool annotations that intentionally differ from the canonical action semantics.
func (IndividualToolAnnotationOverrides) NarrowingOnly ¶
func (o IndividualToolAnnotationOverrides) NarrowingOnly(readOnly, idempotent bool) IndividualToolAnnotationOverrides
NarrowingOnly returns the overrides with every claim removed that would make a mutating or non-repeatable action look safer than the action itself is.
readOnlyHint and idempotentHint both say "this call is safe to make, and safe to repeat", and both are consulted by things that act on them: --read-only removes what is not read-only, safe mode previews what is not, and a gateway may auto-allow readOnlyHint:true without asking anyone. An override that raises either one is therefore not a presentation choice, it is a silent widening of the operator's own controls.
Overrides that narrow are untouched, and are the reason this type exists: a delete whose confirmation is handled elsewhere may declare destructiveHint false, and an update that is not repeatable may declare idempotentHint false.
The case this was written for is system_hook_test, a mutating create that declared readOnlyHint true on the individual surface alone because the test event changes nothing on the instance. It changes no GitLab state, but it makes GitLab deliver an event to the hook's configured URL, so it is not a read — and one action classified read-only on one surface and mutating on the other two cannot be right on more than one of them.
type IndividualToolProjectionOptions ¶
IndividualToolProjectionOptions contains surface-level metadata that is shared by an individual tool projection but not owned by the action spec itself.
type IndividualToolSpec ¶
type IndividualToolSpec struct {
Name string
Title string
Description string
AnnotationOverrides IndividualToolAnnotationOverrides
}
IndividualToolSpec carries compatibility metadata for the individual-tool surface.
func CloneIndividualToolSpec ¶
func CloneIndividualToolSpec(spec IndividualToolSpec) IndividualToolSpec
CloneIndividualToolSpec returns a defensive copy of individual-tool metadata.
type InputSchemaOverride ¶
InputSchemaOverride describes a deterministic JSON Schema patch for an action input schema. PropertyPath is a dot-separated input property path; an empty path applies Values at the schema root. Array properties automatically traverse through their items schema for nested paths.
func FilterOverridesForSchema ¶
func FilterOverridesForSchema(schema map[string]any, overrides []InputSchemaOverride) []InputSchemaOverride
FilterOverridesForSchema returns the subset of overrides whose property path still resolves against schema (an empty path targets the root and is always kept). It is used after tier pruning removes higher-tier properties: an override that targeted a now-removed field (e.g. an ultimate-only parameter pruned for a Free instance) is dropped so it does not fail [validateInputSchemaOverrides] during catalog assembly. The enum/patch values were already applied to the property before pruning, so dropping the override here only keeps the override list consistent with the pruned schema.
func SchemaAnyOfRequired ¶
func SchemaAnyOfRequired(propertyNames ...string) InputSchemaOverride
SchemaAnyOfRequired returns a root override that requires at least one of the supplied property names to be present.
func SchemaApproverIDsOverride ¶
func SchemaApproverIDsOverride(propertyPath string) InputSchemaOverride
SchemaApproverIDsOverride widens the array item type of an ApproverIDsFilter parameter so both numeric user IDs and the "Any"/"None" literals pass input validation. Without it the reflected schema advertises strings only, which would reject the numeric IDs every existing caller sends.
func SchemaEnumOverride ¶
func SchemaEnumOverride(propertyPath string, values ...string) InputSchemaOverride
SchemaEnumOverride returns an input-schema override that constrains the string parameter at propertyPath to a fixed set of enum values. It collapses the repeated `SchemaPropertyOverride(path, map[string]any{"enum": []any{...}})` block used across domains into a single call so the fixed-vocabulary constraint is expressed once per action without structural duplication.
func SchemaFormatOverride ¶
func SchemaFormatOverride(propertyPath, format string) InputSchemaOverride
SchemaFormatOverride returns an input-schema override that sets the JSON Schema `format` of the string parameter at propertyPath (e.g. "date" for a YYYY-MM-DD field or "uri" for a URL field).
func SchemaPropertyOverride ¶
func SchemaPropertyOverride(propertyPath string, values map[string]any) InputSchemaOverride
SchemaPropertyOverride returns an input-schema override for a property path.
func SchemaRootOverride ¶
func SchemaRootOverride(values map[string]any) InputSchemaOverride
SchemaRootOverride returns an input-schema override applied at the schema root.
type InstanceUserExtra ¶
type InstanceUserExtra struct {
UserExtra
BioHTML string `json:"bio_html"`
EnterpriseGroupID *int64 `json:"enterprise_group_id"`
EnterpriseGroupAssociatedAt *time.Time `json:"enterprise_group_associated_at"`
ProvisionedByGroupID *int64 `json:"provisioned_by_group_id"`
UnconfirmedEmail string `json:"unconfirmed_email"`
}
InstanceUserExtra is UserExtra plus the five keys only the instance-wide user routes ever send, which is what separates internal/tools/users from the three group-scoped packages sharing the smaller shape: those serve GET /groups/:id/{enterprise_users,provisioned_users,saml_users}, and GitLab presents every one of them with UserPublic.
bio_html comes from lib/api/entities/users/bio_html.rb, which only UserProfile includes, so of the routes here it is on GET /users/:id alone. The three license-gated keys come from ee/lib/ee/api/entities/user_with_admin.rb, which only POST /users and PUT /users/:id present. unconfirmed_email is not a user key at all: lib/api/entities/service_account.rb sends it, on the six-key object POST /service_accounts answers with, when the account has an address change waiting to be confirmed.
The two identifiers are pointers for the reason the counts are: a license that does not carry the feature sends no key, and group 0 is not that.
func CapturedInstanceUser ¶
func CapturedInstanceUser(capture *gitlabclient.ResponseCapture) (InstanceUserExtra, error)
CapturedInstanceUser reads, off the captured answer to a request for one user on an instance-wide route, everything CapturedUser reads and the five keys beside it.
func CapturedInstanceUsers ¶
func CapturedInstanceUsers(capture *gitlabclient.ResponseCapture, decoded int) ([]InstanceUserExtra, error)
CapturedInstanceUsers reads the same off a list answer, one extra per user in order, the count held to what the SDK decoded.
type InvitationExtra ¶
type InvitationExtra struct {
InviteToken string `json:"invite_token"`
}
InvitationExtra is the token lib/api/entities/invitation.rb exposes under no condition and client-go's PendingInvite does not model. It is what the invitation URL a recipient follows is built from, so a caller allowed to list a group's pending invitations can reissue one without the mail.
func CapturedPendingInvites ¶
func CapturedPendingInvites(capture *gitlabclient.ResponseCapture, decoded int) ([]InvitationExtra, error)
CapturedPendingInvites reads it off the captured answer to a list of pending invitations, one extra per invitation in order, the count held to what the SDK decoded.
type IssueLinksOutput ¶
type IssueLinksOutput struct {
Self string `json:"self"`
Notes string `json:"notes"`
AwardEmoji string `json:"award_emoji"`
Project string `json:"project"`
}
IssueLinksOutput mirrors gl.Links (the _links object on an issue). Field set is intentionally smaller than the release _links object in toolutil.LinksOutput — issues expose only self / notes / award_emoji / project URLs.
func NewIssueLinksOutput ¶
func NewIssueLinksOutput(l *gl.IssueLinks) *IssueLinksOutput
NewIssueLinksOutput converts a gl.IssueLinks value into the canonical issue-links object, returning nil for a nil source.
type IssueUserOutput ¶
type IssueUserOutput struct {
ID int64 `json:"id"`
State string `json:"state"`
WebURL string `json:"web_url"`
Name string `json:"name"`
AvatarURL string `json:"avatar_url"`
Username string `json:"username"`
}
IssueUserOutput is the documented 6-field user object that appears inside issue resources (author / assignees[] / closed_by) and inside the nested epic.author pointer. The fields mirror the per-resource JSON shape documented for issues (the full BasicUser shape omits `state` on this resource, so IssueUserOutput intentionally omits it too — see the package-local shapes.go history for the audit notes).
func NewIssueUserOutputFromBasicUser ¶
func NewIssueUserOutputFromBasicUser(u gl.BasicUser) IssueUserOutput
NewIssueUserOutputFromBasicUser converts a gl.BasicUser into the canonical issue-user shape, populating only the documented fields.
func NewIssueUserOutputFromEpicAuthor ¶
func NewIssueUserOutputFromEpicAuthor(u *gl.EpicAuthor) *IssueUserOutput
NewIssueUserOutputFromEpicAuthor converts a *gl.EpicAuthor pointer into the canonical issue-user shape. gl.EpicAuthor has the same 6 field layout as gl.BasicUser so the conversion is structural — the type distinction in the SDK is purely for documentation.
func NewIssueUserOutputFromIssueAssignee ¶
func NewIssueUserOutputFromIssueAssignee(a *gl.IssueAssignee) *IssueUserOutput
NewIssueUserOutputFromIssueAssignee converts a single *gl.IssueAssignee pointer into the canonical issue-user shape (used for the deprecated singular Assignee field on gl.Issue).
func NewIssueUserOutputFromIssueAuthor ¶
func NewIssueUserOutputFromIssueAuthor(u *gl.IssueAuthor) *IssueUserOutput
NewIssueUserOutputFromIssueAuthor converts a *gl.IssueAuthor pointer into the canonical issue-user shape. gl.IssueAuthor is the dedicated author type on gl.Issue (distinct from gl.BasicUser so the documented "issues have an author" reference is preserved) — fields are the same 6 we surface elsewhere.
func NewIssueUserOutputFromIssueCloser ¶
func NewIssueUserOutputFromIssueCloser(u *gl.IssueCloser) *IssueUserOutput
NewIssueUserOutputFromIssueCloser converts a *gl.IssueCloser pointer into the canonical issue-user shape. Same 6-field layout as the other issue-user types.
func NewIssueUserOutputFromPointer ¶
func NewIssueUserOutputFromPointer(u *gl.BasicUser) *IssueUserOutput
NewIssueUserOutputFromPointer converts a *gl.BasicUser, returning nil for a nil source so call sites can pass through SDK pointers without an extra nil check.
func NewIssueUserOutputsFromIssueAssignees ¶
func NewIssueUserOutputsFromIssueAssignees(as []*gl.IssueAssignee) []*IssueUserOutput
NewIssueUserOutputsFromIssueAssignees converts a slice of gl.IssueAssignee, skipping nil entries and returning nil for an empty / all-nil input.
type IterationOutput ¶
type IterationOutput struct {
ID int64 `json:"id"`
IID int64 `json:"iid"`
Sequence int64 `json:"sequence"`
GroupID int64 `json:"group_id"`
Title string `json:"title"`
Description string `json:"description"`
State int64 `json:"state"`
WebURL string `json:"web_url"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
StartDate string `json:"start_date,omitempty"`
DueDate string `json:"due_date,omitempty"`
}
IterationOutput mirrors gl.Iteration (the iteration object surfaced on issue.iteration). State is an int per the SDK type (an enum of 0=upcoming, 1=current, 2=closed).
func NewIterationOutput ¶
func NewIterationOutput(it *gl.Iteration) *IterationOutput
NewIterationOutput converts a gl.Iteration pointer into the canonical iteration object, returning nil for a nil source.
func NewIterationOutputFromGroupIteration ¶
func NewIterationOutputFromGroupIteration(it *gl.GroupIteration) *IterationOutput
NewIterationOutputFromGroupIteration converts a gl.GroupIteration pointer (the type surfaced on gl.Issue.Iteration) into the canonical iteration object. gl.GroupIteration has the same 11 fields as gl.Iteration but with a separate type identity for documentation.
func NewIterationOutputFromProjectIteration ¶
func NewIterationOutputFromProjectIteration(it *gl.ProjectIteration) *IterationOutput
NewIterationOutputFromProjectIteration converts a gl.ProjectIteration pointer (the type surfaced on board lists) into the canonical iteration object. gl.ProjectIteration has the same field layout as gl.Iteration but with a separate type identity for documentation.
type JSONDepthScanner ¶
type JSONDepthScanner struct {
// contains filtered or unexported fields
}
JSONDepthScanner measures the nesting depth of a JSON value one chunk at a time, so a body can be judged as it streams rather than after it is buffered.
It counts brackets and braces outside string literals, which is all that nesting depth is, and deliberately does not validate the JSON: a scanner that also parsed would be a second, divergent implementation of a decoder this server already runs twice. Miscounting a malformed document is harmless because the decoder behind it refuses that document anyway, and the count is never an undercount for the shape this exists to stop.
The zero value is not usable; construct one with NewJSONDepthScanner.
func NewJSONDepthScanner ¶
func NewJSONDepthScanner(limit int) *JSONDepthScanner
NewJSONDepthScanner returns a scanner that trips once nesting passes limit.
func (*JSONDepthScanner) Exceeded ¶
func (s *JSONDepthScanner) Exceeded() bool
Exceeded reports whether any chunk scanned so far passed the limit.
func (*JSONDepthScanner) Scan ¶
func (s *JSONDepthScanner) Scan(chunk []byte) bool
Scan folds the next chunk of bytes into the measurement and reports whether the limit has been passed. State carries across calls, so the chunk boundaries an io.Reader happens to produce do not change the answer.
type KeyExtra ¶
type KeyExtra struct {
ExpiresAt *time.Time `json:"expires_at"`
LastUsedAt *time.Time `json:"last_used_at"`
UsageType string `json:"usage_type"`
}
KeyExtra is what lib/api/entities/ssh_key.rb sends on a key that client-go's Key does not carry: the expiry, the last use and the usage type, all sent on every key.
func CapturedKey ¶
func CapturedKey(capture *gitlabclient.ResponseCapture) (KeyExtra, error)
CapturedKey reads, off the captured answer to a request for one key, the fields client-go's Key does not model.
type KeysetPaginationInput ¶
type KeysetPaginationInput struct {
Pagination string `` /* 185-byte string literal not displayed */
PageToken string `` /* 186-byte string literal not displayed */
}
KeysetPaginationInput holds GitLab keyset-pagination parameters for list endpoints that support keyset pagination in addition to offset pagination. Embed it alongside PaginationInput on a list input and wire it with ApplyListOptions. Keyset pagination is more efficient than offset pagination for deep pages of large, ordered result sets.
type LabelDetailsOutput ¶
type LabelDetailsOutput struct {
ID int64 `json:"id"`
Name string `json:"name"`
Color string `json:"color"`
Description string `json:"description"`
DescriptionHTML string `json:"description_html"`
TextColor string `json:"text_color"`
}
LabelDetailsOutput mirrors gl.LabelDetails (the inline label details surfaced on labels array inside issue and MR resources).
func NewLabelDetailsOutputs ¶
func NewLabelDetailsOutputs(details []*gl.LabelDetails) []*LabelDetailsOutput
NewLabelDetailsOutputs converts a slice of gl.LabelDetails, skipping nil entries and returning nil for an empty / all-nil input.
type LabelExtra ¶
type LabelExtra struct {
DescriptionHTML string `json:"description_html"`
}
LabelExtra is what lib/api/entities/label.rb sends on a label that client-go's Label and GroupLabel do not carry: the description rendered as HTML, sent on every label.
func CapturedLabel ¶
func CapturedLabel(capture *gitlabclient.ResponseCapture) (LabelExtra, error)
CapturedLabel reads, off the captured answer to a request for one label, the field client-go's label structs do not model.
func CapturedLabels ¶
func CapturedLabels(capture *gitlabclient.ResponseCapture, decoded int) ([]LabelExtra, error)
CapturedLabels reads the same off a list answer, one extra per label in order, the count held to what the SDK decoded.
type LabelMarkdown ¶
type LabelMarkdown struct {
ID int64
Name string
Color string
Description string
OpenIssuesCount int64
ClosedIssuesCount int64
OpenMergeRequestsCount int64
Priority int64
PrioritySpecified bool
IsProjectLabel bool
Subscribed bool
}
LabelMarkdown holds the common fields rendered for project and group labels.
type LabelMarkdownOptions ¶
type LabelMarkdownOptions struct {
DetailTitle string
ListTitle string
EmptyListText string
DetailHints []string
ListHints []string
EscapeDescription bool
}
LabelMarkdownOptions controls label detail and list Markdown copy.
type LastPipelineOutput ¶
type LastPipelineOutput struct {
ID int64 `json:"id"`
IID int64 `json:"iid,omitempty"`
ProjectID int64 `json:"project_id,omitempty"`
Status string `json:"status,omitempty"`
Source string `json:"source,omitempty"`
Ref string `json:"ref,omitempty"`
SHA string `json:"sha,omitempty"`
Name string `json:"name,omitempty"`
WebURL string `json:"web_url,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
}
LastPipelineOutput mirrors gl.PipelineInfo, the pipeline summary embedded in a commit payload as last_pipeline (commits, branch head commits).
func NewLastPipelineOutput ¶
func NewLastPipelineOutput(p *gl.PipelineInfo) *LastPipelineOutput
NewLastPipelineOutput maps gl.PipelineInfo to *LastPipelineOutput, or nil when the commit has no associated pipeline.
type LicenseTemplateExtra ¶
type LicenseTemplateExtra struct {
Popular bool `json:"popular"`
}
LicenseTemplateExtra is whether a license template is one of the popular ones GitLab offers first, exposed under no condition.
func CapturedLicenseTemplate ¶
func CapturedLicenseTemplate(capture *gitlabclient.ResponseCapture) (LicenseTemplateExtra, error)
CapturedLicenseTemplate reads it off the captured answer to a request for one template.
func CapturedLicenseTemplates ¶
func CapturedLicenseTemplates(capture *gitlabclient.ResponseCapture, decoded int) ([]LicenseTemplateExtra, error)
CapturedLicenseTemplates reads the same off a list answer, one extra per template in order, the count held to what the SDK decoded.
type LinePositionOutput ¶
type LinePositionOutput struct {
LineCode string `json:"line_code,omitempty"`
Type string `json:"type,omitempty"`
OldLine int64 `json:"old_line,omitempty"`
NewLine int64 `json:"new_line,omitempty"`
}
LinePositionOutput mirrors gl.LinePosition: one endpoint (start or end) of a multi-line diff note position.
func NewLinePositionOutput ¶
func NewLinePositionOutput(p *gl.LinePosition) *LinePositionOutput
NewLinePositionOutput converts a *gl.LinePosition into the canonical-key line-position object, returning nil when the SDK value is nil.
type LineRangeOutput ¶
type LineRangeOutput struct {
Start *LinePositionOutput `json:"start,omitempty"`
End *LinePositionOutput `json:"end,omitempty"`
}
LineRangeOutput mirrors gl.LineRange (the start/end of a multi-line diff note position). The full *LinePositionOutput objects are surfaced on the canonical `start` / `end` keys (mirroring gl.LineRange.StartRange / gl.LineRange.EndRange, whose JSON tags are `start` / `end`).
func NewLineRangeOutput ¶
func NewLineRangeOutput(lr *gl.LineRange) *LineRangeOutput
NewLineRangeOutput converts a *gl.LineRange into the line-range object, returning nil when absent (or when both endpoints are nil).
type LineType ¶
type LineType int
LineType classifies a line within a unified diff hunk.
const ( // LineContext identifies an unchanged line present in both old and new file versions. LineContext LineType = iota // Unchanged line (present in both old and new file) // LineAdded identifies a line present only in the new file version. LineAdded // Added line (present only in new file) // LineRemoved identifies a line present only in the old file version. LineRemoved // Removed line (present only in old file) )
type LinksOutput ¶
type LinksOutput struct {
Self string `json:"self,omitempty"`
EditURL string `json:"edit_url,omitempty"`
OpenedIssuesURL string `json:"opened_issues_url,omitempty"`
OpenedMergeRequestsURL string `json:"opened_merge_requests_url,omitempty"`
MergedMergeRequestsURL string `json:"merged_merge_requests_url,omitempty"`
ClosedIssuesURL string `json:"closed_issues_url,omitempty"`
ClosedMergeRequestsURL string `json:"closed_merge_requests_url,omitempty"`
}
LinksOutput mirrors gl.ReleaseLinks (the _links object on a release). Per the documented release-by-tag response GitLab returns URL strings for self, edit, opened_issues, opened_merge_requests, merged_merge_requests, and closed_merge_requests. The JSON tags follow the SDK's snake_case pluralisation (opened_issues_url, etc.) which differs from the older opened_issues / merged_issues / closed_issues names used in some docs.
func NewLinksOutput ¶
func NewLinksOutput(l gl.ReleaseLinks) *LinksOutput
NewLinksOutput converts a gl.ReleaseLinks into the canonical-key links object, returning nil when the SDK value has every URL field empty.
type LintExtra ¶
type LintExtra struct {
Jobs []LintJobOutput `json:"jobs"`
}
LintExtra is what lib/api/entities/ci/lint/result.rb sends that client-go's ProjectLintResult does not carry.
func CapturedLint ¶
func CapturedLint(capture *gitlabclient.ResponseCapture) (LintExtra, error)
CapturedLint reads, off the captured answer to a lint request, the jobs array client-go does not model.
type LintJobOutput ¶
type LintJobOutput struct {
Name string `json:"name"`
Stage string `json:"stage"`
BeforeScript []string `json:"before_script"`
Script []string `json:"script"`
AfterScript []string `json:"after_script"`
TagList []string `json:"tag_list"`
Only any `json:"only,omitempty"`
Except any `json:"except,omitempty"`
Environment any `json:"environment,omitempty"`
When string `json:"when"`
AllowFailure bool `json:"allow_failure"`
Needs any `json:"needs,omitempty"`
}
LintJobOutput is one job of the jobs array a CI lint answer carries when include_jobs is set, built by lib/gitlab/ci/lint.rb from the processed configuration; client-go's ProjectLintResult does not carry the array. A static check carries only, except and needs as the configuration spelled them, so those three keep the JSON shape GitLab sent, and environment is the name on a pipeline simulation and the configuration on a static check.
type MRMilestoneOutput ¶
type MRMilestoneOutput struct {
ID int64 `json:"id"`
IID int64 `json:"iid"`
GroupID int64 `json:"group_id"`
ProjectID int64 `json:"project_id"`
Title string `json:"title"`
Description string `json:"description"`
State string `json:"state"`
WebURL string `json:"web_url"`
StartDate string `json:"start_date,omitempty"`
DueDate string `json:"due_date,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
Expired *bool `json:"expired,omitempty"`
}
MRMilestoneOutput mirrors gl.Milestone as surfaced inside merge request and issue resources. Distinct from toolutil.MilestoneOutput (the release-milestone shape) — see file-level comment for the rationale and field-level deltas.
func NewMRMilestoneOutputs ¶
func NewMRMilestoneOutputs(ms []*gl.Milestone) []*MRMilestoneOutput
NewMRMilestoneOutputs converts a slice of gl.Milestone, skipping nil entries and returning nil for an empty / all-nil input.
type MemberExtra ¶
type MemberExtra struct {
Locked bool `json:"locked"`
PublicEmail string `json:"public_email"`
MembershipState string `json:"membership_state"`
TwoFactorEnabled *bool `json:"two_factor_enabled"`
GroupSAMLIdentity *SAMLIdentityOutput `json:"group_saml_identity"`
GroupSCIMIdentity *SCIMIdentityOutput `json:"group_scim_identity"`
Override *bool `json:"override"`
// AvatarPath is the avatar as a path on the instance rather than a full
// URL, and CustomAttributes the attributes an administrator who asked for
// them receives. Both come from the user object merged into the member.
AvatarPath string `json:"avatar_path"`
CustomAttributes []CustomAttributeOutput `json:"custom_attributes"`
}
MemberExtra is what lib/api/entities/member.rb sends on a member that client-go's GroupMember and ProjectMember do not carry, read from the captured response beside the SDK's own decode (ADR-0021). locked is on every member and membership_state on every member of an Enterprise instance; the rest are sent when their condition holds, so each is a pointer that stays nil otherwise. public_email and group_saml_identity are on GroupMember, and only a project member reads them from here.
func CapturedMember ¶
func CapturedMember(capture *gitlabclient.ResponseCapture) (MemberExtra, error)
CapturedMember reads, off the captured answer to a request for one member, the fields client-go's member structs do not model. A body that decoded for the SDK and does not for MemberExtra is reported, since the fault is then in the type naming the fields.
func CapturedMembers ¶
func CapturedMembers(capture *gitlabclient.ResponseCapture, decoded int) ([]MemberExtra, error)
CapturedMembers reads the same off a list answer, one extra per member in order, the count held to what the SDK decoded as CapturedNotes holds it.
type MemberRoleOutput ¶
type MemberRoleOutput struct {
ID int64 `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
GroupID int64 `json:"group_id"`
BaseAccessLevel int `json:"base_access_level"`
AdminCICDVariables bool `json:"admin_cicd_variables,omitempty"`
AdminComplianceFramework bool `json:"admin_compliance_framework,omitempty"`
AdminGroupMembers bool `json:"admin_group_member,omitempty"`
AdminMergeRequests bool `json:"admin_merge_request,omitempty"`
AdminPushRules bool `json:"admin_push_rules,omitempty"`
AdminTerraformState bool `json:"admin_terraform_state,omitempty"`
AdminVulnerability bool `json:"admin_vulnerability,omitempty"`
AdminWebHook bool `json:"admin_web_hook,omitempty"`
ArchiveProject bool `json:"archive_project,omitempty"`
ManageDeployTokens bool `json:"manage_deploy_tokens,omitempty"`
ManageGroupAccessTokens bool `json:"manage_group_access_tokens,omitempty"`
ManageMergeRequestSettings bool `json:"manage_merge_request_settings,omitempty"`
ManageProjectAccessTokens bool `json:"manage_project_access_tokens,omitempty"`
ManageSecurityPolicyLink bool `json:"manage_security_policy_link,omitempty"`
ReadCode bool `json:"read_code,omitempty"`
ReadRunners bool `json:"read_runners,omitempty"`
ReadDependency bool `json:"read_dependency,omitempty"`
ReadVulnerability bool `json:"read_vulnerability,omitempty"`
RemoveGroup bool `json:"remove_group,omitempty"`
RemoveProject bool `json:"remove_project,omitempty"`
}
MemberRoleOutput mirrors gl.MemberRole (the member_role object). Custom member roles are an Enterprise (Premium/Ultimate) feature; the object is nil on instances or members without a custom role. All permission flags are surfaced for 1:1 SDK fidelity.
func NewMemberRoleOutput ¶
func NewMemberRoleOutput(r *gl.MemberRole) *MemberRoleOutput
NewMemberRoleOutput mirrors a gl.MemberRole into the shared output shape, returning nil when the SDK value is nil.
type MemberUserOutput ¶
type MemberUserOutput struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
State string `json:"state"`
AvatarURL string `json:"avatar_url,omitempty"`
WebURL string `json:"web_url,omitempty"`
}
MemberUserOutput mirrors gl.MemberCreatedBy (the created_by object).
func NewMemberUserOutput ¶
func NewMemberUserOutput(u *gl.MemberCreatedBy) *MemberUserOutput
NewMemberUserOutput mirrors a gl.MemberCreatedBy into the shared output shape, returning nil when the SDK value is nil.
type MergeRequestDiffExtra ¶
type MergeRequestDiffExtra struct {
PatchIDSHA string `json:"patch_id_sha"`
}
MergeRequestDiffExtra is the patch id of a merge request version, which identifies the change independently of the commits carrying it. The diff entity exposes it under no condition.
func CapturedMergeRequestDiff ¶
func CapturedMergeRequestDiff(capture *gitlabclient.ResponseCapture) (MergeRequestDiffExtra, error)
CapturedMergeRequestDiff reads it off the captured answer to a request for one version.
func CapturedMergeRequestDiffs ¶
func CapturedMergeRequestDiffs(capture *gitlabclient.ResponseCapture, decoded int) ([]MergeRequestDiffExtra, error)
CapturedMergeRequestDiffs reads the same off a list answer, one extra per version in order, the count held to what the SDK decoded.
type MergeRequestExtra ¶
type MergeRequestExtra struct {
ApprovalsBeforeMerge *int64 `json:"approvals_before_merge"`
MergeStatus string `json:"merge_status"`
Reference string `json:"reference"`
WorkInProgress bool `json:"work_in_progress"`
TitleHTML string `json:"title_html"`
DescriptionHTML string `json:"description_html"`
}
MergeRequestExtra is what lib/api/entities/merge_request_basic.rb sends that client-go's BasicMergeRequest does not carry.
Four of the six are the older spelling of something the entity also sends under a newer name, and GitLab still sends both: merge_status beside detailed_merge_status, reference beside references, work_in_progress beside draft, and approvals_before_merge beside the approval rules API. Deprecated is not absent, and a caller reading a merge request through this server should see what GitLab put on the wire.
title_html and description_html are the exception: the entity exposes them under the render_html presenter option, and of every route GitLab mounts only GET /projects/:id/merge_requests/:merge_request_iid declares render_html as a request parameter. They arrive on that one response, when the caller asked for them, and on no other, which is why the output shape publishes them omitempty and why a type serving only the other routes leaves them out altogether.
approvals_before_merge is a pointer because GitLab sends null where no approval count applies, which a bare int64 would flatten into zero, a number that means something else.
func CapturedMergeRequest ¶
func CapturedMergeRequest(capture *gitlabclient.ResponseCapture) (MergeRequestExtra, error)
CapturedMergeRequest reads them off the captured answer to a request that returned one merge request.
func CapturedMergeRequests ¶
func CapturedMergeRequests(capture *gitlabclient.ResponseCapture, decoded int) ([]MergeRequestExtra, error)
CapturedMergeRequests reads the same off a list answer, one extra per merge request in order, the count held to what the SDK decoded.
type MergeRequestOutput ¶
type MergeRequestOutput struct {
HintableOutput
ID int64 `json:"id"`
IID int64 `json:"iid"`
ProjectID int64 `json:"project_id"`
SourceProjectID int64 `json:"source_project_id,omitempty"`
TargetProjectID int64 `json:"target_project_id,omitempty"`
Title string `json:"title"`
Description string `json:"description"`
State string `json:"state"`
Imported bool `json:"imported,omitempty"`
ImportedFrom string `json:"imported_from,omitempty"`
SourceBranch string `json:"source_branch"`
TargetBranch string `json:"target_branch"`
WebURL string `json:"web_url"`
DetailedMergeStatus string `json:"detailed_merge_status,omitempty"`
Draft bool `json:"draft"`
WorkInProgress bool `json:"work_in_progress,omitempty"`
HasConflicts bool `json:"has_conflicts"`
BlockingDiscussionsResolved bool `json:"blocking_discussions_resolved"`
Squash bool `json:"squash,omitempty"`
SquashOnMerge bool `json:"squash_on_merge,omitempty"`
MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds,omitempty"`
ShouldRemoveSourceBranch bool `json:"should_remove_source_branch,omitempty"`
AllowMaintainerToPush bool `json:"allow_maintainer_to_push,omitempty"`
DiscussionLocked bool `json:"discussion_locked"`
RebaseInProgress bool `json:"rebase_in_progress,omitempty"`
Author *BasicUserOutput `json:"author,omitempty"`
Assignee *BasicUserOutput `json:"assignee,omitempty"`
MergeUser *BasicUserOutput `json:"merge_user,omitempty"`
MergedBy *BasicUserOutput `json:"merged_by,omitempty"`
ClosedBy *BasicUserOutput `json:"closed_by,omitempty"`
Assignees []*BasicUserOutput `json:"assignees"`
Reviewers []*BasicUserOutput `json:"reviewers"`
Labels []string `json:"labels"`
LabelDetails []*LabelDetailsOutput `json:"label_details,omitempty"`
Milestone *MRMilestoneOutput `json:"milestone,omitempty"`
References *ReferencesOutput `json:"references,omitempty"`
SHA string `json:"sha,omitempty"`
MergeCommitSHA string `json:"merge_commit_sha,omitempty"`
MergeError string `json:"merge_error,omitempty"`
ChangesCount string `json:"changes_count,omitempty"`
DivergedCommitsCount int64 `json:"diverged_commits_count,omitempty"`
Upvotes int64 `json:"upvotes,omitempty"`
Downvotes int64 `json:"downvotes,omitempty"`
SquashCommitSHA string `json:"squash_commit_sha,omitempty"`
ForceRemoveSourceBranch bool `json:"force_remove_source_branch,omitempty"`
AllowCollaboration bool `json:"allow_collaboration,omitempty"`
MergeAfter string `json:"merge_after,omitempty"`
TaskCompletionStatus *TaskCompletionStatusOutput `json:"task_completion_status,omitempty"`
TimeStats *TimeStatsOutput `json:"time_stats,omitempty"`
Subscribed bool `json:"subscribed,omitempty"`
FirstContribution bool `json:"first_contribution,omitempty"`
User *MergeRequestUserOutput `json:"user,omitempty"`
DiffRefs *DiffRefsOutput `json:"diff_refs,omitempty"`
Pipeline *PipelineInfoOutput `json:"pipeline,omitempty"`
HeadPipeline *PipelineOutput `json:"head_pipeline,omitempty"`
LatestBuildStartedAt string `json:"latest_build_started_at,omitempty"`
LatestBuildFinishedAt string `json:"latest_build_finished_at,omitempty"`
FirstDeployedToProductionAt string `json:"first_deployed_to_production_at,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
MergedAt string `json:"merged_at,omitempty"`
ClosedAt string `json:"closed_at,omitempty"`
PreparedAt string `json:"prepared_at,omitempty"`
UserNotesCount int64 `json:"user_notes_count,omitempty"`
// The keys GitLab's merge request entity sends that client-go's structs do
// not model, read from the captured response beside the SDK's own decode
// (ADR-0021) and described on [MergeRequestExtra]. approvals_before_merge
// carries the tier the sibling shapes already give it, since the count only
// exists where merge request approvals are licensed.
ApprovalsBeforeMerge *int64 `json:"approvals_before_merge,omitempty" tier:"premium"`
MergeStatus string `json:"merge_status,omitempty"`
Reference string `json:"reference,omitempty"`
TitleHTML string `json:"title_html,omitempty"`
DescriptionHTML string `json:"description_html,omitempty"`
}
MergeRequestOutput mirrors gl.MergeRequest (the full merge-request payload returned by MR list/get/create/update endpoints). It is the canonical Output shape shared by the mergerequests and deploymentmergerequests domains via type aliases, eliminating the ~80-line duplicated struct block identified by SonarCloud while avoiding cross-package import cycles (ADR-0004).
HintableOutput is embedded first so next_steps appears at the top of the serialized JSON, giving LLMs workflow guidance before parsing the payload.
func (*MergeRequestOutput) ApplyExtra ¶
func (o *MergeRequestOutput) ApplyExtra(extra MergeRequestExtra)
ApplyExtra fills the keys read off the captured response.
It is a method rather than six assignments at each call site because the merge request converters are reached from four packages, and a key added to MergeRequestExtra that one of them forgot would be a schema field nothing ever fills.
work_in_progress is filled from here even though client-go models it, because it models it on MergeRequest alone: a list decodes into BasicMergeRequest, which does not carry it, so before this the key was published on every list and set on none of them. The capture reads the same bytes the SDK decoded, so the two answers cannot disagree where both exist.
type MergeRequestUserOutput ¶
type MergeRequestUserOutput struct {
CanMerge bool `json:"can_merge"`
}
MergeRequestUserOutput mirrors gl.MergeRequestUser (the user object inside MR.user_notes_count type contexts — only the CanMerge flag is part of the documented subset).
func NewMergeRequestUserOutput ¶
func NewMergeRequestUserOutput(u *gl.MergeRequestUser) *MergeRequestUserOutput
NewMergeRequestUserOutput converts a gl.MergeRequestUser pointer into the canonical-key MR user object, returning nil for a nil source.
type MetaSchemaActionEntry ¶
type MetaSchemaActionEntry struct {
Action string `json:"action"`
SchemaURI string `json:"schema_uri"`
Destructive bool `json:"destructive"`
}
MetaSchemaActionEntry describes one meta-tool action in the tool-call index.
type MetaSchemaDiscoveryIndex ¶
type MetaSchemaDiscoveryIndex struct {
URITemplate string `json:"uri_template"`
ToolCount int `json:"tool_count"`
ActionCount int `json:"action_count"`
Tools []MetaSchemaToolEntry `json:"tools"`
}
MetaSchemaDiscoveryIndex is a model-controlled schema discovery payload.
func BuildMetaSchemaDiscoveryIndex ¶
func BuildMetaSchemaDiscoveryIndex(routes map[string]ActionMap) MetaSchemaDiscoveryIndex
BuildMetaSchemaDiscoveryIndex builds the richer tool-call schema index payload.
func BuildMetaSchemaDiscoveryIndexForTool ¶
func BuildMetaSchemaDiscoveryIndexForTool(routes map[string]ActionMap, tool string) (MetaSchemaDiscoveryIndex, bool)
BuildMetaSchemaDiscoveryIndexForTool builds the tool-call index for one meta-tool.
type MetaSchemaIndex ¶
type MetaSchemaIndex struct {
URITemplate string `json:"uri_template"`
Tools []MetaSchemaIndexEntry `json:"tools"`
}
MetaSchemaIndex is the payload returned by the schema index resource.
func BuildMetaSchemaIndex ¶
func BuildMetaSchemaIndex(routes map[string]ActionMap) MetaSchemaIndex
BuildMetaSchemaIndex builds the resource-compatible schema index payload.
type MetaSchemaIndexEntry ¶
MetaSchemaIndexEntry is a single tool entry in the resource index payload.
type MetaSchemaRegistry ¶
type MetaSchemaRegistry struct {
// contains filtered or unexported fields
}
MetaSchemaRegistry stores the visible meta-tool route snapshot used by model-controlled schema discovery actions.
func NewMetaSchemaRegistry ¶
func NewMetaSchemaRegistry(routes map[string]ActionMap) *MetaSchemaRegistry
NewMetaSchemaRegistry creates a registry initialized with a route snapshot.
func (*MetaSchemaRegistry) Routes ¶
func (r *MetaSchemaRegistry) Routes() map[string]ActionMap
Routes returns a snapshot of the registry contents, taken with CloneMetaSchemaRoutes: later SetRoutes calls do not reach it, and the schemas in it are shared and must not be mutated.
func (*MetaSchemaRegistry) SetRoutes ¶
func (r *MetaSchemaRegistry) SetRoutes(routes map[string]ActionMap)
SetRoutes replaces the registry contents with a snapshot of routes, taken with CloneMetaSchemaRoutes: the maps are the registry's own, the schemas inside them are shared with the caller and frozen.
type MetaSchemaToolEntry ¶
type MetaSchemaToolEntry struct {
Tool string `json:"tool"`
ActionCount int `json:"action_count"`
Actions []MetaSchemaActionEntry `json:"actions"`
}
MetaSchemaToolEntry describes one meta-tool in the tool-call index.
type MetaToolInput ¶
type MetaToolInput struct {
Action string `json:"action" jsonschema:"Action to perform. See the tool description for available actions and their parameters."`
Params map[string]any `` /* 147-byte string literal not displayed */
}
MetaToolInput is the common input for all meta-tools. The LLM sends an action name and a params object; the dispatcher routes to the underlying handler function and deserializes params into the action-specific input struct.
type MilestoneExtra ¶
MilestoneExtra is what GitLab's milestone entity sends that a group milestone struct does not carry: the milestone's own page, exposed under no condition, and the project a project-scoped milestone belongs to, exposed only when there is one, so a group milestone leaves it zero.
func CapturedMilestone ¶
func CapturedMilestone(capture *gitlabclient.ResponseCapture) (MilestoneExtra, error)
CapturedMilestone reads them off the captured answer to a request for one milestone.
func CapturedMilestones ¶
func CapturedMilestones(capture *gitlabclient.ResponseCapture, decoded int) ([]MilestoneExtra, error)
CapturedMilestones reads the same off a list answer, one extra per milestone in order, the count held to what the SDK decoded.
type MilestoneIssueStatsOutput ¶
type MilestoneIssueStatsOutput struct {
Total int64 `json:"total,omitempty"`
Closed int64 `json:"closed,omitempty"`
}
MilestoneIssueStatsOutput mirrors gl.ReleaseMilestoneIssueStats (the total / closed counts object surfaced under each associated milestone on a release).
func NewMilestoneIssueStatsOutput ¶
func NewMilestoneIssueStatsOutput(s *gl.ReleaseMilestoneIssueStats) *MilestoneIssueStatsOutput
NewMilestoneIssueStatsOutput converts a gl.ReleaseMilestoneIssueStats into the canonical-key stats object.
type MilestoneOutput ¶
type MilestoneOutput struct {
ID int64 `json:"id,omitempty"`
IID int64 `json:"iid,omitempty"`
ProjectID int64 `json:"project_id,omitempty"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
State string `json:"state,omitempty"`
WebURL string `json:"web_url,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
StartDate string `json:"start_date,omitempty"`
DueDate string `json:"due_date,omitempty"`
IssueStats *MilestoneIssueStatsOutput `json:"issue_stats,omitempty"`
}
MilestoneOutput mirrors gl.ReleaseMilestone (the milestone object surfaced on the release's milestones array). Timestamps are surfaced as RFC 3339 strings via toolutil.FormatTimePtr / FormatISOTimePtr.
func NewMilestoneOutputs ¶
func NewMilestoneOutputs(ms []*gl.ReleaseMilestone) []*MilestoneOutput
NewMilestoneOutputs converts a slice of gl.ReleaseMilestone, skipping nil elements and returning nil for an empty input. Timestamps are formatted as RFC 3339 (or YYYY-MM-DD for ISOTime).
type NamespaceBasicOutput ¶
type NamespaceBasicOutput struct {
ID int64 `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Kind string `json:"kind"`
FullPath string `json:"full_path"`
ParentID int64 `json:"parent_id,omitempty"`
AvatarURL string `json:"avatar_url,omitempty"`
WebURL string `json:"web_url,omitempty"`
}
NamespaceBasicOutput mirrors lib/api/entities/namespace_basic.rb, the group object GitLab renders on a todo raised in a group rather than a project.
type NamespaceExtra ¶
type NamespaceExtra struct {
ProjectsCount int64 `json:"projects_count"`
RootRepositorySize int64 `json:"root_repository_size"`
AdditionalPurchasedStorageSize *int64 `json:"additional_purchased_storage_size"`
AdditionalPurchasedStorageEndsOn string `json:"additional_purchased_storage_ends_on"`
MaxSeatsUsedChangedAt *time.Time `json:"max_seats_used_changed_at"`
EndDate string `json:"end_date"`
}
NamespaceExtra is what GitLab's namespace entity sends to a caller allowed to see it. An administrator asking about a group is told how many projects it holds and how much room their repositories take; a caller who may change the namespace's limits is told the compute minutes and the purchased storage; and a namespace with a subscription carries when that subscription ends and when its seat high-water mark last moved.
func CapturedNamespace ¶
func CapturedNamespace(capture *gitlabclient.ResponseCapture) (NamespaceExtra, error)
CapturedNamespace reads them off the captured answer to a request for one namespace.
func CapturedNamespaces ¶
func CapturedNamespaces(capture *gitlabclient.ResponseCapture, decoded int) ([]NamespaceExtra, error)
CapturedNamespaces reads the same off a list answer, one extra per namespace in order, the count held to what the SDK decoded.
type NoteExtra ¶
type NoteExtra struct {
Confidential bool `json:"confidential"`
Imported bool `json:"imported"`
ImportedFrom string `json:"imported_from"`
CommandsChanges map[string]any `json:"commands_changes"`
Suggestions []SuggestionOutput `json:"suggestions"`
Author NoteUserExtra `json:"author"`
ResolvedBy NoteUserExtra `json:"resolved_by"`
}
NoteExtra is what GitLab's Note entity sends that client-go's Note does not model, read from the captured response beside the SDK's own decoding (see CapturedNote). `confidential` is here too: client-go carries it as a deprecated field some converters read and others mirror from `internal`, and reading GitLab's own value ends that difference.
func CapturedNote ¶
func CapturedNote(capture *gitlabclient.ResponseCapture) (NoteExtra, error)
CapturedNote reads, from the captured answer of a call that returned one note, what GitLab sends that client-go's Note does not model.
func CapturedNotes ¶
func CapturedNotes(capture *gitlabclient.ResponseCapture, decoded int) ([]NoteExtra, error)
CapturedNotes reads the same from the captured answer of a call that returned a list of notes, one extra per note in the list's order. The count is held to what the SDK decoded: the two read the same bytes, so a difference is a fault in this reader and not in GitLab's answer.
type NoteListMarkdownOptions ¶
type NoteListMarkdownOptions struct {
Title string
EmptyMessage string
IncludeInternal bool
Hints []string
}
NoteListMarkdownOptions configures shared note list rendering.
type NoteMarkdown ¶
type NoteMarkdown struct {
ID int64
Body string
Author string
CreatedAt string
System bool
Internal bool
Resolvable bool
Resolved bool
ResolvedBy string
}
NoteMarkdown carries common fields rendered by issue, merge request, and snippet note tools.
func NewNoteMarkdown ¶
func NewNoteMarkdown(id int64, body, author, createdAt string, flags NoteMarkdownFlags, resolvedBy string) NoteMarkdown
NewNoteMarkdown builds a shared Markdown view model for GitLab notes.
func NoteMarkdowns ¶
func NoteMarkdowns[T any](notes []T, convert func(T) NoteMarkdown) []NoteMarkdown
NoteMarkdowns maps package-specific note outputs to the shared note Markdown view model.
type NoteMarkdownFlags ¶
NoteMarkdownFlags groups boolean note attributes for Markdown view-model construction.
type NoteMarkdownOptions ¶
type NoteMarkdownOptions struct {
Title string
IncludeInternal bool
IncludeResolvable bool
Hints []string
}
NoteMarkdownOptions configures shared note detail rendering.
type NoteOutput ¶
type NoteOutput struct {
HintableOutput
ID int64 `json:"id"`
Body string `json:"body"`
Author *NoteUserOutput `json:"author,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
System bool `json:"system"`
Internal bool `json:"internal"`
Resolvable bool `json:"resolvable,omitempty"`
Resolved bool `json:"resolved,omitempty"`
ResolvedAt string `json:"resolved_at,omitempty"`
ResolvedBy *NoteUserOutput `json:"resolved_by,omitempty"`
NoteableType string `json:"noteable_type,omitempty"`
NoteableID int64 `json:"noteable_id,omitempty"`
NoteableIID int64 `json:"noteable_iid,omitempty"`
CommitID string `json:"commit_id,omitempty"`
Type string `json:"type,omitempty"`
Position *NotePositionOutput `json:"position,omitempty"`
ProjectID int64 `json:"project_id,omitempty"`
Confidential bool `json:"confidential"`
Imported bool `json:"imported"`
ImportedFrom string `json:"imported_from,omitempty"`
CommandsChanges map[string]any `json:"commands_changes,omitempty"`
Suggestions []SuggestionOutput `json:"suggestions,omitempty"`
}
NoteOutput mirrors every field of GitLab's Note entity as the REST Notes API sends it (notes on merge requests, issues, snippets, etc.): the fields client-go's Note models, and the ones only the captured response carries. It is the canonical shared output shape for standalone note tools (mrnotes, issuenotes). Field order and JSON tags are locked; any change is a breaking wire-format change.
`attachment`, `title`, `file_name` and `expires_at`, which client-go's Note still carries, are not here: GitLab's entity does not expose them, and the R-PATH type grain reported them as fields no operation sends.
func NoteOutputFromGitLab ¶
func NoteOutputFromGitLab(n *gl.Note, extra NoteExtra) NoteOutput
NoteOutputFromGitLab converts a gl.Note and what the captured response adds to it into the canonical NoteOutput shape used by standalone note tools (mrnotes, issuenotes). Timestamps are formatted as RFC 3339 strings.
type NotePositionOutput ¶
type NotePositionOutput struct {
BaseSHA string `json:"base_sha,omitempty"`
StartSHA string `json:"start_sha,omitempty"`
HeadSHA string `json:"head_sha,omitempty"`
PositionType string `json:"position_type,omitempty"`
NewPath string `json:"new_path,omitempty"`
NewLine int64 `json:"new_line,omitempty"`
OldPath string `json:"old_path,omitempty"`
OldLine int64 `json:"old_line,omitempty"`
LineRange *LineRangeOutput `json:"line_range,omitempty"`
}
NotePositionOutput mirrors gl.NotePosition: the diff position of a note that is attached to a specific line of a file.
func NewNotePositionOutput ¶
func NewNotePositionOutput(p *gl.NotePosition) *NotePositionOutput
NewNotePositionOutput converts a *gl.NotePosition into the position object, returning nil when the note has no diff position.
type NoteUserExtra ¶
NoteUserExtra is what a note's author or resolver carries that client-go's NoteAuthor and NoteResolvedBy do not model, read from the captured response.
type NoteUserOutput ¶
type NoteUserOutput = UserBasicOutput
NoteUserOutput mirrors GitLab's UserBasic entity, which is what a note's author and resolver are rendered with: the identity fields, the account state and lock, and the two URLs. It carries no email, since UserBasic exposes `public_email` and never `email`; client-go's NoteAuthor carries an `email` GitLab does not send, and `public_email` and `locked` it does not model, which is why the two shared values come from the captured response (see NoteUserExtra).
func NewNoteUserOutputFromAuthor ¶
func NewNoteUserOutputFromAuthor(a gl.NoteAuthor, extra NoteUserExtra) *NoteUserOutput
NewNoteUserOutputFromAuthor converts a gl.NoteAuthor value into the additive author object. The author is always present on a note, so this returns a pointer to a populated value (never nil) to keep the canonical `author` key stable.
func NewNoteUserOutputFromResolvedBy ¶
func NewNoteUserOutputFromResolvedBy(r gl.NoteResolvedBy, extra NoteUserExtra) *NoteUserOutput
NewNoteUserOutputFromResolvedBy converts a gl.NoteResolvedBy value into the resolved-by object, returning nil when no user has resolved the note (zero ID + empty username).
type OnceMap ¶
type OnceMap[K comparable, V any] struct { // contains filtered or unexported fields }
OnceMap memoizes one value per key and builds each value exactly once, however many callers ask for it at the same moment.
The caches this replaces were all written as load, build, store-if-absent, which is correct and wasteful in the one situation they exist for: the HTTP pool starting a server per credential, where every one of them misses the same cold key, every one builds a full copy of a registry shape, a manifest snapshot or a reflected schema, and all but one are dropped having cost what the survivor cost. The entry carries the sync.Once, so the callers that lose the race wait for the winner's build instead of racing it.
The zero value is ready to use. The mutex is held only while the entry is looked up, never while a value is built, so builds for different keys still run in parallel.
func (*OnceMap[K, V]) Load ¶
func (m *OnceMap[K, V]) Load(key K, build func() V) V
Load returns the value memoized for key, calling build to produce it the first time the key is asked for. Concurrent callers for one key wait for that single build; callers for different keys build in parallel.
A build that returns a zero value is memoized like any other, so a deterministic failure is not retried on every call. A build that panics memoizes nothing: the panic reaches its own caller unchanged and the key is left to be built again, which is what the load, build, store-if-absent caches this replaced did. sync.Once does not do that by itself, since it marks itself done however its function ends, so the spent slot is dropped by the next caller to find it holding nothing. Without that the key would be poisoned for the life of the process: the zero value served to everyone, no rebuild, and OnceMap.Peek reporting that nobody ever built it.
type PackageExtra ¶
type PackageExtra struct {
CreatorID int64 `json:"creator_id"`
ConanPackageName string `json:"conan_package_name"`
ProjectID int64 `json:"project_id"`
ProjectPath string `json:"project_path"`
Versions []PackageVersionOutput `json:"versions"`
}
PackageExtra is what GitLab's package entity sends that the package itself does not say: who published it, unconditionally; the Conan recipe's own name on a Conan package; the owning project's id and path, sent when the package is listed across a group; and the package's other versions, sent when one package is asked for rather than a page of them.
func CapturedPackages ¶
func CapturedPackages(capture *gitlabclient.ResponseCapture, decoded int) ([]PackageExtra, error)
CapturedPackages reads them off the captured answer to a list of packages, one extra per package in order, the count held to what the SDK decoded.
type PackagePipelineOutput ¶
type PackagePipelineOutput struct {
ID int64 `json:"id"`
IID int64 `json:"iid"`
ProjectID int64 `json:"project_id"`
SHA string `json:"sha"`
Ref string `json:"ref"`
Status string `json:"status"`
Source string `json:"source"`
CreatedAt *time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
WebURL string `json:"web_url"`
User *UserBasicOutput `json:"user"`
}
PackagePipelineOutput is the pipeline that built a package version, sent to a caller allowed to read it.
type PackageTagOutput ¶
type PackageTagOutput struct {
ID int64 `json:"id"`
PackageID int64 `json:"package_id"`
Name string `json:"name"`
CreatedAt *time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
}
PackageTagOutput is one tag pointing at a package version.
type PackageVersionOutput ¶
type PackageVersionOutput struct {
ID int64 `json:"id"`
Version string `json:"version"`
CreatedAt *time.Time `json:"created_at"`
Tags []PackageTagOutput `json:"tags"`
Pipeline *PackagePipelineOutput `json:"pipeline"`
}
PackageVersionOutput is one other version of the same package, with the tags pointing at it and the pipeline that built it.
type PagesCertificateExpirationOutput ¶
type PagesCertificateExpirationOutput struct {
Expired bool `json:"expired"`
Expiration *time.Time `json:"expiration"`
}
PagesCertificateExpirationOutput is when a Pages domain's certificate stops being valid, and whether it already has.
type PagesDomainExtra ¶
type PagesDomainExtra struct {
CertificateExpiration *PagesCertificateExpirationOutput `json:"certificate_expiration"`
}
PagesDomainExtra is that object on the domain, which GitLab exposes only on a domain that has a certificate at all.
func CapturedPagesDomain ¶
func CapturedPagesDomain(capture *gitlabclient.ResponseCapture) (PagesDomainExtra, error)
CapturedPagesDomain reads it off the captured answer to a request for one domain.
func CapturedPagesDomains ¶
func CapturedPagesDomains(capture *gitlabclient.ResponseCapture, decoded int) ([]PagesDomainExtra, error)
CapturedPagesDomains reads the same off a list answer, one extra per domain in order, the count held to what the SDK decoded.
type PaginationInput ¶
type PaginationInput struct {
Page int `` /* 156-byte string literal not displayed */
PerPage int `` /* 156-byte string literal not displayed */
}
PaginationInput holds common pagination query parameters for list endpoints. Constraints (page>=1, per_page in [1,100]) are also enforced at the JSON Schema level by EnrichPaginationConstraints so LLM clients see the bounds directly in tools/list responses.
type PaginationOutput ¶
type PaginationOutput struct {
Page int64 `json:"page"`
PerPage int64 `json:"per_page"`
TotalItems int64 `json:"total_items"`
TotalPages int64 `json:"total_pages"`
NextPage int64 `json:"next_page"`
PrevPage int64 `json:"prev_page"`
HasMore bool `json:"has_more"`
}
PaginationOutput holds pagination metadata extracted from GitLab API responses. Fields map to GitLab's X-Page, X-Per-Page, X-Total, X-Total-Pages, X-Next-Page, X-Prev-Page headers. HasMore is a derived convenience flag (NextPage > 0) so LLM clients can decide whether to paginate without inspecting NextPage.
func PaginationFromResponse ¶
func PaginationFromResponse(resp *gl.Response) PaginationOutput
PaginationFromResponse extracts pagination metadata from a GitLab API response.
type ParamAliasExplanation ¶
type ParamAliasExplanation struct {
Alias string `json:"alias"`
Canonical string `json:"canonical"`
Source string `json:"source"`
Notes string `json:"notes,omitempty"`
}
ParamAliasExplanation describes a compatibility parameter normalization. It intentionally records parameter names only, never parameter values.
func NormalizeParamAliasesForSchemaWithExplanation ¶
func NormalizeParamAliasesForSchemaWithExplanation(params, schema map[string]any) (map[string]any, []ParamAliasExplanation)
NormalizeParamAliasesForSchemaWithExplanation returns the normalized params and name-only metadata describing compatibility aliases that were applied.
type ParamValidationError ¶
type ParamValidationError struct {
Err error
}
ParamValidationError marks parameter decoding failures that should be surfaced as recoverable tool errors instead of protocol errors.
func (*ParamValidationError) Error ¶
func (e *ParamValidationError) Error() string
Error returns the underlying validation error message.
func (*ParamValidationError) Unwrap ¶
func (e *ParamValidationError) Unwrap() error
Unwrap returns the underlying validation error.
type ParameterAliasSpec ¶
type ParameterAliasSpec struct {
Alias string
Target string
Source string
Searchable bool
Deprecated bool
RemovalVersion string
Reason string
}
ParameterAliasSpec describes a compatibility alias for one action parameter.
type ParameterGuidance ¶
type ParameterGuidance struct {
SemanticRole string `json:"semantic_role,omitempty"`
ValueSource string `json:"value_source,omitempty"`
CommonConfusions []string `json:"common_confusions,omitempty"`
ExampleBinding string `json:"example_binding,omitempty"`
}
ParameterGuidance carries compact model-facing hints for parameters that are easy to confuse across similar GitLab actions.
func DiscussionIDParamGuidance ¶
func DiscussionIDParamGuidance(valueSource string) ParameterGuidance
DiscussionIDParamGuidance returns the canonical parameter guidance for the discussion_id parameter used by discussion-scoped actions across the discussion domains (MR, issue, snippet, commit, epic). valueSource is the domain-specific description of where the thread id comes from; the semantic role, example binding, and thread-vs-note confusion note are identical for every domain.
func DiscussionNoteIDParamGuidance ¶
func DiscussionNoteIDParamGuidance(valueSource string) ParameterGuidance
DiscussionNoteIDParamGuidance returns the canonical parameter guidance for the note_id parameter of discussion note update/delete actions. valueSource is the domain-specific description of where the note id comes from; the semantic role, example binding, and note-vs-thread confusion note are identical for every discussion domain.
type PersonalTokenOutput ¶
type PersonalTokenOutput struct {
ID int64 `json:"id"`
Name string `json:"name"`
Active bool `json:"active"`
Token string `json:"token,omitempty"`
Scopes []string `json:"scopes"`
Granular bool `json:"granular"`
GranularScopes []TokenGranularScopeOutput `json:"granular_scopes,omitempty"`
Revoked bool `json:"revoked"`
Description string `json:"description,omitempty"`
UserID int64 `json:"user_id"`
CreatedAt string `json:"created_at,omitempty"`
ExpiresAt string `json:"expires_at,omitempty"`
LastUsedAt string `json:"last_used_at,omitempty"`
LastUsedIPs []string `json:"last_used_ips,omitempty"`
}
PersonalTokenOutput mirrors gl.PersonalAccessToken as surfaced by the impersonation-token and current-user PAT tools: identity, scopes, and RFC3339/ISO-date lifecycle timestamps. The token value is only present on creation responses. It also carries what lib/api/entities/personal_access_token.rb sends and the SDK struct does not model, read from the captured response (ADR-0021): whether the token is granular, its granular scopes when it is and the endpoint asked for them, and the addresses it was last used from while the instance exposes them.
func NewPersonalTokenOutput ¶
func NewPersonalTokenOutput(t *gl.PersonalAccessToken, extra TokenExtra) PersonalTokenOutput
NewPersonalTokenOutput converts a gl.PersonalAccessToken into the shared output shape, formatting created/last-used as RFC3339 and expiry as an ISO date, and takes the fields the capture read beside the SDK.
type PipelineDetailedStatusIllustrationOutput ¶
type PipelineDetailedStatusIllustrationOutput struct {
Image string `json:"image"`
}
PipelineDetailedStatusIllustrationOutput mirrors gl.DetailedStatus.Illustration (the icon image sub-object).
func NewPipelineDetailedStatusIllustrationOutput ¶
func NewPipelineDetailedStatusIllustrationOutput(image string) *PipelineDetailedStatusIllustrationOutput
NewPipelineDetailedStatusIllustrationOutput is reserved for SDK versions that surface Illustration as a pointer; currently the SDK exposes it as a value type, so NewPipelineDetailedStatusOutput handles the conversion inline. Kept for forward compatibility.
type PipelineDetailedStatusOutput ¶
type PipelineDetailedStatusOutput struct {
Icon string `json:"icon"`
Text string `json:"text"`
Label string `json:"label"`
Group string `json:"group"`
Tooltip string `json:"tooltip"`
HasDetails bool `json:"has_details"`
DetailsPath string `json:"details_path"`
Illustration *PipelineDetailedStatusIllustrationOutput `json:"illustration,omitempty"`
Favicon string `json:"favicon"`
}
PipelineDetailedStatusOutput mirrors gl.DetailedStatus (the icon / text / label / group / tooltip / details_path / illustration / favicon object that GitLab returns inside gl.Pipeline.DetailedStatus).
func NewPipelineDetailedStatusOutput ¶
func NewPipelineDetailedStatusOutput(s *gl.DetailedStatus) *PipelineDetailedStatusOutput
NewPipelineDetailedStatusOutput converts a *gl.DetailedStatus into the canonical-key detailed-status object, returning nil when the SDK value is nil. The SDK's Illustration field is a non-pointer gl.DetailedStatusIllustration value; we surface the nested image only when populated, keeping the canonical nil-on-empty contract.
type PipelineExtra ¶
type PipelineExtra struct {
Archived bool `json:"archived"`
}
PipelineExtra is what lib/api/entities/ci/pipeline.rb sends on a pipeline that client-go's Pipeline does not carry: whether it is archived, sent on every pipeline rendered whole.
func CapturedPipeline ¶
func CapturedPipeline(capture *gitlabclient.ResponseCapture) (PipelineExtra, error)
CapturedPipeline reads, off the captured answer to a request for one pipeline, the field client-go's Pipeline does not model.
type PipelineInfoOutput ¶
type PipelineInfoOutput struct {
ID int64 `json:"id"`
IID int64 `json:"iid"`
ProjectID int64 `json:"project_id"`
Status string `json:"status"`
Source string `json:"source"`
Ref string `json:"ref"`
SHA string `json:"sha"`
Name string `json:"name"`
WebURL string `json:"web_url"`
UpdatedAt string `json:"updated_at,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
}
PipelineInfoOutput mirrors gl.PipelineInfo (the compact pipeline summary surfaced on a merge request's head_pipeline / pipeline fields).
func NewPipelineInfoOutput ¶
func NewPipelineInfoOutput(p *gl.PipelineInfo) *PipelineInfoOutput
NewPipelineInfoOutput converts a gl.PipelineInfo pointer into the canonical-key pipeline info object, returning nil for a nil source.
type PipelineOutput ¶
type PipelineOutput struct {
ID int64 `json:"id"`
IID int64 `json:"iid"`
ProjectID int64 `json:"project_id"`
Status string `json:"status"`
Source string `json:"source"`
Ref string `json:"ref"`
Name string `json:"name"`
SHA string `json:"sha"`
BeforeSHA string `json:"before_sha"`
Tag bool `json:"tag"`
YamlErrors string `json:"yaml_errors"`
User *BasicUserOutput `json:"user,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
StartedAt string `json:"started_at,omitempty"`
FinishedAt string `json:"finished_at,omitempty"`
CommittedAt string `json:"committed_at,omitempty"`
Duration int64 `json:"duration"`
QueuedDuration int64 `json:"queued_duration"`
Coverage string `json:"coverage"`
WebURL string `json:"web_url"`
DetailedStatus *PipelineDetailedStatusOutput `json:"detailed_status,omitempty"`
}
PipelineOutput mirrors gl.Pipeline (the per-pipeline summary object returned by head_pipeline, merge_train.pipeline, deployment.merge_request .head_pipeline, etc.). It surfaces every field of the SDK struct that the documented GitLab API returns (1:1 audit policy) plus the nested user and detailed_status sub-objects on their canonical keys.
func NewPipelineOutput ¶
func NewPipelineOutput(p *gl.Pipeline) *PipelineOutput
NewPipelineOutput converts a *gl.Pipeline into the canonical-key pipeline object, returning nil when the SDK value is nil. Timestamps are surfaced as RFC 3339 strings via toolutil.FormatTimePtr.
type PipelineTriggerExtra ¶
PipelineTriggerExtra is when a trigger token stops working, exposed under no condition and null on a token that never expires.
func CapturedPipelineTrigger ¶
func CapturedPipelineTrigger(capture *gitlabclient.ResponseCapture) (PipelineTriggerExtra, error)
CapturedPipelineTrigger reads it off the captured answer to a request for one trigger.
func CapturedPipelineTriggers ¶
func CapturedPipelineTriggers(capture *gitlabclient.ResponseCapture, decoded int) ([]PipelineTriggerExtra, error)
CapturedPipelineTriggers reads the same off a list answer, one extra per trigger in order, the count held to what the SDK decoded.
type ProgressReader ¶
type ProgressReader struct {
// contains filtered or unexported fields
}
ProgressReader wraps an io.Reader and reports progress to an MCP progress tracker as bytes are read. Safe to use with a zero-value/inactive tracker.
func NewProgressReader ¶
func NewProgressReader(ctx context.Context, r io.Reader, total int64, tracker progress.Tracker) *ProgressReader
NewProgressReader creates a ProgressReader that reports upload progress. If the tracker is inactive, the wrapper still works but skips notifications.
func (*ProgressReader) BytesRead ¶
func (pr *ProgressReader) BytesRead() int64
BytesRead returns the total number of bytes read so far.
type ProgressWriter ¶
type ProgressWriter struct {
// contains filtered or unexported fields
}
ProgressWriter wraps an io.Writer and reports progress to an MCP progress tracker as bytes are written (used for downloads to disk).
func NewProgressWriter ¶
func NewProgressWriter(ctx context.Context, w io.Writer, total int64, tracker progress.Tracker) *ProgressWriter
NewProgressWriter creates a ProgressWriter that reports download progress.
func (*ProgressWriter) BytesWritten ¶
func (pw *ProgressWriter) BytesWritten() int64
BytesWritten returns the total number of bytes written so far.
type ProtectedBranchExtra ¶
type ProtectedBranchExtra struct {
Inherited bool `json:"inherited"`
}
ProtectedBranchExtra is whether a protected branch rule was inherited from the group rather than declared on the project, exposed under no condition.
func CapturedProtectedBranch ¶
func CapturedProtectedBranch(capture *gitlabclient.ResponseCapture) (ProtectedBranchExtra, error)
CapturedProtectedBranch reads it off the captured answer to a request for one protected branch.
func CapturedProtectedBranches ¶
func CapturedProtectedBranches(capture *gitlabclient.ResponseCapture, decoded int) ([]ProtectedBranchExtra, error)
CapturedProtectedBranches reads the same off a list answer, one extra per branch in order, the count held to what the SDK decoded.
type RateLimiter ¶
type RateLimiter struct {
// contains filtered or unexported fields
}
RateLimiter enforces a token-bucket rate limit on the methods that cost a deployment something: those reaching GitLab with the caller's credential, plus `completion/complete` and `tools/list`, each on the bucket AttachRateLimit describes. A zero RPS disables the limiter (the constructor returns nil and the resulting middleware is a no-op).
Limits are advisory; the primary defense remains GitLab's own per-token rate limits. The local limiter exists to soften bursts (typical LLM retry-loop with a flaky tool can fire dozens of identical calls per second) and to give operators a single knob they can tighten when they see 429s in practice. HTTP mode enables it by default (10 rps, burst 40); stdio leaves it off, since there the bucket would be global to one client.
The limiter shares a single bucket across the server. In HTTP mode each server instance from the pool gets its own RateLimiter, so the limit is effectively per token and GitLab URL. In stdio mode the bucket is global to the single process.
rate.Limiter is safe for concurrent use by design, so RateLimiter does not need additional synchronization of its own.
func NewRateLimiter ¶
func NewRateLimiter(rps float64, burst int) *RateLimiter
NewRateLimiter builds a RateLimiter with the given rate (requests per second) and burst (maximum concurrent tokens in the bucket). Returns nil if rps <= 0, which the middleware treats as "disabled". Burst is clamped to a minimum of 1 when rps > 0 to avoid an unusable zero-burst limiter.
type ReferencesOutput ¶
type ReferencesOutput struct {
Short string `json:"short"`
Relative string `json:"relative"`
Full string `json:"full"`
}
ReferencesOutput mirrors gl.References (the short / relative / full reference triplet surfaced inside issue and MR resources).
func NewReferencesOutput ¶
func NewReferencesOutput(r *gl.IssueReferences) *ReferencesOutput
NewReferencesOutput converts a gl.IssueReferences value into the canonical-key references object, returning nil when the source is the zero value.
type RegistryRepositoryExtra ¶
type RegistryRepositoryExtra struct {
Size int64 `json:"size"`
DeleteAPIPath string `json:"delete_api_path"`
}
RegistryRepositoryExtra is what GitLab's container registry repository entity sends beside the name and the path: the size, when the caller asked for it, and the path a caller allowed to administer images deletes through.
func CapturedRegistryRepositories ¶
func CapturedRegistryRepositories(capture *gitlabclient.ResponseCapture, decoded int) ([]RegistryRepositoryExtra, error)
CapturedRegistryRepositories reads the same off a list answer, one extra per repository in order, the count held to what the SDK decoded.
func CapturedRegistryRepository ¶
func CapturedRegistryRepository(capture *gitlabclient.ResponseCapture) (RegistryRepositoryExtra, error)
CapturedRegistryRepository reads them off the captured answer to a request for one repository.
type ResourceMilestoneEventExtra ¶
type ResourceMilestoneEventExtra struct {
State string `json:"state"`
}
ResourceMilestoneEventExtra is the issue or merge request's own state at the moment the milestone changed, which the milestone event entity exposes under no condition.
func CapturedResourceMilestoneEvent ¶
func CapturedResourceMilestoneEvent(capture *gitlabclient.ResponseCapture) (ResourceMilestoneEventExtra, error)
CapturedResourceMilestoneEvent reads it off the captured answer to a request for one event.
func CapturedResourceMilestoneEvents ¶
func CapturedResourceMilestoneEvents(capture *gitlabclient.ResponseCapture, decoded int) ([]ResourceMilestoneEventExtra, error)
CapturedResourceMilestoneEvents reads the same off a list answer, one extra per event in order, the count held to what the SDK decoded.
type ResourceStateEventExtra ¶
type ResourceStateEventExtra struct {
SourceCommit string `json:"source_commit"`
SourceMergeRequestID int64 `json:"source_merge_request_id"`
}
ResourceStateEventExtra is what GitLab's resource state event entity sends that client-go's StateEvent does not carry: the commit that closed the issue, and the merge request that did, each empty when something else did.
func CapturedResourceStateEvent ¶
func CapturedResourceStateEvent(capture *gitlabclient.ResponseCapture) (ResourceStateEventExtra, error)
CapturedResourceStateEvent reads them off the captured answer to a request for one event.
func CapturedResourceStateEvents ¶
func CapturedResourceStateEvents(capture *gitlabclient.ResponseCapture, decoded int) ([]ResourceStateEventExtra, error)
CapturedResourceStateEvents reads the same off a list answer, one extra per event in order, the count held to what the SDK decoded.
type ResourceTokenExtra ¶
type ResourceTokenExtra struct {
TokenExtra
ResourceType string `json:"resource_type"`
ResourceID int64 `json:"resource_id"`
}
ResourceTokenExtra is what lib/api/entities/resource_access_token.rb sends beyond TokenExtra on a project or group access token: which kind of resource the token belongs to and its id, the second absent when the bot user has no namespace.
func CapturedResourceToken ¶
func CapturedResourceToken(capture *gitlabclient.ResponseCapture) (ResourceTokenExtra, error)
CapturedResourceToken reads, off the captured answer to a request for one project or group access token, the fields the SDK's resource access token does not model.
func CapturedResourceTokens ¶
func CapturedResourceTokens(capture *gitlabclient.ResponseCapture, decoded int) ([]ResourceTokenExtra, error)
CapturedResourceTokens reads the same off a list answer, one extra per token in order, the count held to what the SDK decoded.
type RunnerExtra ¶
type RunnerExtra struct {
CreatedAt *time.Time `json:"created_at"`
CreatedBy *UserBasicOutput `json:"created_by"`
JobExecutionStatus string `json:"job_execution_status"`
}
RunnerExtra is what lib/api/entities/ci/runner.rb sends on a runner that client-go's Runner and RunnerDetails do not carry: when it was created, who created it, sent to a caller allowed to read that user, and the job execution status.
func CapturedRunner ¶
func CapturedRunner(capture *gitlabclient.ResponseCapture) (RunnerExtra, error)
CapturedRunner reads, off the captured answer to a request for one runner, the fields client-go's runner structs do not model.
func CapturedRunners ¶
func CapturedRunners(capture *gitlabclient.ResponseCapture, decoded int) ([]RunnerExtra, error)
CapturedRunners reads the same off a list answer, one extra per runner in order, the count held to what the SDK decoded.
type RunnerManagerExtra ¶
type RunnerManagerExtra struct {
JobExecutionStatus string `json:"job_execution_status"`
}
RunnerManagerExtra is what the manager is doing now, exposed under no condition on the runner manager entity. It is the same key RunnerExtra carries on the runner itself and a different object: a runner's status is the aggregate of its managers'.
func CapturedRunnerManagers ¶
func CapturedRunnerManagers(capture *gitlabclient.ResponseCapture, decoded int) ([]RunnerManagerExtra, error)
CapturedRunnerManagers reads it off the captured answer to a list of managers, one extra per manager in order, the count held to what the SDK decoded.
type SAMLIdentityOutput ¶
type SAMLIdentityOutput struct {
ExternUID string `json:"extern_uid"`
Provider string `json:"provider"`
SAMLProviderID int64 `json:"saml_provider_id"`
}
SAMLIdentityOutput mirrors gl.GroupMemberSAMLIdentity (the group_saml_identity object).
func NewSAMLIdentityOutput ¶
func NewSAMLIdentityOutput(s *gl.GroupMemberSAMLIdentity) *SAMLIdentityOutput
NewSAMLIdentityOutput mirrors a gl.GroupMemberSAMLIdentity into the shared output shape, returning nil when the SDK value is nil.
type SCIMIdentityExtra ¶
type SCIMIdentityExtra struct {
ExternUID string `json:"extern_uid"`
}
SCIMIdentityExtra is the identifier the SCIM provider knows a user by, which GitLab's identity detail entity exposes under no condition.
func CapturedSCIMIdentities ¶
func CapturedSCIMIdentities(capture *gitlabclient.ResponseCapture, decoded int) ([]SCIMIdentityExtra, error)
CapturedSCIMIdentities reads the same off a list answer, one extra per identity in order, the count held to what the SDK decoded.
func CapturedSCIMIdentity ¶
func CapturedSCIMIdentity(capture *gitlabclient.ResponseCapture) (SCIMIdentityExtra, error)
CapturedSCIMIdentity reads it off the captured answer to a request for one identity.
type SCIMIdentityOutput ¶
type SCIMIdentityOutput struct {
ExternUID string `json:"extern_uid"`
GroupID int64 `json:"group_id"`
Active bool `json:"active"`
}
SCIMIdentityOutput mirrors the group_scim_identity object, ee/lib/api/entities/scim_identity.rb, which client-go does not model: the SCIM identity a member holds in an SSO-enabled group, sent to the group's owners.
type SafeModePreview ¶
type SafeModePreview struct {
Status string `json:"status"`
Mode string `json:"mode"`
Tool string `json:"tool"`
Params json.RawMessage `json:"params"`
Hint string `json:"hint"`
}
SafeModePreview is the structured response returned when a mutating operation is intercepted by Safe Mode. Status is always "blocked", Mode is "safe", Tool names the intercepted tool or canonical action, Params mirrors the would-be call arguments, and Hint tells the operator how to disable safe mode.
func NewSafeModePreview ¶
func NewSafeModePreview(name string, params any) SafeModePreview
NewSafeModePreview builds a preview for name, marshaling params defensively: when params cannot be marshaled the preview still reports the blocked operation with a null params payload rather than failing the call.
type SecureFileExtra ¶
type SecureFileExtra struct {
FileExtension string `json:"file_extension"`
}
SecureFileExtra is a secure file's extension, exposed under no condition.
func CapturedSecureFile ¶
func CapturedSecureFile(capture *gitlabclient.ResponseCapture) (SecureFileExtra, error)
CapturedSecureFile reads it off the captured answer to a request for one secure file.
func CapturedSecureFiles ¶
func CapturedSecureFiles(capture *gitlabclient.ResponseCapture, decoded int) ([]SecureFileExtra, error)
CapturedSecureFiles reads the same off a list answer, one extra per file in order, the count held to what the SDK decoded.
type ServiceAccountExtra ¶
type ServiceAccountExtra struct {
PublicEmail string `json:"public_email"`
UnconfirmedEmail string `json:"unconfirmed_email"`
}
ServiceAccountExtra is what GitLab's service account entity sends beside the name and username: the public email always, and the unconfirmed one while a change of address is waiting to be confirmed.
Both keys are read here for the group endpoint, whose GroupServiceAccount carries neither. The project endpoint's ServiceAccount already models the unconfirmed address, so that package takes it from the SDK and only the public email from here: the same GitLab entity, modeled twice upstream and unevenly.
func CapturedServiceAccount ¶
func CapturedServiceAccount(capture *gitlabclient.ResponseCapture) (ServiceAccountExtra, error)
CapturedServiceAccount reads them off the captured answer to a request for one service account.
func CapturedServiceAccounts ¶
func CapturedServiceAccounts(capture *gitlabclient.ResponseCapture, decoded int) ([]ServiceAccountExtra, error)
CapturedServiceAccounts reads the same off a list answer, one extra per account in order, the count held to what the SDK decoded.
type SnippetExtra ¶
type SnippetExtra struct {
Imported bool `json:"imported"`
ImportedFrom string `json:"imported_from"`
SSHURLToRepo string `json:"ssh_url_to_repo"`
HTTPURLToRepo string `json:"http_url_to_repo"`
}
SnippetExtra is what GitLab's snippet entity sends that the snippet itself does not say: whether it arrived with an import rather than being written here and which platform it came from, both unconditional, and the two clone URLs of its repository, sent once that repository exists.
func CapturedSnippet ¶
func CapturedSnippet(capture *gitlabclient.ResponseCapture) (SnippetExtra, error)
CapturedSnippet reads them off the captured answer to a request for one snippet.
func CapturedSnippets ¶
func CapturedSnippets(capture *gitlabclient.ResponseCapture, decoded int) ([]SnippetExtra, error)
CapturedSnippets reads the same off a list answer, one extra per snippet in order, the count held to what the SDK decoded.
type StorageMoveEntityMarkdown ¶
StorageMoveEntityMarkdown carries the optional GitLab resource associated with a repository storage move.
func NewStorageMoveEntityMarkdown ¶
func NewStorageMoveEntityMarkdown(label, name, url string, id int64) *StorageMoveEntityMarkdown
NewStorageMoveEntityMarkdown builds the optional entity view model for a repository storage move.
type StorageMoveExtra ¶
type StorageMoveExtra struct {
ErrorMessage string `json:"error_message"`
}
StorageMoveExtra is why a repository storage move failed, exposed under no condition by the group, project and snippet storage move entities alike and empty on a move that did not fail.
func CapturedStorageMove ¶
func CapturedStorageMove(capture *gitlabclient.ResponseCapture) (StorageMoveExtra, error)
CapturedStorageMove reads it off the captured answer to a request for one storage move.
func CapturedStorageMoves ¶
func CapturedStorageMoves(capture *gitlabclient.ResponseCapture, decoded int) ([]StorageMoveExtra, error)
CapturedStorageMoves reads the same off a list answer, one extra per move in order, the count held to what the SDK decoded.
type StorageMoveListMarkdownOptions ¶
type StorageMoveListMarkdownOptions struct {
Title string
EmptyMessage string
EntityColumn string
Pagination PaginationOutput
}
StorageMoveListMarkdownOptions configures the shared storage move list renderer.
type StorageMoveMarkdown ¶
type StorageMoveMarkdown struct {
ID int64
State string
SourceStorageName string
DestinationStorageName string
CreatedAt time.Time
Entity *StorageMoveEntityMarkdown
}
StorageMoveMarkdown carries the common fields rendered by repository storage move tools at group, snippet, and other resource scopes.
func NewStorageMoveMarkdown ¶
func NewStorageMoveMarkdown(id int64, state, sourceStorageName, destinationStorageName string, createdAt time.Time, entity *StorageMoveEntityMarkdown) StorageMoveMarkdown
NewStorageMoveMarkdown builds a shared repository storage move Markdown view model without forcing tool packages to duplicate composite literals.
func StorageMoveMarkdowns ¶
func StorageMoveMarkdowns[T any](moves []T, convert func(T) StorageMoveMarkdown) []StorageMoveMarkdown
StorageMoveMarkdowns maps package-specific storage move outputs to the shared Markdown view model.
type StringOrInt ¶
type StringOrInt string
StringOrInt is a string type that accepts both JSON strings and JSON numbers during unmarshalling. It always stores the value as a string internally. This is needed because LLMs frequently send numeric IDs (e.g. 405) as JSON numbers rather than strings, even when the schema declares "type": "string".
func (StringOrInt) Int64 ¶
func (s StringOrInt) Int64() (int64, error)
Int64 parses the stored string as a base-10 integer and returns it. Returns 0 and an error if the value is empty or not a valid integer.
func (StringOrInt) MarshalJSON ¶
func (s StringOrInt) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler to always output a JSON string.
func (StringOrInt) String ¶
func (s StringOrInt) String() string
String returns the underlying string value.
func (*StringOrInt) UnmarshalJSON ¶
func (s *StringOrInt) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler to accept both JSON strings (e.g. "405", "group/project") and JSON numbers (e.g. 405, 42.0).
type SuggestionOutput ¶
type SuggestionOutput struct {
ID int64 `json:"id"`
FromLine int64 `json:"from_line"`
ToLine int64 `json:"to_line"`
Appliable bool `json:"appliable"`
Applied bool `json:"applied"`
FromContent string `json:"from_content"`
ToContent string `json:"to_content"`
}
SuggestionOutput mirrors GitLab's Suggestion entity, the code suggestion a merge request diff note carries.
type SurfaceToolRegisterOptions ¶
type SurfaceToolRegisterOptions struct {
Description string
Icons []mcp.Icon
FormatResult FormatResultFunc
}
SurfaceToolRegisterOptions controls how an ActionSpec is exposed as a standalone visible MCP tool.
type SystemHookExtra ¶
type SystemHookExtra struct {
PushEventsBranchFilter string `json:"push_events_branch_filter"`
BranchFilterStrategy string `json:"branch_filter_strategy"`
AlertStatus string `json:"alert_status"`
DisabledUntil *time.Time `json:"disabled_until"`
CustomWebhookTemplate string `json:"custom_webhook_template"`
CustomHeaders []HookHeaderOutput `json:"custom_headers"`
OrganizationID int64 `json:"organization_id"`
}
SystemHookExtra is what GitLab's hook entity sends beside the event flags: which branches a push triggers on and how that filter is read, whether the hook has been disabled after failing and until when, the template its payload is rendered from, the custom headers configured on it, and the organization a system hook belongs to.
All of them are exposed unconditionally except the headers, which a caller can ask to be left out, and the organization, which only a system hook has.
func CapturedSystemHook ¶
func CapturedSystemHook(capture *gitlabclient.ResponseCapture) (SystemHookExtra, error)
CapturedSystemHook reads them off the captured answer to a request for one hook.
func CapturedSystemHooks ¶
func CapturedSystemHooks(capture *gitlabclient.ResponseCapture, decoded int) ([]SystemHookExtra, error)
CapturedSystemHooks reads the same off a list answer, one extra per hook in order, the count held to what the SDK decoded.
type TaskCompletionStatusOutput ¶
type TaskCompletionStatusOutput struct {
Count int64 `json:"count"`
CompletedCount int64 `json:"completed_count"`
}
TaskCompletionStatusOutput mirrors gl.TaskCompletionStatus (the task-count object surfaced on merge requests).
func NewTaskCompletionStatusOutput ¶
func NewTaskCompletionStatusOutput(t *gl.TasksCompletionStatus) *TaskCompletionStatusOutput
NewTaskCompletionStatusOutput converts a gl.TasksCompletionStatus pointer into the canonical-key task status object, returning nil for a nil source.
type TemplateAttributeListMarkdownItem ¶
TemplateAttributeListMarkdownItem carries common list-row fields for template-style Markdown tables with a third attribute column.
type TemplateAttributeListMarkdownOptions ¶
type TemplateAttributeListMarkdownOptions struct {
Title string
EmptyMessage string
AttributeHeader string
Pagination PaginationOutput
Hints []string
}
TemplateAttributeListMarkdownOptions configures template-style list rendering for tables that include a third attribute column.
type TemplateDetailMarkdown ¶
type TemplateDetailMarkdown struct {
Title string
Key string
Nickname string
Popular bool
Description string
Permissions []string
Conditions []string
Limitations []string
Content string
ContentHeading string
PlainFields bool
Hints []string
}
TemplateDetailMarkdown carries common fields for template-style detail pages.
type TemplateListMarkdownOptions ¶
TemplateListMarkdownOptions configures shared template list rendering.
type TemplateMarkdown ¶
TemplateMarkdown carries common fields rendered by template list tools.
func NewTemplateMarkdown ¶
func NewTemplateMarkdown(key, name string) TemplateMarkdown
NewTemplateMarkdown builds a shared Markdown view model for GitLab template list entries.
func TemplateMarkdowns ¶
func TemplateMarkdowns[T any](templates []T, convert func(T) TemplateMarkdown) []TemplateMarkdown
TemplateMarkdowns maps package-specific template outputs to the shared template Markdown view model.
type TemplateRenderer ¶
type TemplateRenderer struct {
ListTitle string
EmptyMessage string
ListHint string
DetailTitle string
Language string
DetailHint string
}
TemplateRenderer stores the stable labels and hints for a GitLab template family so package formatters can avoid repeating identical rendering glue.
func NewTemplateRenderer ¶
func NewTemplateRenderer(listTitle, emptyMessage, listHint, detailTitle, language, detailHint string) TemplateRenderer
NewTemplateRenderer builds a renderer for a GitLab template family.
func (TemplateRenderer) FormatContent ¶
func (r TemplateRenderer) FormatContent(name, content string) string
FormatContent renders a single GitLab template body with the renderer configuration.
func (TemplateRenderer) FormatList ¶
func (r TemplateRenderer) FormatList(templates []TemplateMarkdown, pagination PaginationOutput) string
FormatList renders a GitLab template list with the renderer configuration.
type TimeStatsOutput ¶
type TimeStatsOutput struct {
HumanTimeEstimate string `json:"human_time_estimate"`
HumanTotalTimeSpent string `json:"human_total_time_spent"`
TimeEstimate int64 `json:"time_estimate"`
TotalTimeSpent int64 `json:"total_time_spent"`
}
TimeStatsOutput mirrors gl.TimeStats (the time-tracking sub-object on merge requests and issues). It is the pure nested form — no next_steps — used when time_stats appears as a sub-field of another output type rather than as the standalone return value of a time-tracking handler. The standalone handlers (SetTimeEstimate, AddSpentTime, etc.) compose this with HintableOutput to add next_steps at the top level of their response.
func NewTimeStatsOutput ¶
func NewTimeStatsOutput(t *gl.TimeStats) *TimeStatsOutput
NewTimeStatsOutput converts a gl.TimeStats pointer to the canonical pure TimeStatsOutput, returning nil when the source is nil.
type TodoExtra ¶
type TodoExtra struct {
UpdatedAt *time.Time `json:"updated_at"`
Group *NamespaceBasicOutput `json:"group"`
}
TodoExtra is what GitLab's todo entity sends that client-go's Todo does not carry: when the todo last changed, and the group it belongs to, which is present only on a todo raised in a group rather than a project.
func CapturedTodo ¶
func CapturedTodo(capture *gitlabclient.ResponseCapture) (TodoExtra, error)
CapturedTodo reads them off the captured answer to a request that returned one todo.
func CapturedTodos ¶
func CapturedTodos(capture *gitlabclient.ResponseCapture, decoded int) ([]TodoExtra, error)
CapturedTodos reads the same off a list answer, one extra per todo in order, the count held to what the SDK decoded.
type TokenExtra ¶
type TokenExtra struct {
Granular bool `json:"granular"`
GranularScopes []TokenGranularScopeOutput `json:"granular_scopes"`
LastUsedIPs []string `json:"last_used_ips"`
}
TokenExtra is what lib/api/entities/personal_access_token.rb and the entities inheriting it send on a token that client-go's PersonalAccessToken does not carry: granular on every token, granular_scopes when the token is granular and the endpoint asked for them, and last_used_ips while the instance has the feature flag on.
func CapturedToken ¶
func CapturedToken(capture *gitlabclient.ResponseCapture) (TokenExtra, error)
CapturedToken reads, off the captured answer to a request for one token, the fields client-go's PersonalAccessToken does not model.
func CapturedTokens ¶
func CapturedTokens(capture *gitlabclient.ResponseCapture, decoded int) ([]TokenExtra, error)
CapturedTokens reads the same off a list answer, one extra per token in order, the count held to what the SDK decoded.
type TokenGranularScopeOutput ¶
type TokenGranularScopeOutput struct {
Access string `json:"access"`
Permissions []string `json:"permissions"`
ProjectID int64 `json:"project_id,omitempty"`
GroupID int64 `json:"group_id,omitempty"`
}
TokenGranularScopeOutput mirrors lib/api/entities/personal_access_token_granular_scope.rb, one entry of the granular_scopes array a granular token carries. project_id is set only when the scope's namespace is a project and group_id only when it is a group, so each is absent rather than zero on the other kind.
type ToolError ¶
type ToolError struct {
Tool string `json:"tool"`
Message string `json:"message"`
StatusCode int `json:"status_code,omitempty"`
}
ToolError represents a structured error from a tool handler.
type TopicExtra ¶
type TopicExtra struct {
OrganizationID int64 `json:"organization_id"`
}
TopicExtra is the organization a topic belongs to, which GitLab's topic entity exposes under no condition and so sends on every topic.
func CapturedTopic ¶
func CapturedTopic(capture *gitlabclient.ResponseCapture) (TopicExtra, error)
CapturedTopic reads it off the captured answer to a request for one topic.
func CapturedTopics ¶
func CapturedTopics(capture *gitlabclient.ResponseCapture, decoded int) ([]TopicExtra, error)
CapturedTopics reads the same off a list answer, one extra per topic in order, the count held to what the SDK decoded.
type UploadConfig ¶
type UploadConfig struct {
MaxFileSize int64
}
UploadConfig holds runtime-configurable upload parameters. Initialized with package defaults; use SetUploadConfig to override from environment config.
func GetUploadConfig ¶
func GetUploadConfig() UploadConfig
GetUploadConfig returns the current upload configuration (for testing).
type UserBasicOutput ¶
type UserBasicOutput struct {
ID int64 `json:"id"`
Username string `json:"username"`
PublicEmail string `json:"public_email,omitempty"`
Name string `json:"name"`
State string `json:"state,omitempty"`
Locked bool `json:"locked"`
AvatarURL string `json:"avatar_url,omitempty"`
WebURL string `json:"web_url,omitempty"`
}
UserBasicOutput mirrors lib/api/entities/user_basic.rb, the user object GitLab renders on a note's author and resolver and on a runner's creator.
type UserExtra ¶
type UserExtra struct {
CommitEmail string `json:"commit_email"`
Discord string `json:"discord"`
GitHub string `json:"github"`
LocalTime string `json:"local_time"`
PreferredLanguage string `json:"preferred_language"`
Pronouns string `json:"pronouns"`
WorkInformation string `json:"work_information"`
Followers *int64 `json:"followers"`
Following *int64 `json:"following"`
IsFollowed *bool `json:"is_followed"`
}
UserExtra is what lib/api/entities/user_public.rb, and the User it inherits, send on a user that client-go's User does not carry. It is the set every route presenting UserPublic answers with, which is what the group-scoped user lists (enterprise users, provisioned users, SAML users) and the instance-wide ones alike present, so the four packages publishing a user share it.
Seven of the ten are exposed under no condition. The three counts are gated on Ability.allowed?(current_user, :read_user_profile, user) together with following_users_allowed, so the same endpoint sends them to a caller who may read the profile and to nobody else. Each is a pointer because zero followers and a profile this caller may not read are different answers, and a bare number would tell them apart from nothing.
func CapturedUser ¶
func CapturedUser(capture *gitlabclient.ResponseCapture) (UserExtra, error)
CapturedUser reads, off the captured answer to a request for one user, the fields client-go's User does not model.
func CapturedUsers ¶
func CapturedUsers(capture *gitlabclient.ResponseCapture, decoded int) ([]UserExtra, error)
CapturedUsers reads the same off a list answer, one extra per user in order, the count held to what the SDK decoded.
type UserIdentity ¶
type UserIdentity struct {
UserID string
Username string
// Instance is the GitLab instance the identity was resolved against, when
// the caller knows it.
//
// A GitLab user id is unique within an instance and means nothing across
// them, so a deployment publishing several through --gitlab-url can log two
// different people as user_id 7. ADR-0008 fixes this struct as
// {UserID, Username} and motivates it expressly for audit logging, without
// recording that limit; an audit trail whose subject is ambiguous is the one
// place it matters.
//
// Empty where there is nothing to say: stdio resolves one identity at
// startup against one instance, and a deployment that pins --gitlab-url has
// only the one. The field is filled where it is already known rather than
// resolved again: the HTTP gate computes the instance per request to pick a
// pool entry and used to throw it away.
Instance string
}
UserIdentity holds the authenticated user's identity. Populated from OAuth TokenInfo (HTTP modes) or from the startup-resolved identity stored in context (stdio mode).
func IdentityFromContext ¶
func IdentityFromContext(ctx context.Context) UserIdentity
IdentityFromContext retrieves the UserIdentity stored in the context. Returns a zero-value UserIdentity if none was stored.
func ResolveIdentity ¶
func ResolveIdentity(ctx context.Context, req *mcp.CallToolRequest) UserIdentity
ResolveIdentity returns the authenticated user's identity by checking two sources in priority order:
- req.Extra.TokenInfo (populated by SDK in HTTP modes via RequireBearerToken)
- Context-stored identity (populated at startup in stdio mode)
Returns a zero-value UserIdentity if neither source has identity.
func (UserIdentity) IsAuthenticated ¶
func (u UserIdentity) IsAuthenticated() bool
IsAuthenticated returns true if the identity contains a non-empty UserID.
type UserRefOutput ¶
type UserRefOutput struct {
ID int64 `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
State string `json:"state"`
AvatarURL string `json:"avatar_url,omitempty"`
WebURL string `json:"web_url,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
}
UserRefOutput mirrors gl.BasicUser as surfaced on user resources (the created_by object): identity fields always present, avatar/web URL and created_at omitted when empty. It differs from BasicUserOutput (pipeline sub-objects), whose avatar_url and web_url are always serialized.
func NewUserRefOutput ¶
func NewUserRefOutput(u *gl.BasicUser) *UserRefOutput
NewUserRefOutput converts a *gl.BasicUser into the user-resource reference shape, returning nil when the SDK value is nil.
type VoidOutput ¶
type VoidOutput struct {
HintableOutput
Status string `json:"status"`
Message string `json:"message"`
}
VoidOutput is a confirmation message returned by tool handlers that perform an action without returning domain data (e.g., set header, start mirroring).
func VoidResult ¶
func VoidResult(message string) (*mcp.CallToolResult, VoidOutput, error)
VoidResult builds a VoidOutput and its Markdown representation for a successful void operation. The message describes what happened.
type WikiExtra ¶
type WikiExtra struct {
WikiPageMetaID int64 `json:"wiki_page_meta_id"`
FrontMatter map[string]any `json:"front_matter"`
}
WikiExtra is what GitLab's wiki page entity sends beside the title and the content: the identifier of the page's metadata record, and the YAML front matter parsed out of the page, which is a map of whatever keys the author wrote. Both are exposed under no condition, and the front matter is empty on a page that has none.
func CapturedWiki ¶
func CapturedWiki(capture *gitlabclient.ResponseCapture) (WikiExtra, error)
CapturedWiki reads them off the captured answer to a request for one page.
func CapturedWikis ¶
func CapturedWikis(capture *gitlabclient.ResponseCapture, decoded int) ([]WikiExtra, error)
CapturedWikis reads the same off a list answer, one extra per page in order, the count held to what the SDK decoded.
Source Files
¶
- access_level.go
- action_meta.go
- action_schema_override.go
- action_spec.go
- action_spec_individual.go
- action_timeout.go
- annotations.go
- approver_ids.go
- board_shapes.go
- brandmark_gen.go
- confirm.go
- constants.go
- diff.go
- diff_position.go
- discussion_guidance.go
- doc.go
- embed.go
- embed_template.go
- errors.go
- file_source.go
- file_utils.go
- file_utils_unix.go
- graphql.go
- graphql_note_mutation.go
- hints.go
- icons.go
- identity.go
- issue_shapes.go
- label_markdown.go
- logging.go
- markdown.go
- md_registry.go
- member_capture.go
- member_shapes.go
- meta_schema.go
- meta_tool.go
- mr_shapes.go
- names.go
- not_found.go
- note_capture.go
- note_shapes.go
- once_map.go
- output.go
- pagination.go
- pipeline_inputs.go
- pipeline_shapes.go
- polling.go
- rate_limit.go
- release_shapes.go
- rpc_code.go
- safe_mode.go
- schema_compile.go
- schema_lockdown.go
- schema_middleware.go
- schema_pagination.go
- schema_share.go
- sent_shapes.go
- string_or_int.go
- surface_tool.go
- template_markdown.go
- text.go
- time_helpers.go
- tool_listing.go
- user_shapes.go