diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index 650763719..9b892a6f0 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -734,17 +734,17 @@ func (r *Resolver) UpdateDatumTool(ctx context.Context, req *mcp.CallToolRequest }, nil } -func (r *Resolver) ListNonconformitiesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListNonconformitiesInput) (*mcp.CallToolResult, types.ListNonconformitiesOutput, error) { - r.MustAuthorize(ctx, input.OrganizationID, probo.ActionNonconformityList) +func (r *Resolver) ListFindingsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListFindingsInput) (*mcp.CallToolResult, types.ListFindingsOutput, error) { + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFindingList) prb := r.ProboService(ctx, input.OrganizationID) - pageOrderBy := page.OrderBy[coredata.NonconformityOrderField]{ - Field: coredata.NonconformityOrderFieldCreatedAt, + pageOrderBy := page.OrderBy[coredata.FindingOrderField]{ + Field: coredata.FindingOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { - pageOrderBy = page.OrderBy[coredata.NonconformityOrderField]{ + pageOrderBy = page.OrderBy[coredata.FindingOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } @@ -753,91 +753,100 @@ func (r *Resolver) ListNonconformitiesTool(ctx context.Context, req *mcp.CallToo cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) noSnapshot := (*gid.GID)(nil) - nonconformityFilter := coredata.NewNonconformityFilter(&noSnapshot) + findingFilter := coredata.NewFindingFilter(&noSnapshot, nil, nil, nil, nil) if input.Filter != nil { - nonconformityFilter = coredata.NewNonconformityFilter(&input.Filter.SnapshotID) + findingFilter = coredata.NewFindingFilter( + &input.Filter.SnapshotID, + input.Filter.Kind, + input.Filter.Status, + input.Filter.Priority, + input.Filter.OwnerID, + ) } - page, err := prb.Nonconformities.ListForOrganizationID(ctx, input.OrganizationID, cursor, nonconformityFilter) + page, err := prb.Findings.ListForOrganizationID(ctx, input.OrganizationID, cursor, findingFilter) if err != nil { - panic(fmt.Errorf("cannot list organization nonconformities: %w", err)) + panic(fmt.Errorf("cannot list organization findings: %w", err)) } - return nil, types.NewListNonconformitiesOutput(page), nil + return nil, types.NewListFindingsOutput(page), nil } -func (r *Resolver) GetNonconformityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetNonconformityInput) (*mcp.CallToolResult, types.GetNonconformityOutput, error) { - r.MustAuthorize(ctx, input.ID, probo.ActionNonconformityGet) +func (r *Resolver) GetFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetFindingInput) (*mcp.CallToolResult, types.GetFindingOutput, error) { + r.MustAuthorize(ctx, input.ID, probo.ActionFindingGet) prb := r.ProboService(ctx, input.ID) - nonconformity, err := prb.Nonconformities.Get(ctx, input.ID) + finding, err := prb.Findings.Get(ctx, input.ID) if err != nil { - return nil, types.GetNonconformityOutput{}, fmt.Errorf("failed to get nonconformity: %w", err) + return nil, types.GetFindingOutput{}, fmt.Errorf("cannot get finding: %w", err) } - return nil, types.GetNonconformityOutput{ - Nonconformity: types.NewNonconformity(nonconformity), + return nil, types.GetFindingOutput{ + Finding: types.NewFinding(finding), }, nil } -func (r *Resolver) AddNonconformityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddNonconformityInput) (*mcp.CallToolResult, types.AddNonconformityOutput, error) { - r.MustAuthorize(ctx, input.OrganizationID, probo.ActionNonconformityCreate) +func (r *Resolver) AddFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddFindingInput) (*mcp.CallToolResult, types.AddFindingOutput, error) { + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFindingCreate) svc := r.ProboService(ctx, input.OrganizationID) - nonconformity, err := svc.Nonconformities.Create( + finding, err := svc.Findings.Create( ctx, - &probo.CreateNonconformityRequest{ + &probo.CreateFindingRequest{ OrganizationID: input.OrganizationID, - ReferenceID: input.ReferenceID, + Kind: input.Kind, Description: input.Description, - AuditID: input.AuditID, - DateIdentified: input.DateIdentified, + Source: input.Source, + IdentifiedOn: input.IdentifiedOn, RootCause: input.RootCause, CorrectiveAction: input.CorrectiveAction, OwnerID: input.OwnerID, DueDate: input.DueDate, Status: input.Status, + Priority: input.Priority, + RiskID: input.RiskID, EffectivenessCheck: input.EffectivenessCheck, }, ) if err != nil { - return nil, types.AddNonconformityOutput{}, fmt.Errorf("failed to create nonconformity: %w", err) + return nil, types.AddFindingOutput{}, fmt.Errorf("failed to create finding: %w", err) } - return nil, types.AddNonconformityOutput{ - Nonconformity: types.NewNonconformity(nonconformity), + return nil, types.AddFindingOutput{ + Finding: types.NewFinding(finding), }, nil } -func (r *Resolver) UpdateNonconformityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateNonconformityInput) (*mcp.CallToolResult, types.UpdateNonconformityOutput, error) { - r.MustAuthorize(ctx, input.ID, probo.ActionNonconformityUpdate) +func (r *Resolver) UpdateFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateFindingInput) (*mcp.CallToolResult, types.UpdateFindingOutput, error) { + r.MustAuthorize(ctx, input.ID, probo.ActionFindingUpdate) svc := r.ProboService(ctx, input.ID) - nonconformity, err := svc.Nonconformities.Update( + finding, err := svc.Findings.Update( ctx, - &probo.UpdateNonconformityRequest{ + &probo.UpdateFindingRequest{ ID: input.ID, - ReferenceID: input.ReferenceID, Description: UnwrapOmittable(input.Description), - DateIdentified: UnwrapOmittable(input.DateIdentified), - RootCause: input.RootCause, + Source: UnwrapOmittable(input.Source), + IdentifiedOn: UnwrapOmittable(input.IdentifiedOn), + RootCause: UnwrapOmittable(input.RootCause), CorrectiveAction: UnwrapOmittable(input.CorrectiveAction), OwnerID: input.OwnerID, - AuditID: UnwrapOmittable(input.AuditID), DueDate: UnwrapOmittable(input.DueDate), Status: input.Status, + Priority: input.Priority, + RiskID: UnwrapOmittable(input.RiskID), EffectivenessCheck: UnwrapOmittable(input.EffectivenessCheck), }, ) if err != nil { - return nil, types.UpdateNonconformityOutput{}, fmt.Errorf("failed to update nonconformity: %w", err) + return nil, types.UpdateFindingOutput{}, fmt.Errorf("failed to update finding: %w", err) } - return nil, types.UpdateNonconformityOutput{ - Nonconformity: types.NewNonconformity(nonconformity), + return nil, types.UpdateFindingOutput{ + Finding: types.NewFinding(finding), }, nil } @@ -1304,107 +1313,6 @@ func (r *Resolver) DeleteTransferImpactAssessmentTool(ctx context.Context, req * }, nil } -func (r *Resolver) ListContinualImprovementsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListContinualImprovementsInput) (*mcp.CallToolResult, types.ListContinualImprovementsOutput, error) { - r.MustAuthorize(ctx, input.OrganizationID, probo.ActionContinualImprovementList) - - prb := r.ProboService(ctx, input.OrganizationID) - - pageOrderBy := page.OrderBy[coredata.ContinualImprovementOrderField]{ - Field: coredata.ContinualImprovementOrderFieldCreatedAt, - Direction: page.OrderDirectionDesc, - } - if input.OrderBy != nil { - pageOrderBy = page.OrderBy[coredata.ContinualImprovementOrderField]{ - Field: input.OrderBy.Field, - Direction: input.OrderBy.Direction, - } - } - - cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) - - noSnapshot := (*gid.GID)(nil) - continualImprovementFilter := coredata.NewContinualImprovementFilter(&noSnapshot) - if input.Filter != nil { - continualImprovementFilter = coredata.NewContinualImprovementFilter(&input.Filter.SnapshotID) - } - - page, err := prb.ContinualImprovements.ListForOrganizationID(ctx, input.OrganizationID, cursor, continualImprovementFilter) - if err != nil { - panic(fmt.Errorf("cannot list organization continual improvements: %w", err)) - } - - return nil, types.NewListContinualImprovementsOutput(page), nil -} - -func (r *Resolver) GetContinualImprovementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetContinualImprovementInput) (*mcp.CallToolResult, types.GetContinualImprovementOutput, error) { - r.MustAuthorize(ctx, input.ID, probo.ActionContinualImprovementGet) - - prb := r.ProboService(ctx, input.ID) - - continualImprovement, err := prb.ContinualImprovements.Get(ctx, input.ID) - if err != nil { - return nil, types.GetContinualImprovementOutput{}, fmt.Errorf("failed to get continual improvement: %w", err) - } - - return nil, types.GetContinualImprovementOutput{ - ContinualImprovement: types.NewContinualImprovement(continualImprovement), - }, nil -} - -func (r *Resolver) AddContinualImprovementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddContinualImprovementInput) (*mcp.CallToolResult, types.AddContinualImprovementOutput, error) { - r.MustAuthorize(ctx, input.OrganizationID, probo.ActionContinualImprovementCreate) - - svc := r.ProboService(ctx, input.OrganizationID) - - continualImprovement, err := svc.ContinualImprovements.Create( - ctx, - &probo.CreateContinualImprovementRequest{ - OrganizationID: input.OrganizationID, - ReferenceID: input.ReferenceID, - Description: input.Description, - Source: input.Source, - OwnerID: input.OwnerID, - TargetDate: input.TargetDate, - Status: input.Status, - Priority: input.Priority, - }, - ) - if err != nil { - return nil, types.AddContinualImprovementOutput{}, fmt.Errorf("failed to create continual improvement: %w", err) - } - - return nil, types.AddContinualImprovementOutput{ - ContinualImprovement: types.NewContinualImprovement(continualImprovement), - }, nil -} - -func (r *Resolver) UpdateContinualImprovementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateContinualImprovementInput) (*mcp.CallToolResult, types.UpdateContinualImprovementOutput, error) { - r.MustAuthorize(ctx, input.ID, probo.ActionContinualImprovementUpdate) - - svc := r.ProboService(ctx, input.ID) - - continualImprovement, err := svc.ContinualImprovements.Update( - ctx, - &probo.UpdateContinualImprovementRequest{ - ID: input.ID, - ReferenceID: input.ReferenceID, - Description: UnwrapOmittable(input.Description), - Source: UnwrapOmittable(input.Source), - OwnerID: input.OwnerID, - TargetDate: UnwrapOmittable(input.TargetDate), - Status: input.Status, - Priority: input.Priority, - }, - ) - if err != nil { - return nil, types.UpdateContinualImprovementOutput{}, fmt.Errorf("failed to update continual improvement: %w", err) - } - - return nil, types.UpdateContinualImprovementOutput{ - ContinualImprovement: types.NewContinualImprovement(continualImprovement), - }, nil -} - func (r *Resolver) ListAuditsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAuditsInput) (*mcp.CallToolResult, types.ListAuditsOutput, error) { r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAuditList) @@ -3219,3 +3127,76 @@ func (r *Resolver) DeleteVendorTool(ctx context.Context, req *mcp.CallToolReques DeletedVendorID: input.ID, }, nil } + +func (r *Resolver) DeleteFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteFindingInput) (*mcp.CallToolResult, types.DeleteFindingOutput, error) { + r.MustAuthorize(ctx, input.ID, probo.ActionFindingDelete) + + svc := r.ProboService(ctx, input.ID) + + err := svc.Findings.Delete(ctx, input.ID) + if err != nil { + return nil, types.DeleteFindingOutput{}, fmt.Errorf("cannot delete finding: %w", err) + } + + return nil, types.DeleteFindingOutput{ + DeletedFindingID: input.ID, + }, nil +} + +func (r *Resolver) LinkFindingAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.LinkFindingAuditInput) (*mcp.CallToolResult, types.LinkFindingAuditOutput, error) { + r.MustAuthorize(ctx, input.FindingID, probo.ActionFindingAuditMappingCreate) + + svc := r.ProboService(ctx, input.FindingID) + + finding, audit, err := svc.Findings.CreateAuditMapping(ctx, input.FindingID, input.AuditID, input.ReferenceID) + if err != nil { + return nil, types.LinkFindingAuditOutput{}, fmt.Errorf("cannot link finding to audit: %w", err) + } + + return nil, types.LinkFindingAuditOutput{ + Finding: types.NewFinding(finding), + Audit: types.NewAudit(audit), + }, nil +} + +func (r *Resolver) UnlinkFindingAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnlinkFindingAuditInput) (*mcp.CallToolResult, types.UnlinkFindingAuditOutput, error) { + r.MustAuthorize(ctx, input.FindingID, probo.ActionFindingAuditMappingDelete) + + svc := r.ProboService(ctx, input.FindingID) + + finding, audit, err := svc.Findings.DeleteAuditMapping(ctx, input.FindingID, input.AuditID) + if err != nil { + return nil, types.UnlinkFindingAuditOutput{}, fmt.Errorf("cannot unlink finding from audit: %w", err) + } + + return nil, types.UnlinkFindingAuditOutput{ + DeletedFindingID: finding.ID, + DeletedAuditID: audit.ID, + }, nil +} + +func (r *Resolver) ListFindingAuditsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListFindingAuditsInput) (*mcp.CallToolResult, types.ListFindingAuditsOutput, error) { + r.MustAuthorize(ctx, input.FindingID, probo.ActionFindingGet) + + prb := r.ProboService(ctx, input.FindingID) + + pageOrderBy := page.OrderBy[coredata.AuditOrderField]{ + Field: coredata.AuditOrderFieldCreatedAt, + Direction: page.OrderDirectionDesc, + } + if input.OrderBy != nil { + pageOrderBy = page.OrderBy[coredata.AuditOrderField]{ + Field: input.OrderBy.Field, + Direction: input.OrderBy.Direction, + } + } + + cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) + + auditPage, err := prb.Audits.ListForFindingID(ctx, input.FindingID, cursor) + if err != nil { + return nil, types.ListFindingAuditsOutput{}, fmt.Errorf("cannot list finding audits: %w", err) + } + + return nil, types.NewListFindingAuditsOutput(auditPage), nil +} diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index e8157c470..bc8baa223 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -2306,15 +2306,34 @@ components: datum: $ref: "#/components/schemas/Datum" - NonconformityStatus: + FindingKind: + type: string + enum: + - NONCONFORMITY + - OBSERVATION + - EXCEPTION + go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.FindingKind + + FindingStatus: type: string enum: - OPEN - IN_PROGRESS - CLOSED - go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.NonconformityStatus + - RISK_ACCEPTED + - MITIGATED + - FALSE_POSITIVE + go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.FindingStatus - NonconformityOrderField: + FindingPriority: + type: string + enum: + - LOW + - MEDIUM + - HIGH + go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.FindingPriority + + FindingOrderField: type: string enum: - CREATED_AT @@ -2322,36 +2341,38 @@ components: - DATE_IDENTIFIED - DUE_DATE - STATUS - go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.NonconformityOrderField + - PRIORITY + - KIND + go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.FindingOrderField - NonconformityOrderBy: + FindingOrderBy: type: object required: - field - direction properties: field: - $ref: "#/components/schemas/NonconformityOrderField" - description: Nonconformity order field + $ref: "#/components/schemas/FindingOrderField" + description: Finding order field direction: $ref: "#/components/schemas/OrderDirection" - description: Nonconformity order direction + description: Finding order direction - Nonconformity: + Finding: type: object required: - id - organization_id + - kind - reference_id - - root_cause - - owner_id - status + - priority - created_at - updated_at properties: id: $ref: "#/components/schemas/GID" - description: Nonconformity ID + description: Finding ID organization_id: $ref: "#/components/schemas/GID" description: Organization ID @@ -2362,6 +2383,14 @@ components: - type: "null" description: No snapshot description: Snapshot ID + source_id: + type: + - string + - "null" + description: Source ID + kind: + $ref: "#/components/schemas/FindingKind" + description: Finding kind reference_id: type: string description: Reference ID @@ -2370,21 +2399,21 @@ components: - string - "null" description: Description - audit_id: - anyOf: - - $ref: "#/components/schemas/GID" - description: Audit ID - - type: "null" - description: No audit - description: Audit ID - date_identified: + source: + type: + - string + - "null" + description: Source + identified_on: type: - string - "null" format: date-time - description: Date identified + description: Identified on root_cause: - type: string + type: + - string + - "null" description: Root cause corrective_action: type: @@ -2392,7 +2421,9 @@ components: - "null" description: Corrective action owner_id: - $ref: "#/components/schemas/GID" + anyOf: + - $ref: "#/components/schemas/GID" + - type: "null" description: Owner ID due_date: type: @@ -2401,8 +2432,18 @@ components: format: date-time description: Due date status: - $ref: "#/components/schemas/NonconformityStatus" + $ref: "#/components/schemas/FindingStatus" description: Status + priority: + $ref: "#/components/schemas/FindingPriority" + description: Priority + risk_id: + anyOf: + - $ref: "#/components/schemas/GID" + description: Risk ID + - type: "null" + description: No risk + description: Risk ID effectiveness_check: type: - string @@ -2417,7 +2458,7 @@ components: format: date-time description: Update timestamp - ListNonconformitiesInput: + ListFindingsInput: type: object required: - organization_id @@ -2426,8 +2467,8 @@ components: $ref: "#/components/schemas/GID" description: Organization ID order_by: - $ref: "#/components/schemas/NonconformityOrderBy" - description: Nonconformity order by + $ref: "#/components/schemas/FindingOrderBy" + description: Finding order by size: type: integer description: Page size @@ -2441,68 +2482,81 @@ components: anyOf: - $ref: "#/components/schemas/GID" - type: "null" - description: Filter by snapshot ID. Defaults to null, which returns only nonconformities with no snapshot (current live data). Pass a specific snapshot ID to retrieve nonconformities as they were at that snapshot. + description: Filter by snapshot ID. Defaults to null, which returns only findings with no snapshot (current live data). Pass a specific snapshot ID to retrieve findings as they were at that snapshot. default: null + kind: + anyOf: + - $ref: "#/components/schemas/FindingKind" + - type: "null" + description: Filter by finding kind (NONCONFORMITY, OBSERVATION, EXCEPTION). Defaults to null which returns all kinds. + status: + anyOf: + - $ref: "#/components/schemas/FindingStatus" + - type: "null" + description: Filter by finding status (OPEN, IN_PROGRESS, CLOSED, RISK_ACCEPTED, MITIGATED, FALSE_POSITIVE). Defaults to null which returns all statuses. + priority: + anyOf: + - $ref: "#/components/schemas/FindingPriority" + - type: "null" + description: Filter by finding priority (LOW, MEDIUM, HIGH). Defaults to null which returns all priorities. + owner_id: + anyOf: + - $ref: "#/components/schemas/GID" + - type: "null" + description: Filter by owner profile ID. Defaults to null which returns all owners. - ListNonconformitiesOutput: + ListFindingsOutput: type: object required: - - nonconformities + - findings properties: next_cursor: $ref: "#/components/schemas/CursorKey" description: Next cursor - nonconformities: + findings: type: array items: - $ref: "#/components/schemas/Nonconformity" + $ref: "#/components/schemas/Finding" - GetNonconformityInput: + GetFindingInput: type: object required: - id properties: id: $ref: "#/components/schemas/GID" - description: Nonconformity ID + description: Finding ID - GetNonconformityOutput: + GetFindingOutput: type: object required: - - nonconformity + - finding properties: - nonconformity: - $ref: "#/components/schemas/Nonconformity" + finding: + $ref: "#/components/schemas/Finding" - AddNonconformityInput: + AddFindingInput: type: object required: - organization_id - - reference_id - - root_cause - - owner_id - - status + - kind properties: organization_id: $ref: "#/components/schemas/GID" description: Organization ID - reference_id: - type: string - description: Reference ID + kind: + $ref: "#/components/schemas/FindingKind" + description: Finding kind description: type: string description: Description - audit_id: - anyOf: - - $ref: "#/components/schemas/GID" - description: Audit ID - - type: "null" - description: No audit - description: Audit ID - date_identified: + source: + type: string + description: Source + identified_on: type: string format: date-time - description: Date identified + description: Identified on root_cause: type: string description: Root cause @@ -2510,7 +2564,9 @@ components: type: string description: Corrective action owner_id: - $ref: "#/components/schemas/GID" + anyOf: + - $ref: "#/components/schemas/GID" + - type: "null" description: Owner ID due_date: type: string @@ -2518,46 +2574,62 @@ components: description: Due date status: anyOf: - - $ref: "#/components/schemas/NonconformityStatus" - description: Nonconformity status + - $ref: "#/components/schemas/FindingStatus" + description: Finding status - type: "null" description: No status description: Status + priority: + anyOf: + - $ref: "#/components/schemas/FindingPriority" + description: Finding priority + - type: "null" + description: No priority + description: Priority + risk_id: + anyOf: + - $ref: "#/components/schemas/GID" + description: Risk ID + - type: "null" + description: No risk + description: Risk ID effectiveness_check: type: string description: Effectiveness check - AddNonconformityOutput: + AddFindingOutput: type: object required: - - nonconformity + - finding properties: - nonconformity: - $ref: "#/components/schemas/Nonconformity" + finding: + $ref: "#/components/schemas/Finding" - UpdateNonconformityInput: + UpdateFindingInput: type: object required: - id properties: id: $ref: "#/components/schemas/GID" - description: Nonconformity ID - reference_id: - type: string - description: Reference ID + description: Finding ID description: type: ["string", "null"] description: Description go.probo.inc/mcpgen/omittable: true - date_identified: + source: + type: ["string", "null"] + description: Source + go.probo.inc/mcpgen/omittable: true + identified_on: type: ["string", "null"] format: date-time - description: Date identified + description: Identified on go.probo.inc/mcpgen/omittable: true root_cause: - type: string + type: ["string", "null"] description: Root cause + go.probo.inc/mcpgen/omittable: true corrective_action: type: ["string", "null"] description: Corrective action @@ -2568,33 +2640,139 @@ components: $ref: "#/components/schemas/GID" - type: "null" description: Owner ID - audit_id: - anyOf: - - type: string - $ref: "#/components/schemas/GID" - - type: "null" - description: Audit ID - go.probo.inc/mcpgen/omittable: true due_date: type: ["string", "null"] format: date-time description: Due date go.probo.inc/mcpgen/omittable: true status: - $ref: "#/components/schemas/NonconformityStatus" + $ref: "#/components/schemas/FindingStatus" description: Status + priority: + $ref: "#/components/schemas/FindingPriority" + description: Priority + risk_id: + anyOf: + - type: string + $ref: "#/components/schemas/GID" + - type: "null" + description: Risk ID + go.probo.inc/mcpgen/omittable: true effectiveness_check: type: ["string", "null"] description: Effectiveness check go.probo.inc/mcpgen/omittable: true - UpdateNonconformityOutput: + UpdateFindingOutput: type: object required: - - nonconformity + - finding properties: - nonconformity: - $ref: "#/components/schemas/Nonconformity" + finding: + $ref: "#/components/schemas/Finding" + + DeleteFindingInput: + type: object + required: + - id + properties: + id: + $ref: "#/components/schemas/GID" + description: Finding ID + + DeleteFindingOutput: + type: object + required: + - deleted_finding_id + properties: + deleted_finding_id: + $ref: "#/components/schemas/GID" + description: Deleted finding ID + + LinkFindingAuditInput: + type: object + required: + - finding_id + - audit_id + - reference_id + properties: + finding_id: + $ref: "#/components/schemas/GID" + description: Finding ID + audit_id: + $ref: "#/components/schemas/GID" + description: Audit ID + reference_id: + type: string + description: Reference ID for the finding within this audit + + LinkFindingAuditOutput: + type: object + required: + - finding + - audit + properties: + finding: + $ref: "#/components/schemas/Finding" + audit: + $ref: "#/components/schemas/Audit" + + UnlinkFindingAuditInput: + type: object + required: + - finding_id + - audit_id + properties: + finding_id: + $ref: "#/components/schemas/GID" + description: Finding ID + audit_id: + $ref: "#/components/schemas/GID" + description: Audit ID + + UnlinkFindingAuditOutput: + type: object + required: + - deleted_finding_id + - deleted_audit_id + properties: + deleted_finding_id: + $ref: "#/components/schemas/GID" + description: Deleted finding ID + deleted_audit_id: + $ref: "#/components/schemas/GID" + description: Deleted audit ID + + ListFindingAuditsInput: + type: object + required: + - finding_id + properties: + finding_id: + $ref: "#/components/schemas/GID" + description: Finding ID + cursor: + $ref: "#/components/schemas/CursorKey" + description: Page cursor + size: + type: integer + description: Page size + order_by: + $ref: "#/components/schemas/AuditOrderBy" + description: Audit order by + + ListFindingAuditsOutput: + type: object + required: + - audits + properties: + next_cursor: + $ref: "#/components/schemas/CursorKey" + description: Next cursor + audits: + type: array + items: + $ref: "#/components/schemas/Audit" ObligationStatus: type: string @@ -3704,270 +3882,6 @@ components: deleted_transfer_impact_assessment_id: $ref: "#/components/schemas/GID" - ContinualImprovementStatus: - type: string - enum: - - OPEN - - IN_PROGRESS - - CLOSED - go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.ContinualImprovementStatus - - ContinualImprovementPriority: - type: string - enum: - - LOW - - MEDIUM - - HIGH - go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.ContinualImprovementPriority - - ContinualImprovementOrderField: - type: string - enum: - - CREATED_AT - - REFERENCE_ID - - TARGET_DATE - - STATUS - - PRIORITY - go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.ContinualImprovementOrderField - - ContinualImprovementOrderBy: - type: object - required: - - field - - direction - properties: - field: - $ref: "#/components/schemas/ContinualImprovementOrderField" - description: Continual improvement order field - direction: - $ref: "#/components/schemas/OrderDirection" - description: Continual improvement order direction - - ContinualImprovement: - type: object - required: - - id - - organization_id - - reference_id - - owner_id - - status - - priority - - created_at - - updated_at - properties: - id: - $ref: "#/components/schemas/GID" - description: Continual improvement ID - organization_id: - $ref: "#/components/schemas/GID" - description: Organization ID - snapshot_id: - anyOf: - - $ref: "#/components/schemas/GID" - description: Snapshot ID - - type: "null" - description: No snapshot - description: Snapshot ID - source_id: - type: - - string - - "null" - description: Source ID - reference_id: - type: string - description: Reference ID - description: - type: - - string - - "null" - description: Description - source: - type: - - string - - "null" - description: Source - owner_id: - $ref: "#/components/schemas/GID" - description: Owner ID - target_date: - type: - - string - - "null" - format: date-time - description: Target date - status: - $ref: "#/components/schemas/ContinualImprovementStatus" - description: Status - priority: - $ref: "#/components/schemas/ContinualImprovementPriority" - description: Priority - created_at: - type: string - format: date-time - description: Creation timestamp - updated_at: - type: string - format: date-time - description: Update timestamp - - ListContinualImprovementsInput: - type: object - required: - - organization_id - properties: - organization_id: - $ref: "#/components/schemas/GID" - description: Organization ID - order_by: - $ref: "#/components/schemas/ContinualImprovementOrderBy" - description: Continual improvement order by - size: - type: integer - description: Page size - cursor: - $ref: "#/components/schemas/CursorKey" - description: Page cursor - filter: - type: object - properties: - snapshot_id: - anyOf: - - $ref: "#/components/schemas/GID" - - type: "null" - description: Filter by snapshot ID. Defaults to null, which returns only continual improvements with no snapshot (current live data). Pass a specific snapshot ID to retrieve continual improvements as they were at that snapshot. - default: null - - ListContinualImprovementsOutput: - type: object - required: - - continual_improvements - properties: - next_cursor: - $ref: "#/components/schemas/CursorKey" - description: Next cursor - continual_improvements: - type: array - items: - $ref: "#/components/schemas/ContinualImprovement" - - GetContinualImprovementInput: - type: object - required: - - id - properties: - id: - $ref: "#/components/schemas/GID" - description: Continual improvement ID - - GetContinualImprovementOutput: - type: object - required: - - continual_improvement - properties: - continual_improvement: - $ref: "#/components/schemas/ContinualImprovement" - - AddContinualImprovementInput: - type: object - required: - - organization_id - - reference_id - - owner_id - properties: - organization_id: - $ref: "#/components/schemas/GID" - description: Organization ID - reference_id: - type: string - description: Reference ID - description: - type: string - description: Description - source: - type: string - description: Source - owner_id: - $ref: "#/components/schemas/GID" - description: Owner ID - target_date: - type: string - format: date-time - description: Target date - status: - anyOf: - - $ref: "#/components/schemas/ContinualImprovementStatus" - description: Continual improvement status - - type: "null" - description: No status - description: Status - priority: - anyOf: - - $ref: "#/components/schemas/ContinualImprovementPriority" - description: Continual improvement priority - - type: "null" - description: No priority - description: Priority - - AddContinualImprovementOutput: - type: object - required: - - continual_improvement - properties: - continual_improvement: - $ref: "#/components/schemas/ContinualImprovement" - - UpdateContinualImprovementInput: - type: object - required: - - id - properties: - id: - $ref: "#/components/schemas/GID" - description: Continual improvement ID - reference_id: - type: string - description: Reference ID - description: - type: ["string", "null"] - description: Description - go.probo.inc/mcpgen/omittable: true - source: - type: ["string", "null"] - description: Source - go.probo.inc/mcpgen/omittable: true - owner_id: - anyOf: - - type: string - $ref: "#/components/schemas/GID" - - type: "null" - description: Owner ID - target_date: - type: ["string", "null"] - format: date-time - description: Target date - go.probo.inc/mcpgen/omittable: true - status: - anyOf: - - $ref: "#/components/schemas/ContinualImprovementStatus" - description: Continual improvement status - - type: "null" - description: No status - description: Status - priority: - anyOf: - - $ref: "#/components/schemas/ContinualImprovementPriority" - description: Continual improvement priority - - type: "null" - description: No priority - description: Priority - - UpdateContinualImprovementOutput: - type: object - required: - - continual_improvement - properties: - continual_improvement: - $ref: "#/components/schemas/ContinualImprovement" AuditState: type: string @@ -6703,40 +6617,75 @@ tools: $ref: "#/components/schemas/UpdateDatumInput" outputSchema: $ref: "#/components/schemas/UpdateDatumOutput" - - name: listNonconformities - description: List all nonconformities for the organization + - name: listFindings + description: List all findings (nonconformities, observations, exceptions) for the organization hints: readonly: true idempotent: true inputSchema: - $ref: "#/components/schemas/ListNonconformitiesInput" + $ref: "#/components/schemas/ListFindingsInput" outputSchema: - $ref: "#/components/schemas/ListNonconformitiesOutput" - - name: getNonconformity - description: Get a nonconformity by ID + $ref: "#/components/schemas/ListFindingsOutput" + - name: getFinding + description: Get a finding by ID hints: readonly: true idempotent: true inputSchema: - $ref: "#/components/schemas/GetNonconformityInput" + $ref: "#/components/schemas/GetFindingInput" outputSchema: - $ref: "#/components/schemas/GetNonconformityOutput" - - name: addNonconformity - description: Add a new nonconformity to the organization + $ref: "#/components/schemas/GetFindingOutput" + - name: addFinding + description: Add a new finding (nonconformity, observation, or exception) to the organization hints: readonly: false inputSchema: - $ref: "#/components/schemas/AddNonconformityInput" + $ref: "#/components/schemas/AddFindingInput" outputSchema: - $ref: "#/components/schemas/AddNonconformityOutput" - - name: updateNonconformity - description: Update an existing nonconformity + $ref: "#/components/schemas/AddFindingOutput" + - name: updateFinding + description: Update an existing finding hints: readonly: false inputSchema: - $ref: "#/components/schemas/UpdateNonconformityInput" + $ref: "#/components/schemas/UpdateFindingInput" outputSchema: - $ref: "#/components/schemas/UpdateNonconformityOutput" + $ref: "#/components/schemas/UpdateFindingOutput" + - name: deleteFinding + description: Delete a finding + hints: + readonly: false + destructive: true + inputSchema: + $ref: "#/components/schemas/DeleteFindingInput" + outputSchema: + $ref: "#/components/schemas/DeleteFindingOutput" + - name: linkFindingAudit + description: Link a finding to an audit with a reference ID + hints: + readonly: false + inputSchema: + $ref: "#/components/schemas/LinkFindingAuditInput" + outputSchema: + $ref: "#/components/schemas/LinkFindingAuditOutput" + - name: unlinkFindingAudit + description: Unlink a finding from an audit + hints: + readonly: false + destructive: true + inputSchema: + $ref: "#/components/schemas/UnlinkFindingAuditInput" + outputSchema: + $ref: "#/components/schemas/UnlinkFindingAuditOutput" + - name: listFindingAudits + description: List audits linked to a finding + hints: + readonly: true + idempotent: true + inputSchema: + $ref: "#/components/schemas/ListFindingAuditsInput" + outputSchema: + $ref: "#/components/schemas/ListFindingAuditsOutput" - name: listObligations description: List all obligations for the organization hints: @@ -6897,40 +6846,6 @@ tools: $ref: "#/components/schemas/DeleteTransferImpactAssessmentInput" outputSchema: $ref: "#/components/schemas/DeleteTransferImpactAssessmentOutput" - - name: listContinualImprovements - description: List all continual improvements for the organization - hints: - readonly: true - idempotent: true - inputSchema: - $ref: "#/components/schemas/ListContinualImprovementsInput" - outputSchema: - $ref: "#/components/schemas/ListContinualImprovementsOutput" - - name: getContinualImprovement - description: Get a continual improvement by ID - hints: - readonly: true - idempotent: true - inputSchema: - $ref: "#/components/schemas/GetContinualImprovementInput" - outputSchema: - $ref: "#/components/schemas/GetContinualImprovementOutput" - - name: addContinualImprovement - description: Add a new continual improvement to the organization - hints: - readonly: false - inputSchema: - $ref: "#/components/schemas/AddContinualImprovementInput" - outputSchema: - $ref: "#/components/schemas/AddContinualImprovementOutput" - - name: updateContinualImprovement - description: Update an existing continual improvement - hints: - readonly: false - inputSchema: - $ref: "#/components/schemas/UpdateContinualImprovementInput" - outputSchema: - $ref: "#/components/schemas/UpdateContinualImprovementOutput" - name: listAudits description: List all audits for the organization hints: @@ -7163,7 +7078,7 @@ tools: outputSchema: $ref: "#/components/schemas/GetSnapshotOutput" - name: takeSnapshot - description: Take a snapshot of a collection of objects (risks, vendors, assets, data, nonconformities, obligations, continual improvements, or processing activities) + description: Take a snapshot of a collection of objects (risks, vendors, assets, data, findings, obligations, or processing activities) hints: readonly: false inputSchema: diff --git a/pkg/server/api/mcp/v1/types/audit.go b/pkg/server/api/mcp/v1/types/audit.go index 813d7fdbb..c38cbf986 100644 --- a/pkg/server/api/mcp/v1/types/audit.go +++ b/pkg/server/api/mcp/v1/types/audit.go @@ -69,3 +69,21 @@ func NewListAuditsOutput(auditPage *page.Page[*coredata.Audit, coredata.AuditOrd Audits: audits, } } + +func NewListFindingAuditsOutput(auditPage *page.Page[*coredata.Audit, coredata.AuditOrderField]) ListFindingAuditsOutput { + audits := make([]*Audit, 0, len(auditPage.Data)) + for _, v := range auditPage.Data { + audits = append(audits, NewAudit(v)) + } + + var nextCursor *page.CursorKey + if len(auditPage.Data) > 0 { + cursorKey := auditPage.Data[len(auditPage.Data)-1].CursorKey(auditPage.Cursor.OrderBy.Field) + nextCursor = &cursorKey + } + + return ListFindingAuditsOutput{ + NextCursor: nextCursor, + Audits: audits, + } +} diff --git a/pkg/server/api/mcp/v1/types/continious_improvment.go b/pkg/server/api/mcp/v1/types/continious_improvment.go deleted file mode 100644 index 5df1dee82..000000000 --- a/pkg/server/api/mcp/v1/types/continious_improvment.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2025 Probo Inc . -// -// Permission to use, copy, modify, and/or distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -package types - -import ( - "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/page" -) - -func NewContinualImprovement(c *coredata.ContinualImprovement) *ContinualImprovement { - return &ContinualImprovement{ - ID: c.ID, - OrganizationID: c.OrganizationID, - ReferenceID: c.ReferenceID, - Description: c.Description, - Source: c.Source, - OwnerID: c.OwnerID, - TargetDate: c.TargetDate, - Status: c.Status, - Priority: c.Priority, - SnapshotID: c.SnapshotID, - CreatedAt: c.CreatedAt, - UpdatedAt: c.UpdatedAt, - } -} - -func NewListContinualImprovementsOutput(continualImprovementPage *page.Page[*coredata.ContinualImprovement, coredata.ContinualImprovementOrderField]) ListContinualImprovementsOutput { - continualImprovements := make([]*ContinualImprovement, 0, len(continualImprovementPage.Data)) - for _, v := range continualImprovementPage.Data { - continualImprovements = append(continualImprovements, NewContinualImprovement(v)) - } - - var nextCursor *page.CursorKey - if len(continualImprovementPage.Data) > 0 { - cursorKey := continualImprovementPage.Data[len(continualImprovementPage.Data)-1].CursorKey(continualImprovementPage.Cursor.OrderBy.Field) - nextCursor = &cursorKey - } - - return ListContinualImprovementsOutput{ - NextCursor: nextCursor, - ContinualImprovements: continualImprovements, - } -} diff --git a/pkg/server/api/mcp/v1/types/finding.go b/pkg/server/api/mcp/v1/types/finding.go new file mode 100644 index 000000000..c83bf380a --- /dev/null +++ b/pkg/server/api/mcp/v1/types/finding.go @@ -0,0 +1,68 @@ +// Copyright (c) 2025-2026 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package types + +import ( + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/page" +) + +func NewFinding(f *coredata.Finding) *Finding { + finding := &Finding{ + ID: f.ID, + OrganizationID: f.OrganizationID, + SnapshotID: f.SnapshotID, + Kind: f.Kind, + ReferenceID: f.ReferenceID, + Description: f.Description, + Source: f.Source, + IdentifiedOn: f.IdentifiedOn, + RootCause: f.RootCause, + CorrectiveAction: f.CorrectiveAction, + OwnerID: f.OwnerID, + DueDate: f.DueDate, + Status: f.Status, + Priority: f.Priority, + RiskID: f.RiskID, + EffectivenessCheck: f.EffectivenessCheck, + CreatedAt: f.CreatedAt, + UpdatedAt: f.UpdatedAt, + } + + if f.SourceID != nil { + s := f.SourceID.String() + finding.SourceID = &s + } + + return finding +} + +func NewListFindingsOutput(findingPage *page.Page[*coredata.Finding, coredata.FindingOrderField]) ListFindingsOutput { + findings := make([]*Finding, 0, len(findingPage.Data)) + for _, v := range findingPage.Data { + findings = append(findings, NewFinding(v)) + } + + var nextCursor *page.CursorKey + if len(findingPage.Data) > 0 { + cursorKey := findingPage.Data[len(findingPage.Data)-1].CursorKey(findingPage.Cursor.OrderBy.Field) + nextCursor = &cursorKey + } + + return ListFindingsOutput{ + NextCursor: nextCursor, + Findings: findings, + } +} diff --git a/pkg/server/api/mcp/v1/types/nonconformity.go b/pkg/server/api/mcp/v1/types/nonconformity.go deleted file mode 100644 index a3b0ff791..000000000 --- a/pkg/server/api/mcp/v1/types/nonconformity.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2025 Probo Inc . -// -// Permission to use, copy, modify, and/or distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -package types - -import ( - "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/page" -) - -func NewNonconformity(n *coredata.Nonconformity) *Nonconformity { - return &Nonconformity{ - ID: n.ID, - SnapshotID: n.SnapshotID, - ReferenceID: n.ReferenceID, - Description: n.Description, - AuditID: n.AuditID, - DateIdentified: n.DateIdentified, - RootCause: n.RootCause, - CorrectiveAction: n.CorrectiveAction, - OwnerID: n.OwnerID, - DueDate: n.DueDate, - Status: n.Status, - EffectivenessCheck: n.EffectivenessCheck, - CreatedAt: n.CreatedAt, - UpdatedAt: n.UpdatedAt, - } -} - -func NewListNonconformitiesOutput(nonconformityPage *page.Page[*coredata.Nonconformity, coredata.NonconformityOrderField]) ListNonconformitiesOutput { - nonconformities := make([]*Nonconformity, 0, len(nonconformityPage.Data)) - for _, v := range nonconformityPage.Data { - nonconformities = append(nonconformities, NewNonconformity(v)) - } - - var nextCursor *page.CursorKey - if len(nonconformityPage.Data) > 0 { - cursorKey := nonconformityPage.Data[len(nonconformityPage.Data)-1].CursorKey(nonconformityPage.Cursor.OrderBy.Field) - nextCursor = &cursorKey - } - - return ListNonconformitiesOutput{ - NextCursor: nextCursor, - Nonconformities: nonconformities, - } -}