Add finding MCP API

Replace nonconformity and continual improvement MCP tools with
unified finding tools: list_findings, get_finding, create_finding,
update_finding, delete_finding, link_finding_to_audit, and
unlink_finding_from_audit.

Update specification and resolvers to use the new finding types.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-03-17 00:38:28 +01:00
parent 0ab88a9bbc
commit 69ab9c60cd
6 changed files with 517 additions and 647 deletions

View File

@@ -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
}

View File

@@ -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:

View File

@@ -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,
}
}

View File

@@ -1,55 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// 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,
}
}

View File

@@ -0,0 +1,68 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// 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,
}
}

View File

@@ -1,57 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// 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,
}
}