package mcp_v1 // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. // Code generated by mcpgen. DO NOT EDIT. import ( "context" "encoding/json" "errors" "fmt" "time" "github.com/modelcontextprotocol/go-sdk/mcp" "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/cookiebanner" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/iam" "go.probo.inc/probo/pkg/itam" "go.probo.inc/probo/pkg/mail" "go.probo.inc/probo/pkg/mailman" "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/probo" "go.probo.inc/probo/pkg/resourcealias" "go.probo.inc/probo/pkg/riskmanagement" "go.probo.inc/probo/pkg/server/api/authn" "go.probo.inc/probo/pkg/server/api/authz" "go.probo.inc/probo/pkg/server/api/mcp/v1/types" "go.probo.inc/probo/pkg/thirdparty" "go.probo.inc/probo/pkg/validator" ) // ListOrganizationsTool handles the listOrganizations tool // List all organizations the user has access to func (r *Resolver) ListOrganizationsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListOrganizationsInput) (*mcp.CallToolResult, types.ListOrganizationsOutput, error) { user := authn.IdentityFromContext(ctx) organizations, err := r.iamSvc.AccountService.ListOrganizations(ctx, user.ID) if err != nil { return nil, types.ListOrganizationsOutput{}, fmt.Errorf("failed to list organizations: %w", err) } result := types.ListOrganizationsOutput{ Organizations: make([]*types.Organization, 0, len(organizations)), } for _, org := range organizations { result.Organizations = append(result.Organizations, types.NewOrganization(org)) } return nil, result, nil } // ListThirdPartiesTool handles the listThirdParties tool // List all thirdParties for the organization func (r *Resolver) ListThirdPartiesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListThirdPartiesInput) (*mcp.CallToolResult, types.ListThirdPartiesOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionThirdPartyList) if err != nil { return nil, types.ListThirdPartiesOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ThirdPartyOrderField]{ Field: coredata.ThirdPartyOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ThirdPartyOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) level := input.Level if level == nil { level = new(1) } thirdPartyFilter := coredata.NewThirdPartyFilter(nil, level, nil, nil, nil) page, err := prb.ThirdParties.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor, thirdPartyFilter) if err != nil { panic(fmt.Errorf("cannot list organization thirdParties: %w", err)) } return nil, types.NewListThirdPartiesOutput(page), nil } // AddThirdPartyTool handles the addThirdParty tool // Add a new thirdParty to the organization func (r *Resolver) AddThirdPartyTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddThirdPartyInput) (*mcp.CallToolResult, types.AddThirdPartyOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionThirdPartyCreate) if err != nil { return nil, types.AddThirdPartyOutput{}, err } svc := r.proboSvc var category *coredata.ThirdPartyCategory if input.Category != nil { cat := coredata.ThirdPartyCategory(*input.Category) category = &cat } var countries coredata.CountryCodes if len(input.Countries) > 0 { countries = make(coredata.CountryCodes, len(input.Countries)) for i, c := range input.Countries { countries[i] = coredata.CountryCode(c) } } thirdParty, err := svc.ThirdParties.Create( ctx, scope, probo.CreateThirdPartyRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Description: input.Description, Category: category, HeadquarterAddress: input.HeadquarterAddress, LegalName: input.LegalName, WebsiteURL: input.WebsiteURL, PrivacyPolicyURL: input.PrivacyPolicyURL, ServiceLevelAgreementURL: input.ServiceLevelAgreementURL, DataProcessingAgreementURL: input.DataProcessingAgreementURL, BusinessAssociateAgreementURL: input.BusinessAssociateAgreementURL, SubprocessorsListURL: input.SubprocessorsListURL, Certifications: input.Certifications, Countries: countries, BusinessOwnerID: input.BusinessOwnerID, SecurityOwnerID: input.SecurityOwnerID, StatusPageURL: input.StatusPageURL, TermsOfServiceURL: input.TermsOfServiceURL, SecurityPageURL: input.SecurityPageURL, TrustPageURL: input.TrustPageURL, }, ) if err != nil { return nil, types.AddThirdPartyOutput{}, fmt.Errorf("failed to create thirdParty: %w", err) } return nil, types.NewAddThirdPartyOutput(thirdParty), nil } // UpdateThirdPartyTool handles the updateThirdParty tool // Update an existing thirdParty func (r *Resolver) UpdateThirdPartyTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateThirdPartyInput) (*mcp.CallToolResult, types.UpdateThirdPartyOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyUpdate) if err != nil { return nil, types.UpdateThirdPartyOutput{}, err } svc := r.proboSvc var description **string if input.Description != nil { description = &input.Description } var headquarterAddress **string if input.HeadquarterAddress != nil { headquarterAddress = &input.HeadquarterAddress } var legalName **string if input.LegalName != nil { legalName = &input.LegalName } var websiteURL **string if input.WebsiteURL != nil { websiteURL = &input.WebsiteURL } var privacyPolicyURL **string if input.PrivacyPolicyURL != nil { privacyPolicyURL = &input.PrivacyPolicyURL } var serviceLevelAgreementURL **string if input.ServiceLevelAgreementURL != nil { serviceLevelAgreementURL = &input.ServiceLevelAgreementURL } var dataProcessingAgreementURL **string if input.DataProcessingAgreementURL != nil { dataProcessingAgreementURL = &input.DataProcessingAgreementURL } var businessAssociateAgreementURL **string if input.BusinessAssociateAgreementURL != nil { businessAssociateAgreementURL = &input.BusinessAssociateAgreementURL } var subprocessorsListURL **string if input.SubprocessorsListURL != nil { subprocessorsListURL = &input.SubprocessorsListURL } var statusPageURL **string if input.StatusPageURL != nil { statusPageURL = &input.StatusPageURL } var termsOfServiceURL **string if input.TermsOfServiceURL != nil { termsOfServiceURL = &input.TermsOfServiceURL } var securityPageURL **string if input.SecurityPageURL != nil { securityPageURL = &input.SecurityPageURL } var trustPageURL **string if input.TrustPageURL != nil { trustPageURL = &input.TrustPageURL } var businessOwnerID **gid.GID if input.BusinessOwnerID != nil { businessOwnerID = &input.BusinessOwnerID } var securityOwnerID **gid.GID if input.SecurityOwnerID != nil { securityOwnerID = &input.SecurityOwnerID } var category *coredata.ThirdPartyCategory if input.Category != nil { cat := coredata.ThirdPartyCategory(*input.Category) category = &cat } var countries coredata.CountryCodes if len(input.Countries) > 0 { countries = make(coredata.CountryCodes, len(input.Countries)) for i, c := range input.Countries { countries[i] = coredata.CountryCode(c) } } thirdParty, err := svc.ThirdParties.Update( ctx, scope, probo.UpdateThirdPartyRequest{ ID: input.ID, Name: input.Name, Description: description, Category: category, HeadquarterAddress: headquarterAddress, LegalName: legalName, WebsiteURL: websiteURL, PrivacyPolicyURL: privacyPolicyURL, ServiceLevelAgreementURL: serviceLevelAgreementURL, DataProcessingAgreementURL: dataProcessingAgreementURL, BusinessAssociateAgreementURL: businessAssociateAgreementURL, SubprocessorsListURL: subprocessorsListURL, Certifications: input.Certifications, Countries: countries, BusinessOwnerID: businessOwnerID, SecurityOwnerID: securityOwnerID, StatusPageURL: statusPageURL, TermsOfServiceURL: termsOfServiceURL, SecurityPageURL: securityPageURL, TrustPageURL: trustPageURL, }, ) if err != nil { return nil, types.UpdateThirdPartyOutput{}, fmt.Errorf("failed to update thirdParty: %w", err) } return nil, types.NewUpdateThirdPartyOutput(thirdParty), nil } func (r *Resolver) ListRisksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRisksInput) (*mcp.CallToolResult, types.ListRisksOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionRiskList) if err != nil { return nil, types.ListRisksOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.RiskOrderField]{ Field: coredata.RiskOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) riskFilter := coredata.NewRiskFilter(nil) if input.Filter != nil { riskFilter = coredata.NewRiskFilter(input.Filter.Query) } page, err := prb.Risks.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor, riskFilter) if err != nil { panic(fmt.Errorf("cannot list organization risks: %w", err)) } return nil, types.NewListRisksOutput(page), nil } func (r *Resolver) GetRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskInput) (*mcp.CallToolResult, types.GetRiskOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskGet) if err != nil { return nil, types.GetRiskOutput{}, err } prb := r.proboSvc risk, err := prb.Risks.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskOutput{}, fmt.Errorf("failed to get risk: %w", err) } return nil, types.GetRiskOutput{ Risk: types.NewRisk(risk), }, nil } func (r *Resolver) AddRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskInput) (*mcp.CallToolResult, types.AddRiskOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionRiskCreate) if err != nil { return nil, types.AddRiskOutput{}, err } svc := r.proboSvc risk, err := svc.Risks.Create( ctx, scope, probo.CreateRiskRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Description: input.Description, Category: input.Category, Treatment: input.Treatment, InherentLikelihood: input.InherentLikelihood, InherentImpact: input.InherentImpact, ResidualLikelihood: input.ResidualLikelihood, ResidualImpact: input.ResidualImpact, }, ) if err != nil { return nil, types.AddRiskOutput{}, fmt.Errorf("failed to create risk: %w", err) } return nil, types.AddRiskOutput{ Risk: types.NewRisk(risk), }, nil } func (r *Resolver) UpdateRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRiskInput) (*mcp.CallToolResult, types.UpdateRiskOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskUpdate) if err != nil { return nil, types.UpdateRiskOutput{}, err } svc := r.proboSvc risk, err := svc.Risks.Update( ctx, scope, probo.UpdateRiskRequest{ ID: input.ID, Name: input.Name, Description: UnwrapOmittable(input.Description), Category: input.Category, Treatment: input.Treatment, OwnerID: UnwrapOmittable(input.OwnerID), InherentLikelihood: input.InherentLikelihood, InherentImpact: input.InherentImpact, ResidualLikelihood: input.ResidualLikelihood, ResidualImpact: input.ResidualImpact, Note: input.Note, }, ) if err != nil { return nil, types.UpdateRiskOutput{}, fmt.Errorf("failed to update risk: %w", err) } return nil, types.UpdateRiskOutput{ Risk: types.NewRisk(risk), }, nil } func (r *Resolver) ListMeasuresTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMeasuresInput) (*mcp.CallToolResult, types.ListMeasuresOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionMeasureList) if err != nil { return nil, types.ListMeasuresOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.MeasureOrderField]{ Field: coredata.MeasureOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.MeasureOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) var measureFilter = coredata.NewMeasureFilter(nil, nil, nil) if input.Filter != nil { measureFilter = coredata.NewMeasureFilter(input.Filter.Query, input.Filter.State, input.Filter.Category) } page, err := prb.Measures.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor, measureFilter) if err != nil { panic(fmt.Errorf("cannot list organization measures: %w", err)) } return nil, types.NewListMeasuresOutput(page), nil } func (r *Resolver) GetMeasureTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetMeasureInput) (*mcp.CallToolResult, types.GetMeasureOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionMeasureGet) if err != nil { return nil, types.GetMeasureOutput{}, err } prb := r.proboSvc measure, err := prb.Measures.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetMeasureOutput{}, fmt.Errorf("failed to get measure: %w", err) } return nil, types.GetMeasureOutput{ Measure: types.NewMeasure(measure), }, nil } func (r *Resolver) AddMeasureTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddMeasureInput) (*mcp.CallToolResult, types.AddMeasureOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionMeasureCreate) if err != nil { return nil, types.AddMeasureOutput{}, err } svc := r.proboSvc measure, err := svc.Measures.Create( ctx, scope, probo.CreateMeasureRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Description: input.Description, Category: input.Category, }, ) if err != nil { return nil, types.AddMeasureOutput{}, fmt.Errorf("failed to create measure: %w", err) } return nil, types.AddMeasureOutput{ Measure: types.NewMeasure(measure), }, nil } func (r *Resolver) UpdateMeasureTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateMeasureInput) (*mcp.CallToolResult, types.UpdateMeasureOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionMeasureUpdate) if err != nil { return nil, types.UpdateMeasureOutput{}, err } svc := r.proboSvc measure, err := svc.Measures.Update( ctx, scope, probo.UpdateMeasureRequest{ ID: input.ID, Name: input.Name, Description: UnwrapOmittable(input.Description), Category: input.Category, State: input.State, }, ) if err != nil { return nil, types.UpdateMeasureOutput{}, fmt.Errorf("failed to update measure: %w", err) } return nil, types.UpdateMeasureOutput{ Measure: types.NewMeasure(measure), }, nil } func (r *Resolver) ListFrameworksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListFrameworksInput) (*mcp.CallToolResult, types.ListFrameworksOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionFrameworkList) if err != nil { return nil, types.ListFrameworksOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.FrameworkOrderField]{ Field: coredata.FrameworkOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.FrameworkOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.Frameworks.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization frameworks: %w", err)) } return nil, types.NewListFrameworksOutput(page), nil } func (r *Resolver) GetFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetFrameworkInput) (*mcp.CallToolResult, types.GetFrameworkOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionFrameworkGet) if err != nil { return nil, types.GetFrameworkOutput{}, err } prb := r.proboSvc framework, err := prb.Frameworks.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetFrameworkOutput{}, fmt.Errorf("failed to get framework: %w", err) } return nil, types.GetFrameworkOutput{ Framework: types.NewFramework(framework), }, nil } func (r *Resolver) AddFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddFrameworkInput) (*mcp.CallToolResult, types.AddFrameworkOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionFrameworkCreate) if err != nil { return nil, types.AddFrameworkOutput{}, err } svc := r.proboSvc framework, err := svc.Frameworks.Create( ctx, scope, probo.CreateFrameworkRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Description: input.Description, }, ) if err != nil { return nil, types.AddFrameworkOutput{}, fmt.Errorf("failed to create framework: %w", err) } return nil, types.AddFrameworkOutput{ Framework: types.NewFramework(framework), }, nil } func (r *Resolver) UpdateFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateFrameworkInput) (*mcp.CallToolResult, types.UpdateFrameworkOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionFrameworkUpdate) if err != nil { return nil, types.UpdateFrameworkOutput{}, err } svc := r.proboSvc framework, err := svc.Frameworks.Update( ctx, scope, probo.UpdateFrameworkRequest{ ID: input.ID, Name: input.Name, Description: UnwrapOmittable(input.Description), }, ) if err != nil { return nil, types.UpdateFrameworkOutput{}, fmt.Errorf("failed to update framework: %w", err) } return nil, types.UpdateFrameworkOutput{ Framework: types.NewFramework(framework), }, nil } func (r *Resolver) ListAssetsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAssetsInput) (*mcp.CallToolResult, types.ListAssetsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionAssetList) if err != nil { return nil, types.ListAssetsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.AssetOrderField]{ Field: coredata.AssetOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.AssetOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.Assets.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization assets: %w", err)) } return nil, types.NewListAssetsOutput(page), nil } func (r *Resolver) GetAssetTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetAssetInput) (*mcp.CallToolResult, types.GetAssetOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionAssetGet) if err != nil { return nil, types.GetAssetOutput{}, err } prb := r.proboSvc asset, err := prb.Assets.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetAssetOutput{}, fmt.Errorf("failed to get asset: %w", err) } return nil, types.GetAssetOutput{ Asset: types.NewAsset(asset), }, nil } func (r *Resolver) AddAssetTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddAssetInput) (*mcp.CallToolResult, types.AddAssetOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionAssetCreate) if err != nil { return nil, types.AddAssetOutput{}, err } svc := r.proboSvc asset, err := svc.Assets.Create( ctx, scope, probo.CreateAssetRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Amount: input.Amount, OwnerID: input.OwnerID, AssetType: input.AssetType, DataTypesStored: input.DataTypesStored, ThirdPartyIDs: input.ThirdPartyIds, }, ) if err != nil { return nil, types.AddAssetOutput{}, fmt.Errorf("failed to create asset: %w", err) } return nil, types.AddAssetOutput{ Asset: types.NewAsset(asset), }, nil } func (r *Resolver) UpdateAssetTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateAssetInput) (*mcp.CallToolResult, types.UpdateAssetOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionAssetUpdate) if err != nil { return nil, types.UpdateAssetOutput{}, err } svc := r.proboSvc asset, err := svc.Assets.Update( ctx, scope, probo.UpdateAssetRequest{ ID: input.ID, Name: input.Name, Amount: input.Amount, OwnerID: input.OwnerID, AssetType: input.AssetType, DataTypesStored: input.DataTypesStored, ThirdPartyIDs: input.ThirdPartyIds, }, ) if err != nil { return nil, types.UpdateAssetOutput{}, fmt.Errorf("failed to update asset: %w", err) } return nil, types.UpdateAssetOutput{ Asset: types.NewAsset(asset), }, nil } func (r *Resolver) ListDataTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDataInput) (*mcp.CallToolResult, types.ListDataOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionDatumList) if err != nil { return nil, types.ListDataOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.DatumOrderField]{ Field: coredata.DatumOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DatumOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.Data.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization data: %w", err)) } return nil, types.NewListDataOutput(page), nil } func (r *Resolver) GetDatumTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetDatumInput) (*mcp.CallToolResult, types.GetDatumOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDatumGet) if err != nil { return nil, types.GetDatumOutput{}, err } prb := r.proboSvc datum, err := prb.Data.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetDatumOutput{}, fmt.Errorf("failed to get datum: %w", err) } return nil, types.GetDatumOutput{ Datum: types.NewDatum(datum), }, nil } func (r *Resolver) AddDatumTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddDatumInput) (*mcp.CallToolResult, types.AddDatumOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionDatumCreate) if err != nil { return nil, types.AddDatumOutput{}, err } svc := r.proboSvc datum, err := svc.Data.Create( ctx, scope, probo.CreateDatumRequest{ OrganizationID: input.OrganizationID, Name: input.Name, DataClassification: input.DataClassification, OwnerID: input.OwnerID, ThirdPartyIDs: input.ThirdPartyIds, }, ) if err != nil { return nil, types.AddDatumOutput{}, fmt.Errorf("failed to create datum: %w", err) } return nil, types.AddDatumOutput{ Datum: types.NewDatum(datum), }, nil } func (r *Resolver) UpdateDatumTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateDatumInput) (*mcp.CallToolResult, types.UpdateDatumOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDatumUpdate) if err != nil { return nil, types.UpdateDatumOutput{}, err } svc := r.proboSvc datum, err := svc.Data.Update( ctx, scope, probo.UpdateDatumRequest{ ID: input.ID, Name: input.Name, DataClassification: input.DataClassification, OwnerID: input.OwnerID, ThirdPartyIDs: input.ThirdPartyIds, }, ) if err != nil { return nil, types.UpdateDatumOutput{}, fmt.Errorf("failed to update datum: %w", err) } return nil, types.UpdateDatumOutput{ Datum: types.NewDatum(datum), }, nil } func (r *Resolver) ListFindingsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListFindingsInput) (*mcp.CallToolResult, types.ListFindingsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionFindingList) if err != nil { return nil, types.ListFindingsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.FindingOrderField]{ Field: coredata.FindingOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.FindingOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) findingFilter := coredata.NewFindingFilter(nil, nil, nil, nil) if input.Filter != nil { findingFilter = coredata.NewFindingFilter( input.Filter.Kind, input.Filter.Status, input.Filter.Priority, input.Filter.OwnerID, ) } page, err := prb.Findings.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor, findingFilter) if err != nil { panic(fmt.Errorf("cannot list organization findings: %w", err)) } return nil, types.NewListFindingsOutput(page), nil } func (r *Resolver) GetFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetFindingInput) (*mcp.CallToolResult, types.GetFindingOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionFindingGet) if err != nil { return nil, types.GetFindingOutput{}, err } prb := r.proboSvc finding, err := prb.Findings.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetFindingOutput{}, fmt.Errorf("cannot get finding: %w", err) } return nil, types.GetFindingOutput{ Finding: types.NewFinding(finding), }, nil } func (r *Resolver) AddFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddFindingInput) (*mcp.CallToolResult, types.AddFindingOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionFindingCreate) if err != nil { return nil, types.AddFindingOutput{}, err } svc := r.proboSvc finding, err := svc.Findings.Create( ctx, scope, &probo.CreateFindingRequest{ OrganizationID: input.OrganizationID, Kind: input.Kind, Description: input.Description, 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.AddFindingOutput{}, fmt.Errorf("failed to create finding: %w", err) } return nil, types.AddFindingOutput{ Finding: types.NewFinding(finding), }, nil } func (r *Resolver) UpdateFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateFindingInput) (*mcp.CallToolResult, types.UpdateFindingOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionFindingUpdate) if err != nil { return nil, types.UpdateFindingOutput{}, err } svc := r.proboSvc finding, err := svc.Findings.Update( ctx, scope, &probo.UpdateFindingRequest{ ID: input.ID, Description: UnwrapOmittable(input.Description), Source: UnwrapOmittable(input.Source), IdentifiedOn: UnwrapOmittable(input.IdentifiedOn), RootCause: UnwrapOmittable(input.RootCause), CorrectiveAction: UnwrapOmittable(input.CorrectiveAction), OwnerID: input.OwnerID, DueDate: UnwrapOmittable(input.DueDate), Status: input.Status, Priority: input.Priority, RiskID: UnwrapOmittable(input.RiskID), EffectivenessCheck: UnwrapOmittable(input.EffectivenessCheck), }, ) if err != nil { return nil, types.UpdateFindingOutput{}, fmt.Errorf("failed to update finding: %w", err) } return nil, types.UpdateFindingOutput{ Finding: types.NewFinding(finding), }, nil } func (r *Resolver) ListObligationsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListObligationsInput) (*mcp.CallToolResult, types.ListObligationsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionObligationList) if err != nil { return nil, types.ListObligationsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ObligationOrderField]{ Field: coredata.ObligationOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ObligationOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.Obligations.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization obligations: %w", err)) } return nil, types.NewListObligationsOutput(page), nil } func (r *Resolver) GetObligationTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetObligationInput) (*mcp.CallToolResult, types.GetObligationOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionObligationGet) if err != nil { return nil, types.GetObligationOutput{}, err } prb := r.proboSvc obligation, err := prb.Obligations.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetObligationOutput{}, fmt.Errorf("failed to get obligation: %w", err) } return nil, types.GetObligationOutput{ Obligation: types.NewObligation(obligation), }, nil } func (r *Resolver) AddObligationTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddObligationInput) (*mcp.CallToolResult, types.AddObligationOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionObligationCreate) if err != nil { return nil, types.AddObligationOutput{}, err } svc := r.proboSvc obligation, err := svc.Obligations.Create( ctx, scope, &probo.CreateObligationRequest{ OrganizationID: input.OrganizationID, Area: input.Area, Source: input.Source, Requirement: input.Requirement, ActionsToBeImplemented: input.ActionsToBeImplemented, Regulator: input.Regulator, OwnerID: input.OwnerID, LastReviewDate: input.LastReviewDate, DueDate: input.DueDate, Status: *input.Status, Type: *input.Type, }, ) if err != nil { return nil, types.AddObligationOutput{}, fmt.Errorf("failed to create obligation: %w", err) } return nil, types.AddObligationOutput{ Obligation: types.NewObligation(obligation), }, nil } func (r *Resolver) UpdateObligationTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateObligationInput) (*mcp.CallToolResult, types.UpdateObligationOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionObligationUpdate) if err != nil { return nil, types.UpdateObligationOutput{}, err } svc := r.proboSvc obligation, err := svc.Obligations.Update( ctx, scope, &probo.UpdateObligationRequest{ ID: input.ID, Area: UnwrapOmittable(input.Area), Source: UnwrapOmittable(input.Source), Requirement: UnwrapOmittable(input.Requirement), ActionsToBeImplemented: UnwrapOmittable(input.ActionsToBeImplemented), Regulator: UnwrapOmittable(input.Regulator), OwnerID: input.OwnerID, LastReviewDate: UnwrapOmittable(input.LastReviewDate), DueDate: UnwrapOmittable(input.DueDate), Status: input.Status, Type: input.Type, }, ) if err != nil { return nil, types.UpdateObligationOutput{}, fmt.Errorf("failed to update obligation: %w", err) } return nil, types.UpdateObligationOutput{ Obligation: types.NewObligation(obligation), }, nil } func (r *Resolver) ListProcessingActivitiesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListProcessingActivitiesInput) (*mcp.CallToolResult, types.ListProcessingActivitiesOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionProcessingActivityList) if err != nil { return nil, types.ListProcessingActivitiesOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ProcessingActivityOrderField]{ Field: coredata.ProcessingActivityOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ProcessingActivityOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.ProcessingActivities.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization processing activities: %w", err)) } return nil, types.NewListProcessingActivitiesOutput(page), nil } func (r *Resolver) GetProcessingActivityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetProcessingActivityInput) (*mcp.CallToolResult, types.GetProcessingActivityOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionProcessingActivityGet) if err != nil { return nil, types.GetProcessingActivityOutput{}, err } prb := r.proboSvc processingActivity, err := prb.ProcessingActivities.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetProcessingActivityOutput{}, fmt.Errorf("failed to get processing activity: %w", err) } return nil, types.GetProcessingActivityOutput{ ProcessingActivity: types.NewProcessingActivity(processingActivity), }, nil } func (r *Resolver) AddProcessingActivityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddProcessingActivityInput) (*mcp.CallToolResult, types.AddProcessingActivityOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionProcessingActivityCreate) if err != nil { return nil, types.AddProcessingActivityOutput{}, err } svc := r.proboSvc processingActivity, err := svc.ProcessingActivities.Create( ctx, scope, &probo.CreateProcessingActivityRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Purpose: input.Purpose, DataSubjectCategory: input.DataSubjectCategory, PersonalDataCategory: input.PersonalDataCategory, SpecialOrCriminalData: input.SpecialOrCriminalData, ConsentEvidenceLink: input.ConsentEvidenceLink, LawfulBasis: input.LawfulBasis, Recipients: input.Recipients, Location: input.Location, InternationalTransfers: input.InternationalTransfers, TransferSafeguard: input.TransferSafeguard, RetentionPeriod: input.RetentionPeriod, SecurityMeasures: input.SecurityMeasures, DataProtectionImpactAssessmentNeeded: input.DataProtectionImpactAssessmentNeeded, TransferImpactAssessmentNeeded: input.TransferImpactAssessmentNeeded, LastReviewDate: input.LastReviewDate, NextReviewDate: input.NextReviewDate, Role: input.Role, DataProtectionOfficerID: input.DataProtectionOfficerID, ThirdPartyIDs: input.ThirdPartyIds, }, ) if err != nil { return nil, types.AddProcessingActivityOutput{}, fmt.Errorf("failed to create processing activity: %w", err) } return nil, types.AddProcessingActivityOutput{ ProcessingActivity: types.NewProcessingActivity(processingActivity), }, nil } func (r *Resolver) UpdateProcessingActivityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateProcessingActivityInput) (*mcp.CallToolResult, types.UpdateProcessingActivityOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionProcessingActivityUpdate) if err != nil { return nil, types.UpdateProcessingActivityOutput{}, err } svc := r.proboSvc var thirdPartyIDs *[]gid.GID if input.ThirdPartyIds != nil { thirdPartyIDs = &input.ThirdPartyIds } processingActivity, err := svc.ProcessingActivities.Update( ctx, scope, &probo.UpdateProcessingActivityRequest{ ID: input.ID, Name: input.Name, Purpose: UnwrapOmittable(input.Purpose), DataSubjectCategory: UnwrapOmittable(input.DataSubjectCategory), PersonalDataCategory: UnwrapOmittable(input.PersonalDataCategory), SpecialOrCriminalData: input.SpecialOrCriminalData, ConsentEvidenceLink: UnwrapOmittable(input.ConsentEvidenceLink), LawfulBasis: input.LawfulBasis, Recipients: UnwrapOmittable(input.Recipients), Location: UnwrapOmittable(input.Location), InternationalTransfers: input.InternationalTransfers, TransferSafeguard: UnwrapOmittable(input.TransferSafeguard), RetentionPeriod: UnwrapOmittable(input.RetentionPeriod), SecurityMeasures: UnwrapOmittable(input.SecurityMeasures), DataProtectionImpactAssessmentNeeded: input.DataProtectionImpactAssessmentNeeded, TransferImpactAssessmentNeeded: input.TransferImpactAssessmentNeeded, LastReviewDate: UnwrapOmittable(input.LastReviewDate), NextReviewDate: UnwrapOmittable(input.NextReviewDate), Role: input.Role, DataProtectionOfficerID: UnwrapOmittable(input.DataProtectionOfficerID), ThirdPartyIDs: thirdPartyIDs, }, ) if err != nil { return nil, types.UpdateProcessingActivityOutput{}, fmt.Errorf("failed to update processing activity: %w", err) } return nil, types.UpdateProcessingActivityOutput{ ProcessingActivity: types.NewProcessingActivity(processingActivity), }, nil } func (r *Resolver) DeleteProcessingActivityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteProcessingActivityInput) (*mcp.CallToolResult, types.DeleteProcessingActivityOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionProcessingActivityDelete) if err != nil { return nil, types.DeleteProcessingActivityOutput{}, err } svc := r.proboSvc err = svc.ProcessingActivities.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteProcessingActivityOutput{}, fmt.Errorf("failed to delete processing activity: %w", err) } return nil, types.DeleteProcessingActivityOutput{ DeletedProcessingActivityID: input.ID, }, nil } func (r *Resolver) ListDataProtectionImpactAssessmentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDataProtectionImpactAssessmentsInput) (*mcp.CallToolResult, types.ListDataProtectionImpactAssessmentsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionDataProtectionImpactAssessmentList) if err != nil { return nil, types.ListDataProtectionImpactAssessmentsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.DataProtectionImpactAssessmentOrderField]{ Field: coredata.DataProtectionImpactAssessmentOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DataProtectionImpactAssessmentOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.DataProtectionImpactAssessments.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization data protection impact assessments: %w", err)) } return nil, types.NewListDataProtectionImpactAssessmentsOutput(page), nil } func (r *Resolver) GetDataProtectionImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetDataProtectionImpactAssessmentInput) (*mcp.CallToolResult, types.GetDataProtectionImpactAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentGet) if err != nil { return nil, types.GetDataProtectionImpactAssessmentOutput{}, err } prb := r.proboSvc dpia, err := prb.DataProtectionImpactAssessments.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetDataProtectionImpactAssessmentOutput{}, fmt.Errorf("failed to get data protection impact assessment: %w", err) } return nil, types.GetDataProtectionImpactAssessmentOutput{ DataProtectionImpactAssessment: types.NewDataProtectionImpactAssessment(dpia), }, nil } func (r *Resolver) AddDataProtectionImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddDataProtectionImpactAssessmentInput) (*mcp.CallToolResult, types.AddDataProtectionImpactAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ProcessingActivityID, probo.ActionDataProtectionImpactAssessmentCreate) if err != nil { return nil, types.AddDataProtectionImpactAssessmentOutput{}, err } svc := r.proboSvc dpia, err := svc.DataProtectionImpactAssessments.Create( ctx, scope, &probo.CreateDataProtectionImpactAssessmentRequest{ ProcessingActivityID: input.ProcessingActivityID, Description: input.Description, NecessityAndProportionality: input.NecessityAndProportionality, PotentialRisk: input.PotentialRisk, Mitigations: input.Mitigations, ResidualRisk: input.ResidualRisk, }, ) if err != nil { return nil, types.AddDataProtectionImpactAssessmentOutput{}, fmt.Errorf("failed to create data protection impact assessment: %w", err) } return nil, types.AddDataProtectionImpactAssessmentOutput{ DataProtectionImpactAssessment: types.NewDataProtectionImpactAssessment(dpia), }, nil } func (r *Resolver) UpdateDataProtectionImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateDataProtectionImpactAssessmentInput) (*mcp.CallToolResult, types.UpdateDataProtectionImpactAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentUpdate) if err != nil { return nil, types.UpdateDataProtectionImpactAssessmentOutput{}, err } svc := r.proboSvc dpia, err := svc.DataProtectionImpactAssessments.Update( ctx, scope, &probo.UpdateDataProtectionImpactAssessmentRequest{ ID: input.ID, Description: UnwrapOmittable(input.Description), NecessityAndProportionality: UnwrapOmittable(input.NecessityAndProportionality), PotentialRisk: UnwrapOmittable(input.PotentialRisk), Mitigations: UnwrapOmittable(input.Mitigations), ResidualRisk: input.ResidualRisk, }, ) if err != nil { return nil, types.UpdateDataProtectionImpactAssessmentOutput{}, fmt.Errorf("failed to update data protection impact assessment: %w", err) } return nil, types.UpdateDataProtectionImpactAssessmentOutput{ DataProtectionImpactAssessment: types.NewDataProtectionImpactAssessment(dpia), }, nil } func (r *Resolver) ListTransferImpactAssessmentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListTransferImpactAssessmentsInput) (*mcp.CallToolResult, types.ListTransferImpactAssessmentsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionTransferImpactAssessmentList) if err != nil { return nil, types.ListTransferImpactAssessmentsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.TransferImpactAssessmentOrderField]{ Field: coredata.TransferImpactAssessmentOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.TransferImpactAssessmentOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.TransferImpactAssessments.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization transfer impact assessments: %w", err)) } return nil, types.NewListTransferImpactAssessmentsOutput(page), nil } func (r *Resolver) GetTransferImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetTransferImpactAssessmentInput) (*mcp.CallToolResult, types.GetTransferImpactAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTransferImpactAssessmentGet) if err != nil { return nil, types.GetTransferImpactAssessmentOutput{}, err } prb := r.proboSvc tia, err := prb.TransferImpactAssessments.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetTransferImpactAssessmentOutput{}, fmt.Errorf("failed to get transfer impact assessment: %w", err) } return nil, types.GetTransferImpactAssessmentOutput{ TransferImpactAssessment: types.NewTransferImpactAssessment(tia), }, nil } func (r *Resolver) AddTransferImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddTransferImpactAssessmentInput) (*mcp.CallToolResult, types.AddTransferImpactAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ProcessingActivityID, probo.ActionTransferImpactAssessmentCreate) if err != nil { return nil, types.AddTransferImpactAssessmentOutput{}, err } svc := r.proboSvc tia, err := svc.TransferImpactAssessments.Create( ctx, scope, &probo.CreateTransferImpactAssessmentRequest{ ProcessingActivityID: input.ProcessingActivityID, DataSubjects: input.DataSubjects, LegalMechanism: input.LegalMechanism, Transfer: input.Transfer, LocalLawRisk: input.LocalLawRisk, SupplementaryMeasures: input.SupplementaryMeasures, }, ) if err != nil { return nil, types.AddTransferImpactAssessmentOutput{}, fmt.Errorf("failed to create transfer impact assessment: %w", err) } return nil, types.AddTransferImpactAssessmentOutput{ TransferImpactAssessment: types.NewTransferImpactAssessment(tia), }, nil } func (r *Resolver) UpdateTransferImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTransferImpactAssessmentInput) (*mcp.CallToolResult, types.UpdateTransferImpactAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTransferImpactAssessmentUpdate) if err != nil { return nil, types.UpdateTransferImpactAssessmentOutput{}, err } svc := r.proboSvc tia, err := svc.TransferImpactAssessments.Update( ctx, scope, &probo.UpdateTransferImpactAssessmentRequest{ ID: input.ID, DataSubjects: UnwrapOmittable(input.DataSubjects), LegalMechanism: UnwrapOmittable(input.LegalMechanism), Transfer: UnwrapOmittable(input.Transfer), LocalLawRisk: UnwrapOmittable(input.LocalLawRisk), SupplementaryMeasures: UnwrapOmittable(input.SupplementaryMeasures), }, ) if err != nil { return nil, types.UpdateTransferImpactAssessmentOutput{}, fmt.Errorf("failed to update transfer impact assessment: %w", err) } return nil, types.UpdateTransferImpactAssessmentOutput{ TransferImpactAssessment: types.NewTransferImpactAssessment(tia), }, nil } func (r *Resolver) DeleteTransferImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteTransferImpactAssessmentInput) (*mcp.CallToolResult, types.DeleteTransferImpactAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTransferImpactAssessmentDelete) if err != nil { return nil, types.DeleteTransferImpactAssessmentOutput{}, err } svc := r.proboSvc err = svc.TransferImpactAssessments.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteTransferImpactAssessmentOutput{}, fmt.Errorf("failed to delete transfer impact assessment: %w", err) } return nil, types.DeleteTransferImpactAssessmentOutput{ DeletedTransferImpactAssessmentID: input.ID, }, nil } func (r *Resolver) ListAuditsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAuditsInput) (*mcp.CallToolResult, types.ListAuditsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionAuditList) if err != nil { return nil, types.ListAuditsOutput{}, err } prb := r.proboSvc 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) page, err := prb.Audits.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization audits: %w", err)) } return nil, types.NewListAuditsOutput(page), nil } func (r *Resolver) GetAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetAuditInput) (*mcp.CallToolResult, types.GetAuditOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionAuditGet) if err != nil { return nil, types.GetAuditOutput{}, err } prb := r.proboSvc audit, err := prb.Audits.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetAuditOutput{}, fmt.Errorf("cannot get audit: %w", err) } var file *coredata.File if audit.ReportFileID != nil { file, err = prb.Files.Get(ctx, scope, *audit.ReportFileID) if err != nil { return nil, types.GetAuditOutput{}, fmt.Errorf("cannot get audit report file: %w", err) } } return nil, types.GetAuditOutput{ Audit: types.NewAudit(audit, file), }, nil } func (r *Resolver) AddAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddAuditInput) (*mcp.CallToolResult, types.AddAuditOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionAuditCreate) if err != nil { return nil, types.AddAuditOutput{}, err } svc := r.proboSvc audit, err := svc.Audits.Create( ctx, scope, &probo.CreateAuditRequest{ OrganizationID: input.OrganizationID, Name: input.Name, ValidFrom: input.ValidFrom, ValidUntil: input.ValidUntil, AuditStartDate: input.AuditStartDate, AuditEndDate: input.AuditEndDate, State: input.State, FrameworkID: input.FrameworkID, }, ) if err != nil { return nil, types.AddAuditOutput{}, fmt.Errorf("failed to create audit: %w", err) } return nil, types.AddAuditOutput{ Audit: types.NewAudit(audit, nil), }, nil } func (r *Resolver) UpdateAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateAuditInput) (*mcp.CallToolResult, types.UpdateAuditOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionAuditUpdate) if err != nil { return nil, types.UpdateAuditOutput{}, err } svc := r.proboSvc audit, err := svc.Audits.Update( ctx, scope, &probo.UpdateAuditRequest{ ID: input.ID, Name: UnwrapOmittable(input.Name), ValidFrom: input.ValidFrom, ValidUntil: input.ValidUntil, AuditStartDate: input.AuditStartDate, AuditEndDate: input.AuditEndDate, State: input.State, CompliancePortalVisibility: input.CompliancePortalVisibility, }, ) if err != nil { return nil, types.UpdateAuditOutput{}, fmt.Errorf("cannot update audit: %w", err) } var file *coredata.File if audit.ReportFileID != nil { file, err = svc.Files.Get(ctx, scope, *audit.ReportFileID) if err != nil { return nil, types.UpdateAuditOutput{}, fmt.Errorf("cannot get audit report file: %w", err) } } return nil, types.UpdateAuditOutput{ Audit: types.NewAudit(audit, file), }, nil } func (r *Resolver) ListControlsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListControlsInput) (*mcp.CallToolResult, types.ListControlsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionControlList) if err != nil { return nil, types.ListControlsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ControlOrderField]{ Field: coredata.ControlOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ControlOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) var controlFilter = coredata.NewControlFilter(nil) if input.Filter != nil { controlFilter = coredata.NewControlFilter(input.Filter.Query) } var ( controlPage *page.Page[*coredata.Control, coredata.ControlOrderField] ) if input.Filter != nil && input.Filter.FrameworkID != nil { controlPage, err = prb.Controls.ListForFrameworkID(ctx, scope, *input.Filter.FrameworkID, cursor, controlFilter) } else { controlPage, err = prb.Controls.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor, controlFilter) } if err != nil { panic(fmt.Errorf("cannot list organization controls: %w", err)) } return nil, types.NewListControlsOutput(controlPage), nil } func (r *Resolver) GetControlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetControlInput) (*mcp.CallToolResult, types.GetControlOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionControlGet) if err != nil { return nil, types.GetControlOutput{}, err } prb := r.proboSvc control, err := prb.Controls.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetControlOutput{}, fmt.Errorf("failed to get control: %w", err) } return nil, types.GetControlOutput{ Control: types.NewControl(control), }, nil } func (r *Resolver) AddControlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddControlInput) (*mcp.CallToolResult, types.AddControlOutput, error) { scope, err := r.Authorize(ctx, input.FrameworkID, probo.ActionControlCreate) if err != nil { return nil, types.AddControlOutput{}, err } svc := r.proboSvc control, err := svc.Controls.Create( ctx, scope, probo.CreateControlRequest{ FrameworkID: input.FrameworkID, Name: input.Name, Description: input.Description, SectionTitle: input.SectionTitle, BestPractice: input.BestPractice, MaturityLevel: coredata.ControlMaturityLevel(input.MaturityLevel), NotImplementedJustification: input.NotImplementedJustification, }, ) if err != nil { return nil, types.AddControlOutput{}, fmt.Errorf("failed to create control: %w", err) } return nil, types.AddControlOutput{ Control: types.NewControl(control), }, nil } func (r *Resolver) UpdateControlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateControlInput) (*mcp.CallToolResult, types.UpdateControlOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionControlUpdate) if err != nil { return nil, types.UpdateControlOutput{}, err } svc := r.proboSvc var maturityLevel *coredata.ControlMaturityLevel if input.MaturityLevel != nil { v := coredata.ControlMaturityLevel(*input.MaturityLevel) maturityLevel = &v } control, err := svc.Controls.Update( ctx, scope, probo.UpdateControlRequest{ ID: input.ID, Name: input.Name, Description: UnwrapOmittable(input.Description), SectionTitle: input.SectionTitle, BestPractice: input.BestPractice, MaturityLevel: maturityLevel, NotImplementedJustification: UnwrapOmittable(input.NotImplementedJustification), }, ) if err != nil { return nil, types.UpdateControlOutput{}, fmt.Errorf("failed to update control: %w", err) } return nil, types.UpdateControlOutput{ Control: types.NewControl(control), }, nil } func (r *Resolver) LinkControlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.LinkControlInput) (*mcp.CallToolResult, types.LinkControlOutput, error) { svc := r.proboSvc switch input.ResourceID.EntityType() { case coredata.MeasureEntityType: scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlMeasureMappingCreate) if err != nil { return nil, types.LinkControlOutput{}, err } if _, _, err := svc.Controls.CreateMeasureMapping(ctx, scope, input.ControlID, input.ResourceID); err != nil { return nil, types.LinkControlOutput{}, fmt.Errorf("failed to link control to measure: %w", err) } case coredata.DocumentEntityType: scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlDocumentMappingCreate) if err != nil { return nil, types.LinkControlOutput{}, err } if _, _, err := svc.Controls.CreateDocumentMapping(ctx, scope, input.ControlID, input.ResourceID); err != nil { return nil, types.LinkControlOutput{}, fmt.Errorf("failed to link control to document: %w", err) } case coredata.AuditEntityType: scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlAuditMappingCreate) if err != nil { return nil, types.LinkControlOutput{}, err } if _, _, err := svc.Controls.CreateAuditMapping(ctx, scope, input.ControlID, input.ResourceID); err != nil { return nil, types.LinkControlOutput{}, fmt.Errorf("failed to link control to audit: %w", err) } case coredata.ObligationEntityType: scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlObligationMappingCreate) if err != nil { return nil, types.LinkControlOutput{}, err } if _, _, err := svc.Controls.CreateObligationMapping(ctx, scope, input.ControlID, input.ResourceID); err != nil { return nil, types.LinkControlOutput{}, fmt.Errorf("failed to link control to obligation: %w", err) } default: return nil, types.LinkControlOutput{}, fmt.Errorf("unsupported resource type for control linking: entity type %d", input.ResourceID.EntityType()) } return nil, types.LinkControlOutput{}, nil } func (r *Resolver) UnlinkControlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnlinkControlInput) (*mcp.CallToolResult, types.UnlinkControlOutput, error) { svc := r.proboSvc switch input.ResourceID.EntityType() { case coredata.MeasureEntityType: scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlMeasureMappingDelete) if err != nil { return nil, types.UnlinkControlOutput{}, err } if _, _, err := svc.Controls.DeleteMeasureMapping(ctx, scope, input.ControlID, input.ResourceID); err != nil { return nil, types.UnlinkControlOutput{}, fmt.Errorf("failed to unlink control from measure: %w", err) } case coredata.DocumentEntityType: scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlDocumentMappingDelete) if err != nil { return nil, types.UnlinkControlOutput{}, err } if _, _, err := svc.Controls.DeleteDocumentMapping(ctx, scope, input.ControlID, input.ResourceID); err != nil { return nil, types.UnlinkControlOutput{}, fmt.Errorf("failed to unlink control from document: %w", err) } case coredata.AuditEntityType: scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlAuditMappingDelete) if err != nil { return nil, types.UnlinkControlOutput{}, err } if _, _, err := svc.Controls.DeleteAuditMapping(ctx, scope, input.ControlID, input.ResourceID); err != nil { return nil, types.UnlinkControlOutput{}, fmt.Errorf("failed to unlink control from audit: %w", err) } case coredata.ObligationEntityType: scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlObligationMappingDelete) if err != nil { return nil, types.UnlinkControlOutput{}, err } if _, _, err := svc.Controls.DeleteObligationMapping(ctx, scope, input.ControlID, input.ResourceID); err != nil { return nil, types.UnlinkControlOutput{}, fmt.Errorf("failed to unlink control from obligation: %w", err) } default: return nil, types.UnlinkControlOutput{}, fmt.Errorf("unsupported resource type for control unlinking: entity type %d", input.ResourceID.EntityType()) } return nil, types.UnlinkControlOutput{}, nil } func (r *Resolver) ListControlObligationsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListControlObligationsInput) (*mcp.CallToolResult, types.ListControlObligationsOutput, error) { scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlGet) if err != nil { return nil, types.ListControlObligationsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ObligationOrderField]{ Field: coredata.ObligationOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ObligationOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) obligationPage, err := prb.Obligations.ListForControlID(ctx, scope, input.ControlID, cursor) if err != nil { return nil, types.ListControlObligationsOutput{}, fmt.Errorf("failed to list control obligations: %w", err) } return nil, types.NewListControlObligationsOutput(obligationPage), nil } func (r *Resolver) ListControlMeasuresTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListControlMeasuresInput) (*mcp.CallToolResult, types.ListControlMeasuresOutput, error) { scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlGet) if err != nil { return nil, types.ListControlMeasuresOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.MeasureOrderField]{ Field: coredata.MeasureOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.MeasureOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) measurePage, err := prb.Measures.ListForControlID(ctx, scope, input.ControlID, cursor, coredata.NewMeasureFilter(nil, nil, nil)) if err != nil { return nil, types.ListControlMeasuresOutput{}, fmt.Errorf("failed to list control measures: %w", err) } return nil, types.NewListControlMeasuresOutput(measurePage), nil } func (r *Resolver) ListControlDocumentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListControlDocumentsInput) (*mcp.CallToolResult, types.ListControlDocumentsOutput, error) { scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlGet) if err != nil { return nil, types.ListControlDocumentsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{ Field: coredata.DocumentOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) docPage, err := prb.Documents.ListForControlID(ctx, scope, input.ControlID, cursor, coredata.NewDocumentFilter(nil)) if err != nil { return nil, types.ListControlDocumentsOutput{}, fmt.Errorf("failed to list control documents: %w", err) } return nil, types.NewListControlDocumentsOutput(docPage), nil } func (r *Resolver) ListControlAuditsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListControlAuditsInput) (*mcp.CallToolResult, types.ListControlAuditsOutput, error) { scope, err := r.Authorize(ctx, input.ControlID, probo.ActionControlGet) if err != nil { return nil, types.ListControlAuditsOutput{}, err } prb := r.proboSvc 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.ListForControlID(ctx, scope, input.ControlID, cursor) if err != nil { return nil, types.ListControlAuditsOutput{}, fmt.Errorf("failed to list control audits: %w", err) } return nil, types.NewListControlAuditsOutput(auditPage), nil } func (r *Resolver) ListRiskObligationsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskObligationsInput) (*mcp.CallToolResult, types.ListRiskObligationsOutput, error) { scope, err := r.Authorize(ctx, input.RiskID, probo.ActionRiskGet) if err != nil { return nil, types.ListRiskObligationsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ObligationOrderField]{ Field: coredata.ObligationOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ObligationOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) obligationPage, err := prb.Obligations.ListForRiskID(ctx, scope, input.RiskID, cursor) if err != nil { return nil, types.ListRiskObligationsOutput{}, fmt.Errorf("failed to list risk obligations: %w", err) } return nil, types.NewListRiskObligationsOutput(obligationPage), nil } func (r *Resolver) LinkRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.LinkRiskInput) (*mcp.CallToolResult, types.LinkRiskOutput, error) { svc := r.proboSvc switch input.ResourceID.EntityType() { case coredata.DocumentEntityType: scope, err := r.Authorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingCreate) if err != nil { return nil, types.LinkRiskOutput{}, err } if _, _, err := svc.Risks.CreateDocumentMapping(ctx, scope, input.RiskID, input.ResourceID); err != nil { return nil, types.LinkRiskOutput{}, fmt.Errorf("failed to link risk to document: %w", err) } case coredata.MeasureEntityType: scope, err := r.Authorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingCreate) if err != nil { return nil, types.LinkRiskOutput{}, err } if _, _, err := svc.Risks.CreateMeasureMapping(ctx, scope, input.RiskID, input.ResourceID); err != nil { return nil, types.LinkRiskOutput{}, fmt.Errorf("failed to link risk to measure: %w", err) } case coredata.ObligationEntityType: scope, err := r.Authorize(ctx, input.RiskID, probo.ActionRiskObligationMappingCreate) if err != nil { return nil, types.LinkRiskOutput{}, err } if _, _, err := svc.Risks.CreateObligationMapping(ctx, scope, input.RiskID, input.ResourceID); err != nil { return nil, types.LinkRiskOutput{}, fmt.Errorf("failed to link risk to obligation: %w", err) } default: return nil, types.LinkRiskOutput{}, fmt.Errorf("unsupported resource type for risk linking: entity type %d", input.ResourceID.EntityType()) } return nil, types.LinkRiskOutput{}, nil } func (r *Resolver) UnlinkRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnlinkRiskInput) (*mcp.CallToolResult, types.UnlinkRiskOutput, error) { svc := r.proboSvc switch input.ResourceID.EntityType() { case coredata.DocumentEntityType: scope, err := r.Authorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingDelete) if err != nil { return nil, types.UnlinkRiskOutput{}, err } if _, _, err := svc.Risks.DeleteDocumentMapping(ctx, scope, input.RiskID, input.ResourceID); err != nil { return nil, types.UnlinkRiskOutput{}, fmt.Errorf("failed to unlink risk from document: %w", err) } case coredata.MeasureEntityType: scope, err := r.Authorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingDelete) if err != nil { return nil, types.UnlinkRiskOutput{}, err } if _, _, err := svc.Risks.DeleteMeasureMapping(ctx, scope, input.RiskID, input.ResourceID); err != nil { return nil, types.UnlinkRiskOutput{}, fmt.Errorf("failed to unlink risk from measure: %w", err) } case coredata.ObligationEntityType: scope, err := r.Authorize(ctx, input.RiskID, probo.ActionRiskObligationMappingDelete) if err != nil { return nil, types.UnlinkRiskOutput{}, err } if _, _, err := svc.Risks.DeleteObligationMapping(ctx, scope, input.RiskID, input.ResourceID); err != nil { return nil, types.UnlinkRiskOutput{}, fmt.Errorf("failed to unlink risk from obligation: %w", err) } default: return nil, types.UnlinkRiskOutput{}, fmt.Errorf("unsupported resource type for risk unlinking: entity type %d", input.ResourceID.EntityType()) } return nil, types.UnlinkRiskOutput{}, nil } func (r *Resolver) ListTasksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListTasksInput) (*mcp.CallToolResult, types.ListTasksOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionTaskList) if err != nil { return nil, types.ListTasksOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.TaskOrderField]{ Field: coredata.TaskOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.TaskOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.Tasks.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization tasks: %w", err)) } return nil, types.NewListTasksOutput(page), nil } func (r *Resolver) GetTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetTaskInput) (*mcp.CallToolResult, types.GetTaskOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTaskGet) if err != nil { return nil, types.GetTaskOutput{}, err } prb := r.proboSvc task, err := prb.Tasks.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetTaskOutput{}, fmt.Errorf("failed to get task: %w", err) } return nil, types.GetTaskOutput{ Task: types.NewTask(task), }, nil } func (r *Resolver) AddTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddTaskInput) (*mcp.CallToolResult, types.AddTaskOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionTaskCreate) if err != nil { return nil, types.AddTaskOutput{}, err } svc := r.proboSvc priority := coredata.TaskPriorityMedium if input.Priority != nil { priority = *input.Priority } task, err := svc.Tasks.Create( ctx, scope, probo.CreateTaskRequest{ OrganizationID: input.OrganizationID, MeasureID: input.MeasureID, Name: input.Name, Description: input.Description, Priority: priority, TimeEstimate: input.TimeEstimate, Deadline: input.Deadline, AssignedToID: input.AssignedToID, }, ) if err != nil { return nil, types.AddTaskOutput{}, fmt.Errorf("failed to create task: %w", err) } return nil, types.AddTaskOutput{ Task: types.NewTask(task), }, nil } func (r *Resolver) UpdateTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTaskInput) (*mcp.CallToolResult, types.UpdateTaskOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTaskUpdate) if err != nil { return nil, types.UpdateTaskOutput{}, err } svc := r.proboSvc task, err := svc.Tasks.Update( ctx, scope, probo.UpdateTaskRequest{ TaskID: input.ID, Name: input.Name, Description: UnwrapOmittable(input.Description), State: input.State, Priority: input.Priority, Rank: input.Rank, TimeEstimate: UnwrapOmittable(input.TimeEstimate), Deadline: UnwrapOmittable(input.Deadline), AssignedToID: UnwrapOmittable(input.AssignedToID), MeasureID: UnwrapOmittable(input.MeasureID), }, ) if err != nil { return nil, types.UpdateTaskOutput{}, fmt.Errorf("failed to update task: %w", err) } return nil, types.UpdateTaskOutput{ Task: types.NewTask(task), }, nil } func (r *Resolver) AssignTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AssignTaskInput) (*mcp.CallToolResult, types.AssignTaskOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTaskAssign) if err != nil { return nil, types.AssignTaskOutput{}, err } svc := r.proboSvc task, err := svc.Tasks.Assign(ctx, scope, input.ID, input.AssignedToID) if err != nil { return nil, types.AssignTaskOutput{}, fmt.Errorf("failed to assign task: %w", err) } return nil, types.AssignTaskOutput{ Task: types.NewTask(task), }, nil } func (r *Resolver) UnassignTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnassignTaskInput) (*mcp.CallToolResult, types.UnassignTaskOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTaskUnassign) if err != nil { return nil, types.UnassignTaskOutput{}, err } svc := r.proboSvc task, err := svc.Tasks.Unassign(ctx, scope, input.ID) if err != nil { return nil, types.UnassignTaskOutput{}, fmt.Errorf("failed to unassign task: %w", err) } return nil, types.UnassignTaskOutput{ Task: types.NewTask(task), }, nil } func (r *Resolver) DeleteTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteTaskInput) (*mcp.CallToolResult, types.DeleteTaskOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTaskDelete) if err != nil { return nil, types.DeleteTaskOutput{}, err } svc := r.proboSvc err = svc.Tasks.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteTaskOutput{}, fmt.Errorf("failed to delete task: %w", err) } return nil, types.DeleteTaskOutput{ DeletedTaskID: input.ID, }, nil } func (r *Resolver) ListDocumentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDocumentsInput) (*mcp.CallToolResult, types.ListDocumentsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionDocumentList) if err != nil { return nil, types.ListDocumentsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{ Field: coredata.DocumentOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) documentFilter := coredata.NewDocumentFilter(nil). WithStatus([]coredata.DocumentStatus{coredata.DocumentStatusActive}) if input.Filter != nil { var query *string if input.Filter.Query != nil && *input.Filter.Query != "" { query = input.Filter.Query } documentFilter = coredata.NewDocumentFilter(query). WithWriteModes(input.Filter.WriteModes). WithDocumentTypes(input.Filter.DocumentTypes). WithClassifications(input.Filter.Classifications). WithStatus(input.Filter.Status) if len(input.Filter.Status) == 0 { documentFilter = documentFilter.WithStatus([]coredata.DocumentStatus{coredata.DocumentStatusActive}) } } docPage, err := prb.Documents.ListByOrganizationID(ctx, scope, input.OrganizationID, cursor, documentFilter) if err != nil { panic(fmt.Errorf("cannot list organization documents: %w", err)) } return nil, types.NewListDocumentsOutput(docPage), nil } func (r *Resolver) GetDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetDocumentInput) (*mcp.CallToolResult, types.GetDocumentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentGet) if err != nil { return nil, types.GetDocumentOutput{}, err } prb := r.proboSvc document, err := prb.Documents.Get(ctx, scope, input.ID) if err != nil { panic(fmt.Errorf("cannot get document: %w", err)) } return nil, types.GetDocumentOutput{ Document: types.NewDocument(document), }, nil } func (r *Resolver) AddDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddDocumentInput) (*mcp.CallToolResult, types.AddDocumentOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionDocumentCreate) if err != nil { return nil, types.AddDocumentOutput{}, err } svc := r.proboSvc var compliancePortalVisibility *coredata.CompliancePortalVisibility if input.CompliancePortalVisibility != nil { compliancePortalVisibility = input.CompliancePortalVisibility } contentJSON, err := markdownToProseMirrorJSON(input.Content) if err != nil { panic(fmt.Errorf("cannot convert markdown to prosemirror: %w", err)) } document, documentVersion, err := svc.Documents.Create( ctx, scope, probo.CreateDocumentRequest{ OrganizationID: input.OrganizationID, Title: input.Title, Content: contentJSON, Classification: input.Classification, DocumentType: input.DocumentType, CompliancePortalVisibility: compliancePortalVisibility, DefaultApproverIDs: input.DefaultApproverIds, }, ) if err != nil { panic(fmt.Errorf("cannot create document: %w", err)) } return nil, types.NewAddDocumentOutput(document, documentVersion), nil } func (r *Resolver) UpdateDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateDocumentInput) (*mcp.CallToolResult, types.UpdateDocumentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentUpdate) if err != nil { return nil, types.UpdateDocumentOutput{}, err } svc := r.proboSvc var defaultApproverIDs *[]gid.GID if input.DefaultApproverIds != nil { defaultApproverIDs = &input.DefaultApproverIds } var content *string if input.Content != nil { c, err := markdownToProseMirrorJSON(*input.Content) if err != nil { panic(fmt.Errorf("cannot convert markdown to prosemirror: %w", err)) } content = &c } document, documentVersion, _, err := svc.Documents.Update( ctx, scope, probo.UpdateDocumentRequest{ DocumentID: input.ID, Title: input.Title, Content: content, Classification: input.Classification, DocumentType: input.DocumentType, CompliancePortalVisibility: input.CompliancePortalVisibility, DefaultApproverIDs: defaultApproverIDs, }, ) if err != nil { panic(fmt.Errorf("cannot update document: %w", err)) } output := types.UpdateDocumentOutput{ Document: types.NewDocument(document), } if documentVersion != nil { output.DocumentVersion = types.NewDocumentVersion(documentVersion) } return nil, output, nil } func (r *Resolver) ListDocumentVersionsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDocumentVersionsInput) (*mcp.CallToolResult, types.ListDocumentVersionsOutput, error) { scope, err := r.Authorize(ctx, input.DocumentID, probo.ActionDocumentVersionList) if err != nil { return nil, types.ListDocumentVersionsOutput{}, err } pageOrderBy := page.OrderBy[coredata.DocumentVersionOrderField]{ Field: coredata.DocumentVersionOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DocumentVersionOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) svc := r.proboSvc versionFilter := coredata.NewDocumentVersionFilter() if input.Filter != nil && len(input.Filter.Statuses) > 0 { versionFilter = versionFilter.WithStatuses(input.Filter.Statuses...) } versionPage, err := svc.Documents.ListVersions(ctx, scope, input.DocumentID, cursor, versionFilter) if err != nil { panic(fmt.Errorf("cannot list document versions: %w", err)) } return nil, types.NewListDocumentVersionsOutput(versionPage), nil } func (r *Resolver) GetDocumentVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetDocumentVersionInput) (*mcp.CallToolResult, types.GetDocumentVersionOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentVersionGet) if err != nil { return nil, types.GetDocumentVersionOutput{}, err } svc := r.proboSvc version, err := svc.Documents.GetVersion(ctx, scope, input.ID) if err != nil { panic(fmt.Errorf("cannot get document version: %w", err)) } return nil, types.GetDocumentVersionOutput{ DocumentVersion: types.NewDocumentVersion(version), }, nil } func (r *Resolver) ListDocumentVersionSignaturesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDocumentVersionSignaturesInput) (*mcp.CallToolResult, types.ListDocumentVersionSignaturesOutput, error) { scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSignatureList) if err != nil { return nil, types.ListDocumentVersionSignaturesOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.DocumentVersionSignatureOrderField]{ Field: coredata.DocumentVersionSignatureOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DocumentVersionSignatureOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) var ( signatureStates []coredata.DocumentVersionSignatureState activeContract *bool profileStates []coredata.ProfileState ) if input.Filter != nil { if input.Filter.States != nil { signatureStates = input.Filter.States } if input.Filter.ActiveContract != nil { activeContract = input.Filter.ActiveContract } if input.Filter.ProfileStates != nil { profileStates = input.Filter.ProfileStates } } signatureFilter := coredata.NewDocumentVersionSignatureFilter(signatureStates, activeContract, profileStates) page, err := prb.Documents.ListSignatures(ctx, scope, input.DocumentVersionID, cursor, signatureFilter) if err != nil { panic(fmt.Errorf("cannot list document version signatures: %w", err)) } return nil, types.NewListDocumentVersionSignaturesOutput(page), nil } func (r *Resolver) GetDocumentVersionSignatureTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetDocumentVersionSignatureInput) (*mcp.CallToolResult, types.GetDocumentVersionSignatureOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentVersionSignatureGet) if err != nil { return nil, types.GetDocumentVersionSignatureOutput{}, err } prb := r.proboSvc signature, err := prb.Documents.GetVersionSignature(ctx, scope, input.ID) if err != nil { panic(fmt.Errorf("cannot get document version signature: %w", err)) } return nil, types.GetDocumentVersionSignatureOutput{ DocumentVersionSignature: types.NewDocumentVersionSignature(signature), }, nil } func (r *Resolver) RequestDocumentVersionSignatureTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RequestDocumentVersionSignatureInput) (*mcp.CallToolResult, types.RequestDocumentVersionSignatureOutput, error) { scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSignatureRequest) if err != nil { return nil, types.RequestDocumentVersionSignatureOutput{}, err } svc := r.proboSvc documentVersionSignature, err := svc.Documents.RequestSignature( ctx, scope, probo.RequestSignatureRequest{ DocumentVersionID: input.DocumentVersionID, Signatory: input.SignatoryID, }, ) if err != nil { if _, ok := errors.AsType[*probo.ErrDocumentVersionNotCurrent](err); ok { return nil, types.RequestDocumentVersionSignatureOutput{}, fmt.Errorf("cannot request signature: %w", err) } panic(fmt.Errorf("cannot request signature: %w", err)) } return nil, types.RequestDocumentVersionSignatureOutput{ DocumentVersionSignature: types.NewDocumentVersionSignature(documentVersionSignature), }, nil } func (r *Resolver) DeleteDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteDocumentInput) (*mcp.CallToolResult, types.DeleteDocumentOutput, error) { scope, err := r.Authorize(ctx, input.DocumentID, probo.ActionDocumentDelete) if err != nil { return nil, types.DeleteDocumentOutput{}, err } svc := r.proboSvc err = svc.Documents.SoftDelete(ctx, scope, input.DocumentID) if err != nil { panic(fmt.Errorf("cannot soft delete document: %w", err)) } return nil, types.DeleteDocumentOutput{ DeletedDocumentID: input.DocumentID, }, nil } func (r *Resolver) CancelSignatureRequestTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CancelSignatureRequestInput) (*mcp.CallToolResult, types.CancelSignatureRequestOutput, error) { scope, err := r.Authorize(ctx, input.DocumentVersionSignatureID, probo.ActionDocumentVersionCancelSignature) if err != nil { return nil, types.CancelSignatureRequestOutput{}, err } svc := r.proboSvc err = svc.Documents.CancelSignatureRequest(ctx, scope, input.DocumentVersionSignatureID) if err != nil { panic(fmt.Errorf("cannot cancel signature request: %w", err)) } return nil, types.CancelSignatureRequestOutput{ DeletedDocumentVersionSignatureID: input.DocumentVersionSignatureID, }, nil } func (r *Resolver) DeleteRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRiskInput) (*mcp.CallToolResult, types.DeleteRiskOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskDelete) if err != nil { return nil, types.DeleteRiskOutput{}, err } svc := r.proboSvc err = svc.Risks.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteRiskOutput{}, fmt.Errorf("failed to delete risk: %w", err) } return nil, types.DeleteRiskOutput{ DeletedRiskID: input.ID, }, nil } func (r *Resolver) DeleteMeasureTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteMeasureInput) (*mcp.CallToolResult, types.DeleteMeasureOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionMeasureDelete) if err != nil { return nil, types.DeleteMeasureOutput{}, err } svc := r.proboSvc err = svc.Measures.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteMeasureOutput{}, fmt.Errorf("failed to delete measure: %w", err) } return nil, types.DeleteMeasureOutput{ DeletedMeasureID: input.ID, }, nil } func (r *Resolver) ListMeasureRisksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMeasureRisksInput) (*mcp.CallToolResult, types.ListMeasureRisksOutput, error) { scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureGet) if err != nil { return nil, types.ListMeasureRisksOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.RiskOrderField]{ Field: coredata.RiskOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) riskPage, err := prb.Risks.ListForMeasureID(ctx, scope, input.MeasureID, cursor, coredata.NewRiskFilter(nil)) if err != nil { return nil, types.ListMeasureRisksOutput{}, fmt.Errorf("failed to list measure risks: %w", err) } return nil, types.NewListMeasureRisksOutput(riskPage), nil } func (r *Resolver) ListMeasureControlsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMeasureControlsInput) (*mcp.CallToolResult, types.ListMeasureControlsOutput, error) { scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureGet) if err != nil { return nil, types.ListMeasureControlsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ControlOrderField]{ Field: coredata.ControlOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ControlOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) controlPage, err := prb.Controls.ListForMeasureID(ctx, scope, input.MeasureID, cursor, coredata.NewControlFilter(nil)) if err != nil { return nil, types.ListMeasureControlsOutput{}, fmt.Errorf("failed to list measure controls: %w", err) } return nil, types.NewListMeasureControlsOutput(controlPage), nil } func (r *Resolver) ListMeasureTasksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMeasureTasksInput) (*mcp.CallToolResult, types.ListMeasureTasksOutput, error) { scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureGet) if err != nil { return nil, types.ListMeasureTasksOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.TaskOrderField]{ Field: coredata.TaskOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.TaskOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) taskPage, err := prb.Tasks.ListForMeasureID(ctx, scope, input.MeasureID, cursor) if err != nil { return nil, types.ListMeasureTasksOutput{}, fmt.Errorf("failed to list measure tasks: %w", err) } return nil, types.NewListMeasureTasksOutput(taskPage), nil } func (r *Resolver) ListMeasureEvidencesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMeasureEvidencesInput) (*mcp.CallToolResult, types.ListMeasureEvidencesOutput, error) { scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureGet) if err != nil { return nil, types.ListMeasureEvidencesOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.EvidenceOrderField]{ Field: coredata.EvidenceOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) evidencePage, err := prb.Evidences.ListForMeasureID(ctx, scope, input.MeasureID, cursor) if err != nil { return nil, types.ListMeasureEvidencesOutput{}, fmt.Errorf("failed to list measure evidences: %w", err) } return nil, types.NewListMeasureEvidencesOutput(evidencePage), nil } func (r *Resolver) LinkMeasureTool(ctx context.Context, req *mcp.CallToolRequest, input *types.LinkMeasureInput) (*mcp.CallToolResult, types.LinkMeasureOutput, error) { svc := r.proboSvc switch input.ResourceID.EntityType() { case coredata.ControlEntityType: scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionControlMeasureMappingCreate) if err != nil { return nil, types.LinkMeasureOutput{}, err } if _, _, err := svc.Controls.CreateMeasureMapping(ctx, scope, input.ResourceID, input.MeasureID); err != nil { return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to control: %w", err) } case coredata.RiskEntityType: scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionRiskMeasureMappingCreate) if err != nil { return nil, types.LinkMeasureOutput{}, err } if _, _, err := svc.Risks.CreateMeasureMapping(ctx, scope, input.ResourceID, input.MeasureID); err != nil { return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to risk: %w", err) } case coredata.DocumentEntityType: scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingCreate) if err != nil { return nil, types.LinkMeasureOutput{}, err } if _, _, err := svc.Measures.CreateDocumentMapping(ctx, scope, input.MeasureID, input.ResourceID); err != nil { return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to document: %w", err) } case coredata.ThirdPartyEntityType: scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureThirdPartyMappingCreate) if err != nil { return nil, types.LinkMeasureOutput{}, err } if _, _, err := svc.Measures.CreateThirdPartyMapping(ctx, scope, input.MeasureID, input.ResourceID); err != nil { return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to third party: %w", err) } default: return nil, types.LinkMeasureOutput{}, fmt.Errorf("unsupported resource type for measure linking: entity type %d", input.ResourceID.EntityType()) } return nil, types.LinkMeasureOutput{}, nil } func (r *Resolver) UnlinkMeasureTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnlinkMeasureInput) (*mcp.CallToolResult, types.UnlinkMeasureOutput, error) { svc := r.proboSvc switch input.ResourceID.EntityType() { case coredata.ControlEntityType: scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionControlMeasureMappingDelete) if err != nil { return nil, types.UnlinkMeasureOutput{}, err } if _, _, err := svc.Controls.DeleteMeasureMapping(ctx, scope, input.ResourceID, input.MeasureID); err != nil { return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from control: %w", err) } case coredata.RiskEntityType: scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionRiskMeasureMappingDelete) if err != nil { return nil, types.UnlinkMeasureOutput{}, err } if _, _, err := svc.Risks.DeleteMeasureMapping(ctx, scope, input.ResourceID, input.MeasureID); err != nil { return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from risk: %w", err) } case coredata.DocumentEntityType: scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingDelete) if err != nil { return nil, types.UnlinkMeasureOutput{}, err } if _, _, err := svc.Measures.DeleteDocumentMapping(ctx, scope, input.MeasureID, input.ResourceID); err != nil { return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from document: %w", err) } case coredata.ThirdPartyEntityType: scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureThirdPartyMappingDelete) if err != nil { return nil, types.UnlinkMeasureOutput{}, err } if _, _, err := svc.Measures.DeleteThirdPartyMapping(ctx, scope, input.MeasureID, input.ResourceID); err != nil { return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from third party: %w", err) } default: return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("unsupported resource type for measure unlinking: entity type %d", input.ResourceID.EntityType()) } return nil, types.UnlinkMeasureOutput{}, nil } func (r *Resolver) ListUsersTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListUsersInput) (*mcp.CallToolResult, types.ListUsersOutput, error) { if _, err := r.Authorize(ctx, input.OrganizationID, iam.ActionMembershipProfileList); err != nil { return nil, types.ListUsersOutput{}, err } pageOrderBy := page.OrderBy[coredata.MembershipProfileOrderField]{ Field: coredata.MembershipProfileOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.MembershipProfileOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) filter := coredata.NewMembershipProfileFilter(nil).WithMembership() if input.Filter != nil { filter = coredata.NewMembershipProfileFilter(input.Filter.ContractEnded).WithMembership() if len(input.Filter.States) > 0 { filter.WithStates(input.Filter.States...) } if input.Filter.Query != nil { filter.WithQuery(input.Filter.Query) } if input.Filter.Role != nil { filter.WithRole(*input.Filter.Role) } if input.Filter.Kind != nil { kind := string(*input.Filter.Kind) filter.WithKind(&kind) } } pageResult, err := r.iamSvc.OrganizationService.ListProfiles(ctx, input.OrganizationID, cursor, filter) if err != nil { return nil, types.ListUsersOutput{}, fmt.Errorf("list users: %w", err) } users := make([]*types.Profile, 0, len(pageResult.Data)) for _, p := range pageResult.Data { users = append(users, types.NewProfile(p)) } var nextCursor *page.CursorKey if len(pageResult.Data) > 0 && pageResult.Cursor != nil { cursorKey := pageResult.Data[len(pageResult.Data)-1].CursorKey(pageResult.Cursor.OrderBy.Field) nextCursor = &cursorKey } return nil, types.ListUsersOutput{ Users: users, NextCursor: nextCursor, }, nil } func (r *Resolver) GetUserTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetUserInput) (*mcp.CallToolResult, types.GetUserOutput, error) { profile, err := r.iamSvc.OrganizationService.GetProfile(ctx, input.ID) if err != nil { if _, ok := errors.AsType[*iam.ErrProfileNotFound](err); ok { return nil, types.GetUserOutput{}, fmt.Errorf("user not found: %w", err) } return nil, types.GetUserOutput{}, fmt.Errorf("get user: %w", err) } if _, err := r.Authorize(ctx, profile.OrganizationID, iam.ActionMembershipProfileGet); err != nil { return nil, types.GetUserOutput{}, err } return nil, types.GetUserOutput{User: types.NewProfile(profile)}, nil } func (r *Resolver) CreateUserTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateUserInput) (*mcp.CallToolResult, types.CreateUserOutput, error) { scope, err := r.Authorize( ctx, input.OrganizationID, iam.ActionMembershipProfileCreate, authz.WithAttr("target_role", input.Role.String()), ) if err != nil { return nil, types.CreateUserOutput{}, err } var contractStart, contractEnd **time.Time if input.ContractStartDate != nil { contractStart = &input.ContractStartDate } if input.ContractEndDate != nil { contractEnd = &input.ContractEndDate } profile, err := r.iamSvc.OrganizationService.CreateUser(ctx, scope, &iam.CreateUserRequest{ OrganizationID: input.OrganizationID, EmailAddress: input.EmailAddress, Role: input.Role, FullName: input.FullName, AdditionalEmailAddresses: input.AdditionalEmailAddresses, Kind: input.Kind, Position: input.Position, ContractStartDate: contractStart, ContractEndDate: contractEnd, }) if err != nil { if _, ok := errors.AsType[*iam.ErrUserAlreadyExists](err); ok { return nil, types.CreateUserOutput{}, fmt.Errorf("user with email already exists: %w", err) } return nil, types.CreateUserOutput{}, fmt.Errorf("create user: %w", err) } return nil, types.CreateUserOutput{User: types.NewProfile(profile)}, nil } func (r *Resolver) InviteUserTool(ctx context.Context, req *mcp.CallToolRequest, input *types.InviteUserInput) (*mcp.CallToolResult, types.InviteUserOutput, error) { if _, err := r.Authorize(ctx, input.ProfileID, iam.ActionInvitationCreate); err != nil { return nil, types.InviteUserOutput{}, err } invitation, err := r.iamSvc.OrganizationService.InviteUser(ctx, &iam.CreateInvitationRequest{ OrganizationID: input.OrganizationID, ProfileID: input.ProfileID, }) if err != nil { if _, ok := errors.AsType[*iam.ErrOrganizationNotFound](err); ok { return nil, types.InviteUserOutput{}, fmt.Errorf("organization not found: %w", err) } if _, ok := errors.AsType[*iam.ErrUserAlreadyExists](err); ok { return nil, types.InviteUserOutput{}, fmt.Errorf("user already in organization: %w", err) } return nil, types.InviteUserOutput{}, fmt.Errorf("invite user: %w", err) } return nil, types.InviteUserOutput{InvitationID: invitation.ID}, nil } func (r *Resolver) UpdateUserTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateUserInput) (*mcp.CallToolResult, types.UpdateUserOutput, error) { if _, err := r.Authorize(ctx, input.ID, iam.ActionMembershipProfileUpdate); err != nil { return nil, types.UpdateUserOutput{}, err } var additionalEmails []mail.Addr if input.AdditionalEmailAddresses != nil { additionalEmails = *input.AdditionalEmailAddresses } var position *string if p := UnwrapOmittable(input.Position); p != nil { position = *p } var contractStart, contractEnd **time.Time if p := UnwrapOmittable(input.ContractStartDate); p != nil { contractStart = p } if p := UnwrapOmittable(input.ContractEndDate); p != nil { contractEnd = p } profile, err := r.iamSvc.OrganizationService.UpdateUser(ctx, &iam.UpdateUserRequest{ ID: input.ID, FullName: input.FullName, AdditionalEmailAddresses: additionalEmails, Kind: input.Kind, Position: position, ContractStartDate: contractStart, ContractEndDate: contractEnd, }) if err != nil { return nil, types.UpdateUserOutput{}, fmt.Errorf("update user: %w", err) } return nil, types.UpdateUserOutput{User: types.NewProfile(profile)}, nil } func (r *Resolver) UpdateMembershipTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateMembershipInput) (*mcp.CallToolResult, types.UpdateMembershipOutput, error) { if _, err := r.Authorize( ctx, input.MembershipID, iam.ActionMembershipUpdate, authz.WithAttr("target_role", input.Role.String()), ); err != nil { return nil, types.UpdateMembershipOutput{}, err } membership, err := r.iamSvc.OrganizationService.UpdateMembership(ctx, input.OrganizationID, input.MembershipID, input.Role) if err != nil { return nil, types.UpdateMembershipOutput{}, fmt.Errorf("update membership: %w", err) } return nil, types.UpdateMembershipOutput{ Membership: &types.Membership{ ID: membership.ID, Role: membership.Role, CreatedAt: membership.CreatedAt, }, }, nil } func (r *Resolver) RemoveUserTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RemoveUserInput) (*mcp.CallToolResult, types.RemoveUserOutput, error) { scope, err := r.Authorize(ctx, input.ProfileID, iam.ActionMembershipDelete) if err != nil { return nil, types.RemoveUserOutput{}, err } err = r.iamSvc.OrganizationService.RemoveUser(ctx, scope, input.OrganizationID, input.ProfileID) if err != nil { if _, ok := errors.AsType[*iam.ErrUserManagedBySCIM](err); ok { return nil, types.RemoveUserOutput{}, fmt.Errorf("user is managed by SCIM and cannot be removed: %w", err) } if _, ok := errors.AsType[*iam.ErrLastActiveOwner](err); ok { return nil, types.RemoveUserOutput{}, fmt.Errorf("cannot remove last active owner: %w", err) } if _, ok := errors.AsType[*iam.ErrProfileInUse](err); ok { return nil, types.RemoveUserOutput{}, fmt.Errorf("cannot remove person: referenced by other resources: %w", err) } return nil, types.RemoveUserOutput{}, fmt.Errorf("remove user: %w", err) } return nil, types.RemoveUserOutput{DeletedUserID: input.ProfileID}, nil } func (r *Resolver) DeactivateUserTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeactivateUserInput) (*mcp.CallToolResult, types.DeactivateUserOutput, error) { scope, err := r.Authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDeactivate) if err != nil { return nil, types.DeactivateUserOutput{}, err } err = r.iamSvc.OrganizationService.DeactivateUser(ctx, scope, input.OrganizationID, input.ProfileID) if err != nil { if _, ok := errors.AsType[*iam.ErrUserManagedBySCIM](err); ok { return nil, types.DeactivateUserOutput{}, fmt.Errorf("user is managed by SCIM and cannot be deactivated: %w", err) } if _, ok := errors.AsType[*iam.ErrLastActiveOwner](err); ok { return nil, types.DeactivateUserOutput{}, fmt.Errorf("cannot deactivate last active owner: %w", err) } return nil, types.DeactivateUserOutput{}, fmt.Errorf("deactivate user: %w", err) } return nil, types.DeactivateUserOutput{DeactivatedUserID: input.ProfileID}, nil } func (r *Resolver) DeleteDataProtectionImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteDataProtectionImpactAssessmentInput) (*mcp.CallToolResult, types.DeleteDataProtectionImpactAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentDelete) if err != nil { return nil, types.DeleteDataProtectionImpactAssessmentOutput{}, err } svc := r.proboSvc err = svc.DataProtectionImpactAssessments.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteDataProtectionImpactAssessmentOutput{}, fmt.Errorf("failed to delete data protection impact assessment: %w", err) } return nil, types.DeleteDataProtectionImpactAssessmentOutput{ DeletedDataProtectionImpactAssessmentID: input.ID, }, nil } func (r *Resolver) ListStatementsOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListStatementsOfApplicabilityInput) (*mcp.CallToolResult, types.ListStatementsOfApplicabilityOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionStatementOfApplicabilityList) if err != nil { return nil, types.ListStatementsOfApplicabilityOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.StatementOfApplicabilityOrderField]{ Field: coredata.StatementOfApplicabilityOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.StatementOfApplicabilityOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) pg, err := prb.StatementsOfApplicability.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { return nil, types.ListStatementsOfApplicabilityOutput{}, fmt.Errorf("failed to list statements of applicability: %w", err) } return nil, types.NewListStatementsOfApplicabilityOutput(pg), nil } func (r *Resolver) GetStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetStatementOfApplicabilityInput) (*mcp.CallToolResult, types.GetStatementOfApplicabilityOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionStatementOfApplicabilityGet) if err != nil { return nil, types.GetStatementOfApplicabilityOutput{}, err } prb := r.proboSvc soa, err := prb.StatementsOfApplicability.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetStatementOfApplicabilityOutput{}, fmt.Errorf("failed to get statement of applicability: %w", err) } return nil, types.GetStatementOfApplicabilityOutput{ StatementOfApplicability: types.NewStatementOfApplicability(soa), }, nil } func (r *Resolver) AddStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddStatementOfApplicabilityInput) (*mcp.CallToolResult, types.AddStatementOfApplicabilityOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionStatementOfApplicabilityCreate) if err != nil { return nil, types.AddStatementOfApplicabilityOutput{}, err } svc := r.proboSvc soa, err := svc.StatementsOfApplicability.Create(ctx, scope, probo.CreateStatementOfApplicabilityRequest{ OrganizationID: input.OrganizationID, Name: input.Name, }) if err != nil { return nil, types.AddStatementOfApplicabilityOutput{}, fmt.Errorf("failed to create statement of applicability: %w", err) } return nil, types.AddStatementOfApplicabilityOutput{ StatementOfApplicability: types.NewStatementOfApplicability(soa), }, nil } func (r *Resolver) UpdateStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateStatementOfApplicabilityInput) (*mcp.CallToolResult, types.UpdateStatementOfApplicabilityOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionStatementOfApplicabilityUpdate) if err != nil { return nil, types.UpdateStatementOfApplicabilityOutput{}, err } svc := r.proboSvc soa, err := svc.StatementsOfApplicability.Update(ctx, scope, probo.UpdateStatementOfApplicabilityRequest{ StatementOfApplicabilityID: input.ID, Name: input.Name, }) if err != nil { return nil, types.UpdateStatementOfApplicabilityOutput{}, fmt.Errorf("failed to update statement of applicability: %w", err) } return nil, types.UpdateStatementOfApplicabilityOutput{ StatementOfApplicability: types.NewStatementOfApplicability(soa), }, nil } func (r *Resolver) DeleteStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteStatementOfApplicabilityInput) (*mcp.CallToolResult, types.DeleteStatementOfApplicabilityOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionStatementOfApplicabilityDelete) if err != nil { return nil, types.DeleteStatementOfApplicabilityOutput{}, err } svc := r.proboSvc err = svc.StatementsOfApplicability.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteStatementOfApplicabilityOutput{}, fmt.Errorf("failed to delete statement of applicability: %w", err) } return nil, types.DeleteStatementOfApplicabilityOutput{ DeletedStatementOfApplicabilityID: input.ID, }, nil } func (r *Resolver) ListApplicabilityStatementsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListApplicabilityStatementsInput) (*mcp.CallToolResult, types.ListApplicabilityStatementsOutput, error) { scope, err := r.Authorize(ctx, input.StatementOfApplicabilityID, probo.ActionApplicabilityStatementList) if err != nil { return nil, types.ListApplicabilityStatementsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ApplicabilityStatementOrderField]{ Field: coredata.ApplicabilityStatementOrderFieldControlSectionTitle, Direction: page.OrderDirectionAsc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ApplicabilityStatementOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) pg, err := prb.StatementsOfApplicability.ListApplicabilityStatements(ctx, scope, input.StatementOfApplicabilityID, cursor) if err != nil { return nil, types.ListApplicabilityStatementsOutput{}, fmt.Errorf("failed to list applicability statements: %w", err) } return nil, types.NewListApplicabilityStatementsOutput(pg), nil } func (r *Resolver) GetApplicabilityStatementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetApplicabilityStatementInput) (*mcp.CallToolResult, types.GetApplicabilityStatementOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionApplicabilityStatementGet) if err != nil { return nil, types.GetApplicabilityStatementOutput{}, err } prb := r.proboSvc stmt, err := prb.StatementsOfApplicability.GetApplicabilityStatement(ctx, scope, input.ID) if err != nil { return nil, types.GetApplicabilityStatementOutput{}, fmt.Errorf("failed to get applicability statement: %w", err) } return nil, types.GetApplicabilityStatementOutput{ ApplicabilityStatement: types.NewApplicabilityStatement(stmt), }, nil } func (r *Resolver) AddApplicabilityStatementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddApplicabilityStatementInput) (*mcp.CallToolResult, types.AddApplicabilityStatementOutput, error) { scope, err := r.Authorize(ctx, input.StatementOfApplicabilityID, probo.ActionApplicabilityStatementCreate) if err != nil { return nil, types.AddApplicabilityStatementOutput{}, err } svc := r.proboSvc stmt, err := svc.StatementsOfApplicability.CreateApplicabilityStatement( ctx, scope, input.StatementOfApplicabilityID, input.ControlID, input.Applicability, input.Justification, ) if err != nil { return nil, types.AddApplicabilityStatementOutput{}, fmt.Errorf("failed to create applicability statement: %w", err) } return nil, types.AddApplicabilityStatementOutput{ ApplicabilityStatement: types.NewApplicabilityStatement(stmt), }, nil } func (r *Resolver) UpdateApplicabilityStatementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateApplicabilityStatementInput) (*mcp.CallToolResult, types.UpdateApplicabilityStatementOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionApplicabilityStatementUpdate) if err != nil { return nil, types.UpdateApplicabilityStatementOutput{}, err } svc := r.proboSvc stmt, err := svc.StatementsOfApplicability.UpdateApplicabilityStatement( ctx, scope, input.ID, input.Applicability, input.Justification, ) if err != nil { return nil, types.UpdateApplicabilityStatementOutput{}, fmt.Errorf("failed to update applicability statement: %w", err) } return nil, types.UpdateApplicabilityStatementOutput{ ApplicabilityStatement: types.NewApplicabilityStatement(stmt), }, nil } func (r *Resolver) DeleteApplicabilityStatementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteApplicabilityStatementInput) (*mcp.CallToolResult, types.DeleteApplicabilityStatementOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionApplicabilityStatementDelete) if err != nil { return nil, types.DeleteApplicabilityStatementOutput{}, err } svc := r.proboSvc err = svc.StatementsOfApplicability.DeleteApplicabilityStatement(ctx, scope, input.ID) if err != nil { return nil, types.DeleteApplicabilityStatementOutput{}, fmt.Errorf("failed to delete applicability statement: %w", err) } return nil, types.DeleteApplicabilityStatementOutput{ DeletedApplicabilityStatementID: input.ID, }, nil } // ListThirdPartyRiskAssessmentsTool handles the listThirdPartyRiskAssessments tool // List all risk assessments for a thirdParty func (r *Resolver) ListThirdPartyRiskAssessmentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListThirdPartyRiskAssessmentsInput) (*mcp.CallToolResult, types.ListThirdPartyRiskAssessmentsOutput, error) { scope, err := r.Authorize(ctx, input.ThirdPartyID, probo.ActionThirdPartyRiskAssessmentList) if err != nil { return nil, types.ListThirdPartyRiskAssessmentsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ThirdPartyRiskAssessmentOrderField]{ Field: coredata.ThirdPartyRiskAssessmentOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ThirdPartyRiskAssessmentOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := prb.ThirdParties.ListRiskAssessments(ctx, scope, input.ThirdPartyID, cursor) if err != nil { return nil, types.ListThirdPartyRiskAssessmentsOutput{}, fmt.Errorf("cannot list thirdParty risk assessments: %w", err) } return nil, types.NewListThirdPartyRiskAssessmentsOutput(p), nil } // AddThirdPartyRiskAssessmentTool handles the addThirdPartyRiskAssessment tool // Add a new risk assessment for a thirdParty func (r *Resolver) AddThirdPartyRiskAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddThirdPartyRiskAssessmentInput) (*mcp.CallToolResult, types.AddThirdPartyRiskAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ThirdPartyID, probo.ActionThirdPartyRiskAssessmentCreate) if err != nil { return nil, types.AddThirdPartyRiskAssessmentOutput{}, err } prb := r.proboSvc assessment, err := prb.ThirdParties.CreateRiskAssessment( ctx, scope, probo.CreateThirdPartyRiskAssessmentRequest{ ThirdPartyID: input.ThirdPartyID, ExpiresAt: input.ExpiresAt, DataSensitivity: input.DataSensitivity, BusinessImpact: input.BusinessImpact, Notes: input.Notes, }, ) if err != nil { return nil, types.AddThirdPartyRiskAssessmentOutput{}, fmt.Errorf("failed to create thirdParty risk assessment: %w", err) } return nil, types.NewAddThirdPartyRiskAssessmentOutput(assessment), nil } func (r *Resolver) DeleteThirdPartyTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteThirdPartyInput) (*mcp.CallToolResult, types.DeleteThirdPartyOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyDelete) if err != nil { return nil, types.DeleteThirdPartyOutput{}, err } svc := r.proboSvc err = svc.ThirdParties.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteThirdPartyOutput{}, fmt.Errorf("failed to delete thirdParty: %w", err) } return nil, types.DeleteThirdPartyOutput{ DeletedThirdPartyID: input.ID, }, nil } func (r *Resolver) DeleteFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteFindingInput) (*mcp.CallToolResult, types.DeleteFindingOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionFindingDelete) if err != nil { return nil, types.DeleteFindingOutput{}, err } svc := r.proboSvc err = svc.Findings.Delete(ctx, scope, 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) { scope, err := r.Authorize(ctx, input.FindingID, probo.ActionFindingAuditMappingCreate) if err != nil { return nil, types.LinkFindingAuditOutput{}, err } svc := r.proboSvc finding, audit, err := svc.Findings.CreateAuditMapping(ctx, scope, 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), }, nil } func (r *Resolver) UnlinkFindingAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnlinkFindingAuditInput) (*mcp.CallToolResult, types.UnlinkFindingAuditOutput, error) { scope, err := r.Authorize(ctx, input.FindingID, probo.ActionFindingAuditMappingDelete) if err != nil { return nil, types.UnlinkFindingAuditOutput{}, err } svc := r.proboSvc finding, audit, err := svc.Findings.DeleteAuditMapping(ctx, scope, 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) { scope, err := r.Authorize(ctx, input.FindingID, probo.ActionFindingGet) if err != nil { return nil, types.ListFindingAuditsOutput{}, err } prb := r.proboSvc 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, scope, input.FindingID, cursor) if err != nil { return nil, types.ListFindingAuditsOutput{}, fmt.Errorf("cannot list finding audits: %w", err) } return nil, types.NewListFindingAuditsOutput(auditPage), nil } // ListAccessReviewCampaignsTool handles the listAccessReviewCampaigns tool // List access review campaigns for an organization func (r *Resolver) ListAccessReviewCampaignsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAccessReviewCampaignsInput) (*mcp.CallToolResult, types.ListAccessReviewCampaignsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, accessreview.ActionCampaignList) if err != nil { return nil, types.ListAccessReviewCampaignsOutput{}, err } pageOrderBy := page.OrderBy[coredata.AccessReviewCampaignOrderField]{ Field: coredata.AccessReviewCampaignOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.AccessReviewCampaignOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.accessReview.ListCampaignsForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list access review campaigns: %w", err)) } return nil, types.NewListAccessReviewCampaignsOutput(p), nil } // ListAccessEntriesTool handles the listAccessEntries tool // List access entries for a campaign or campaign source with optional filters func (r *Resolver) ListAccessEntriesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAccessEntriesInput) (*mcp.CallToolResult, types.ListAccessEntriesOutput, error) { if input.AccessReviewCampaignSourceID == nil && input.CampaignID == nil { return nil, types.ListAccessEntriesOutput{}, fmt.Errorf("campaign_id or access_review_campaign_source_id is required") } var ( scope *coredata.Scope campaignID gid.GID sourceID *gid.GID err error ) if input.AccessReviewCampaignSourceID != nil { scope, err = r.Authorize(ctx, *input.AccessReviewCampaignSourceID, accessreview.ActionEntryList) if err != nil { return nil, types.ListAccessEntriesOutput{}, err } campaignSource, err := r.accessReview.GetCampaignSource(ctx, scope, *input.AccessReviewCampaignSourceID) if err != nil { panic(fmt.Errorf("cannot get campaign source: %w", err)) } campaignID = campaignSource.AccessReviewCampaignID sourceID = input.AccessReviewCampaignSourceID } else { scope, err = r.Authorize(ctx, *input.CampaignID, accessreview.ActionEntryList) if err != nil { return nil, types.ListAccessEntriesOutput{}, err } campaignID = *input.CampaignID } pageOrderBy := page.OrderBy[coredata.AccessReviewEntryOrderField]{ Field: coredata.AccessReviewEntryOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.AccessReviewEntryOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) var filter *coredata.AccessReviewEntryFilter if input.Filter != nil { filter = &coredata.AccessReviewEntryFilter{ Decision: input.Filter.Decision, Flag: input.Filter.Flag, IncrementalTag: input.Filter.IncrementalTag, IsAdmin: input.Filter.IsAdmin, Active: input.Filter.Active, AuthMethod: input.Filter.AuthMethod, AccountType: input.Filter.AccountType, } } var p *page.Page[*coredata.AccessReviewEntry, coredata.AccessReviewEntryOrderField] if sourceID != nil { p, err = r.accessReview.ListEntriesForCampaignIDAndSourceID( ctx, scope, campaignID, *sourceID, cursor, filter, ) if err != nil { panic(fmt.Errorf("cannot list access entries: %w", err)) } } else { p, err = r.accessReview.ListEntriesForCampaignID(ctx, scope, campaignID, cursor, filter) if err != nil { panic(fmt.Errorf("cannot list access entries: %w", err)) } } return nil, types.NewListAccessEntriesOutput(p), nil } // GetAccessReviewStatisticsTool handles the getAccessReviewCampaignStatistics tool // Get statistics for an access review campaign func (r *Resolver) GetAccessReviewStatisticsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetAccessReviewStatisticsInput) (*mcp.CallToolResult, types.GetAccessReviewStatisticsOutput, error) { scope, err := r.Authorize(ctx, input.CampaignID, accessreview.ActionCampaignGet) if err != nil { return nil, types.GetAccessReviewStatisticsOutput{}, err } stats, err := r.accessReview.CampaignStatistics(ctx, scope, input.CampaignID) if err != nil { panic(fmt.Errorf("cannot get campaign statistics: %w", err)) } return nil, types.GetAccessReviewStatisticsOutput{ Statistics: types.NewAccessReviewStatistics(stats), }, nil } // RecordAccessReviewEntryDecisionTool handles the recordAccessEntryDecision tool // Record a decision on an access entry func (r *Resolver) RecordAccessReviewEntryDecisionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RecordAccessReviewEntryDecisionInput) (*mcp.CallToolResult, types.RecordAccessReviewEntryDecisionOutput, error) { scope, err := r.Authorize(ctx, input.AccessReviewEntryID, accessreview.ActionEntryDecide) if err != nil { return nil, types.RecordAccessReviewEntryDecisionOutput{}, err } entry, err := r.accessReview.RecordDecision( ctx, scope, accessreview.RecordAccessReviewEntryDecisionRequest{ EntryID: input.AccessReviewEntryID, Decision: input.Decision, DecisionNote: input.DecisionNote, DecidedByID: &authn.IdentityFromContext(ctx).ID, }, ) if err != nil { return nil, types.RecordAccessReviewEntryDecisionOutput{}, fmt.Errorf("cannot record decision: %w", err) } return nil, types.RecordAccessReviewEntryDecisionOutput{ AccessEntry: types.NewAccessReviewEntry(entry), }, nil } // RecordAccessReviewEntryDecisionsTool handles the recordAccessEntryDecisions tool // Record decisions on multiple access entries in a single batch func (r *Resolver) RecordAccessReviewEntryDecisionsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RecordAccessReviewEntryDecisionsInput) (*mcp.CallToolResult, types.RecordAccessReviewEntryDecisionsOutput, error) { if len(input.Decisions) == 0 { return nil, types.RecordAccessReviewEntryDecisionsOutput{ AccessReviewEntries: []*types.AccessReviewEntry{}, }, nil } const maxBatchSize = 100 if len(input.Decisions) > maxBatchSize { return nil, types.RecordAccessReviewEntryDecisionsOutput{}, fmt.Errorf("cannot record decisions: batch size %d exceeds maximum of %d", len(input.Decisions), maxBatchSize) } // Authorize each entry individually to prevent cross-org bypass. for _, d := range input.Decisions { if _, err := r.Authorize(ctx, d.AccessReviewEntryID, accessreview.ActionEntryDecide); err != nil { return nil, types.RecordAccessReviewEntryDecisionsOutput{}, err } } scope := coredata.NewScopeFromObjectID(input.Decisions[0].AccessReviewEntryID) identity := authn.IdentityFromContext(ctx) if identity == nil { return nil, types.RecordAccessReviewEntryDecisionsOutput{}, fmt.Errorf("no identity in context") } decidedByID := &identity.ID decisions := make([]accessreview.RecordAccessReviewEntryDecisionRequest, len(input.Decisions)) for i, d := range input.Decisions { decisions[i] = accessreview.RecordAccessReviewEntryDecisionRequest{ EntryID: d.AccessReviewEntryID, Decision: d.Decision, DecisionNote: d.DecisionNote, DecidedByID: decidedByID, } } entries, err := r.accessReview.RecordDecisions(ctx, scope, decisions) if err != nil { return nil, types.RecordAccessReviewEntryDecisionsOutput{}, fmt.Errorf("cannot record decisions: %w", err) } accessEntries := make([]*types.AccessReviewEntry, len(entries)) for i, e := range entries { accessEntries[i] = types.NewAccessReviewEntry(e) } return nil, types.RecordAccessReviewEntryDecisionsOutput{ AccessReviewEntries: accessEntries, }, nil } // CloseAccessReviewCampaignTool handles the closeAccessReviewCampaign tool // Close an access review campaign func (r *Resolver) CloseAccessReviewCampaignTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CloseAccessReviewCampaignInput) (*mcp.CallToolResult, types.CloseAccessReviewCampaignOutput, error) { scope, err := r.Authorize(ctx, input.CampaignID, accessreview.ActionCampaignClose) if err != nil { return nil, types.CloseAccessReviewCampaignOutput{}, err } campaign, err := r.accessReview.CloseCampaign(ctx, scope, input.CampaignID) if err != nil { return nil, types.CloseAccessReviewCampaignOutput{}, fmt.Errorf("cannot close campaign: %w", err) } return nil, types.CloseAccessReviewCampaignOutput{ Campaign: types.NewAccessReviewCampaign(campaign), }, nil } // ListAccessReviewSourcesTool handles the listAccessSources tool // List access sources for an organization func (r *Resolver) ListAccessReviewSourcesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAccessReviewSourcesInput) (*mcp.CallToolResult, types.ListAccessReviewSourcesOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, accessreview.ActionSourceList) if err != nil { return nil, types.ListAccessReviewSourcesOutput{}, err } pageOrderBy := page.OrderBy[coredata.AccessReviewSourceOrderField]{ Field: coredata.AccessReviewSourceOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.AccessReviewSourceOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.accessReview.ListSourcesForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list access sources: %w", err)) } return nil, types.NewListAccessReviewSourcesOutput(p), nil } // CreateAccessReviewSourceTool handles the createAccessSource tool // Create a new access source for an organization func (r *Resolver) CreateAccessReviewSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateAccessReviewSourceInput) (*mcp.CallToolResult, types.CreateAccessReviewSourceOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, accessreview.ActionSourceCreate) if err != nil { return nil, types.CreateAccessReviewSourceOutput{}, err } source, err := r.accessReview.CreateSource(ctx, scope, accessreview.CreateAccessReviewSourceRequest{ OrganizationID: input.OrganizationID, ConnectorID: input.ConnectorID, Name: input.Name, CsvData: input.CsvData, }) if err != nil { return nil, types.CreateAccessReviewSourceOutput{}, fmt.Errorf("cannot create access source: %w", err) } r.accessReview.AutoSelectDefaultOrganization(ctx, scope, source) return nil, types.CreateAccessReviewSourceOutput{ AccessReviewSource: types.NewAccessReviewSource(source), }, nil } // UpdateAccessReviewSourceTool handles the updateAccessSource tool // Update an existing access source func (r *Resolver) UpdateAccessReviewSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateAccessReviewSourceInput) (*mcp.CallToolResult, types.UpdateAccessReviewSourceOutput, error) { scope, err := r.Authorize(ctx, input.AccessReviewSourceID, accessreview.ActionSourceUpdate) if err != nil { return nil, types.UpdateAccessReviewSourceOutput{}, err } updateReq := accessreview.UpdateAccessReviewSourceRequest{ AccessReviewSourceID: input.AccessReviewSourceID, } if input.Name != nil { updateReq.Name = &input.Name } connectorSet := false if rawConnectorID := UnwrapOmittable(input.ConnectorID); rawConnectorID != nil { connectorSet = true if *rawConnectorID != nil { id, err := gid.ParseGID(**rawConnectorID) if err != nil { return nil, types.UpdateAccessReviewSourceOutput{}, fmt.Errorf("cannot parse connector_id: %w", err) } idPtr := &id updateReq.ConnectorID = &idPtr } else { var nilGID *gid.GID updateReq.ConnectorID = &nilGID } } if rawCsvData := UnwrapOmittable(input.CsvData); rawCsvData != nil { updateReq.CsvData = rawCsvData } source, err := r.accessReview.UpdateSource(ctx, scope, updateReq) if err != nil { return nil, types.UpdateAccessReviewSourceOutput{}, fmt.Errorf("cannot update access source: %w", err) } // A connector was just (re)linked: default its org so the source is // usable right away. Matches the GraphQL surface; skipped on name/CSV-only // updates to avoid a needless provider round-trip. if connectorSet { r.accessReview.AutoSelectDefaultOrganization(ctx, scope, source) } return nil, types.UpdateAccessReviewSourceOutput{ AccessReviewSource: types.NewAccessReviewSource(source), }, nil } // DeleteAccessReviewSourceTool handles the deleteAccessSource tool // Delete an access source func (r *Resolver) DeleteAccessReviewSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteAccessReviewSourceInput) (*mcp.CallToolResult, types.DeleteAccessReviewSourceOutput, error) { scope, err := r.Authorize(ctx, input.AccessReviewSourceID, accessreview.ActionSourceDelete) if err != nil { return nil, types.DeleteAccessReviewSourceOutput{}, err } if err := r.accessReview.DeleteSource(ctx, scope, input.AccessReviewSourceID); err != nil { return nil, types.DeleteAccessReviewSourceOutput{}, fmt.Errorf("cannot delete access source: %w", err) } return nil, types.DeleteAccessReviewSourceOutput{ DeletedAccessReviewSourceID: input.AccessReviewSourceID, }, nil } // CreateAccessReviewCampaignTool handles the createAccessReviewCampaign tool // Create a new access review campaign for an organization func (r *Resolver) CreateAccessReviewCampaignTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateAccessReviewCampaignInput) (*mcp.CallToolResult, types.CreateAccessReviewCampaignOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, accessreview.ActionCampaignCreate) if err != nil { return nil, types.CreateAccessReviewCampaignOutput{}, err } var description string if input.Description != nil { description = *input.Description } campaign, err := r.accessReview.CreateCampaign(ctx, scope, accessreview.CreateAccessReviewCampaignRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Description: description, AccessReviewSourceIDs: input.AccessReviewSourceIds, }) if err != nil { return nil, types.CreateAccessReviewCampaignOutput{}, fmt.Errorf("cannot create access review campaign: %w", err) } return nil, types.CreateAccessReviewCampaignOutput{ Campaign: types.NewAccessReviewCampaign(campaign), }, nil } // UpdateAccessReviewCampaignTool handles the updateAccessReviewCampaign tool // Update an existing access review campaign func (r *Resolver) UpdateAccessReviewCampaignTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateAccessReviewCampaignInput) (*mcp.CallToolResult, types.UpdateAccessReviewCampaignOutput, error) { scope, err := r.Authorize(ctx, input.CampaignID, accessreview.ActionCampaignUpdate) if err != nil { return nil, types.UpdateAccessReviewCampaignOutput{}, err } updateReq := accessreview.UpdateAccessReviewCampaignRequest{ CampaignID: input.CampaignID, } if input.Name != nil { updateReq.Name = &input.Name } if input.Description != nil { updateReq.Description = &input.Description } campaign, err := r.accessReview.UpdateCampaign(ctx, scope, updateReq) if err != nil { return nil, types.UpdateAccessReviewCampaignOutput{}, fmt.Errorf("cannot update access review campaign: %w", err) } return nil, types.UpdateAccessReviewCampaignOutput{ Campaign: types.NewAccessReviewCampaign(campaign), }, nil } // DeleteAccessReviewCampaignTool handles the deleteAccessReviewCampaign tool // Delete an access review campaign func (r *Resolver) DeleteAccessReviewCampaignTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteAccessReviewCampaignInput) (*mcp.CallToolResult, types.DeleteAccessReviewCampaignOutput, error) { scope, err := r.Authorize(ctx, input.CampaignID, accessreview.ActionCampaignDelete) if err != nil { return nil, types.DeleteAccessReviewCampaignOutput{}, err } if err := r.accessReview.DeleteCampaign(ctx, scope, input.CampaignID); err != nil { return nil, types.DeleteAccessReviewCampaignOutput{}, fmt.Errorf("cannot delete access review campaign: %w", err) } return nil, types.DeleteAccessReviewCampaignOutput{ DeletedCampaignID: input.CampaignID, }, nil } // StartAccessReviewCampaignTool handles the startAccessReviewCampaign tool // Start an access review campaign func (r *Resolver) StartAccessReviewCampaignTool(ctx context.Context, req *mcp.CallToolRequest, input *types.StartAccessReviewCampaignInput) (*mcp.CallToolResult, types.StartAccessReviewCampaignOutput, error) { scope, err := r.Authorize(ctx, input.CampaignID, accessreview.ActionCampaignStart) if err != nil { return nil, types.StartAccessReviewCampaignOutput{}, err } campaign, err := r.accessReview.StartCampaign(ctx, scope, input.CampaignID) if err != nil { return nil, types.StartAccessReviewCampaignOutput{}, fmt.Errorf("cannot start access review campaign: %w", err) } return nil, types.StartAccessReviewCampaignOutput{ Campaign: types.NewAccessReviewCampaign(campaign), }, nil } // CancelAccessReviewCampaignTool handles the cancelAccessReviewCampaign tool // Cancel an in-progress access review campaign func (r *Resolver) CancelAccessReviewCampaignTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CancelAccessReviewCampaignInput) (*mcp.CallToolResult, types.CancelAccessReviewCampaignOutput, error) { scope, err := r.Authorize(ctx, input.CampaignID, accessreview.ActionCampaignCancel) if err != nil { return nil, types.CancelAccessReviewCampaignOutput{}, err } campaign, err := r.accessReview.CancelCampaign(ctx, scope, input.CampaignID) if err != nil { return nil, types.CancelAccessReviewCampaignOutput{}, fmt.Errorf("cannot cancel access review campaign: %w", err) } return nil, types.CancelAccessReviewCampaignOutput{ Campaign: types.NewAccessReviewCampaign(campaign), }, nil } // AddAccessReviewCampaignSourceTool handles the addAccessReviewCampaignScopeSource tool // Add an access source to an access review campaign's scope func (r *Resolver) AddAccessReviewCampaignSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddAccessReviewCampaignSourceInput) (*mcp.CallToolResult, types.AddAccessReviewCampaignSourceOutput, error) { scope, err := r.Authorize(ctx, input.CampaignID, accessreview.ActionCampaignAddSource) if err != nil { return nil, types.AddAccessReviewCampaignSourceOutput{}, err } campaign, err := r.accessReview.AddCampaignSource(ctx, scope, accessreview.AddCampaignSourceRequest{ CampaignID: input.CampaignID, AccessReviewSourceID: input.AccessReviewSourceID, }) if err != nil { return nil, types.AddAccessReviewCampaignSourceOutput{}, fmt.Errorf("cannot add scope source to access review campaign: %w", err) } return nil, types.AddAccessReviewCampaignSourceOutput{ Campaign: types.NewAccessReviewCampaign(campaign), }, nil } // RemoveAccessReviewCampaignSourceTool handles the removeAccessReviewCampaignScopeSource tool // Remove an access source from an access review campaign's scope func (r *Resolver) RemoveAccessReviewCampaignSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RemoveAccessReviewCampaignSourceInput) (*mcp.CallToolResult, types.RemoveAccessReviewCampaignSourceOutput, error) { scope, err := r.Authorize(ctx, input.CampaignID, accessreview.ActionCampaignRemoveSource) if err != nil { return nil, types.RemoveAccessReviewCampaignSourceOutput{}, err } campaign, err := r.accessReview.RemoveCampaignSource(ctx, scope, accessreview.RemoveCampaignSourceRequest{ CampaignID: input.CampaignID, AccessReviewSourceID: input.AccessReviewSourceID, }) if err != nil { return nil, types.RemoveAccessReviewCampaignSourceOutput{}, fmt.Errorf("cannot remove scope source from access review campaign: %w", err) } return nil, types.RemoveAccessReviewCampaignSourceOutput{ Campaign: types.NewAccessReviewCampaign(campaign), }, nil } // FlagAccessReviewEntryTool handles the flagAccessEntry tool // Flag an access entry during review func (r *Resolver) FlagAccessReviewEntryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.FlagAccessReviewEntryInput) (*mcp.CallToolResult, types.FlagAccessReviewEntryOutput, error) { scope, err := r.Authorize(ctx, input.AccessReviewEntryID, accessreview.ActionEntryFlag) if err != nil { return nil, types.FlagAccessReviewEntryOutput{}, err } entry, err := r.accessReview.FlagEntry(ctx, scope, accessreview.FlagAccessReviewEntryRequest{ EntryID: input.AccessReviewEntryID, Flags: input.Flags, FlagReasons: input.FlagReasons, }) if err != nil { return nil, types.FlagAccessReviewEntryOutput{}, fmt.Errorf("cannot flag access entry: %w", err) } return nil, types.FlagAccessReviewEntryOutput{ AccessEntry: types.NewAccessReviewEntry(entry), }, nil } func (r *Resolver) GetAuditReportUrlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetAuditReportUrlInput) (*mcp.CallToolResult, types.GetAuditReportUrlOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionReportGetReportUrl) if err != nil { return nil, types.GetAuditReportUrlOutput{}, err } prb := r.proboSvc url, err := prb.Audits.GenerateReportURL(ctx, scope, input.ID, 15*time.Minute) if err != nil { return nil, types.GetAuditReportUrlOutput{}, fmt.Errorf("cannot generate audit report URL: %w", err) } return nil, types.GetAuditReportUrlOutput{ URL: *url, }, nil } func (r *Resolver) ArchiveDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ArchiveDocumentInput) (*mcp.CallToolResult, types.ArchiveDocumentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentArchive) if err != nil { return nil, types.ArchiveDocumentOutput{}, err } svc := r.proboSvc document, err := svc.Documents.Archive(ctx, scope, input.ID) if err != nil { return nil, types.ArchiveDocumentOutput{}, fmt.Errorf("cannot archive document: %w", err) } return nil, types.ArchiveDocumentOutput{ Document: types.NewDocument(document), }, nil } func (r *Resolver) UnarchiveDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnarchiveDocumentInput) (*mcp.CallToolResult, types.UnarchiveDocumentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentUnarchive) if err != nil { return nil, types.UnarchiveDocumentOutput{}, err } svc := r.proboSvc document, err := svc.Documents.Unarchive(ctx, scope, input.ID) if err != nil { return nil, types.UnarchiveDocumentOutput{}, fmt.Errorf("cannot unarchive document: %w", err) } return nil, types.UnarchiveDocumentOutput{ Document: types.NewDocument(document), }, nil } func (r *Resolver) GetOrganizationContextTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetOrganizationContextInput) (*mcp.CallToolResult, types.GetOrganizationContextOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionOrganizationContextGet) if err != nil { return nil, types.GetOrganizationContextOutput{}, err } prb := r.proboSvc orgContext, err := prb.Organizations.GetContext(ctx, scope, input.OrganizationID) if err != nil { return nil, types.GetOrganizationContextOutput{}, fmt.Errorf("cannot get organization context: %w", err) } return nil, types.GetOrganizationContextOutput{ OrganizationContext: types.NewOrganizationContext(orgContext), }, nil } func (r *Resolver) UpdateOrganizationContextTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateOrganizationContextInput) (*mcp.CallToolResult, types.UpdateOrganizationContextOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionOrganizationContextUpdate) if err != nil { return nil, types.UpdateOrganizationContextOutput{}, err } prb := r.proboSvc orgContext, err := prb.Organizations.UpdateContext( ctx, scope, probo.UpdateOrganizationContextRequest{ OrganizationID: input.OrganizationID, Product: &input.Product, Architecture: &input.Architecture, Team: &input.Team, Processes: &input.Processes, Customers: &input.Customers, }, ) if err != nil { return nil, types.UpdateOrganizationContextOutput{}, fmt.Errorf("cannot update organization context: %w", err) } return nil, types.UpdateOrganizationContextOutput{ OrganizationContext: types.NewOrganizationContext(orgContext), }, nil } func (r *Resolver) GetAuditLogEntryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetAuditLogEntryInput) (*mcp.CallToolResult, types.GetAuditLogEntryOutput, error) { if _, err := r.Authorize(ctx, input.ID, iam.ActionAuditLogEntryGet); err != nil { return nil, types.GetAuditLogEntryOutput{}, err } entry, err := r.iamSvc.OrganizationService.GetAuditLogEntry(ctx, input.ID) if err != nil { panic(fmt.Errorf("cannot get audit log entry: %w", err)) } return nil, types.GetAuditLogEntryOutput{ AuditLogEntry: types.NewAuditLogEntry(entry), }, nil } func (r *Resolver) ListAuditLogEntriesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAuditLogEntriesInput) (*mcp.CallToolResult, types.ListAuditLogEntriesOutput, error) { if _, err := r.Authorize(ctx, input.OrganizationID, iam.ActionAuditLogEntryList); err != nil { return nil, types.ListAuditLogEntriesOutput{}, err } pageOrderBy := page.OrderBy[coredata.AuditLogEntryOrderField]{ Field: coredata.AuditLogEntryOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) filter := coredata.NewAuditLogEntryFilter() if input.Filter != nil { if input.Filter.Action != nil { filter.WithAction(*input.Filter.Action) } if input.Filter.ActorID != nil { filter.WithActorID(*input.Filter.ActorID) } if input.Filter.ResourceType != nil { filter.WithResourceType(*input.Filter.ResourceType) } if input.Filter.ResourceID != nil { filter.WithResourceID(*input.Filter.ResourceID) } } p, err := r.iamSvc.OrganizationService.ListAuditLogEntries(ctx, input.OrganizationID, cursor, filter) if err != nil { panic(fmt.Errorf("cannot list audit log entries: %w", err)) } return nil, types.NewListAuditLogEntriesOutput(p), nil } func (r *Resolver) ListMeasureDocumentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMeasureDocumentsInput) (*mcp.CallToolResult, types.ListMeasureDocumentsOutput, error) { scope, err := r.Authorize(ctx, input.MeasureID, probo.ActionMeasureGet) if err != nil { return nil, types.ListMeasureDocumentsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{ Field: coredata.DocumentOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) docPage, err := prb.Documents.ListForMeasureID(ctx, scope, input.MeasureID, cursor, coredata.NewDocumentFilter(nil)) if err != nil { return nil, types.ListMeasureDocumentsOutput{}, fmt.Errorf("failed to list measure documents: %w", err) } return nil, types.NewListMeasureDocumentsOutput(docPage), nil } func (r *Resolver) VoidDocumentVersionApprovalTool(ctx context.Context, req *mcp.CallToolRequest, input *types.VoidDocumentVersionApprovalInput) (*mcp.CallToolResult, types.VoidDocumentVersionApprovalOutput, error) { scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionVoidApproval) if err != nil { return nil, types.VoidDocumentVersionApprovalOutput{}, err } svc := r.proboSvc _, documentVersion, err := svc.DocumentApprovals.VoidApproval(ctx, scope, input.DocumentVersionID) if err != nil { panic(fmt.Errorf("cannot void document version approval: %w", err)) } return nil, types.VoidDocumentVersionApprovalOutput{ DocumentVersion: types.NewDocumentVersion(documentVersion), }, nil } func (r *Resolver) DeleteDocumentDraftTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteDocumentDraftInput) (*mcp.CallToolResult, types.DeleteDocumentDraftOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentDeleteDraft) if err != nil { return nil, types.DeleteDocumentDraftOutput{}, err } svc := r.proboSvc document, err := svc.Documents.DeleteDraft(ctx, scope, input.ID) if err != nil { return nil, types.DeleteDocumentDraftOutput{}, fmt.Errorf("cannot delete document draft: %w", err) } return nil, types.DeleteDocumentDraftOutput{ Document: types.NewDocument(document), }, nil } func (r *Resolver) PublishStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishStatementOfApplicabilityInput) (*mcp.CallToolResult, types.PublishStatementOfApplicabilityOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionStatementOfApplicabilityPublish) if err != nil { return nil, types.PublishStatementOfApplicabilityOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishStatementOfApplicability(ctx, scope, input.ID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishStatementOfApplicabilityOutput{}, fmt.Errorf("cannot publish statement of applicability: %w", err) } return nil, types.PublishStatementOfApplicabilityOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) ListWebhookSubscriptionsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListWebhookSubscriptionsInput) (*mcp.CallToolResult, types.ListWebhookSubscriptionsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionWebhookSubscriptionList) if err != nil { return nil, types.ListWebhookSubscriptionsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.WebhookSubscriptionOrderField]{ Field: coredata.WebhookSubscriptionOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.WebhookSubscriptionOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.WebhookSubscriptions.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list webhook subscriptions: %w", err)) } return nil, types.NewListWebhookSubscriptionsOutput(page), nil } func (r *Resolver) GetWebhookSubscriptionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetWebhookSubscriptionInput) (*mcp.CallToolResult, types.GetWebhookSubscriptionOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionWebhookSubscriptionGet) if err != nil { return nil, types.GetWebhookSubscriptionOutput{}, err } prb := r.proboSvc subscription, err := prb.WebhookSubscriptions.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetWebhookSubscriptionOutput{}, fmt.Errorf("failed to get webhook subscription: %w", err) } return nil, types.GetWebhookSubscriptionOutput{ WebhookSubscription: types.NewWebhookSubscription(subscription), }, nil } func (r *Resolver) CreateWebhookSubscriptionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateWebhookSubscriptionInput) (*mcp.CallToolResult, types.CreateWebhookSubscriptionOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionWebhookSubscriptionCreate) if err != nil { return nil, types.CreateWebhookSubscriptionOutput{}, err } prb := r.proboSvc subscription, err := prb.WebhookSubscriptions.Create( ctx, scope, probo.CreateWebhookSubscriptionRequest{ OrganizationID: input.OrganizationID, EndpointURL: input.EndpointURL, SelectedEvents: input.SelectedEvents, }, ) if err != nil { return nil, types.CreateWebhookSubscriptionOutput{}, fmt.Errorf("failed to create webhook subscription: %w", err) } return nil, types.CreateWebhookSubscriptionOutput{ WebhookSubscription: types.NewWebhookSubscription(subscription), }, nil } func (r *Resolver) UpdateWebhookSubscriptionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateWebhookSubscriptionInput) (*mcp.CallToolResult, types.UpdateWebhookSubscriptionOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionWebhookSubscriptionUpdate) if err != nil { return nil, types.UpdateWebhookSubscriptionOutput{}, err } prb := r.proboSvc subscription, err := prb.WebhookSubscriptions.Update( ctx, scope, probo.UpdateWebhookSubscriptionRequest{ WebhookSubscriptionID: input.ID, EndpointURL: input.EndpointURL, SelectedEvents: input.SelectedEvents, }, ) if err != nil { return nil, types.UpdateWebhookSubscriptionOutput{}, fmt.Errorf("failed to update webhook subscription: %w", err) } return nil, types.UpdateWebhookSubscriptionOutput{ WebhookSubscription: types.NewWebhookSubscription(subscription), }, nil } func (r *Resolver) DeleteWebhookSubscriptionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteWebhookSubscriptionInput) (*mcp.CallToolResult, types.DeleteWebhookSubscriptionOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionWebhookSubscriptionDelete) if err != nil { return nil, types.DeleteWebhookSubscriptionOutput{}, err } prb := r.proboSvc err = prb.WebhookSubscriptions.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteWebhookSubscriptionOutput{}, fmt.Errorf("failed to delete webhook subscription: %w", err) } return nil, types.DeleteWebhookSubscriptionOutput{ DeletedWebhookSubscriptionID: input.ID, }, nil } func (r *Resolver) ListWebhookEventsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListWebhookEventsInput) (*mcp.CallToolResult, types.ListWebhookEventsOutput, error) { scope, err := r.Authorize(ctx, input.WebhookSubscriptionID, probo.ActionWebhookSubscriptionGet) if err != nil { return nil, types.ListWebhookEventsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.WebhookEventOrderField]{ Field: coredata.WebhookEventOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.WebhookEventOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.WebhookSubscriptions.ListEventsForSubscriptionID(ctx, scope, input.WebhookSubscriptionID, cursor) if err != nil { panic(fmt.Errorf("cannot list webhook events: %w", err)) } return nil, types.NewListWebhookEventsOutput(page), nil } func (r *Resolver) ListDocumentVersionApprovalQuorumsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDocumentVersionApprovalQuorumsInput) (*mcp.CallToolResult, types.ListDocumentVersionApprovalQuorumsOutput, error) { scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionApprovalList) if err != nil { return nil, types.ListDocumentVersionApprovalQuorumsOutput{}, err } svc := r.proboSvc pageOrderBy := page.OrderBy[coredata.DocumentVersionApprovalQuorumOrderField]{ Field: coredata.DocumentVersionApprovalQuorumOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DocumentVersionApprovalQuorumOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := svc.DocumentApprovals.ListQuorums(ctx, scope, input.DocumentVersionID, cursor) if err != nil { panic(fmt.Errorf("cannot list approval quorums: %w", err)) } return nil, types.NewListDocumentVersionApprovalQuorumsOutput(p), nil } func (r *Resolver) GetDocumentVersionApprovalQuorumTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetDocumentVersionApprovalQuorumInput) (*mcp.CallToolResult, types.GetDocumentVersionApprovalQuorumOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentVersionApprovalList) if err != nil { return nil, types.GetDocumentVersionApprovalQuorumOutput{}, err } svc := r.proboSvc quorum, err := svc.DocumentApprovals.GetQuorum(ctx, scope, input.ID) if err != nil { panic(fmt.Errorf("cannot get approval quorum: %w", err)) } return nil, types.GetDocumentVersionApprovalQuorumOutput{ ApprovalQuorum: types.NewDocumentVersionApprovalQuorum(quorum), }, nil } func (r *Resolver) ListDocumentVersionApprovalDecisionsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDocumentVersionApprovalDecisionsInput) (*mcp.CallToolResult, types.ListDocumentVersionApprovalDecisionsOutput, error) { scope, err := r.Authorize(ctx, input.QuorumID, probo.ActionDocumentVersionApprovalList) if err != nil { return nil, types.ListDocumentVersionApprovalDecisionsOutput{}, err } svc := r.proboSvc pageOrderBy := page.OrderBy[coredata.DocumentVersionApprovalDecisionOrderField]{ Field: coredata.DocumentVersionApprovalDecisionOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DocumentVersionApprovalDecisionOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) var states []coredata.DocumentVersionApprovalDecisionState if input.Filter != nil { states = input.Filter.States } filter := coredata.NewDocumentVersionApprovalDecisionFilter(states) p, err := svc.DocumentApprovals.ListDecisions(ctx, scope, input.QuorumID, cursor, filter) if err != nil { panic(fmt.Errorf("cannot list approval decisions: %w", err)) } return nil, types.NewListDocumentVersionApprovalDecisionsOutput(p), nil } func (r *Resolver) GetDocumentVersionApprovalDecisionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetDocumentVersionApprovalDecisionInput) (*mcp.CallToolResult, types.GetDocumentVersionApprovalDecisionOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDocumentVersionApprovalList) if err != nil { return nil, types.GetDocumentVersionApprovalDecisionOutput{}, err } svc := r.proboSvc decision, err := svc.DocumentApprovals.GetDecision(ctx, scope, input.ID) if err != nil { panic(fmt.Errorf("cannot get approval decision: %w", err)) } return nil, types.GetDocumentVersionApprovalDecisionOutput{ ApprovalDecision: types.NewDocumentVersionApprovalDecision(decision), }, nil } func (r *Resolver) PublishDataListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishDataListInput) (*mcp.CallToolResult, types.PublishDataListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionDatumPublish) if err != nil { return nil, types.PublishDataListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishDataList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishDataListOutput{}, fmt.Errorf("cannot publish data list: %w", err) } return nil, types.PublishDataListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) PublishAssetListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishAssetListInput) (*mcp.CallToolResult, types.PublishAssetListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionAssetPublish) if err != nil { return nil, types.PublishAssetListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishAssetList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishAssetListOutput{}, fmt.Errorf("cannot publish asset list: %w", err) } return nil, types.PublishAssetListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } // ListThirdPartyContactsTool handles the listThirdPartyContacts tool // List all contacts for a thirdParty func (r *Resolver) ListThirdPartyContactsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListThirdPartyContactsInput) (*mcp.CallToolResult, types.ListThirdPartyContactsOutput, error) { scope, err := r.Authorize(ctx, input.ThirdPartyID, probo.ActionThirdPartyContactList) if err != nil { return nil, types.ListThirdPartyContactsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ThirdPartyContactOrderField]{ Field: coredata.ThirdPartyContactOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ThirdPartyContactOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := prb.ThirdPartyContacts.List(ctx, scope, input.ThirdPartyID, cursor) if err != nil { return nil, types.ListThirdPartyContactsOutput{}, fmt.Errorf("cannot list thirdParty contacts: %w", err) } return nil, types.NewListThirdPartyContactsOutput(p), nil } // AddThirdPartyContactTool handles the addThirdPartyContact tool // Add a new contact to a thirdParty func (r *Resolver) AddThirdPartyContactTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddThirdPartyContactInput) (*mcp.CallToolResult, types.AddThirdPartyContactOutput, error) { scope, err := r.Authorize(ctx, input.ThirdPartyID, probo.ActionThirdPartyContactCreate) if err != nil { return nil, types.AddThirdPartyContactOutput{}, err } prb := r.proboSvc emailAddr, err := mail.ParseAddr(input.Email) if err != nil { return nil, types.AddThirdPartyContactOutput{}, fmt.Errorf("invalid email address: %w", err) } thirdPartyContact, err := prb.ThirdPartyContacts.Create(ctx, scope, probo.CreateThirdPartyContactRequest{ ThirdPartyID: input.ThirdPartyID, FullName: &input.FullName, Email: &emailAddr, Phone: &input.Phone, Role: &input.Role, }) if err != nil { return nil, types.AddThirdPartyContactOutput{}, fmt.Errorf("cannot create thirdParty contact: %w", err) } return nil, types.AddThirdPartyContactOutput{ ThirdPartyContact: types.NewThirdPartyContact(thirdPartyContact), }, nil } // UpdateThirdPartyContactTool handles the updateThirdPartyContact tool // Update an existing thirdParty contact func (r *Resolver) UpdateThirdPartyContactTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateThirdPartyContactInput) (*mcp.CallToolResult, types.UpdateThirdPartyContactOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyContactUpdate) if err != nil { return nil, types.UpdateThirdPartyContactOutput{}, err } prb := r.proboSvc updateReq := probo.UpdateThirdPartyContactRequest{ ID: input.ID, } if input.FullName != nil { updateReq.FullName = &input.FullName } if input.Email != nil { emailAddr, err := mail.ParseAddr(*input.Email) if err != nil { return nil, types.UpdateThirdPartyContactOutput{}, fmt.Errorf("invalid email address: %w", err) } emailPtr := &emailAddr updateReq.Email = &emailPtr } if input.Phone != nil { updateReq.Phone = &input.Phone } if input.Role != nil { updateReq.Role = &input.Role } thirdPartyContact, err := prb.ThirdPartyContacts.Update(ctx, scope, updateReq) if err != nil { return nil, types.UpdateThirdPartyContactOutput{}, fmt.Errorf("cannot update thirdParty contact: %w", err) } return nil, types.UpdateThirdPartyContactOutput{ ThirdPartyContact: types.NewThirdPartyContact(thirdPartyContact), }, nil } // DeleteThirdPartyContactTool handles the deleteThirdPartyContact tool // Delete a thirdParty contact func (r *Resolver) DeleteThirdPartyContactTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteThirdPartyContactInput) (*mcp.CallToolResult, types.DeleteThirdPartyContactOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyContactDelete) if err != nil { return nil, types.DeleteThirdPartyContactOutput{}, err } prb := r.proboSvc err = prb.ThirdPartyContacts.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteThirdPartyContactOutput{}, fmt.Errorf("cannot delete thirdParty contact: %w", err) } return nil, types.DeleteThirdPartyContactOutput{ DeletedThirdPartyContactID: input.ID, }, nil } // ListThirdPartyServicesTool handles the listThirdPartyServices tool // List all services for a thirdParty func (r *Resolver) ListThirdPartyServicesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListThirdPartyServicesInput) (*mcp.CallToolResult, types.ListThirdPartyServicesOutput, error) { scope, err := r.Authorize(ctx, input.ThirdPartyID, probo.ActionThirdPartyServiceList) if err != nil { return nil, types.ListThirdPartyServicesOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.ThirdPartyServiceOrderField]{ Field: coredata.ThirdPartyServiceOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ThirdPartyServiceOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := prb.ThirdPartyServices.List(ctx, scope, input.ThirdPartyID, cursor) if err != nil { return nil, types.ListThirdPartyServicesOutput{}, fmt.Errorf("cannot list thirdParty services: %w", err) } return nil, types.NewListThirdPartyServicesOutput(p), nil } // AddThirdPartyServiceTool handles the addThirdPartyService tool // Add a new service to a thirdParty func (r *Resolver) AddThirdPartyServiceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddThirdPartyServiceInput) (*mcp.CallToolResult, types.AddThirdPartyServiceOutput, error) { scope, err := r.Authorize(ctx, input.ThirdPartyID, probo.ActionThirdPartyServiceCreate) if err != nil { return nil, types.AddThirdPartyServiceOutput{}, err } prb := r.proboSvc thirdPartyService, err := prb.ThirdPartyServices.Create(ctx, scope, probo.CreateThirdPartyServiceRequest{ ThirdPartyID: input.ThirdPartyID, Name: input.Name, Description: input.Description, }) if err != nil { return nil, types.AddThirdPartyServiceOutput{}, fmt.Errorf("cannot create thirdParty service: %w", err) } return nil, types.AddThirdPartyServiceOutput{ ThirdPartyService: types.NewThirdPartyService(thirdPartyService), }, nil } // UpdateThirdPartyServiceTool handles the updateThirdPartyService tool // Update an existing thirdParty service func (r *Resolver) UpdateThirdPartyServiceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateThirdPartyServiceInput) (*mcp.CallToolResult, types.UpdateThirdPartyServiceOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyServiceUpdate) if err != nil { return nil, types.UpdateThirdPartyServiceOutput{}, err } prb := r.proboSvc updateReq := probo.UpdateThirdPartyServiceRequest{ ID: input.ID, } if input.Name != nil { updateReq.Name = input.Name } if input.Description != nil { updateReq.Description = &input.Description } thirdPartyService, err := prb.ThirdPartyServices.Update(ctx, scope, updateReq) if err != nil { return nil, types.UpdateThirdPartyServiceOutput{}, fmt.Errorf("cannot update thirdParty service: %w", err) } return nil, types.UpdateThirdPartyServiceOutput{ ThirdPartyService: types.NewThirdPartyService(thirdPartyService), }, nil } // DeleteThirdPartyServiceTool handles the deleteThirdPartyService tool // Delete a thirdParty service func (r *Resolver) DeleteThirdPartyServiceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteThirdPartyServiceInput) (*mcp.CallToolResult, types.DeleteThirdPartyServiceOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyServiceDelete) if err != nil { return nil, types.DeleteThirdPartyServiceOutput{}, err } prb := r.proboSvc err = prb.ThirdPartyServices.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteThirdPartyServiceOutput{}, fmt.Errorf("cannot delete thirdParty service: %w", err) } return nil, types.DeleteThirdPartyServiceOutput{ DeletedThirdPartyServiceID: input.ID, }, nil } func (r *Resolver) DeleteAssetTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteAssetInput) (*mcp.CallToolResult, types.DeleteAssetOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionAssetDelete) if err != nil { return nil, types.DeleteAssetOutput{}, err } svc := r.proboSvc err = svc.Assets.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteAssetOutput{}, fmt.Errorf("failed to delete asset: %w", err) } return nil, types.DeleteAssetOutput{ DeletedAssetID: input.ID, }, nil } func (r *Resolver) DeleteDatumTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteDatumInput) (*mcp.CallToolResult, types.DeleteDatumOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionDatumDelete) if err != nil { return nil, types.DeleteDatumOutput{}, err } svc := r.proboSvc err = svc.Data.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteDatumOutput{}, fmt.Errorf("failed to delete datum: %w", err) } return nil, types.DeleteDatumOutput{ DeletedDatumID: input.ID, }, nil } func (r *Resolver) DeleteObligationTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteObligationInput) (*mcp.CallToolResult, types.DeleteObligationOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionObligationDelete) if err != nil { return nil, types.DeleteObligationOutput{}, err } svc := r.proboSvc err = svc.Obligations.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteObligationOutput{}, fmt.Errorf("failed to delete obligation: %w", err) } return nil, types.DeleteObligationOutput{ DeletedObligationID: input.ID, }, nil } func (r *Resolver) DeleteAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteAuditInput) (*mcp.CallToolResult, types.DeleteAuditOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionAuditDelete) if err != nil { return nil, types.DeleteAuditOutput{}, err } svc := r.proboSvc err = svc.Audits.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteAuditOutput{}, fmt.Errorf("failed to delete audit: %w", err) } return nil, types.DeleteAuditOutput{ DeletedAuditID: input.ID, }, nil } func (r *Resolver) ListRightsRequestsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRightsRequestsInput) (*mcp.CallToolResult, types.ListRightsRequestsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionRightsRequestList) if err != nil { return nil, types.ListRightsRequestsOutput{}, err } prb := r.proboSvc pageOrderBy := page.OrderBy[coredata.RightsRequestOrderField]{ Field: coredata.RightsRequestOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RightsRequestOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := prb.RightsRequests.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list organization rights requests: %w", err)) } return nil, types.NewListRightsRequestsOutput(page), nil } func (r *Resolver) GetRightsRequestTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRightsRequestInput) (*mcp.CallToolResult, types.GetRightsRequestOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRightsRequestGet) if err != nil { return nil, types.GetRightsRequestOutput{}, err } prb := r.proboSvc rightsRequest, err := prb.RightsRequests.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetRightsRequestOutput{}, fmt.Errorf("failed to get rights request: %w", err) } return nil, types.GetRightsRequestOutput{ RightsRequest: types.NewRightsRequest(rightsRequest), }, nil } func (r *Resolver) AddRightsRequestTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRightsRequestInput) (*mcp.CallToolResult, types.AddRightsRequestOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionRightsRequestCreate) if err != nil { return nil, types.AddRightsRequestOutput{}, err } svc := r.proboSvc rightsRequest, err := svc.RightsRequests.Create( ctx, scope, &probo.CreateRightsRequestRequest{ OrganizationID: input.OrganizationID, RequestType: &input.RequestType, RequestState: &input.RequestState, DataSubject: &input.DataSubject, Contact: input.Contact, Details: input.Details, Deadline: input.Deadline, ActionTaken: input.ActionTaken, }, ) if err != nil { return nil, types.AddRightsRequestOutput{}, fmt.Errorf("failed to create rights request: %w", err) } return nil, types.AddRightsRequestOutput{ RightsRequest: types.NewRightsRequest(rightsRequest), }, nil } func (r *Resolver) UpdateRightsRequestTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRightsRequestInput) (*mcp.CallToolResult, types.UpdateRightsRequestOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRightsRequestUpdate) if err != nil { return nil, types.UpdateRightsRequestOutput{}, err } svc := r.proboSvc var dataSubject **string if input.DataSubject != nil { dataSubject = &input.DataSubject } rightsRequest, err := svc.RightsRequests.Update( ctx, scope, &probo.UpdateRightsRequestRequest{ ID: input.ID, RequestType: input.RequestType, RequestState: input.RequestState, DataSubject: dataSubject, Contact: UnwrapOmittable(input.Contact), Details: UnwrapOmittable(input.Details), Deadline: UnwrapOmittable(input.Deadline), ActionTaken: UnwrapOmittable(input.ActionTaken), }, ) if err != nil { return nil, types.UpdateRightsRequestOutput{}, fmt.Errorf("failed to update rights request: %w", err) } return nil, types.UpdateRightsRequestOutput{ RightsRequest: types.NewRightsRequest(rightsRequest), }, nil } func (r *Resolver) DeleteRightsRequestTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRightsRequestInput) (*mcp.CallToolResult, types.DeleteRightsRequestOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRightsRequestDelete) if err != nil { return nil, types.DeleteRightsRequestOutput{}, err } svc := r.proboSvc err = svc.RightsRequests.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteRightsRequestOutput{}, fmt.Errorf("failed to delete rights request: %w", err) } return nil, types.DeleteRightsRequestOutput{ DeletedRightsRequestID: input.ID, }, nil } // GetCompliancePortalTool handles the getCompliancePortal tool // Get the compliance portal for an organization func (r *Resolver) GetCompliancePortalTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetCompliancePortalInput) (*mcp.CallToolResult, types.GetCompliancePortalOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, management.ActionCompliancePortalGet) if err != nil { return nil, types.GetCompliancePortalOutput{}, err } prb := r.management compliancePortal, err := prb.GetByOrganizationID(ctx, scope, input.OrganizationID) if err != nil { return nil, types.GetCompliancePortalOutput{}, fmt.Errorf("cannot get compliance portal: %w", err) } tc := types.NewCompliancePortal(compliancePortal) if compliancePortal.LogoFileID != nil { logo, err := r.loadFile(ctx, scope, *compliancePortal.LogoFileID) if err != nil { return nil, types.GetCompliancePortalOutput{}, err } tc.Logo = logo } if compliancePortal.DarkLogoFileID != nil { darkLogo, err := r.loadFile(ctx, scope, *compliancePortal.DarkLogoFileID) if err != nil { return nil, types.GetCompliancePortalOutput{}, err } tc.DarkLogo = darkLogo } if compliancePortal.NonDisclosureAgreementFileID != nil { nda, err := r.loadFile(ctx, scope, *compliancePortal.NonDisclosureAgreementFileID) if err != nil { return nil, types.GetCompliancePortalOutput{}, err } tc.Nda = nda } return nil, types.GetCompliancePortalOutput{CompliancePortal: tc}, nil } // UpdateCompliancePortalTool handles the updateCompliancePortal tool // Update the compliance portal settings func (r *Resolver) UpdateCompliancePortalTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateCompliancePortalInput) (*mcp.CallToolResult, types.UpdateCompliancePortalOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionCompliancePortalUpdate) if err != nil { return nil, types.UpdateCompliancePortalOutput{}, err } prb := r.management updateReq := &management.UpdateRequest{ ID: input.CompliancePortalID, } if active := UnwrapOmittable(input.Active); active != nil { updateReq.Active = *active } if sei := UnwrapOmittable(input.SearchEngineIndexing); sei != nil { updateReq.SearchEngineIndexing = *sei } updateReq.Description = UnwrapOmittable(input.Description) updateReq.WebsiteURL = UnwrapOmittable(input.WebsiteURL) updateReq.Email = UnwrapOmittable(input.Email) updateReq.HeadquarterAddress = UnwrapOmittable(input.HeadquarterAddress) if entityName := UnwrapOmittable(input.EntityName); entityName != nil { updateReq.EntityName = *entityName } compliancePortal, _, err := prb.Update(ctx, scope, updateReq) if err != nil { return nil, types.UpdateCompliancePortalOutput{}, fmt.Errorf("cannot update compliance portal: %w", err) } return nil, types.UpdateCompliancePortalOutput{CompliancePortal: types.NewCompliancePortal(compliancePortal)}, nil } // ListCompliancePortalReferencesTool handles the listCompliancePortalReferences tool // List all references for a compliance portal func (r *Resolver) ListCompliancePortalReferencesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCompliancePortalReferencesInput) (*mcp.CallToolResult, types.ListCompliancePortalReferencesOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionCompliancePortalReferenceList) if err != nil { return nil, types.ListCompliancePortalReferencesOutput{}, err } prb := r.management pageOrderBy := page.OrderBy[coredata.CompliancePortalReferenceOrderField]{ Field: coredata.CompliancePortalReferenceOrderFieldRank, Direction: page.OrderDirectionAsc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.CompliancePortalReferenceOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := prb.ListReferences(ctx, scope, input.CompliancePortalID, cursor) if err != nil { return nil, types.ListCompliancePortalReferencesOutput{}, fmt.Errorf("cannot list compliance portal references: %w", err) } refs := make([]*types.CompliancePortalReference, 0, len(p.Data)) for _, reference := range p.Data { ref := types.NewCompliancePortalReference(reference) logo, err := r.loadFile(ctx, scope, reference.LogoFileID) if err != nil { return nil, types.ListCompliancePortalReferencesOutput{}, err } ref.Logo = logo refs = append(refs, ref) } return nil, types.NewListCompliancePortalReferencesOutput(refs, p), nil } // AddCompliancePortalReferenceTool handles the addCompliancePortalReference tool // Add a new reference to the compliance portal func (r *Resolver) AddCompliancePortalReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddCompliancePortalReferenceInput) (*mcp.CallToolResult, types.AddCompliancePortalReferenceOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionCompliancePortalReferenceCreate) if err != nil { return nil, types.AddCompliancePortalReferenceOutput{}, err } prb := r.management var websiteURL string if input.WebsiteURL != nil { websiteURL = *input.WebsiteURL } reference, err := prb.CreateReference( ctx, scope, &management.CreateReferenceRequest{ CompliancePortalID: input.CompliancePortalID, Name: input.Name, Description: input.Description, WebsiteURL: websiteURL, }, ) if err != nil { return nil, types.AddCompliancePortalReferenceOutput{}, fmt.Errorf("cannot add compliance portal reference: %w", err) } return nil, types.AddCompliancePortalReferenceOutput{CompliancePortalReference: types.NewCompliancePortalReference(reference)}, nil } // UpdateCompliancePortalReferenceTool handles the updateCompliancePortalReference tool // Update a compliance portal reference func (r *Resolver) UpdateCompliancePortalReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateCompliancePortalReferenceInput) (*mcp.CallToolResult, types.UpdateCompliancePortalReferenceOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalReferenceUpdate) if err != nil { return nil, types.UpdateCompliancePortalReferenceOutput{}, err } prb := r.management updateRefReq := &management.UpdateReferenceRequest{ ID: input.ID, Description: UnwrapOmittable(input.Description), } if name := UnwrapOmittable(input.Name); name != nil { updateRefReq.Name = *name } if websiteURL := UnwrapOmittable(input.WebsiteURL); websiteURL != nil { updateRefReq.WebsiteURL = *websiteURL } if rank := UnwrapOmittable(input.Rank); rank != nil { updateRefReq.Rank = *rank } reference, err := prb.UpdateReference(ctx, scope, updateRefReq) if err != nil { return nil, types.UpdateCompliancePortalReferenceOutput{}, fmt.Errorf("cannot update compliance portal reference: %w", err) } return nil, types.UpdateCompliancePortalReferenceOutput{CompliancePortalReference: types.NewCompliancePortalReference(reference)}, nil } // DeleteCompliancePortalReferenceTool handles the deleteCompliancePortalReference tool // Delete a compliance portal reference func (r *Resolver) DeleteCompliancePortalReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCompliancePortalReferenceInput) (*mcp.CallToolResult, types.DeleteCompliancePortalReferenceOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalReferenceDelete) if err != nil { return nil, types.DeleteCompliancePortalReferenceOutput{}, err } prb := r.management err = prb.DeleteReference(ctx, scope, input.ID) if err != nil { return nil, types.DeleteCompliancePortalReferenceOutput{}, fmt.Errorf("cannot delete compliance portal reference: %w", err) } return nil, types.DeleteCompliancePortalReferenceOutput{DeletedCompliancePortalReferenceID: input.ID}, nil } // ListCompliancePortalFilesTool handles the listCompliancePortalFiles tool // List all files for the compliance portal func (r *Resolver) ListCompliancePortalFilesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCompliancePortalFilesInput) (*mcp.CallToolResult, types.ListCompliancePortalFilesOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, management.ActionCompliancePortalFileList) if err != nil { return nil, types.ListCompliancePortalFilesOutput{}, err } prb := r.management pageOrderBy := page.OrderBy[coredata.CompliancePortalFileOrderField]{ Field: coredata.CompliancePortalFileOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.CompliancePortalFileOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) filter := coredata.NewCompliancePortalFileFilter() p, err := prb.ListFilesForOrganizationID(ctx, scope, input.OrganizationID, cursor, filter) if err != nil { return nil, types.ListCompliancePortalFilesOutput{}, fmt.Errorf("cannot list compliance portal files: %w", err) } files := make([]*types.CompliancePortalFile, 0, len(p.Data)) for _, f := range p.Data { file, err := r.loadFile(ctx, scope, f.FileID) if err != nil { return nil, types.ListCompliancePortalFilesOutput{}, err } files = append(files, types.NewCompliancePortalFile(f, file)) } return nil, types.NewListCompliancePortalFilesOutput(files, p), nil } // DeleteCompliancePortalFileTool handles the deleteCompliancePortalFile tool // Delete a compliance portal file func (r *Resolver) DeleteCompliancePortalFileTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCompliancePortalFileInput) (*mcp.CallToolResult, types.DeleteCompliancePortalFileOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalFileDelete) if err != nil { return nil, types.DeleteCompliancePortalFileOutput{}, err } prb := r.management err = prb.DeleteFile(ctx, scope, input.ID) if err != nil { return nil, types.DeleteCompliancePortalFileOutput{}, fmt.Errorf("cannot delete compliance portal file: %w", err) } return nil, types.DeleteCompliancePortalFileOutput{DeletedCompliancePortalFileID: input.ID}, nil } // ListComplianceCustomLinksTool handles the listComplianceCustomLinks tool // List all custom links for a compliance portal func (r *Resolver) ListComplianceCustomLinksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListComplianceCustomLinksInput) (*mcp.CallToolResult, types.ListComplianceCustomLinksOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionComplianceCustomLinkList) if err != nil { return nil, types.ListComplianceCustomLinksOutput{}, err } prb := r.management pageOrderBy := page.OrderBy[coredata.ComplianceCustomLinkOrderField]{ Field: coredata.ComplianceCustomLinkOrderFieldRank, Direction: page.OrderDirectionAsc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ComplianceCustomLinkOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := prb.ListCustomLinks(ctx, scope, input.CompliancePortalID, cursor) if err != nil { return nil, types.ListComplianceCustomLinksOutput{}, fmt.Errorf("cannot list compliance custom links: %w", err) } return nil, types.NewListComplianceCustomLinksOutput(p), nil } // AddComplianceCustomLinkTool handles the addComplianceCustomLink tool // Add a new custom link to the compliance portal func (r *Resolver) AddComplianceCustomLinkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddComplianceCustomLinkInput) (*mcp.CallToolResult, types.AddComplianceCustomLinkOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionComplianceCustomLinkCreate) if err != nil { return nil, types.AddComplianceCustomLinkOutput{}, err } prb := r.management item, err := prb.CreateCustomLink( ctx, scope, &management.CreateCustomLinkRequest{ CompliancePortalID: input.CompliancePortalID, Name: input.Name, URL: input.URL, }, ) if err != nil { return nil, types.AddComplianceCustomLinkOutput{}, fmt.Errorf("cannot add compliance custom link: %w", err) } return nil, types.AddComplianceCustomLinkOutput{ComplianceCustomLink: types.NewComplianceCustomLink(item)}, nil } // UpdateComplianceCustomLinkTool handles the updateComplianceCustomLink tool // Update a compliance custom link func (r *Resolver) UpdateComplianceCustomLinkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateComplianceCustomLinkInput) (*mcp.CallToolResult, types.UpdateComplianceCustomLinkOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionComplianceCustomLinkUpdate) if err != nil { return nil, types.UpdateComplianceCustomLinkOutput{}, err } prb := r.management updateURLReq := &management.UpdateCustomLinkRequest{ ID: input.ID, } if name := UnwrapOmittable(input.Name); name != nil && *name != nil { updateURLReq.Name = **name } if u := UnwrapOmittable(input.URL); u != nil && *u != nil { updateURLReq.URL = **u } if rank := UnwrapOmittable(input.Rank); rank != nil { updateURLReq.Rank = *rank } item, err := prb.UpdateCustomLink(ctx, scope, updateURLReq) if err != nil { return nil, types.UpdateComplianceCustomLinkOutput{}, fmt.Errorf("cannot update compliance custom link: %w", err) } return nil, types.UpdateComplianceCustomLinkOutput{ComplianceCustomLink: types.NewComplianceCustomLink(item)}, nil } // DeleteComplianceCustomLinkTool handles the deleteComplianceCustomLink tool // Delete a compliance custom link func (r *Resolver) DeleteComplianceCustomLinkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteComplianceCustomLinkInput) (*mcp.CallToolResult, types.DeleteComplianceCustomLinkOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionComplianceCustomLinkDelete) if err != nil { return nil, types.DeleteComplianceCustomLinkOutput{}, err } prb := r.management err = prb.DeleteCustomLink( ctx, scope, &management.DeleteCustomLinkRequest{ ID: input.ID, }, ) if err != nil { return nil, types.DeleteComplianceCustomLinkOutput{}, fmt.Errorf("cannot delete compliance custom link: %w", err) } return nil, types.DeleteComplianceCustomLinkOutput{DeletedComplianceCustomLinkID: input.ID}, nil } // CreateCustomDomainTool handles the createCustomDomain tool // Create a custom domain for a compliance page func (r *Resolver) CreateCustomDomainTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateCustomDomainInput) (*mcp.CallToolResult, types.CreateCustomDomainOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionCustomDomainCreate) if err != nil { return nil, types.CreateCustomDomainOutput{}, err } domain, err := r.management.AddCustomDomain( ctx, scope, input.CompliancePortalID, input.Domain, ) if err != nil { return nil, types.CreateCustomDomainOutput{}, fmt.Errorf("cannot create custom domain: %w", err) } var cert *coredata.Certificate if domain.CertificateID != nil { cert, err = r.certManager.Get(ctx, scope, *domain.CertificateID) if err != nil { return nil, types.CreateCustomDomainOutput{}, fmt.Errorf("cannot load certificate: %w", err) } } return nil, types.CreateCustomDomainOutput{CustomDomain: types.NewCustomDomain(domain, cert)}, nil } // DeleteCustomDomainTool handles the deleteCustomDomain tool // Delete the custom domain of a compliance page func (r *Resolver) DeleteCustomDomainTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCustomDomainInput) (*mcp.CallToolResult, types.DeleteCustomDomainOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionCustomDomainDelete) if err != nil { return nil, types.DeleteCustomDomainOutput{}, err } compliancePage, err := r.management.Get(ctx, scope, input.CompliancePortalID) if err != nil { return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("cannot load compliance page: %w", err) } if compliancePage.CustomDomainID == nil { return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("compliance page has no custom domain") } domain, err := r.management.GetDomain(ctx, scope, *compliancePage.CustomDomainID) if err != nil { return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("cannot get custom domain: %w", err) } var cert *coredata.Certificate if domain.CertificateID != nil { cert, err = r.certManager.Get(ctx, scope, *domain.CertificateID) if err != nil { return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("cannot load certificate: %w", err) } } deletedDomain := types.NewCustomDomain(domain, cert) if err := r.management.RemoveCustomDomain(ctx, scope, domain.ID); err != nil { return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("cannot delete custom domain: %w", err) } return nil, types.DeleteCustomDomainOutput{DeletedCustomDomain: deletedDomain}, nil } func (r *Resolver) VetThirdPartyTool(ctx context.Context, req *mcp.CallToolRequest, input *types.VetThirdPartyInput) (*mcp.CallToolResult, types.VetThirdPartyOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyVet) if err != nil { return nil, types.VetThirdPartyOutput{}, err } svc := r.thirdPartySvc thirdParty, err := svc.Vet( ctx, scope, thirdparty.VetRequest{ ID: input.ID, WebsiteURL: input.WebsiteURL, Procedure: input.Procedure, }, ) if err != nil { if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok { return nil, types.VetThirdPartyOutput{}, validationErrors } if errors.Is(err, coredata.ErrResourceNotFound) { return nil, types.VetThirdPartyOutput{}, fmt.Errorf("resource not found") } if errors.Is(err, thirdparty.ErrVettingDisabled) { return nil, types.VetThirdPartyOutput{}, fmt.Errorf("vetting is not configured") } if errors.Is(err, thirdparty.ErrVettingInProgress) { return nil, types.VetThirdPartyOutput{}, fmt.Errorf("vetting is already in progress") } r.logger.ErrorCtx(ctx, "cannot vet thirdParty", log.Error(err)) return nil, types.VetThirdPartyOutput{}, fmt.Errorf("internal server error") } return nil, types.VetThirdPartyOutput{ ThirdParty: types.NewThirdParty(thirdParty), }, nil } func (r *Resolver) PublishFindingListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishFindingListInput) (*mcp.CallToolResult, types.PublishFindingListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionFindingPublish) if err != nil { return nil, types.PublishFindingListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishFindingList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishFindingListOutput{}, fmt.Errorf("cannot publish finding list: %w", err) } return nil, types.PublishFindingListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) PublishObligationListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishObligationListInput) (*mcp.CallToolResult, types.PublishObligationListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionObligationPublish) if err != nil { return nil, types.PublishObligationListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishObligationList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishObligationListOutput{}, fmt.Errorf("cannot publish obligation list: %w", err) } return nil, types.PublishObligationListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) PublishProcessingActivityListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishProcessingActivityListInput) (*mcp.CallToolResult, types.PublishProcessingActivityListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionProcessingActivityPublish) if err != nil { return nil, types.PublishProcessingActivityListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishProcessingActivityList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishProcessingActivityListOutput{}, fmt.Errorf("cannot publish processing activity list: %w", err) } return nil, types.PublishProcessingActivityListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) PublishDataProtectionImpactAssessmentListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishDataProtectionImpactAssessmentListInput) (*mcp.CallToolResult, types.PublishDataProtectionImpactAssessmentListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionDataProtectionImpactAssessmentPublish) if err != nil { return nil, types.PublishDataProtectionImpactAssessmentListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishDataProtectionImpactAssessmentList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishDataProtectionImpactAssessmentListOutput{}, fmt.Errorf("cannot publish DPIA list: %w", err) } return nil, types.PublishDataProtectionImpactAssessmentListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) PublishTransferImpactAssessmentListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishTransferImpactAssessmentListInput) (*mcp.CallToolResult, types.PublishTransferImpactAssessmentListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionTransferImpactAssessmentPublish) if err != nil { return nil, types.PublishTransferImpactAssessmentListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishTransferImpactAssessmentList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishTransferImpactAssessmentListOutput{}, fmt.Errorf("cannot publish TIA list: %w", err) } return nil, types.PublishTransferImpactAssessmentListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) PublishThirdPartyListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishThirdPartyListInput) (*mcp.CallToolResult, types.PublishThirdPartyListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionThirdPartyPublish) if err != nil { return nil, types.PublishThirdPartyListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishThirdPartyList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishThirdPartyListOutput{}, fmt.Errorf("cannot publish thirdParty list: %w", err) } return nil, types.PublishThirdPartyListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) ListCookieBannersTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCookieBannersInput) (*mcp.CallToolResult, types.ListCookieBannersOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionCookieBannerList) if err != nil { return nil, types.ListCookieBannersOutput{}, err } cursor := types.NewCursor(input.Size, input.Cursor, page.OrderBy[coredata.CookieBannerOrderField]{Field: coredata.CookieBannerOrderFieldCreatedAt, Direction: page.OrderDirectionDesc}) banners, err := r.cookieBanner.ListCookieBannersForOrganization(ctx, scope, input.OrganizationID, cursor, coredata.NewCookieBannerFilter(nil)) if err != nil { panic(fmt.Errorf("cannot list cookie banners: %w", err)) } p := page.NewPage(banners, cursor) return nil, types.NewListCookieBannersOutput(p), nil } func (r *Resolver) GetCookieBannerTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetCookieBannerInput) (*mcp.CallToolResult, types.GetCookieBannerOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieBannerGet) if err != nil { return nil, types.GetCookieBannerOutput{}, err } banner, err := r.cookieBanner.GetCookieBanner(ctx, scope, input.ID) if err != nil { return nil, types.GetCookieBannerOutput{}, fmt.Errorf("cannot get cookie banner: %w", err) } return nil, types.GetCookieBannerOutput{CookieBanner: types.NewCookieBanner(banner)}, nil } func (r *Resolver) AddCookieBannerTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddCookieBannerInput) (*mcp.CallToolResult, types.AddCookieBannerOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionCookieBannerCreate) if err != nil { return nil, types.AddCookieBannerOutput{}, err } banner, err := r.cookieBanner.CreateCookieBanner(ctx, scope, cookiebanner.CreateCookieBannerRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Origin: input.Origin, PrivacyPolicyURL: input.PrivacyPolicyURL, CookiePolicyURL: input.CookiePolicyURL, ConsentExpiryDays: input.ConsentExpiryDays, }) if err != nil { return nil, types.AddCookieBannerOutput{}, fmt.Errorf("cannot create cookie banner: %w", err) } return nil, types.AddCookieBannerOutput{CookieBanner: types.NewCookieBanner(banner)}, nil } func (r *Resolver) UpdateCookieBannerTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateCookieBannerInput) (*mcp.CallToolResult, types.UpdateCookieBannerOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieBannerUpdate) if err != nil { return nil, types.UpdateCookieBannerOutput{}, err } updateReq := cookiebanner.UpdateCookieBannerRequest{CookieBannerID: input.ID} if v := UnwrapOmittable(input.Name); v != nil && *v != nil { updateReq.Name = *v } if v := UnwrapOmittable(input.PrivacyPolicyURL); v != nil && *v != nil { updateReq.PrivacyPolicyURL = *v } if v := UnwrapOmittable(input.CookiePolicyURL); v != nil && *v != nil { updateReq.CookiePolicyURL = *v } if v := UnwrapOmittable(input.ConsentExpiryDays); v != nil && *v != nil { updateReq.ConsentExpiryDays = *v } if v := UnwrapOmittable(input.DefaultLanguage); v != nil && *v != nil { updateReq.DefaultLanguage = *v } banner, err := r.cookieBanner.UpdateCookieBanner(ctx, scope, updateReq) if err != nil { return nil, types.UpdateCookieBannerOutput{}, fmt.Errorf("cannot update cookie banner: %w", err) } return nil, types.UpdateCookieBannerOutput{CookieBanner: types.NewCookieBanner(banner)}, nil } func (r *Resolver) DeleteCookieBannerTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCookieBannerInput) (*mcp.CallToolResult, types.DeleteCookieBannerOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieBannerDelete) if err != nil { return nil, types.DeleteCookieBannerOutput{}, err } if err := r.cookieBanner.DeleteCookieBanner(ctx, scope, input.ID); err != nil { return nil, types.DeleteCookieBannerOutput{}, fmt.Errorf("cannot delete cookie banner: %w", err) } return nil, types.DeleteCookieBannerOutput{DeletedID: input.ID}, nil } func (r *Resolver) ActivateCookieBannerTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ActivateCookieBannerInput) (*mcp.CallToolResult, types.ActivateCookieBannerOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieBannerActivate) if err != nil { return nil, types.ActivateCookieBannerOutput{}, err } banner, err := r.cookieBanner.ActivateCookieBanner(ctx, scope, input.ID) if err != nil { return nil, types.ActivateCookieBannerOutput{}, fmt.Errorf("cannot activate cookie banner: %w", err) } return nil, types.ActivateCookieBannerOutput{CookieBanner: types.NewCookieBanner(banner)}, nil } func (r *Resolver) DeactivateCookieBannerTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeactivateCookieBannerInput) (*mcp.CallToolResult, types.DeactivateCookieBannerOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieBannerDeactivate) if err != nil { return nil, types.DeactivateCookieBannerOutput{}, err } banner, err := r.cookieBanner.DeactivateCookieBanner(ctx, scope, input.ID) if err != nil { return nil, types.DeactivateCookieBannerOutput{}, fmt.Errorf("cannot deactivate cookie banner: %w", err) } return nil, types.DeactivateCookieBannerOutput{CookieBanner: types.NewCookieBanner(banner)}, nil } func (r *Resolver) ListCookieCategoriesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCookieCategoriesInput) (*mcp.CallToolResult, types.ListCookieCategoriesOutput, error) { scope, err := r.Authorize(ctx, input.CookieBannerID, probo.ActionCookieCategoryList) if err != nil { return nil, types.ListCookieCategoriesOutput{}, err } cursor := types.NewCursor(input.Size, input.Cursor, page.OrderBy[coredata.CookieCategoryOrderField]{Field: coredata.CookieCategoryOrderFieldRank, Direction: page.OrderDirectionAsc}) categories, err := r.cookieBanner.ListCategoriesForBanner(ctx, scope, input.CookieBannerID, cursor, coredata.NewCookieCategoryFilter(new(coredata.CookieCategoryKindUncategorised))) if err != nil { panic(fmt.Errorf("cannot list cookie categories: %w", err)) } p := page.NewPage(categories, cursor) return nil, types.NewListCookieCategoriesOutput(p), nil } func (r *Resolver) GetCookieCategoryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetCookieCategoryInput) (*mcp.CallToolResult, types.GetCookieCategoryOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieCategoryGet) if err != nil { return nil, types.GetCookieCategoryOutput{}, err } category, err := r.cookieBanner.GetCookieCategory(ctx, scope, input.ID) if err != nil { return nil, types.GetCookieCategoryOutput{}, fmt.Errorf("cannot get cookie category: %w", err) } return nil, types.GetCookieCategoryOutput{CookieCategory: types.NewCookieCategory(category)}, nil } func (r *Resolver) AddCookieCategoryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddCookieCategoryInput) (*mcp.CallToolResult, types.AddCookieCategoryOutput, error) { scope, err := r.Authorize(ctx, input.CookieBannerID, probo.ActionCookieCategoryCreate) if err != nil { return nil, types.AddCookieCategoryOutput{}, err } category, err := r.cookieBanner.CreateCookieCategory(ctx, scope, cookiebanner.CreateCookieCategoryRequest{ CookieBannerID: input.CookieBannerID, Name: input.Name, Slug: input.Slug, Description: input.Description, Rank: input.Rank, }) if err != nil { return nil, types.AddCookieCategoryOutput{}, fmt.Errorf("cannot create cookie category: %w", err) } return nil, types.AddCookieCategoryOutput{CookieCategory: types.NewCookieCategory(category)}, nil } func (r *Resolver) UpdateCookieCategoryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateCookieCategoryInput) (*mcp.CallToolResult, types.UpdateCookieCategoryOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieCategoryUpdate) if err != nil { return nil, types.UpdateCookieCategoryOutput{}, err } updateReq := cookiebanner.UpdateCookieCategoryRequest{CookieCategoryID: input.ID} if v := UnwrapOmittable(input.Name); v != nil && *v != nil { updateReq.Name = *v } if v := UnwrapOmittable(input.Slug); v != nil && *v != nil { updateReq.Slug = *v } if v := UnwrapOmittable(input.Description); v != nil && *v != nil { updateReq.Description = *v } category, err := r.cookieBanner.UpdateCookieCategory(ctx, scope, updateReq) if err != nil { return nil, types.UpdateCookieCategoryOutput{}, fmt.Errorf("cannot update cookie category: %w", err) } return nil, types.UpdateCookieCategoryOutput{CookieCategory: types.NewCookieCategory(category)}, nil } func (r *Resolver) DeleteCookieCategoryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCookieCategoryInput) (*mcp.CallToolResult, types.DeleteCookieCategoryOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieCategoryDelete) if err != nil { return nil, types.DeleteCookieCategoryOutput{}, err } if err := r.cookieBanner.DeleteCookieCategory(ctx, scope, input.ID); err != nil { return nil, types.DeleteCookieCategoryOutput{}, fmt.Errorf("cannot delete cookie category: %w", err) } return nil, types.DeleteCookieCategoryOutput{DeletedID: input.ID}, nil } func (r *Resolver) ReorderCookieCategoryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ReorderCookieCategoryInput) (*mcp.CallToolResult, types.ReorderCookieCategoryOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieCategoryUpdate) if err != nil { return nil, types.ReorderCookieCategoryOutput{}, err } _, err = r.cookieBanner.ReorderCookieCategory(ctx, scope, cookiebanner.ReorderCookieCategoryRequest{ CookieCategoryID: input.ID, Rank: input.Rank, }) if err != nil { return nil, types.ReorderCookieCategoryOutput{}, fmt.Errorf("cannot reorder cookie category: %w", err) } category, err := r.cookieBanner.GetCookieCategory(ctx, scope, input.ID) if err != nil { return nil, types.ReorderCookieCategoryOutput{}, fmt.Errorf("cannot get cookie category: %w", err) } return nil, types.ReorderCookieCategoryOutput{CookieCategory: types.NewCookieCategory(category)}, nil } func (r *Resolver) ListTrackerPatternsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListTrackerPatternsInput) (*mcp.CallToolResult, types.ListTrackerPatternsOutput, error) { scope, err := r.Authorize(ctx, input.CookieCategoryID, probo.ActionTrackerPatternList) if err != nil { return nil, types.ListTrackerPatternsOutput{}, err } cursor := types.NewCursor(input.Size, input.Cursor, page.OrderBy[coredata.TrackerPatternOrderField]{Field: coredata.TrackerPatternOrderFieldCreatedAt, Direction: page.OrderDirectionAsc}) patterns, err := r.cookieBanner.ListTrackerPatternsForCategory(ctx, scope, input.CookieCategoryID, cursor) if err != nil { panic(fmt.Errorf("cannot list tracker patterns: %w", err)) } p := page.NewPage(patterns, cursor) return nil, types.NewListTrackerPatternsOutput(p), nil } func (r *Resolver) GetTrackerPatternTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetTrackerPatternInput) (*mcp.CallToolResult, types.GetTrackerPatternOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTrackerPatternGet) if err != nil { return nil, types.GetTrackerPatternOutput{}, err } pattern, err := r.cookieBanner.GetTrackerPattern(ctx, scope, input.ID) if err != nil { return nil, types.GetTrackerPatternOutput{}, fmt.Errorf("cannot get tracker pattern: %w", err) } return nil, types.GetTrackerPatternOutput{TrackerPattern: types.NewTrackerPattern(pattern)}, nil } func (r *Resolver) AddTrackerPatternTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddTrackerPatternInput) (*mcp.CallToolResult, types.AddTrackerPatternOutput, error) { scope, err := r.Authorize(ctx, input.CookieCategoryID, probo.ActionTrackerPatternCreate) if err != nil { return nil, types.AddTrackerPatternOutput{}, err } pattern, err := r.cookieBanner.CreateTrackerPattern(ctx, scope, cookiebanner.CreateTrackerPatternRequest{ CookieCategoryID: input.CookieCategoryID, TrackerType: coredata.TrackerType(input.TrackerType), Pattern: input.Pattern, MatchType: coredata.TrackerPatternMatchType(input.MatchType), DisplayName: input.DisplayName, MaxAgeSeconds: input.MaxAgeSeconds, Description: input.Description, }) if err != nil { return nil, types.AddTrackerPatternOutput{}, fmt.Errorf("cannot create tracker pattern: %w", err) } return nil, types.AddTrackerPatternOutput{TrackerPattern: types.NewTrackerPattern(pattern)}, nil } func (r *Resolver) UpdateTrackerPatternTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTrackerPatternInput) (*mcp.CallToolResult, types.UpdateTrackerPatternOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTrackerPatternUpdate) if err != nil { return nil, types.UpdateTrackerPatternOutput{}, err } updateReq := cookiebanner.UpdateTrackerPatternRequest{TrackerPatternID: input.ID} if input.MaxAgeSeconds.IsSet() { val, _ := input.MaxAgeSeconds.Value() updateReq.MaxAgeSeconds = &val } if v := UnwrapOmittable(input.Description); v != nil && *v != nil { updateReq.Description = *v } if v := UnwrapOmittable(input.Excluded); v != nil && *v != nil { updateReq.Excluded = *v } pattern, err := r.cookieBanner.UpdateTrackerPattern(ctx, scope, updateReq) if err != nil { return nil, types.UpdateTrackerPatternOutput{}, fmt.Errorf("cannot update tracker pattern: %w", err) } return nil, types.UpdateTrackerPatternOutput{TrackerPattern: types.NewTrackerPattern(pattern)}, nil } func (r *Resolver) DeleteTrackerPatternTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteTrackerPatternInput) (*mcp.CallToolResult, types.DeleteTrackerPatternOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTrackerPatternDelete) if err != nil { return nil, types.DeleteTrackerPatternOutput{}, err } if err := r.cookieBanner.DeleteTrackerPattern(ctx, scope, input.ID); err != nil { return nil, types.DeleteTrackerPatternOutput{}, fmt.Errorf("cannot delete tracker pattern: %w", err) } return nil, types.DeleteTrackerPatternOutput{DeletedID: input.ID}, nil } func (r *Resolver) MoveTrackerPatternToCategoryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.MoveTrackerPatternToCategoryInput) (*mcp.CallToolResult, types.MoveTrackerPatternToCategoryOutput, error) { scope, err := r.Authorize(ctx, input.TrackerPatternID, probo.ActionTrackerPatternUpdate) if err != nil { return nil, types.MoveTrackerPatternToCategoryOutput{}, err } if _, err := r.Authorize(ctx, input.TargetCookieCategoryID, probo.ActionCookieCategoryUpdate); err != nil { return nil, types.MoveTrackerPatternToCategoryOutput{}, err } result, err := r.cookieBanner.MoveTrackerPatternToCategory(ctx, scope, cookiebanner.MoveTrackerPatternToCategoryRequest{ TrackerPatternID: input.TrackerPatternID, TargetCookieCategoryID: input.TargetCookieCategoryID, }) if err != nil { return nil, types.MoveTrackerPatternToCategoryOutput{}, fmt.Errorf("cannot move tracker pattern: %w", err) } return nil, types.MoveTrackerPatternToCategoryOutput{TrackerPattern: types.NewTrackerPattern(result.TrackerPattern)}, nil } func (r *Resolver) PublishCookieBannerVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishCookieBannerVersionInput) (*mcp.CallToolResult, types.PublishCookieBannerVersionOutput, error) { scope, err := r.Authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerVersionPublish) if err != nil { return nil, types.PublishCookieBannerVersionOutput{}, err } version, err := r.cookieBanner.PublishCookieBannerVersion(ctx, scope, input.CookieBannerID) if err != nil { return nil, types.PublishCookieBannerVersionOutput{}, fmt.Errorf("cannot publish cookie banner version: %w", err) } return nil, types.PublishCookieBannerVersionOutput{CookieBannerVersion: types.NewCookieBannerVersion(version)}, nil } func (r *Resolver) RegenerateCookieBannerTrackerPolicyTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RegenerateCookieBannerTrackerPolicyInput) (*mcp.CallToolResult, types.RegenerateCookieBannerTrackerPolicyOutput, error) { scope, err := r.Authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerRegeneratePolicy) if err != nil { return nil, types.RegenerateCookieBannerTrackerPolicyOutput{}, err } banner, err := r.cookieBanner.RegenerateTrackerPolicy(ctx, scope, input.CookieBannerID) if err != nil { return nil, types.RegenerateCookieBannerTrackerPolicyOutput{}, fmt.Errorf("cannot regenerate cookie banner tracker policy: %w", err) } return nil, types.RegenerateCookieBannerTrackerPolicyOutput{CookieBanner: types.NewCookieBanner(banner)}, nil } func (r *Resolver) ListCookieBannerVersionsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCookieBannerVersionsInput) (*mcp.CallToolResult, types.ListCookieBannerVersionsOutput, error) { scope, err := r.Authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerVersionList) if err != nil { return nil, types.ListCookieBannerVersionsOutput{}, err } cursor := types.NewCursor(input.Size, input.Cursor, page.OrderBy[coredata.CookieBannerVersionOrderField]{Field: coredata.CookieBannerVersionOrderFieldCreatedAt, Direction: page.OrderDirectionDesc}) versions, err := r.cookieBanner.ListCookieBannerVersionsForBanner(ctx, scope, input.CookieBannerID, cursor) if err != nil { panic(fmt.Errorf("cannot list cookie banner versions: %w", err)) } p := page.NewPage(versions, cursor) return nil, types.NewListCookieBannerVersionsOutput(p), nil } func (r *Resolver) UpsertCookieBannerTranslationTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpsertCookieBannerTranslationInput) (*mcp.CallToolResult, types.UpsertCookieBannerTranslationOutput, error) { scope, err := r.Authorize(ctx, input.CookieBannerID, probo.ActionCookieBannerUpdate) if err != nil { return nil, types.UpsertCookieBannerTranslationOutput{}, err } translation, err := r.cookieBanner.UpsertCookieBannerTranslation(ctx, scope, cookiebanner.UpsertCookieBannerTranslationRequest{ CookieBannerID: input.CookieBannerID, Language: input.Language, Translations: json.RawMessage(input.Translations), }) if err != nil { return nil, types.UpsertCookieBannerTranslationOutput{}, fmt.Errorf("cannot upsert cookie banner translation: %w", err) } return nil, types.UpsertCookieBannerTranslationOutput{CookieBannerTranslation: types.NewCookieBannerTranslation(translation)}, nil } func (r *Resolver) ListCookieConsentRecordsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCookieConsentRecordsInput) (*mcp.CallToolResult, types.ListCookieConsentRecordsOutput, error) { scope, err := r.Authorize(ctx, input.CookieBannerID, probo.ActionCookieConsentRecordList) if err != nil { return nil, types.ListCookieConsentRecordsOutput{}, err } cursor := types.NewCursor(input.Size, input.Cursor, page.OrderBy[coredata.CookieConsentRecordOrderField]{Field: coredata.CookieConsentRecordOrderFieldCreatedAt, Direction: page.OrderDirectionDesc}) var action *coredata.CookieConsentAction if input.Action != nil { a := coredata.CookieConsentAction(*input.Action) action = &a } filter := coredata.NewCookieConsentRecordFilter(action, input.VisitorID, input.Version) records, err := r.cookieBanner.ListCookieConsentRecordsForBanner(ctx, scope, input.CookieBannerID, cursor, filter) if err != nil { panic(fmt.Errorf("cannot list cookie consent records: %w", err)) } p := page.NewPage(records, cursor) return nil, types.NewListCookieConsentRecordsOutput(p), nil } func (r *Resolver) GetCookieConsentRecordTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetCookieConsentRecordInput) (*mcp.CallToolResult, types.GetCookieConsentRecordOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionCookieConsentRecordList) if err != nil { return nil, types.GetCookieConsentRecordOutput{}, err } record, err := r.cookieBanner.GetCookieConsentRecord(ctx, scope, input.ID) if err != nil { return nil, types.GetCookieConsentRecordOutput{}, fmt.Errorf("cannot get cookie consent record: %w", err) } return nil, types.GetCookieConsentRecordOutput{CookieConsentRecord: types.NewCookieConsentRecord(record)}, nil } func (r *Resolver) PublishRiskListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishRiskListInput) (*mcp.CallToolResult, types.PublishRiskListOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionRiskPublish) if err != nil { return nil, types.PublishRiskListOutput{}, err } svc := r.proboSvc document, documentVersion, err := svc.GeneratedDocuments.PublishRiskList(ctx, scope, input.OrganizationID, input.ApproverIds, input.Minor) if err != nil { return nil, types.PublishRiskListOutput{}, fmt.Errorf("cannot publish risk list: %w", err) } return nil, types.PublishRiskListOutput{ DocumentID: document.ID, DocumentVersionID: documentVersion.ID, }, nil } func (r *Resolver) GetSCIMConfigurationTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetSCIMConfigurationInput) (*mcp.CallToolResult, types.GetSCIMConfigurationOutput, error) { if _, err := r.Authorize(ctx, input.OrganizationID, iam.ActionSCIMConfigurationGet); err != nil { return nil, types.GetSCIMConfigurationOutput{}, err } config, err := r.iamSvc.OrganizationService.GetSCIMConfiguration(ctx, input.OrganizationID) if err != nil { if _, ok := errors.AsType[*iam.ErrNoSCIMConfigurationFound](err); ok { return nil, types.GetSCIMConfigurationOutput{}, fmt.Errorf("SCIM configuration not found") } panic(fmt.Errorf("cannot get SCIM configuration: %w", err)) } return nil, types.GetSCIMConfigurationOutput{ScimConfiguration: types.NewSCIMConfiguration(config)}, nil } func (r *Resolver) CreateSCIMConfigurationTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateSCIMConfigurationInput) (*mcp.CallToolResult, types.CreateSCIMConfigurationOutput, error) { if _, err := r.Authorize(ctx, input.OrganizationID, iam.ActionSCIMConfigurationCreate); err != nil { return nil, types.CreateSCIMConfigurationOutput{}, err } config, token, err := r.iamSvc.OrganizationService.CreateSCIMConfiguration(ctx, input.OrganizationID) if err != nil { return nil, types.CreateSCIMConfigurationOutput{}, fmt.Errorf("cannot create SCIM configuration: %w", err) } output := types.CreateSCIMConfigurationOutput{ ScimConfiguration: types.NewSCIMConfiguration(config), Token: token, } if input.ConnectorID != nil { bridge, err := r.iamSvc.OrganizationService.CreateSCIMBridge(ctx, input.OrganizationID, config.ID, *input.ConnectorID) if err != nil { return nil, types.CreateSCIMConfigurationOutput{}, fmt.Errorf("cannot create SCIM bridge: %w", err) } output.ScimBridge = types.NewSCIMBridge(bridge) } return nil, output, nil } func (r *Resolver) DeleteSCIMConfigurationTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteSCIMConfigurationInput) (*mcp.CallToolResult, types.DeleteSCIMConfigurationOutput, error) { if _, err := r.Authorize(ctx, input.OrganizationID, iam.ActionSCIMConfigurationDelete); err != nil { return nil, types.DeleteSCIMConfigurationOutput{}, err } err := r.iamSvc.OrganizationService.DeleteSCIMConfiguration(ctx, input.OrganizationID, input.ScimConfigurationID) if err != nil { return nil, types.DeleteSCIMConfigurationOutput{}, fmt.Errorf("cannot delete SCIM configuration: %w", err) } return nil, types.DeleteSCIMConfigurationOutput{DeletedScimConfigurationID: input.ScimConfigurationID}, nil } func (r *Resolver) RegenerateSCIMTokenTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RegenerateSCIMTokenInput) (*mcp.CallToolResult, types.RegenerateSCIMTokenOutput, error) { if _, err := r.Authorize(ctx, input.ScimConfigurationID, iam.ActionSCIMConfigurationUpdate); err != nil { return nil, types.RegenerateSCIMTokenOutput{}, err } config, token, err := r.iamSvc.OrganizationService.RegenerateSCIMToken(ctx, input.OrganizationID, input.ScimConfigurationID) if err != nil { return nil, types.RegenerateSCIMTokenOutput{}, fmt.Errorf("cannot regenerate SCIM token: %w", err) } return nil, types.RegenerateSCIMTokenOutput{ ScimConfiguration: types.NewSCIMConfiguration(config), Token: token, }, nil } func (r *Resolver) GetSCIMBridgeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetSCIMBridgeInput) (*mcp.CallToolResult, types.GetSCIMBridgeOutput, error) { if _, err := r.Authorize(ctx, input.ID, iam.ActionSCIMBridgeGet); err != nil { return nil, types.GetSCIMBridgeOutput{}, err } bridge, err := r.iamSvc.OrganizationService.GetSCIMBridgeByID(ctx, input.ID) if err != nil { if _, ok := errors.AsType[*iam.ErrSCIMBridgeNotFound](err); ok { return nil, types.GetSCIMBridgeOutput{}, fmt.Errorf("SCIM bridge %s not found", input.ID) } panic(fmt.Errorf("cannot get SCIM bridge: %w", err)) } return nil, types.GetSCIMBridgeOutput{ScimBridge: types.NewSCIMBridge(bridge)}, nil } func (r *Resolver) UpdateSCIMBridgeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateSCIMBridgeInput) (*mcp.CallToolResult, types.UpdateSCIMBridgeOutput, error) { if _, err := r.Authorize(ctx, input.ScimBridgeID, iam.ActionSCIMBridgeUpdate); err != nil { return nil, types.UpdateSCIMBridgeOutput{}, err } bridge, err := r.iamSvc.OrganizationService.UpdateSCIMBridge(ctx, input.OrganizationID, input.ScimBridgeID, input.ExcludedUserNames) if err != nil { return nil, types.UpdateSCIMBridgeOutput{}, fmt.Errorf("cannot update SCIM bridge: %w", err) } return nil, types.UpdateSCIMBridgeOutput{ScimBridge: types.NewSCIMBridge(bridge)}, nil } func (r *Resolver) ListSCIMEventsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListSCIMEventsInput) (*mcp.CallToolResult, types.ListSCIMEventsOutput, error) { if _, err := r.Authorize(ctx, input.ScimConfigurationID, iam.ActionSCIMEventList); err != nil { return nil, types.ListSCIMEventsOutput{}, err } pageOrderBy := page.OrderBy[coredata.SCIMEventOrderField]{ Field: coredata.SCIMEventOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.SCIMEventOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.iamSvc.OrganizationService.ListSCIMEventsByConfigID(ctx, input.ScimConfigurationID, cursor) if err != nil { panic(fmt.Errorf("cannot list SCIM events: %w", err)) } return nil, types.NewListSCIMEventsOutput(p), nil } func (r *Resolver) PublishDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishDocumentInput) (*mcp.CallToolResult, types.PublishDocumentOutput, error) { scope, err := r.Authorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish) if err != nil { return nil, types.PublishDocumentOutput{}, err } svc := r.proboSvc result, err := svc.Documents.PublishVersionWithDefaultApprovers(ctx, scope, probo.PublishDocumentRequest{ DocumentID: input.DocumentID, Minor: input.Minor, Changelog: input.Changelog, }) if err != nil { panic(fmt.Errorf("cannot publish document: %w", err)) } output := types.PublishDocumentOutput{ Document: types.NewDocument(result.Document), DocumentVersion: types.NewDocumentVersion(result.Version), } if result.Quorum != nil { output.ApprovalQuorum = types.NewDocumentVersionApprovalQuorum(result.Quorum) } return nil, output, nil } func (r *Resolver) ListTrackerResourcesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListTrackerResourcesInput) (*mcp.CallToolResult, types.ListTrackerResourcesOutput, error) { scope, err := r.Authorize(ctx, input.CookieCategoryID, probo.ActionTrackerResourceList) if err != nil { return nil, types.ListTrackerResourcesOutput{}, err } cursor := types.NewCursor(input.Size, input.Cursor, page.OrderBy[coredata.TrackerResourceOrderField]{Field: coredata.TrackerResourceOrderFieldCreatedAt, Direction: page.OrderDirectionAsc}) resources, err := r.cookieBanner.ListTrackerResourcesForCategory(ctx, scope, input.CookieCategoryID, cursor) if err != nil { panic(fmt.Errorf("cannot list tracker resources: %w", err)) } p := page.NewPage(resources, cursor) return nil, types.NewListTrackerResourcesOutput(p), nil } func (r *Resolver) GetTrackerResourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetTrackerResourceInput) (*mcp.CallToolResult, types.GetTrackerResourceOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTrackerResourceGet) if err != nil { return nil, types.GetTrackerResourceOutput{}, err } resource, err := r.cookieBanner.GetTrackerResource(ctx, scope, input.ID) if err != nil { return nil, types.GetTrackerResourceOutput{}, fmt.Errorf("cannot get tracker resource: %w", err) } return nil, types.GetTrackerResourceOutput{TrackerResource: types.NewTrackerResource(resource)}, nil } func (r *Resolver) AddTrackerResourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddTrackerResourceInput) (*mcp.CallToolResult, types.AddTrackerResourceOutput, error) { scope, err := r.Authorize(ctx, input.CookieCategoryID, probo.ActionTrackerResourceCreate) if err != nil { return nil, types.AddTrackerResourceOutput{}, err } description := "" if input.Description != nil { description = *input.Description } resource, err := r.cookieBanner.CreateTrackerResource(ctx, scope, cookiebanner.CreateTrackerResourceRequest{ CookieCategoryID: input.CookieCategoryID, ResourceType: coredata.TrackerResourceType(input.ResourceType), Origin: input.Origin, Path: input.Path, DisplayName: input.DisplayName, Description: description, }) if err != nil { return nil, types.AddTrackerResourceOutput{}, fmt.Errorf("cannot create tracker resource: %w", err) } return nil, types.AddTrackerResourceOutput{TrackerResource: types.NewTrackerResource(resource)}, nil } func (r *Resolver) UpdateTrackerResourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTrackerResourceInput) (*mcp.CallToolResult, types.UpdateTrackerResourceOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTrackerResourceUpdate) if err != nil { return nil, types.UpdateTrackerResourceOutput{}, err } updateReq := cookiebanner.UpdateTrackerResourceRequest{TrackerResourceID: input.ID} if v := UnwrapOmittable(input.DisplayName); v != nil && *v != nil { updateReq.DisplayName = *v } if v := UnwrapOmittable(input.Description); v != nil && *v != nil { updateReq.Description = *v } if v := UnwrapOmittable(input.Excluded); v != nil && *v != nil { updateReq.Excluded = *v } resource, err := r.cookieBanner.UpdateTrackerResource(ctx, scope, updateReq) if err != nil { return nil, types.UpdateTrackerResourceOutput{}, fmt.Errorf("cannot update tracker resource: %w", err) } return nil, types.UpdateTrackerResourceOutput{TrackerResource: types.NewTrackerResource(resource)}, nil } func (r *Resolver) DeleteTrackerResourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteTrackerResourceInput) (*mcp.CallToolResult, types.DeleteTrackerResourceOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionTrackerResourceDelete) if err != nil { return nil, types.DeleteTrackerResourceOutput{}, err } if err := r.cookieBanner.DeleteTrackerResource(ctx, scope, input.ID); err != nil { return nil, types.DeleteTrackerResourceOutput{}, fmt.Errorf("cannot delete tracker resource: %w", err) } return nil, types.DeleteTrackerResourceOutput{DeletedID: input.ID}, nil } func (r *Resolver) MoveTrackerResourceToCategoryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.MoveTrackerResourceToCategoryInput) (*mcp.CallToolResult, types.MoveTrackerResourceToCategoryOutput, error) { scope, err := r.Authorize(ctx, input.TrackerResourceID, probo.ActionTrackerResourceUpdate) if err != nil { return nil, types.MoveTrackerResourceToCategoryOutput{}, err } if _, err := r.Authorize(ctx, input.TargetCookieCategoryID, probo.ActionCookieCategoryUpdate); err != nil { return nil, types.MoveTrackerResourceToCategoryOutput{}, err } result, err := r.cookieBanner.MoveTrackerResourceToCategory(ctx, scope, cookiebanner.MoveTrackerResourceToCategoryRequest{ TrackerResourceID: input.TrackerResourceID, TargetCookieCategoryID: input.TargetCookieCategoryID, }) if err != nil { return nil, types.MoveTrackerResourceToCategoryOutput{}, fmt.Errorf("cannot move tracker resource: %w", err) } return nil, types.MoveTrackerResourceToCategoryOutput{TrackerResource: types.NewTrackerResource(result.TrackerResource)}, nil } func (r *Resolver) ListChildThirdPartiesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListChildThirdPartiesInput) (*mcp.CallToolResult, types.ListChildThirdPartiesOutput, error) { scope, err := r.Authorize(ctx, input.ParentThirdPartyID, probo.ActionThirdPartyRelationList) if err != nil { return nil, types.ListChildThirdPartiesOutput{}, err } pageOrderBy := page.OrderBy[coredata.ThirdPartyOrderField]{ Field: coredata.ThirdPartyOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ThirdPartyOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) page, err := r.proboSvc.ThirdParties.ListForParentThirdPartyID(ctx, scope, input.ParentThirdPartyID, cursor) if err != nil { panic(fmt.Errorf("cannot list child third parties: %w", err)) } return nil, types.NewListChildThirdPartiesOutput(page), nil } func (r *Resolver) ListRiskAssessmentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskAssessmentsInput) (*mcp.CallToolResult, types.ListRiskAssessmentsOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionRiskAssessmentList) if err != nil { return nil, types.ListRiskAssessmentsOutput{}, err } pageOrderBy := page.OrderBy[coredata.RiskAssessmentOrderField]{ Field: coredata.RiskAssessmentOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskAssessmentOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.riskManagement.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { panic(fmt.Errorf("cannot list risk assessments: %w", err)) } return nil, types.NewListRiskAssessmentsOutput(p), nil } func (r *Resolver) GetRiskAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskAssessmentInput) (*mcp.CallToolResult, types.GetRiskAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentGet) if err != nil { return nil, types.GetRiskAssessmentOutput{}, err } ra, err := r.riskManagement.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskAssessmentOutput{}, fmt.Errorf("failed to get risk assessment: %w", err) } return nil, types.GetRiskAssessmentOutput{ RiskAssessment: types.NewRiskAssessment(ra), }, nil } func (r *Resolver) AddRiskAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskAssessmentInput) (*mcp.CallToolResult, types.AddRiskAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, probo.ActionRiskAssessmentCreate) if err != nil { return nil, types.AddRiskAssessmentOutput{}, err } ra, err := r.riskManagement.Create(ctx, scope, riskmanagement.CreateRiskAssessmentRequest{ OrganizationID: input.OrganizationID, Name: input.Name, Description: input.Description, }) if err != nil { return nil, types.AddRiskAssessmentOutput{}, fmt.Errorf("failed to create risk assessment: %w", err) } return nil, types.AddRiskAssessmentOutput{ RiskAssessment: types.NewRiskAssessment(ra), }, nil } func (r *Resolver) UpdateRiskAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRiskAssessmentInput) (*mcp.CallToolResult, types.UpdateRiskAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentUpdate) if err != nil { return nil, types.UpdateRiskAssessmentOutput{}, err } ra, err := r.riskManagement.Update(ctx, scope, riskmanagement.UpdateRiskAssessmentRequest{ ID: input.ID, Name: input.Name, Description: UnwrapOmittable(input.Description), }) if err != nil { return nil, types.UpdateRiskAssessmentOutput{}, fmt.Errorf("failed to update risk assessment: %w", err) } return nil, types.UpdateRiskAssessmentOutput{ RiskAssessment: types.NewRiskAssessment(ra), }, nil } func (r *Resolver) DeleteRiskAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRiskAssessmentInput) (*mcp.CallToolResult, types.DeleteRiskAssessmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentDelete) if err != nil { return nil, types.DeleteRiskAssessmentOutput{}, err } if err := r.riskManagement.Delete(ctx, scope, input.ID); err != nil { return nil, types.DeleteRiskAssessmentOutput{}, fmt.Errorf("failed to delete risk assessment: %w", err) } return nil, types.DeleteRiskAssessmentOutput{ DeletedRiskAssessmentID: input.ID, }, nil } func (r *Resolver) ListRiskAssessmentScopesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskAssessmentScopesInput) (*mcp.CallToolResult, types.ListRiskAssessmentScopesOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentID, probo.ActionRiskAssessmentScopeList) if err != nil { return nil, types.ListRiskAssessmentScopesOutput{}, err } pageOrderBy := page.OrderBy[coredata.RiskAssessmentScopeOrderField]{ Field: coredata.RiskAssessmentScopeOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskAssessmentScopeOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.riskManagement.ListScopesForRiskAssessmentID(ctx, scope, input.RiskAssessmentID, cursor) if err != nil { panic(fmt.Errorf("cannot list risk assessment scopes: %w", err)) } return nil, types.NewListRiskAssessmentScopesOutput(p), nil } func (r *Resolver) GetRiskAssessmentScopeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskAssessmentScopeInput) (*mcp.CallToolResult, types.GetRiskAssessmentScopeOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentScopeGet) if err != nil { return nil, types.GetRiskAssessmentScopeOutput{}, err } s, err := r.riskManagement.GetScope(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskAssessmentScopeOutput{}, fmt.Errorf("failed to get risk assessment scope: %w", err) } return nil, types.GetRiskAssessmentScopeOutput{ RiskAssessmentScope: types.NewRiskAssessmentScope(s), }, nil } func (r *Resolver) AddRiskAssessmentScopeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskAssessmentScopeInput) (*mcp.CallToolResult, types.AddRiskAssessmentScopeOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentID, probo.ActionRiskAssessmentScopeCreate) if err != nil { return nil, types.AddRiskAssessmentScopeOutput{}, err } s, err := r.riskManagement.CreateScope(ctx, scope, riskmanagement.CreateRiskAssessmentScopeRequest{ RiskAssessmentID: input.RiskAssessmentID, Name: input.Name, }) if err != nil { return nil, types.AddRiskAssessmentScopeOutput{}, fmt.Errorf("failed to create risk assessment scope: %w", err) } return nil, types.AddRiskAssessmentScopeOutput{ RiskAssessmentScope: types.NewRiskAssessmentScope(s), }, nil } func (r *Resolver) UpdateRiskAssessmentScopeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRiskAssessmentScopeInput) (*mcp.CallToolResult, types.UpdateRiskAssessmentScopeOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentScopeUpdate) if err != nil { return nil, types.UpdateRiskAssessmentScopeOutput{}, err } s, err := r.riskManagement.UpdateScope(ctx, scope, riskmanagement.UpdateRiskAssessmentScopeRequest{ ID: input.ID, Name: input.Name, }) if err != nil { return nil, types.UpdateRiskAssessmentScopeOutput{}, fmt.Errorf("failed to update risk assessment scope: %w", err) } return nil, types.UpdateRiskAssessmentScopeOutput{ RiskAssessmentScope: types.NewRiskAssessmentScope(s), }, nil } func (r *Resolver) DeleteRiskAssessmentScopeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRiskAssessmentScopeInput) (*mcp.CallToolResult, types.DeleteRiskAssessmentScopeOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentScopeDelete) if err != nil { return nil, types.DeleteRiskAssessmentScopeOutput{}, err } if err := r.riskManagement.DeleteScope(ctx, scope, input.ID); err != nil { return nil, types.DeleteRiskAssessmentScopeOutput{}, fmt.Errorf("failed to delete risk assessment scope: %w", err) } return nil, types.DeleteRiskAssessmentScopeOutput{ DeletedRiskAssessmentScopeID: input.ID, }, nil } func (r *Resolver) ListRiskAssessmentNodesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskAssessmentNodesInput) (*mcp.CallToolResult, types.ListRiskAssessmentNodesOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentNodeList) if err != nil { return nil, types.ListRiskAssessmentNodesOutput{}, err } pageOrderBy := page.OrderBy[coredata.RiskAssessmentNodeOrderField]{ Field: coredata.RiskAssessmentNodeOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskAssessmentNodeOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.riskManagement.ListNodesForScopeID(ctx, scope, input.RiskAssessmentScopeID, cursor) if err != nil { panic(fmt.Errorf("cannot list risk assessment nodes: %w", err)) } return nil, types.NewListRiskAssessmentNodesOutput(p), nil } func (r *Resolver) GetRiskAssessmentNodeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskAssessmentNodeInput) (*mcp.CallToolResult, types.GetRiskAssessmentNodeOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentNodeGet) if err != nil { return nil, types.GetRiskAssessmentNodeOutput{}, err } n, err := r.riskManagement.GetNode(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskAssessmentNodeOutput{}, fmt.Errorf("failed to get risk assessment node: %w", err) } return nil, types.GetRiskAssessmentNodeOutput{ RiskAssessmentNode: types.NewRiskAssessmentNode(n), }, nil } func (r *Resolver) AddRiskAssessmentNodeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskAssessmentNodeInput) (*mcp.CallToolResult, types.AddRiskAssessmentNodeOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentNodeCreate) if err != nil { return nil, types.AddRiskAssessmentNodeOutput{}, err } n, err := r.riskManagement.CreateNode(ctx, scope, riskmanagement.CreateRiskAssessmentNodeRequest{ RiskAssessmentScopeID: input.RiskAssessmentScopeID, BoundaryID: input.BoundaryID, NodeType: input.NodeType, Name: input.Name, }) if err != nil { return nil, types.AddRiskAssessmentNodeOutput{}, fmt.Errorf("failed to create risk assessment node: %w", err) } return nil, types.AddRiskAssessmentNodeOutput{ RiskAssessmentNode: types.NewRiskAssessmentNode(n), }, nil } func (r *Resolver) UpdateRiskAssessmentNodeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRiskAssessmentNodeInput) (*mcp.CallToolResult, types.UpdateRiskAssessmentNodeOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentNodeUpdate) if err != nil { return nil, types.UpdateRiskAssessmentNodeOutput{}, err } var boundaryID **gid.GID if input.BoundaryID != nil { boundaryID = &input.BoundaryID } n, err := r.riskManagement.UpdateNode(ctx, scope, riskmanagement.UpdateRiskAssessmentNodeRequest{ ID: input.ID, BoundaryID: boundaryID, NodeType: input.NodeType, Name: input.Name, }) if err != nil { return nil, types.UpdateRiskAssessmentNodeOutput{}, fmt.Errorf("failed to update risk assessment node: %w", err) } return nil, types.UpdateRiskAssessmentNodeOutput{ RiskAssessmentNode: types.NewRiskAssessmentNode(n), }, nil } func (r *Resolver) DeleteRiskAssessmentNodeTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRiskAssessmentNodeInput) (*mcp.CallToolResult, types.DeleteRiskAssessmentNodeOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentNodeDelete) if err != nil { return nil, types.DeleteRiskAssessmentNodeOutput{}, err } if err := r.riskManagement.DeleteNode(ctx, scope, input.ID); err != nil { return nil, types.DeleteRiskAssessmentNodeOutput{}, fmt.Errorf("failed to delete risk assessment node: %w", err) } return nil, types.DeleteRiskAssessmentNodeOutput{ DeletedRiskAssessmentNodeID: input.ID, }, nil } func (r *Resolver) ListRiskAssessmentProcessesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskAssessmentProcessesInput) (*mcp.CallToolResult, types.ListRiskAssessmentProcessesOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentProcessList) if err != nil { return nil, types.ListRiskAssessmentProcessesOutput{}, err } pageOrderBy := page.OrderBy[coredata.RiskAssessmentProcessOrderField]{ Field: coredata.RiskAssessmentProcessOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskAssessmentProcessOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.riskManagement.ListProcessesForScopeID(ctx, scope, input.RiskAssessmentScopeID, cursor) if err != nil { panic(fmt.Errorf("cannot list risk assessment processes: %w", err)) } return nil, types.NewListRiskAssessmentProcessesOutput(p), nil } func (r *Resolver) GetRiskAssessmentProcessTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskAssessmentProcessInput) (*mcp.CallToolResult, types.GetRiskAssessmentProcessOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentProcessGet) if err != nil { return nil, types.GetRiskAssessmentProcessOutput{}, err } p, err := r.riskManagement.GetProcess(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskAssessmentProcessOutput{}, fmt.Errorf("failed to get risk assessment process: %w", err) } return nil, types.GetRiskAssessmentProcessOutput{ RiskAssessmentProcess: types.NewRiskAssessmentProcess(p), }, nil } func (r *Resolver) AddRiskAssessmentProcessTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskAssessmentProcessInput) (*mcp.CallToolResult, types.AddRiskAssessmentProcessOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentProcessCreate) if err != nil { return nil, types.AddRiskAssessmentProcessOutput{}, err } p, err := r.riskManagement.CreateProcess(ctx, scope, riskmanagement.CreateRiskAssessmentProcessRequest{ RiskAssessmentScopeID: input.RiskAssessmentScopeID, SourceNodeID: input.SourceNodeID, TargetNodeID: input.TargetNodeID, Name: input.Name, }) if err != nil { return nil, types.AddRiskAssessmentProcessOutput{}, fmt.Errorf("failed to create risk assessment process: %w", err) } return nil, types.AddRiskAssessmentProcessOutput{ RiskAssessmentProcess: types.NewRiskAssessmentProcess(p), }, nil } func (r *Resolver) UpdateRiskAssessmentProcessTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRiskAssessmentProcessInput) (*mcp.CallToolResult, types.UpdateRiskAssessmentProcessOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentProcessUpdate) if err != nil { return nil, types.UpdateRiskAssessmentProcessOutput{}, err } p, err := r.riskManagement.UpdateProcess(ctx, scope, riskmanagement.UpdateRiskAssessmentProcessRequest{ ID: input.ID, SourceNodeID: input.SourceNodeID, TargetNodeID: input.TargetNodeID, Name: input.Name, }) if err != nil { return nil, types.UpdateRiskAssessmentProcessOutput{}, fmt.Errorf("failed to update risk assessment process: %w", err) } return nil, types.UpdateRiskAssessmentProcessOutput{ RiskAssessmentProcess: types.NewRiskAssessmentProcess(p), }, nil } func (r *Resolver) DeleteRiskAssessmentProcessTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRiskAssessmentProcessInput) (*mcp.CallToolResult, types.DeleteRiskAssessmentProcessOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentProcessDelete) if err != nil { return nil, types.DeleteRiskAssessmentProcessOutput{}, err } if err := r.riskManagement.DeleteProcess(ctx, scope, input.ID); err != nil { return nil, types.DeleteRiskAssessmentProcessOutput{}, fmt.Errorf("failed to delete risk assessment process: %w", err) } return nil, types.DeleteRiskAssessmentProcessOutput{ DeletedRiskAssessmentProcessID: input.ID, }, nil } func (r *Resolver) ListRiskAssessmentThreatsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskAssessmentThreatsInput) (*mcp.CallToolResult, types.ListRiskAssessmentThreatsOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentThreatList) if err != nil { return nil, types.ListRiskAssessmentThreatsOutput{}, err } pageOrderBy := page.OrderBy[coredata.RiskAssessmentThreatOrderField]{ Field: coredata.RiskAssessmentThreatOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskAssessmentThreatOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.riskManagement.ListThreatsForScopeID(ctx, scope, input.RiskAssessmentScopeID, cursor) if err != nil { panic(fmt.Errorf("cannot list risk assessment threats: %w", err)) } return nil, types.NewListRiskAssessmentThreatsOutput(p), nil } func (r *Resolver) GetRiskAssessmentThreatTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskAssessmentThreatInput) (*mcp.CallToolResult, types.GetRiskAssessmentThreatOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentThreatGet) if err != nil { return nil, types.GetRiskAssessmentThreatOutput{}, err } t, err := r.riskManagement.GetThreat(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskAssessmentThreatOutput{}, fmt.Errorf("failed to get risk assessment threat: %w", err) } return nil, types.GetRiskAssessmentThreatOutput{ RiskAssessmentThreat: types.NewRiskAssessmentThreat(t), }, nil } func (r *Resolver) AddRiskAssessmentThreatTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskAssessmentThreatInput) (*mcp.CallToolResult, types.AddRiskAssessmentThreatOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentThreatCreate) if err != nil { return nil, types.AddRiskAssessmentThreatOutput{}, err } t, err := r.riskManagement.CreateThreat(ctx, scope, riskmanagement.CreateRiskAssessmentThreatRequest{ RiskAssessmentScopeID: input.RiskAssessmentScopeID, ProcessID: input.ProcessID, Name: input.Name, Category: input.Category, }) if err != nil { return nil, types.AddRiskAssessmentThreatOutput{}, fmt.Errorf("failed to create risk assessment threat: %w", err) } return nil, types.AddRiskAssessmentThreatOutput{ RiskAssessmentThreat: types.NewRiskAssessmentThreat(t), }, nil } func (r *Resolver) UpdateRiskAssessmentThreatTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRiskAssessmentThreatInput) (*mcp.CallToolResult, types.UpdateRiskAssessmentThreatOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentThreatUpdate) if err != nil { return nil, types.UpdateRiskAssessmentThreatOutput{}, err } t, err := r.riskManagement.UpdateThreat(ctx, scope, riskmanagement.UpdateRiskAssessmentThreatRequest{ ID: input.ID, ProcessID: input.ProcessID, Name: input.Name, Category: input.Category, }) if err != nil { return nil, types.UpdateRiskAssessmentThreatOutput{}, fmt.Errorf("failed to update risk assessment threat: %w", err) } return nil, types.UpdateRiskAssessmentThreatOutput{ RiskAssessmentThreat: types.NewRiskAssessmentThreat(t), }, nil } func (r *Resolver) DeleteRiskAssessmentThreatTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRiskAssessmentThreatInput) (*mcp.CallToolResult, types.DeleteRiskAssessmentThreatOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentThreatDelete) if err != nil { return nil, types.DeleteRiskAssessmentThreatOutput{}, err } if err := r.riskManagement.DeleteThreat(ctx, scope, input.ID); err != nil { return nil, types.DeleteRiskAssessmentThreatOutput{}, fmt.Errorf("failed to delete risk assessment threat: %w", err) } return nil, types.DeleteRiskAssessmentThreatOutput{ DeletedRiskAssessmentThreatID: input.ID, }, nil } func (r *Resolver) ListRiskAssessmentScenariosTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskAssessmentScenariosInput) (*mcp.CallToolResult, types.ListRiskAssessmentScenariosOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentScenarioList) if err != nil { return nil, types.ListRiskAssessmentScenariosOutput{}, err } pageOrderBy := page.OrderBy[coredata.RiskAssessmentScenarioOrderField]{ Field: coredata.RiskAssessmentScenarioOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskAssessmentScenarioOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.riskManagement.ListScenariosForScopeID(ctx, scope, input.RiskAssessmentScopeID, cursor) if err != nil { panic(fmt.Errorf("cannot list risk assessment scenarios: %w", err)) } return nil, types.NewListRiskAssessmentScenariosOutput(p), nil } func (r *Resolver) GetRiskAssessmentScenarioTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskAssessmentScenarioInput) (*mcp.CallToolResult, types.GetRiskAssessmentScenarioOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentScenarioGet) if err != nil { return nil, types.GetRiskAssessmentScenarioOutput{}, err } s, err := r.riskManagement.GetScenario(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskAssessmentScenarioOutput{}, fmt.Errorf("failed to get risk assessment scenario: %w", err) } return nil, types.GetRiskAssessmentScenarioOutput{ RiskAssessmentScenario: types.NewRiskAssessmentScenario(s), }, nil } func (r *Resolver) AddRiskAssessmentScenarioTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskAssessmentScenarioInput) (*mcp.CallToolResult, types.AddRiskAssessmentScenarioOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentScenarioCreate) if err != nil { return nil, types.AddRiskAssessmentScenarioOutput{}, err } s, err := r.riskManagement.CreateScenario(ctx, scope, riskmanagement.CreateRiskAssessmentScenarioRequest{ RiskAssessmentScopeID: input.RiskAssessmentScopeID, Name: input.Name, Description: input.Description, }) if err != nil { return nil, types.AddRiskAssessmentScenarioOutput{}, fmt.Errorf("failed to create risk assessment scenario: %w", err) } return nil, types.AddRiskAssessmentScenarioOutput{ RiskAssessmentScenario: types.NewRiskAssessmentScenario(s), }, nil } func (r *Resolver) UpdateRiskAssessmentScenarioTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRiskAssessmentScenarioInput) (*mcp.CallToolResult, types.UpdateRiskAssessmentScenarioOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentScenarioUpdate) if err != nil { return nil, types.UpdateRiskAssessmentScenarioOutput{}, err } s, err := r.riskManagement.UpdateScenario(ctx, scope, riskmanagement.UpdateRiskAssessmentScenarioRequest{ ID: input.ID, Name: input.Name, Description: UnwrapOmittable(input.Description), }) if err != nil { return nil, types.UpdateRiskAssessmentScenarioOutput{}, fmt.Errorf("failed to update risk assessment scenario: %w", err) } return nil, types.UpdateRiskAssessmentScenarioOutput{ RiskAssessmentScenario: types.NewRiskAssessmentScenario(s), }, nil } func (r *Resolver) DeleteRiskAssessmentScenarioTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRiskAssessmentScenarioInput) (*mcp.CallToolResult, types.DeleteRiskAssessmentScenarioOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentScenarioDelete) if err != nil { return nil, types.DeleteRiskAssessmentScenarioOutput{}, err } if err := r.riskManagement.DeleteScenario(ctx, scope, input.ID); err != nil { return nil, types.DeleteRiskAssessmentScenarioOutput{}, fmt.Errorf("failed to delete risk assessment scenario: %w", err) } return nil, types.DeleteRiskAssessmentScenarioOutput{ DeletedRiskAssessmentScenarioID: input.ID, }, nil } func (r *Resolver) LinkRiskAssessmentScenarioThreatTool(ctx context.Context, req *mcp.CallToolRequest, input *types.LinkRiskAssessmentScenarioThreatInput) (*mcp.CallToolResult, types.LinkRiskAssessmentScenarioThreatOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScenarioID, probo.ActionRiskAssessmentScenarioThreatLink) if err != nil { return nil, types.LinkRiskAssessmentScenarioThreatOutput{}, err } err = r.riskManagement.LinkScenarioThreat(ctx, scope, riskmanagement.LinkRiskAssessmentScenarioThreatRequest{ RiskAssessmentScenarioID: input.RiskAssessmentScenarioID, ThreatID: input.ThreatID, }) if err != nil { return nil, types.LinkRiskAssessmentScenarioThreatOutput{}, fmt.Errorf("failed to link scenario threat: %w", err) } return nil, types.LinkRiskAssessmentScenarioThreatOutput{}, nil } func (r *Resolver) UnlinkRiskAssessmentScenarioThreatTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnlinkRiskAssessmentScenarioThreatInput) (*mcp.CallToolResult, types.UnlinkRiskAssessmentScenarioThreatOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScenarioID, probo.ActionRiskAssessmentScenarioThreatUnlink) if err != nil { return nil, types.UnlinkRiskAssessmentScenarioThreatOutput{}, err } if err := r.riskManagement.UnlinkScenarioThreat( ctx, scope, riskmanagement.UnlinkRiskAssessmentScenarioThreatRequest{ RiskAssessmentScenarioID: input.RiskAssessmentScenarioID, ThreatID: input.ThreatID, }, ); err != nil { return nil, types.UnlinkRiskAssessmentScenarioThreatOutput{}, fmt.Errorf("failed to unlink scenario threat: %w", err) } return nil, types.UnlinkRiskAssessmentScenarioThreatOutput{}, nil } func (r *Resolver) LinkRiskAssessmentScenarioRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.LinkRiskAssessmentScenarioRiskInput) (*mcp.CallToolResult, types.LinkRiskAssessmentScenarioRiskOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScenarioID, probo.ActionRiskAssessmentScenarioRiskLink) if err != nil { return nil, types.LinkRiskAssessmentScenarioRiskOutput{}, err } if err := r.riskManagement.LinkScenarioRisk( ctx, scope, riskmanagement.LinkRiskAssessmentScenarioRiskRequest{ RiskAssessmentScenarioID: input.RiskAssessmentScenarioID, RiskID: input.RiskID, }, ); err != nil { return nil, types.LinkRiskAssessmentScenarioRiskOutput{}, fmt.Errorf("failed to link scenario risk: %w", err) } return nil, types.LinkRiskAssessmentScenarioRiskOutput{}, nil } func (r *Resolver) UnlinkRiskAssessmentScenarioRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnlinkRiskAssessmentScenarioRiskInput) (*mcp.CallToolResult, types.UnlinkRiskAssessmentScenarioRiskOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScenarioID, probo.ActionRiskAssessmentScenarioRiskUnlink) if err != nil { return nil, types.UnlinkRiskAssessmentScenarioRiskOutput{}, err } if err := r.riskManagement.UnlinkScenarioRisk( ctx, scope, riskmanagement.UnlinkRiskAssessmentScenarioRiskRequest{ RiskAssessmentScenarioID: input.RiskAssessmentScenarioID, RiskID: input.RiskID, }, ); err != nil { return nil, types.UnlinkRiskAssessmentScenarioRiskOutput{}, fmt.Errorf("failed to unlink scenario risk: %w", err) } return nil, types.UnlinkRiskAssessmentScenarioRiskOutput{}, nil } func (r *Resolver) GetRiskAssessmentScopeMermaidChartTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskAssessmentScopeMermaidChartInput) (*mcp.CallToolResult, types.GetRiskAssessmentScopeMermaidChartOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentScopeGet) if err != nil { return nil, types.GetRiskAssessmentScopeMermaidChartOutput{}, err } chart, err := r.riskManagement.BuildScopeMermaidChart(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskAssessmentScopeMermaidChartOutput{}, fmt.Errorf("failed to build mermaid chart: %w", err) } return nil, types.GetRiskAssessmentScopeMermaidChartOutput{ MermaidChart: chart, }, nil } func (r *Resolver) ListRiskAssessmentBoundariesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRiskAssessmentBoundariesInput) (*mcp.CallToolResult, types.ListRiskAssessmentBoundariesOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentBoundaryList) if err != nil { return nil, types.ListRiskAssessmentBoundariesOutput{}, err } pageOrderBy := page.OrderBy[coredata.RiskAssessmentBoundaryOrderField]{ Field: coredata.RiskAssessmentBoundaryOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.RiskAssessmentBoundaryOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.riskManagement.ListBoundariesForScopeID(ctx, scope, input.RiskAssessmentScopeID, cursor) if err != nil { panic(fmt.Errorf("cannot list risk assessment boundaries: %w", err)) } return nil, types.NewListRiskAssessmentBoundariesOutput(p), nil } func (r *Resolver) GetRiskAssessmentBoundaryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskAssessmentBoundaryInput) (*mcp.CallToolResult, types.GetRiskAssessmentBoundaryOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentBoundaryGet) if err != nil { return nil, types.GetRiskAssessmentBoundaryOutput{}, err } b, err := r.riskManagement.GetBoundary(ctx, scope, input.ID) if err != nil { return nil, types.GetRiskAssessmentBoundaryOutput{}, fmt.Errorf("failed to get risk assessment boundary: %w", err) } return nil, types.GetRiskAssessmentBoundaryOutput{ RiskAssessmentBoundary: types.NewRiskAssessmentBoundary(b), }, nil } func (r *Resolver) AddRiskAssessmentBoundaryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskAssessmentBoundaryInput) (*mcp.CallToolResult, types.AddRiskAssessmentBoundaryOutput, error) { scope, err := r.Authorize(ctx, input.RiskAssessmentScopeID, probo.ActionRiskAssessmentBoundaryCreate) if err != nil { return nil, types.AddRiskAssessmentBoundaryOutput{}, err } b, err := r.riskManagement.CreateBoundary(ctx, scope, riskmanagement.CreateRiskAssessmentBoundaryRequest{ RiskAssessmentScopeID: input.RiskAssessmentScopeID, ParentBoundaryID: input.ParentBoundaryID, Name: input.Name, }) if err != nil { return nil, types.AddRiskAssessmentBoundaryOutput{}, fmt.Errorf("failed to create risk assessment boundary: %w", err) } return nil, types.AddRiskAssessmentBoundaryOutput{ RiskAssessmentBoundary: types.NewRiskAssessmentBoundary(b), }, nil } func (r *Resolver) UpdateRiskAssessmentBoundaryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateRiskAssessmentBoundaryInput) (*mcp.CallToolResult, types.UpdateRiskAssessmentBoundaryOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentBoundaryUpdate) if err != nil { return nil, types.UpdateRiskAssessmentBoundaryOutput{}, err } var parentBoundaryID **gid.GID if input.ParentBoundaryID != nil { parentBoundaryID = &input.ParentBoundaryID } b, err := r.riskManagement.UpdateBoundary(ctx, scope, riskmanagement.UpdateRiskAssessmentBoundaryRequest{ ID: input.ID, ParentBoundaryID: parentBoundaryID, Name: input.Name, }) if err != nil { return nil, types.UpdateRiskAssessmentBoundaryOutput{}, fmt.Errorf("failed to update risk assessment boundary: %w", err) } return nil, types.UpdateRiskAssessmentBoundaryOutput{ RiskAssessmentBoundary: types.NewRiskAssessmentBoundary(b), }, nil } func (r *Resolver) DeleteRiskAssessmentBoundaryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteRiskAssessmentBoundaryInput) (*mcp.CallToolResult, types.DeleteRiskAssessmentBoundaryOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionRiskAssessmentBoundaryDelete) if err != nil { return nil, types.DeleteRiskAssessmentBoundaryOutput{}, err } if err := r.riskManagement.DeleteBoundary(ctx, scope, input.ID); err != nil { return nil, types.DeleteRiskAssessmentBoundaryOutput{}, fmt.Errorf("failed to delete risk assessment boundary: %w", err) } return nil, types.DeleteRiskAssessmentBoundaryOutput{ DeletedRiskAssessmentBoundaryID: input.ID, }, nil } func (r *Resolver) SetResourceAliasTool(ctx context.Context, req *mcp.CallToolRequest, input *types.SetResourceAliasInput) (*mcp.CallToolResult, types.SetResourceAliasOutput, error) { scope, err := r.Authorize(ctx, input.ResourceID, resourcealias.ActionAliasSet) if err != nil { return nil, types.SetResourceAliasOutput{}, err } alias, err := r.resourceAlias.Create( ctx, scope, resourcealias.CreateRequest{ ResourceID: input.ResourceID, Alias: input.Alias, }, ) if err != nil { return nil, types.SetResourceAliasOutput{}, fmt.Errorf("cannot set resource alias: %w", err) } return nil, types.SetResourceAliasOutput{ ResourceAlias: types.NewResourceAlias(input.ResourceID, alias), }, nil } func (r *Resolver) RemoveResourceAliasTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RemoveResourceAliasInput) (*mcp.CallToolResult, types.RemoveResourceAliasOutput, error) { scope, err := r.Authorize(ctx, input.ResourceID, resourcealias.ActionAliasRemove) if err != nil { return nil, types.RemoveResourceAliasOutput{}, err } err = r.resourceAlias.Remove(ctx, scope, input.ResourceID) if err != nil { return nil, types.RemoveResourceAliasOutput{}, fmt.Errorf("cannot remove resource alias: %w", err) } return nil, types.RemoveResourceAliasOutput{ DeletedResourceID: input.ResourceID, }, nil } // ListCommitmentGroupsTool handles the listCommitmentGroups tool // List all commitment groups for a trust center func (r *Resolver) ListCommitmentGroupsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCommitmentGroupsInput) (*mcp.CallToolResult, types.ListCommitmentGroupsOutput, error) { scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalCommitmentGroupList) if err != nil { return nil, types.ListCommitmentGroupsOutput{}, err } pageOrderBy := page.OrderBy[coredata.CompliancePortalCommitmentGroupOrderField]{ Field: coredata.CompliancePortalCommitmentGroupOrderFieldRank, Direction: page.OrderDirectionAsc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.CompliancePortalCommitmentGroupOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.management.ListCommitmentGroups(ctx, scope, input.TrustCenterID, cursor) if err != nil { return nil, types.ListCommitmentGroupsOutput{}, fmt.Errorf("cannot list commitment groups: %w", err) } return nil, types.NewListCommitmentGroupsOutput(p), nil } // AddCommitmentGroupTool handles the addCommitmentGroup tool // Add a new commitment group to a trust center func (r *Resolver) AddCommitmentGroupTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddCommitmentGroupInput) (*mcp.CallToolResult, types.AddCommitmentGroupOutput, error) { scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalCommitmentGroupCreate) if err != nil { return nil, types.AddCommitmentGroupOutput{}, err } group, err := r.management.CreateCommitmentGroup( ctx, scope, &management.CreateCompliancePortalCommitmentGroupRequest{ CompliancePortalID: input.TrustCenterID, Title: input.Title, Description: input.Description, }, ) if err != nil { return nil, types.AddCommitmentGroupOutput{}, fmt.Errorf("cannot add commitment group: %w", err) } return nil, types.AddCommitmentGroupOutput{CommitmentGroup: types.NewCommitmentGroup(group)}, nil } // UpdateCommitmentGroupTool handles the updateCommitmentGroup tool // Update an existing commitment group func (r *Resolver) UpdateCommitmentGroupTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateCommitmentGroupInput) (*mcp.CallToolResult, types.UpdateCommitmentGroupOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalCommitmentGroupUpdate) if err != nil { return nil, types.UpdateCommitmentGroupOutput{}, err } updateReq := &management.UpdateCompliancePortalCommitmentGroupRequest{ ID: input.ID, } if title := UnwrapOmittable(input.Title); title != nil { updateReq.Title = *title } if description := UnwrapOmittable(input.Description); description != nil { updateReq.Description = *description } if rank := UnwrapOmittable(input.Rank); rank != nil { updateReq.Rank = *rank } group, err := r.management.UpdateCommitmentGroup(ctx, scope, updateReq) if err != nil { return nil, types.UpdateCommitmentGroupOutput{}, fmt.Errorf("cannot update commitment group: %w", err) } return nil, types.UpdateCommitmentGroupOutput{CommitmentGroup: types.NewCommitmentGroup(group)}, nil } // DeleteCommitmentGroupTool handles the deleteCommitmentGroup tool // Delete a commitment group func (r *Resolver) DeleteCommitmentGroupTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCommitmentGroupInput) (*mcp.CallToolResult, types.DeleteCommitmentGroupOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalCommitmentGroupDelete) if err != nil { return nil, types.DeleteCommitmentGroupOutput{}, err } err = r.management.DeleteCommitmentGroup(ctx, scope, input.ID) if err != nil { return nil, types.DeleteCommitmentGroupOutput{}, fmt.Errorf("cannot delete commitment group: %w", err) } return nil, types.DeleteCommitmentGroupOutput{DeletedCommitmentGroupID: input.ID}, nil } // ListCommitmentsTool handles the listCommitments tool // List all commitments in a commitment group func (r *Resolver) ListCommitmentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCommitmentsInput) (*mcp.CallToolResult, types.ListCommitmentsOutput, error) { scope, err := r.Authorize(ctx, input.GroupID, management.ActionCompliancePortalCommitmentList) if err != nil { return nil, types.ListCommitmentsOutput{}, err } pageOrderBy := page.OrderBy[coredata.CompliancePortalCommitmentOrderField]{ Field: coredata.CompliancePortalCommitmentOrderFieldRank, Direction: page.OrderDirectionAsc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.CompliancePortalCommitmentOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.management.ListCommitments(ctx, scope, input.GroupID, cursor) if err != nil { return nil, types.ListCommitmentsOutput{}, fmt.Errorf("cannot list commitments: %w", err) } return nil, types.NewListCommitmentsOutput(p), nil } // AddCommitmentTool handles the addCommitment tool // Add a new commitment to a commitment group func (r *Resolver) AddCommitmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddCommitmentInput) (*mcp.CallToolResult, types.AddCommitmentOutput, error) { scope, err := r.Authorize(ctx, input.GroupID, management.ActionCompliancePortalCommitmentCreate) if err != nil { return nil, types.AddCommitmentOutput{}, err } commitment, err := r.management.CreateCommitment( ctx, scope, &management.CreateCompliancePortalCommitmentRequest{ GroupID: input.GroupID, Icon: input.Icon, Eyebrow: input.Eyebrow, Title: input.Title, Description: input.Description, }, ) if err != nil { return nil, types.AddCommitmentOutput{}, fmt.Errorf("cannot add commitment: %w", err) } return nil, types.AddCommitmentOutput{Commitment: types.NewCommitment(commitment)}, nil } // UpdateCommitmentTool handles the updateCommitment tool // Update an existing commitment func (r *Resolver) UpdateCommitmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateCommitmentInput) (*mcp.CallToolResult, types.UpdateCommitmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalCommitmentUpdate) if err != nil { return nil, types.UpdateCommitmentOutput{}, err } updateReq := &management.UpdateCompliancePortalCommitmentRequest{ ID: input.ID, } if icon := UnwrapOmittable(input.Icon); icon != nil { updateReq.Icon = *icon } if eyebrow := UnwrapOmittable(input.Eyebrow); eyebrow != nil { updateReq.Eyebrow = *eyebrow } if title := UnwrapOmittable(input.Title); title != nil { updateReq.Title = *title } if description := UnwrapOmittable(input.Description); description != nil { updateReq.Description = *description } if rank := UnwrapOmittable(input.Rank); rank != nil { updateReq.Rank = *rank } commitment, err := r.management.UpdateCommitment(ctx, scope, updateReq) if err != nil { return nil, types.UpdateCommitmentOutput{}, fmt.Errorf("cannot update commitment: %w", err) } return nil, types.UpdateCommitmentOutput{Commitment: types.NewCommitment(commitment)}, nil } // DeleteCommitmentTool handles the deleteCommitment tool // Delete a commitment func (r *Resolver) DeleteCommitmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCommitmentInput) (*mcp.CallToolResult, types.DeleteCommitmentOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalCommitmentDelete) if err != nil { return nil, types.DeleteCommitmentOutput{}, err } err = r.management.DeleteCommitment(ctx, scope, input.ID) if err != nil { return nil, types.DeleteCommitmentOutput{}, fmt.Errorf("cannot delete commitment: %w", err) } return nil, types.DeleteCommitmentOutput{DeletedCommitmentID: input.ID}, nil } func (r *Resolver) RequestAuditLogExportTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RequestAuditLogExportInput) (*mcp.CallToolResult, types.RequestAuditLogExportOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, iam.ActionAuditLogExport) if err != nil { return nil, types.RequestAuditLogExportOutput{}, err } identity := authn.IdentityFromContext(ctx) logExport, err := r.iamSvc.OrganizationService.RequestLogExport( ctx, scope, iam.RequestLogExportRequest{ OrganizationID: input.OrganizationID, Type: coredata.ExportJobTypeAuditLog, FromTime: input.FromTime, ToTime: input.ToTime, RecipientEmail: identity.EmailAddress, RecipientName: identity.FullName, }, ) if err != nil { if _, ok := errors.AsType[*iam.ErrInvalidLogExportTimeRange](err); ok { return nil, types.RequestAuditLogExportOutput{}, err } return nil, types.RequestAuditLogExportOutput{}, fmt.Errorf("cannot request audit log export: %w", err) } return nil, types.RequestAuditLogExportOutput{ ExportJobID: logExport.ID, }, nil } func (r *Resolver) RequestSCIMEventExportTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RequestSCIMEventExportInput) (*mcp.CallToolResult, types.RequestSCIMEventExportOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, iam.ActionSCIMEventExport) if err != nil { return nil, types.RequestSCIMEventExportOutput{}, err } identity := authn.IdentityFromContext(ctx) logExport, err := r.iamSvc.OrganizationService.RequestLogExport( ctx, scope, iam.RequestLogExportRequest{ OrganizationID: input.OrganizationID, Type: coredata.ExportJobTypeSCIMEvent, FromTime: input.FromTime, ToTime: input.ToTime, RecipientEmail: identity.EmailAddress, RecipientName: identity.FullName, }, ) if err != nil { if _, ok := errors.AsType[*iam.ErrInvalidLogExportTimeRange](err); ok { return nil, types.RequestSCIMEventExportOutput{}, err } return nil, types.RequestSCIMEventExportOutput{}, fmt.Errorf("cannot request SCIM event export: %w", err) } return nil, types.RequestSCIMEventExportOutput{ ExportJobID: logExport.ID, }, nil } func (r *Resolver) ListDevicesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDevicesInput) (*mcp.CallToolResult, types.ListDevicesOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, itam.ActionDeviceList) if err != nil { return nil, types.ListDevicesOutput{}, err } pageOrderBy := page.OrderBy[coredata.DeviceOrderField]{ Field: coredata.DeviceOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DeviceOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } size := input.Size if size != nil && *size > maxDeviceListSize { size = new(maxDeviceListSize) } cursor := types.NewCursor(size, input.Cursor, pageOrderBy) devicePage, err := r.itamSvc.ListForOrganizationID(ctx, scope, input.OrganizationID, cursor) if err != nil { r.logger.ErrorCtx(ctx, "cannot list devices", log.Error(err)) return nil, types.ListDevicesOutput{}, fmt.Errorf("internal server error") } includePostures := input.IncludePostures != nil && *input.IncludePostures var postureScope *coredata.Scope if includePostures && len(devicePage.Data) > 0 { deviceIDs := make([]gid.GID, 0, len(devicePage.Data)) for _, d := range devicePage.Data { deviceIDs = append(deviceIDs, d.ID) } postureScope, err = r.AuthorizeBatch(ctx, deviceIDs, itam.ActionDevicePostureList) if err != nil { return nil, types.ListDevicesOutput{}, err } } posturesByDeviceID := make(map[gid.GID]coredata.DevicePostures, len(devicePage.Data)) for _, d := range devicePage.Data { if postureScope == nil { continue } postures, err := r.itamSvc.GetLatestPostures(ctx, postureScope, d.ID) if err != nil { r.logger.ErrorCtx(ctx, "cannot load latest device postures", log.Error(err)) return nil, types.ListDevicesOutput{}, fmt.Errorf("internal server error") } posturesByDeviceID[d.ID] = postures } return nil, types.NewListDevicesOutput(devicePage, posturesByDeviceID), nil } func (r *Resolver) GetDeviceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetDeviceInput) (*mcp.CallToolResult, types.GetDeviceOutput, error) { scope, err := r.Authorize(ctx, input.ID, itam.ActionDeviceGet) if err != nil { return nil, types.GetDeviceOutput{}, err } device, err := r.itamSvc.GetDevice(ctx, scope, input.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, types.GetDeviceOutput{}, fmt.Errorf("resource not found") } r.logger.ErrorCtx(ctx, "cannot get device", log.Error(err)) return nil, types.GetDeviceOutput{}, fmt.Errorf("internal server error") } var postures coredata.DevicePostures if input.IncludePostures != nil && *input.IncludePostures { postureScope, err := r.Authorize(ctx, input.ID, itam.ActionDevicePostureList) if err != nil { return nil, types.GetDeviceOutput{}, err } postures, err = r.itamSvc.GetLatestPostures(ctx, postureScope, device.ID) if err != nil { r.logger.ErrorCtx(ctx, "cannot load latest device postures", log.Error(err)) return nil, types.GetDeviceOutput{}, fmt.Errorf("internal server error") } } return nil, types.GetDeviceOutput{ Device: types.NewDevice(device, postures), }, nil } func (r *Resolver) RevokeDeviceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RevokeDeviceInput) (*mcp.CallToolResult, types.RevokeDeviceOutput, error) { scope, err := r.Authorize(ctx, input.ID, itam.ActionDeviceRevoke) if err != nil { return nil, types.RevokeDeviceOutput{}, err } device, err := r.itamSvc.RevokeDevice(ctx, scope, input.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, types.RevokeDeviceOutput{}, fmt.Errorf("resource not found") } r.logger.ErrorCtx(ctx, "cannot revoke device", log.Error(err)) return nil, types.RevokeDeviceOutput{}, fmt.Errorf("internal server error") } return nil, types.RevokeDeviceOutput{ Device: types.NewDevice(device, nil), }, nil } func (r *Resolver) DeleteDeviceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteDeviceInput) (*mcp.CallToolResult, types.DeleteDeviceOutput, error) { scope, err := r.Authorize(ctx, input.ID, itam.ActionDeviceDelete) if err != nil { return nil, types.DeleteDeviceOutput{}, err } device, err := r.itamSvc.DeleteDevice(ctx, scope, input.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, types.DeleteDeviceOutput{}, fmt.Errorf("resource not found") } if errors.Is(err, itam.ErrDeviceNotDeletable) { return nil, types.DeleteDeviceOutput{}, fmt.Errorf("device cannot be deleted") } r.logger.ErrorCtx(ctx, "cannot delete device", log.Error(err)) return nil, types.DeleteDeviceOutput{}, fmt.Errorf("internal server error") } return nil, types.DeleteDeviceOutput{ DeletedDeviceID: device.ID, }, nil } func (r *Resolver) SetDeviceOwnerTool(ctx context.Context, req *mcp.CallToolRequest, input *types.SetDeviceOwnerInput) (*mcp.CallToolResult, types.SetDeviceOwnerOutput, error) { scope, err := r.Authorize(ctx, input.ID, itam.ActionDeviceAssignOwner) if err != nil { return nil, types.SetDeviceOwnerOutput{}, err } device, err := r.itamSvc.SetDeviceOwner(ctx, scope, input.ID, input.OwnerID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, types.SetDeviceOwnerOutput{}, fmt.Errorf("resource not found") } if errors.Is(err, itam.ErrInvalidOwnerProfile) { return nil, types.SetDeviceOwnerOutput{}, fmt.Errorf("owner_id must reference a membership profile of the device organization") } r.logger.ErrorCtx(ctx, "cannot set device owner", log.Error(err)) return nil, types.SetDeviceOwnerOutput{}, fmt.Errorf("internal server error") } return nil, types.SetDeviceOwnerOutput{ Device: types.NewDevice(device, nil), }, nil } func (r *Resolver) CreateDeviceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateDeviceInput) (*mcp.CallToolResult, types.CreateDeviceOutput, error) { scope, err := r.Authorize(ctx, input.OrganizationID, itam.ActionDeviceCreate) if err != nil { return nil, types.CreateDeviceOutput{}, err } result, err := r.itamSvc.CreateDevice( ctx, scope, itam.CreateDeviceRequest{ OrganizationID: input.OrganizationID, OwnerID: input.OwnerID, }, ) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, types.CreateDeviceOutput{}, fmt.Errorf("resource not found") } if errors.Is(err, itam.ErrInvalidOwnerProfile) { return nil, types.CreateDeviceOutput{}, fmt.Errorf("owner_id must reference a membership profile of the device organization") } r.logger.ErrorCtx(ctx, "cannot create device", log.Error(err)) return nil, types.CreateDeviceOutput{}, fmt.Errorf("internal server error") } urls, err := itam.BuildEnrollmentURLs(r.baseURL, result.EnrollmentToken) if err != nil { r.logger.ErrorCtx(ctx, "cannot build enrollment URLs", log.Error(err)) return nil, types.CreateDeviceOutput{}, fmt.Errorf("internal server error") } return nil, types.CreateDeviceOutput{ Device: types.NewDevice(result.Device, nil), EnrollmentToken: result.EnrollmentToken, ServerURL: urls.ServerURL, EnrollmentURL: urls.EnrollmentURL, }, nil } func (r *Resolver) GetThirdPartyTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetThirdPartyInput) (*mcp.CallToolResult, types.GetThirdPartyOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionThirdPartyGet) if err != nil { return nil, types.GetThirdPartyOutput{}, err } thirdParty, err := r.proboSvc.ThirdParties.Get(ctx, scope, input.ID) if err != nil { return nil, types.GetThirdPartyOutput{}, fmt.Errorf("cannot get third party: %w", err) } return nil, types.GetThirdPartyOutput{ ThirdParty: types.NewThirdParty(thirdParty), }, nil } func (r *Resolver) DeleteEvidenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteEvidenceInput) (*mcp.CallToolResult, types.DeleteEvidenceOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionEvidenceDelete) if err != nil { return nil, types.DeleteEvidenceOutput{}, err } err = r.proboSvc.Evidences.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteEvidenceOutput{}, fmt.Errorf("cannot delete evidence: %w", err) } return nil, types.DeleteEvidenceOutput{ DeletedEvidenceID: input.ID, }, nil } func (r *Resolver) DeleteFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteFrameworkInput) (*mcp.CallToolResult, types.DeleteFrameworkOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionFrameworkDelete) if err != nil { return nil, types.DeleteFrameworkOutput{}, err } err = r.proboSvc.Frameworks.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteFrameworkOutput{}, fmt.Errorf("cannot delete framework: %w", err) } return nil, types.DeleteFrameworkOutput{ DeletedFrameworkID: input.ID, }, nil } func (r *Resolver) DeleteAuditReportTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteAuditReportInput) (*mcp.CallToolResult, types.DeleteAuditReportOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionAuditReportDelete) if err != nil { return nil, types.DeleteAuditReportOutput{}, err } audit, err := r.proboSvc.Audits.DeleteReport(ctx, scope, input.ID) if err != nil { return nil, types.DeleteAuditReportOutput{}, fmt.Errorf("cannot delete audit report: %w", err) } return nil, types.DeleteAuditReportOutput{ Audit: types.NewAudit(audit, nil), }, nil } func (r *Resolver) DeleteControlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteControlInput) (*mcp.CallToolResult, types.DeleteControlOutput, error) { scope, err := r.Authorize(ctx, input.ID, probo.ActionControlDelete) if err != nil { return nil, types.DeleteControlOutput{}, err } err = r.proboSvc.Controls.Delete(ctx, scope, input.ID) if err != nil { return nil, types.DeleteControlOutput{}, fmt.Errorf("cannot delete control: %w", err) } return nil, types.DeleteControlOutput{ DeletedControlID: input.ID, }, nil } func (r *Resolver) ApproveDocumentVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ApproveDocumentVersionInput) (*mcp.CallToolResult, types.ApproveDocumentVersionOutput, error) { scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionApprove) if err != nil { return nil, types.ApproveDocumentVersionOutput{}, err } identity := authn.IdentityFromContext(ctx) signer := signerMetadataFromToolRequest(req) decision, err := r.proboSvc.DocumentApprovals.Approve( ctx, scope, probo.ApproveDocumentVersionRequest{ DocumentVersionID: input.DocumentVersionID, IdentityID: identity.ID, Comment: input.Comment, SignerFullName: identity.FullName, SignerEmail: identity.EmailAddress, SignerIPAddr: signer.IPAddr, SignerUA: signer.UA, }, ) if err != nil { return nil, types.ApproveDocumentVersionOutput{}, fmt.Errorf("cannot approve document version: %w", err) } return nil, types.ApproveDocumentVersionOutput{ DocumentVersionApprovalDecision: types.NewDocumentVersionApprovalDecision(decision), }, nil } func (r *Resolver) RejectDocumentVersionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RejectDocumentVersionInput) (*mcp.CallToolResult, types.RejectDocumentVersionOutput, error) { scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionReject) if err != nil { return nil, types.RejectDocumentVersionOutput{}, err } identity := authn.IdentityFromContext(ctx) decision, err := r.proboSvc.DocumentApprovals.Reject( ctx, scope, probo.RejectDocumentVersionRequest{ DocumentVersionID: input.DocumentVersionID, IdentityID: identity.ID, Comment: input.Comment, }, ) if err != nil { return nil, types.RejectDocumentVersionOutput{}, fmt.Errorf("cannot reject document version: %w", err) } return nil, types.RejectDocumentVersionOutput{ DocumentVersionApprovalDecision: types.NewDocumentVersionApprovalDecision(decision), }, nil } func (r *Resolver) SignDocumentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.SignDocumentInput) (*mcp.CallToolResult, types.SignDocumentOutput, error) { scope, err := r.Authorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSign) if err != nil { return nil, types.SignDocumentOutput{}, err } identity := authn.IdentityFromContext(ctx) signer := signerMetadataFromToolRequest(req) signature, err := r.proboSvc.Documents.SignDocumentVersionByIdentity( ctx, scope, probo.SignDocumentVersionRequest{ DocumentVersionID: input.DocumentVersionID, IdentityID: identity.ID, SignerFullName: identity.FullName, SignerEmail: identity.EmailAddress, SignerIPAddr: signer.IPAddr, SignerUA: signer.UA, }, ) if err != nil { return nil, types.SignDocumentOutput{}, fmt.Errorf("cannot sign document: %w", err) } return nil, types.SignDocumentOutput{ DocumentVersionSignature: types.NewDocumentVersionSignature(signature), }, nil } func (r *Resolver) GetMailingListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetMailingListInput) (*mcp.CallToolResult, types.GetMailingListOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionMailingListSubscriberList) if err != nil { return nil, types.GetMailingListOutput{}, err } mailingList, err := r.management.GetMailingList(ctx, scope, input.CompliancePortalID) if err != nil { return nil, types.GetMailingListOutput{}, fmt.Errorf("cannot get mailing list: %w", err) } return nil, types.GetMailingListOutput{MailingList: types.NewMailingList(mailingList)}, nil } func (r *Resolver) UpdateMailingListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateMailingListInput) (*mcp.CallToolResult, types.UpdateMailingListOutput, error) { if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListUpdate); err != nil { return nil, types.UpdateMailingListOutput{}, err } mailingList, err := r.mailman.UpdateMailingList(ctx, input.ID, input.ReplyTo) if err != nil { return nil, types.UpdateMailingListOutput{}, fmt.Errorf("cannot update mailing list: %w", err) } return nil, types.UpdateMailingListOutput{MailingList: types.NewMailingList(mailingList)}, nil } func (r *Resolver) ListMailingListSubscribersTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMailingListSubscribersInput) (*mcp.CallToolResult, types.ListMailingListSubscribersOutput, error) { if _, err := r.Authorize(ctx, input.MailingListID, management.ActionMailingListSubscriberList); err != nil { return nil, types.ListMailingListSubscribersOutput{}, err } pageOrderBy := page.OrderBy[coredata.MailingListSubscriberOrderField]{ Field: coredata.MailingListSubscriberOrderFieldCreatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.MailingListSubscriberOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.mailman.ListSubscribers(ctx, input.MailingListID, cursor) if err != nil { return nil, types.ListMailingListSubscribersOutput{}, fmt.Errorf("cannot list mailing list subscribers: %w", err) } return nil, types.NewListMailingListSubscribersOutput(p), nil } func (r *Resolver) AddMailingListSubscriberTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddMailingListSubscriberInput) (*mcp.CallToolResult, types.AddMailingListSubscriberOutput, error) { if _, err := r.Authorize(ctx, input.MailingListID, management.ActionMailingListSubscriberCreate); err != nil { return nil, types.AddMailingListSubscriberOutput{}, err } subscriber, err := r.mailman.CreateSubscriber( ctx, &mailman.CreateSubscriberRequest{ MailingListID: input.MailingListID, Email: input.Email, FullName: input.FullName, Confirmed: input.Confirmed != nil && *input.Confirmed, }, ) if err != nil { return nil, types.AddMailingListSubscriberOutput{}, fmt.Errorf("cannot add mailing list subscriber: %w", err) } return nil, types.AddMailingListSubscriberOutput{ MailingListSubscriber: types.NewMailingListSubscriber(subscriber), }, nil } func (r *Resolver) DeleteMailingListSubscriberTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteMailingListSubscriberInput) (*mcp.CallToolResult, types.DeleteMailingListSubscriberOutput, error) { if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListSubscriberDelete); err != nil { return nil, types.DeleteMailingListSubscriberOutput{}, err } if err := r.mailman.DeleteSubscriber(ctx, input.ID); err != nil { return nil, types.DeleteMailingListSubscriberOutput{}, fmt.Errorf("cannot delete mailing list subscriber: %w", err) } return nil, types.DeleteMailingListSubscriberOutput{ DeletedMailingListSubscriberID: input.ID, }, nil } func (r *Resolver) ListMailingListUpdatesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListMailingListUpdatesInput) (*mcp.CallToolResult, types.ListMailingListUpdatesOutput, error) { if _, err := r.Authorize(ctx, input.MailingListID, management.ActionMailingListUpdateList); err != nil { return nil, types.ListMailingListUpdatesOutput{}, err } pageOrderBy := page.OrderBy[coredata.MailingListUpdateOrderField]{ Field: coredata.MailingListUpdateOrderFieldUpdatedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.MailingListUpdateOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.mailman.ListMailingListUpdates(ctx, input.MailingListID, cursor) if err != nil { return nil, types.ListMailingListUpdatesOutput{}, fmt.Errorf("cannot list mailing list updates: %w", err) } return nil, types.NewListMailingListUpdatesOutput(p), nil } func (r *Resolver) AddMailingListUpdateTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddMailingListUpdateInput) (*mcp.CallToolResult, types.AddMailingListUpdateOutput, error) { if _, err := r.Authorize(ctx, input.MailingListID, management.ActionMailingListUpdateCreate); err != nil { return nil, types.AddMailingListUpdateOutput{}, err } update, err := r.mailman.CreateMailingListUpdate( ctx, &mailman.CreateMailingListUpdateRequest{ MailingListID: input.MailingListID, Title: input.Title, Body: input.Body, }, ) if err != nil { return nil, types.AddMailingListUpdateOutput{}, fmt.Errorf("cannot add mailing list update: %w", err) } return nil, types.AddMailingListUpdateOutput{ MailingListUpdate: types.NewMailingListUpdate(update), }, nil } func (r *Resolver) UpdateMailingListUpdateTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateMailingListUpdateInput) (*mcp.CallToolResult, types.UpdateMailingListUpdateOutput, error) { if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListUpdateUpdate); err != nil { return nil, types.UpdateMailingListUpdateOutput{}, err } update, err := r.mailman.UpdateMailingListUpdate( ctx, &mailman.UpdateMailingListUpdateRequest{ ID: input.ID, Title: input.Title, Body: input.Body, }, ) if err != nil { return nil, types.UpdateMailingListUpdateOutput{}, fmt.Errorf("cannot update mailing list update: %w", err) } return nil, types.UpdateMailingListUpdateOutput{ MailingListUpdate: types.NewMailingListUpdate(update), }, nil } func (r *Resolver) SendMailingListUpdateTool(ctx context.Context, req *mcp.CallToolRequest, input *types.SendMailingListUpdateInput) (*mcp.CallToolResult, types.SendMailingListUpdateOutput, error) { if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListUpdateUpdate); err != nil { return nil, types.SendMailingListUpdateOutput{}, err } update, err := r.mailman.SendMailingListUpdate(ctx, input.ID) if err != nil { return nil, types.SendMailingListUpdateOutput{}, fmt.Errorf("cannot send mailing list update: %w", err) } return nil, types.SendMailingListUpdateOutput{ MailingListUpdate: types.NewMailingListUpdate(update), }, nil } func (r *Resolver) DeleteMailingListUpdateTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteMailingListUpdateInput) (*mcp.CallToolResult, types.DeleteMailingListUpdateOutput, error) { if _, err := r.Authorize(ctx, input.ID, management.ActionMailingListUpdateDelete); err != nil { return nil, types.DeleteMailingListUpdateOutput{}, err } if err := r.mailman.DeleteMailingListUpdate(ctx, input.ID); err != nil { return nil, types.DeleteMailingListUpdateOutput{}, fmt.Errorf("cannot delete mailing list update: %w", err) } return nil, types.DeleteMailingListUpdateOutput{ DeletedMailingListUpdateID: input.ID, }, nil } func (r *Resolver) ListDetectedTrackersTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListDetectedTrackersInput) (*mcp.CallToolResult, types.ListDetectedTrackersOutput, error) { scope, err := r.Authorize(ctx, input.TrackerPatternID, probo.ActionTrackerPatternGet) if err != nil { return nil, types.ListDetectedTrackersOutput{}, err } pageOrderBy := page.OrderBy[coredata.DetectedTrackerOrderField]{ Field: coredata.DetectedTrackerOrderFieldLastDetectedAt, Direction: page.OrderDirectionDesc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.DetectedTrackerOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) trackers, err := r.cookieBanner.ListDetectedTrackersForPattern(ctx, scope, input.TrackerPatternID, cursor) if err != nil { return nil, types.ListDetectedTrackersOutput{}, fmt.Errorf("cannot list detected trackers: %w", err) } return nil, types.NewListDetectedTrackersOutput(page.NewPage(trackers, cursor)), nil } func (r *Resolver) ListCompliancePortalFrameworksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCompliancePortalFrameworksInput) (*mcp.CallToolResult, types.ListCompliancePortalFrameworksOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionComplianceFrameworkList) if err != nil { return nil, types.ListCompliancePortalFrameworksOutput{}, err } pageOrderBy := page.OrderBy[coredata.ComplianceFrameworkOrderField]{ Field: coredata.ComplianceFrameworkOrderFieldRank, Direction: page.OrderDirectionAsc, } if input.OrderBy != nil { pageOrderBy = page.OrderBy[coredata.ComplianceFrameworkOrderField]{ Field: input.OrderBy.Field, Direction: input.OrderBy.Direction, } } cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) p, err := r.management.ListFrameworksWithHidden(ctx, scope, input.CompliancePortalID, cursor) if err != nil { return nil, types.ListCompliancePortalFrameworksOutput{}, fmt.Errorf("cannot list compliance portal frameworks: %w", err) } return nil, types.NewListCompliancePortalFrameworksOutput(p), nil } func (r *Resolver) AddCompliancePortalFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddCompliancePortalFrameworkInput) (*mcp.CallToolResult, types.AddCompliancePortalFrameworkOutput, error) { scope, err := r.Authorize(ctx, input.CompliancePortalID, management.ActionComplianceFrameworkCreate) if err != nil { return nil, types.AddCompliancePortalFrameworkOutput{}, err } framework, err := r.management.CreateFramework( ctx, scope, &management.CreateFrameworkRequest{ CompliancePortalID: input.CompliancePortalID, FrameworkID: input.FrameworkID, }, ) if err != nil { return nil, types.AddCompliancePortalFrameworkOutput{}, fmt.Errorf("cannot add compliance portal framework: %w", err) } return nil, types.AddCompliancePortalFrameworkOutput{ CompliancePortalFramework: types.NewCompliancePortalFramework(framework), }, nil } func (r *Resolver) UpdateCompliancePortalFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateCompliancePortalFrameworkInput) (*mcp.CallToolResult, types.UpdateCompliancePortalFrameworkOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionComplianceFrameworkUpdateRank) if err != nil { return nil, types.UpdateCompliancePortalFrameworkOutput{}, err } framework, err := r.management.UpdateFramework( ctx, scope, &management.UpdateFrameworkRequest{ ID: input.ID, Rank: input.Rank, }, ) if err != nil { return nil, types.UpdateCompliancePortalFrameworkOutput{}, fmt.Errorf("cannot update compliance portal framework: %w", err) } return nil, types.UpdateCompliancePortalFrameworkOutput{ CompliancePortalFramework: types.NewCompliancePortalFramework(framework), }, nil } func (r *Resolver) DeleteCompliancePortalFrameworkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCompliancePortalFrameworkInput) (*mcp.CallToolResult, types.DeleteCompliancePortalFrameworkOutput, error) { scope, err := r.Authorize(ctx, input.ID, management.ActionComplianceFrameworkDelete) if err != nil { return nil, types.DeleteCompliancePortalFrameworkOutput{}, err } err = r.management.DeleteFramework( ctx, scope, &management.DeleteFrameworkRequest{ID: input.ID}, ) if err != nil { return nil, types.DeleteCompliancePortalFrameworkOutput{}, fmt.Errorf("cannot delete compliance portal framework: %w", err) } return nil, types.DeleteCompliancePortalFrameworkOutput{ DeletedCompliancePortalFrameworkID: input.ID, }, nil }