Files
probo/pkg/server/api/mcp/v1/schema.resolvers.go
Sacha Al Himdani 1434d8336c Allow publishing generated documents as minor versions
Generated documents (asset list, risk register, SoA, ...) previously
only ever produced a new major version. Every regeneration of an
auto-built register consumed a major number, even when the change was
trivial. They now accept a minor flag and publish as
currentMajor.currentMinor+1 when set, bypassing the approval flow.

To carry the flag through cleanly, the document publish API was
refactored. The three split mutations (publishMajor, publishMinor,
requestDocumentVersionApproval) and the two bulk variants collapse
into a single publishDocument / bulkPublishDocuments, both taking the
new minor: Boolean! and a now-required changelog: String!. The same
shape flows through the CLI ("prb document publish --minor"), the MCP
tool, the n8n operations, and the Relay dialogs, where each
generated-doc dialog gains a "Publish as minor" button. Publishing
minor without an existing major is rejected with
ErrCannotPublishMinorWithoutMajor.

This is a deliberate breaking change for callers of the prior
mutations.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-06 14:02:59 +02:00

5186 lines
202 KiB
Go

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.probo.inc/probo/pkg/accessreview"
"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/mail"
"go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/probo"
"go.probo.inc/probo/pkg/server/api/authn"
"go.probo.inc/probo/pkg/server/api/mcp/v1/types"
)
// 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
}
// ListVendorsTool handles the listVendors tool
// List all vendors for the organization
func (r *Resolver) ListVendorsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListVendorsInput) (*mcp.CallToolResult, types.ListVendorsOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionVendorList)
prb := r.ProboService(ctx, input.OrganizationID)
pageOrderBy := page.OrderBy[coredata.VendorOrderField]{
Field: coredata.VendorOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.VendorOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
vendorFilter := coredata.NewVendorFilter(nil)
page, err := prb.Vendors.ListForOrganizationID(ctx, input.OrganizationID, cursor, vendorFilter)
if err != nil {
panic(fmt.Errorf("cannot list organization vendors: %w", err))
}
return nil, types.NewListVendorsOutput(page), nil
}
// AddVendorTool handles the addVendor tool
// Add a new vendor to the organization
func (r *Resolver) AddVendorTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddVendorInput) (*mcp.CallToolResult, types.AddVendorOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionVendorCreate)
svc := r.ProboService(ctx, input.OrganizationID)
var category *coredata.VendorCategory
if input.Category != nil {
cat := coredata.VendorCategory(*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)
}
}
vendor, err := svc.Vendors.Create(
ctx,
probo.CreateVendorRequest{
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.AddVendorOutput{}, fmt.Errorf("failed to create vendor: %w", err)
}
return nil, types.NewAddVendorOutput(vendor), nil
}
// UpdateVendorTool handles the updateVendor tool
// Update an existing vendor
func (r *Resolver) UpdateVendorTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateVendorInput) (*mcp.CallToolResult, types.UpdateVendorOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionVendorUpdate)
svc := r.ProboService(ctx, input.ID)
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.VendorCategory
if input.Category != nil {
cat := coredata.VendorCategory(*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)
}
}
vendor, err := svc.Vendors.Update(
ctx,
probo.UpdateVendorRequest{
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.UpdateVendorOutput{}, fmt.Errorf("failed to update vendor: %w", err)
}
return nil, types.NewUpdateVendorOutput(vendor), nil
}
func (r *Resolver) ListRisksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRisksInput) (*mcp.CallToolResult, types.ListRisksOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionRiskList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionRiskGet)
prb := r.ProboService(ctx, input.ID)
risk, err := prb.Risks.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionRiskCreate)
svc := r.ProboService(ctx, input.OrganizationID)
risk, err := svc.Risks.Create(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionRiskUpdate)
svc := r.ProboService(ctx, input.ID)
risk, err := svc.Risks.Update(
ctx,
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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionMeasureList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionMeasureGet)
prb := r.ProboService(ctx, input.ID)
measure, err := prb.Measures.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionMeasureCreate)
svc := r.ProboService(ctx, input.OrganizationID)
measure, err := svc.Measures.Create(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionMeasureUpdate)
svc := r.ProboService(ctx, input.ID)
measure, err := svc.Measures.Update(
ctx,
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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFrameworkList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionFrameworkGet)
prb := r.ProboService(ctx, input.ID)
framework, err := prb.Frameworks.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFrameworkCreate)
svc := r.ProboService(ctx, input.OrganizationID)
framework, err := svc.Frameworks.Create(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionFrameworkUpdate)
svc := r.ProboService(ctx, input.ID)
framework, err := svc.Frameworks.Update(
ctx,
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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAssetList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionAssetGet)
prb := r.ProboService(ctx, input.ID)
asset, err := prb.Assets.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAssetCreate)
svc := r.ProboService(ctx, input.OrganizationID)
asset, err := svc.Assets.Create(
ctx,
probo.CreateAssetRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
Amount: input.Amount,
OwnerID: input.OwnerID,
AssetType: input.AssetType,
DataTypesStored: input.DataTypesStored,
VendorIDs: input.VendorIds,
},
)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionAssetUpdate)
svc := r.ProboService(ctx, input.ID)
asset, err := svc.Assets.Update(
ctx,
probo.UpdateAssetRequest{
ID: input.ID,
Name: input.Name,
Amount: input.Amount,
OwnerID: input.OwnerID,
AssetType: input.AssetType,
DataTypesStored: input.DataTypesStored,
VendorIDs: input.VendorIds,
},
)
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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDatumList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDatumGet)
prb := r.ProboService(ctx, input.ID)
datum, err := prb.Data.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDatumCreate)
svc := r.ProboService(ctx, input.OrganizationID)
datum, err := svc.Data.Create(
ctx,
probo.CreateDatumRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
DataClassification: input.DataClassification,
OwnerID: input.OwnerID,
VendorIDs: input.VendorIds,
},
)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDatumUpdate)
svc := r.ProboService(ctx, input.ID)
datum, err := svc.Data.Update(
ctx,
probo.UpdateDatumRequest{
ID: input.ID,
Name: input.Name,
DataClassification: input.DataClassification,
OwnerID: input.OwnerID,
VendorIDs: input.VendorIds,
},
)
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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFindingList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionFindingGet)
prb := r.ProboService(ctx, input.ID)
finding, err := prb.Findings.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFindingCreate)
svc := r.ProboService(ctx, input.OrganizationID)
finding, err := svc.Findings.Create(
ctx,
&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) {
r.MustAuthorize(ctx, input.ID, probo.ActionFindingUpdate)
svc := r.ProboService(ctx, input.ID)
finding, err := svc.Findings.Update(
ctx,
&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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionObligationList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionObligationGet)
prb := r.ProboService(ctx, input.ID)
obligation, err := prb.Obligations.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionObligationCreate)
svc := r.ProboService(ctx, input.OrganizationID)
obligation, err := svc.Obligations.Create(
ctx,
&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) {
r.MustAuthorize(ctx, input.ID, probo.ActionObligationUpdate)
svc := r.ProboService(ctx, input.ID)
obligation, err := svc.Obligations.Update(
ctx,
&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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionProcessingActivityList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionProcessingActivityGet)
prb := r.ProboService(ctx, input.ID)
processingActivity, err := prb.ProcessingActivities.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionProcessingActivityCreate)
svc := r.ProboService(ctx, input.OrganizationID)
processingActivity, err := svc.ProcessingActivities.Create(
ctx,
&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,
VendorIDs: input.VendorIds,
},
)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionProcessingActivityUpdate)
svc := r.ProboService(ctx, input.ID)
var vendorIDs *[]gid.GID
if input.VendorIds != nil {
vendorIDs = &input.VendorIds
}
processingActivity, err := svc.ProcessingActivities.Update(
ctx,
&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),
VendorIDs: vendorIDs,
},
)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionProcessingActivityDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.ProcessingActivities.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDataProtectionImpactAssessmentList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentGet)
prb := r.ProboService(ctx, input.ID)
dpia, err := prb.DataProtectionImpactAssessments.Get(ctx, 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) {
r.MustAuthorize(ctx, input.ProcessingActivityID, probo.ActionDataProtectionImpactAssessmentCreate)
svc := r.ProboService(ctx, input.ProcessingActivityID)
dpia, err := svc.DataProtectionImpactAssessments.Create(
ctx,
&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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentUpdate)
svc := r.ProboService(ctx, input.ID)
dpia, err := svc.DataProtectionImpactAssessments.Update(
ctx,
&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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionTransferImpactAssessmentList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTransferImpactAssessmentGet)
prb := r.ProboService(ctx, input.ID)
tia, err := prb.TransferImpactAssessments.Get(ctx, 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) {
r.MustAuthorize(ctx, input.ProcessingActivityID, probo.ActionTransferImpactAssessmentCreate)
svc := r.ProboService(ctx, input.ProcessingActivityID)
tia, err := svc.TransferImpactAssessments.Create(
ctx,
&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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTransferImpactAssessmentUpdate)
svc := r.ProboService(ctx, input.ID)
tia, err := svc.TransferImpactAssessments.Update(
ctx,
&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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTransferImpactAssessmentDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.TransferImpactAssessments.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAuditList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionAuditGet)
prb := r.ProboService(ctx, input.ID)
audit, err := prb.Audits.Get(ctx, input.ID)
if err != nil {
return nil, types.GetAuditOutput{}, fmt.Errorf("cannot get audit: %w", err)
}
var report *coredata.Report
if audit.ReportID != nil {
report, err = prb.Reports.Get(ctx, *audit.ReportID)
if err != nil {
return nil, types.GetAuditOutput{}, fmt.Errorf("cannot get audit report: %w", err)
}
}
return nil, types.GetAuditOutput{
Audit: types.NewAudit(audit, report),
}, nil
}
func (r *Resolver) AddAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddAuditInput) (*mcp.CallToolResult, types.AddAuditOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAuditCreate)
svc := r.ProboService(ctx, input.OrganizationID)
audit, err := svc.Audits.Create(
ctx,
&probo.CreateAuditRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
ValidFrom: input.ValidFrom,
ValidUntil: input.ValidUntil,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionAuditUpdate)
svc := r.ProboService(ctx, input.ID)
audit, err := svc.Audits.Update(
ctx,
&probo.UpdateAuditRequest{
ID: input.ID,
Name: UnwrapOmittable(input.Name),
ValidFrom: input.ValidFrom,
ValidUntil: input.ValidUntil,
State: input.State,
TrustCenterVisibility: input.TrustCenterVisibility,
},
)
if err != nil {
return nil, types.UpdateAuditOutput{}, fmt.Errorf("cannot update audit: %w", err)
}
var report *coredata.Report
if audit.ReportID != nil {
report, err = svc.Reports.Get(ctx, *audit.ReportID)
if err != nil {
return nil, types.UpdateAuditOutput{}, fmt.Errorf("cannot get audit report: %w", err)
}
}
return nil, types.UpdateAuditOutput{
Audit: types.NewAudit(audit, report),
}, nil
}
func (r *Resolver) ListControlsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListControlsInput) (*mcp.CallToolResult, types.ListControlsOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionControlList)
prb := r.ProboService(ctx, input.OrganizationID)
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]
var err error
if input.Filter != nil && input.Filter.FrameworkID != nil {
controlPage, err = prb.Controls.ListForFrameworkID(ctx, *input.Filter.FrameworkID, cursor, controlFilter)
} else {
controlPage, err = prb.Controls.ListForOrganizationID(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionControlGet)
prb := r.ProboService(ctx, input.ID)
control, err := prb.Controls.Get(ctx, 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) {
r.MustAuthorize(ctx, input.FrameworkID, probo.ActionControlCreate)
svc := r.ProboService(ctx, input.FrameworkID)
control, err := svc.Controls.Create(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionControlUpdate)
svc := r.ProboService(ctx, input.ID)
var maturityLevel *coredata.ControlMaturityLevel
if input.MaturityLevel != nil {
v := coredata.ControlMaturityLevel(*input.MaturityLevel)
maturityLevel = &v
}
control, err := svc.Controls.Update(
ctx,
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.ProboService(ctx, input.ControlID)
switch input.ResourceID.EntityType() {
case coredata.MeasureEntityType:
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlMeasureMappingCreate)
if _, _, err := svc.Controls.CreateMeasureMapping(ctx, input.ControlID, input.ResourceID); err != nil {
return nil, types.LinkControlOutput{}, fmt.Errorf("failed to link control to measure: %w", err)
}
case coredata.DocumentEntityType:
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlDocumentMappingCreate)
if _, _, err := svc.Controls.CreateDocumentMapping(ctx, input.ControlID, input.ResourceID); err != nil {
return nil, types.LinkControlOutput{}, fmt.Errorf("failed to link control to document: %w", err)
}
case coredata.AuditEntityType:
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlAuditMappingCreate)
if _, _, err := svc.Controls.CreateAuditMapping(ctx, input.ControlID, input.ResourceID); err != nil {
return nil, types.LinkControlOutput{}, fmt.Errorf("failed to link control to audit: %w", err)
}
case coredata.ObligationEntityType:
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlObligationMappingCreate)
if _, _, err := svc.Controls.CreateObligationMapping(ctx, 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.ProboService(ctx, input.ControlID)
switch input.ResourceID.EntityType() {
case coredata.MeasureEntityType:
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlMeasureMappingDelete)
if _, _, err := svc.Controls.DeleteMeasureMapping(ctx, input.ControlID, input.ResourceID); err != nil {
return nil, types.UnlinkControlOutput{}, fmt.Errorf("failed to unlink control from measure: %w", err)
}
case coredata.DocumentEntityType:
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlDocumentMappingDelete)
if _, _, err := svc.Controls.DeleteDocumentMapping(ctx, input.ControlID, input.ResourceID); err != nil {
return nil, types.UnlinkControlOutput{}, fmt.Errorf("failed to unlink control from document: %w", err)
}
case coredata.AuditEntityType:
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlAuditMappingDelete)
if _, _, err := svc.Controls.DeleteAuditMapping(ctx, input.ControlID, input.ResourceID); err != nil {
return nil, types.UnlinkControlOutput{}, fmt.Errorf("failed to unlink control from audit: %w", err)
}
case coredata.ObligationEntityType:
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlObligationMappingDelete)
if _, _, err := svc.Controls.DeleteObligationMapping(ctx, 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) {
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlGet)
prb := r.ProboService(ctx, input.ControlID)
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, 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) {
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlGet)
prb := r.ProboService(ctx, input.ControlID)
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, 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) {
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlGet)
prb := r.ProboService(ctx, input.ControlID)
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, 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) {
r.MustAuthorize(ctx, input.ControlID, probo.ActionControlGet)
prb := r.ProboService(ctx, input.ControlID)
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, 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) {
r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskGet)
prb := r.ProboService(ctx, input.RiskID)
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, 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.ProboService(ctx, input.RiskID)
switch input.ResourceID.EntityType() {
case coredata.DocumentEntityType:
r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingCreate)
if _, _, err := svc.Risks.CreateDocumentMapping(ctx, input.RiskID, input.ResourceID); err != nil {
return nil, types.LinkRiskOutput{}, fmt.Errorf("failed to link risk to document: %w", err)
}
case coredata.MeasureEntityType:
r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingCreate)
if _, _, err := svc.Risks.CreateMeasureMapping(ctx, input.RiskID, input.ResourceID); err != nil {
return nil, types.LinkRiskOutput{}, fmt.Errorf("failed to link risk to measure: %w", err)
}
case coredata.ObligationEntityType:
r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskObligationMappingCreate)
if _, _, err := svc.Risks.CreateObligationMapping(ctx, 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.ProboService(ctx, input.RiskID)
switch input.ResourceID.EntityType() {
case coredata.DocumentEntityType:
r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingDelete)
if _, _, err := svc.Risks.DeleteDocumentMapping(ctx, input.RiskID, input.ResourceID); err != nil {
return nil, types.UnlinkRiskOutput{}, fmt.Errorf("failed to unlink risk from document: %w", err)
}
case coredata.MeasureEntityType:
r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingDelete)
if _, _, err := svc.Risks.DeleteMeasureMapping(ctx, input.RiskID, input.ResourceID); err != nil {
return nil, types.UnlinkRiskOutput{}, fmt.Errorf("failed to unlink risk from measure: %w", err)
}
case coredata.ObligationEntityType:
r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskObligationMappingDelete)
if _, _, err := svc.Risks.DeleteObligationMapping(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionTaskList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTaskGet)
prb := r.ProboService(ctx, input.ID)
task, err := prb.Tasks.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionTaskCreate)
svc := r.ProboService(ctx, input.OrganizationID)
priority := coredata.TaskPriorityMedium
if input.Priority != nil {
priority = *input.Priority
}
task, err := svc.Tasks.Create(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTaskUpdate)
svc := r.ProboService(ctx, input.ID)
task, err := svc.Tasks.Update(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTaskAssign)
svc := r.ProboService(ctx, input.ID)
task, err := svc.Tasks.Assign(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTaskUnassign)
svc := r.ProboService(ctx, input.ID)
task, err := svc.Tasks.Unassign(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTaskDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Tasks.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDocumentList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentGet)
prb := r.ProboService(ctx, input.ID)
document, err := prb.Documents.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDocumentCreate)
svc := r.ProboService(ctx, input.OrganizationID)
var trustCenterVisibility *coredata.TrustCenterVisibility
if input.TrustCenterVisibility != nil {
trustCenterVisibility = input.TrustCenterVisibility
}
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,
probo.CreateDocumentRequest{
OrganizationID: input.OrganizationID,
Title: input.Title,
Content: contentJSON,
Classification: input.Classification,
DocumentType: input.DocumentType,
TrustCenterVisibility: trustCenterVisibility,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentUpdate)
svc := r.ProboService(ctx, input.ID)
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,
probo.UpdateDocumentRequest{
DocumentID: input.ID,
Title: input.Title,
Content: content,
Classification: input.Classification,
DocumentType: input.DocumentType,
TrustCenterVisibility: input.TrustCenterVisibility,
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) {
r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentVersionList)
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.ProboService(ctx, input.DocumentID)
versionFilter := coredata.NewDocumentVersionFilter()
if input.Filter != nil && len(input.Filter.Statuses) > 0 {
versionFilter = versionFilter.WithStatuses(input.Filter.Statuses...)
}
versionPage, err := svc.Documents.ListVersions(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentVersionGet)
svc := r.ProboService(ctx, input.ID)
version, err := svc.Documents.GetVersion(ctx, 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) {
r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSignatureList)
prb := r.ProboService(ctx, input.DocumentVersionID)
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
var activeContract *bool
if input.Filter != nil {
if input.Filter.States != nil {
signatureStates = input.Filter.States
}
if input.Filter.ActiveContract != nil {
activeContract = input.Filter.ActiveContract
}
}
signatureFilter := coredata.NewDocumentVersionSignatureFilter(signatureStates, activeContract)
page, err := prb.Documents.ListSignatures(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentVersionSignatureGet)
prb := r.ProboService(ctx, input.ID)
signature, err := prb.Documents.GetVersionSignature(ctx, 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) {
r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSignatureRequest)
svc := r.ProboService(ctx, input.DocumentVersionID)
documentVersionSignature, err := svc.Documents.RequestSignature(
ctx,
probo.RequestSignatureRequest{
DocumentVersionID: input.DocumentVersionID,
Signatory: input.SignatoryID,
},
)
if err != nil {
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) {
r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentDelete)
svc := r.ProboService(ctx, input.DocumentID)
err := svc.Documents.SoftDelete(ctx, 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) {
r.MustAuthorize(ctx, input.DocumentVersionSignatureID, probo.ActionDocumentVersionCancelSignature)
svc := r.ProboService(ctx, input.DocumentVersionSignatureID)
err := svc.Documents.CancelSignatureRequest(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionRiskDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Risks.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionMeasureDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Measures.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureGet)
prb := r.ProboService(ctx, input.MeasureID)
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, 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) {
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureGet)
prb := r.ProboService(ctx, input.MeasureID)
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, 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) {
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureGet)
prb := r.ProboService(ctx, input.MeasureID)
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, 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) {
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureGet)
prb := r.ProboService(ctx, input.MeasureID)
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, 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.ProboService(ctx, input.MeasureID)
switch input.ResourceID.EntityType() {
case coredata.ControlEntityType:
r.MustAuthorize(ctx, input.MeasureID, probo.ActionControlMeasureMappingCreate)
if _, _, err := svc.Controls.CreateMeasureMapping(ctx, input.ResourceID, input.MeasureID); err != nil {
return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to control: %w", err)
}
case coredata.RiskEntityType:
r.MustAuthorize(ctx, input.MeasureID, probo.ActionRiskMeasureMappingCreate)
if _, _, err := svc.Risks.CreateMeasureMapping(ctx, input.ResourceID, input.MeasureID); err != nil {
return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to risk: %w", err)
}
case coredata.DocumentEntityType:
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingCreate)
if _, _, err := svc.Measures.CreateDocumentMapping(ctx, input.MeasureID, input.ResourceID); err != nil {
return nil, types.LinkMeasureOutput{}, fmt.Errorf("failed to link measure to document: %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.ProboService(ctx, input.MeasureID)
switch input.ResourceID.EntityType() {
case coredata.ControlEntityType:
r.MustAuthorize(ctx, input.MeasureID, probo.ActionControlMeasureMappingDelete)
if _, _, err := svc.Controls.DeleteMeasureMapping(ctx, input.ResourceID, input.MeasureID); err != nil {
return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from control: %w", err)
}
case coredata.RiskEntityType:
r.MustAuthorize(ctx, input.MeasureID, probo.ActionRiskMeasureMappingDelete)
if _, _, err := svc.Risks.DeleteMeasureMapping(ctx, input.ResourceID, input.MeasureID); err != nil {
return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from risk: %w", err)
}
case coredata.DocumentEntityType:
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureDocumentMappingDelete)
if _, _, err := svc.Measures.DeleteDocumentMapping(ctx, input.MeasureID, input.ResourceID); err != nil {
return nil, types.UnlinkMeasureOutput{}, fmt.Errorf("failed to unlink measure from document: %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) {
r.MustAuthorize(ctx, input.OrganizationID, iam.ActionMembershipProfileList)
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 input.Filter.State != nil {
filter.WithState(*input.Filter.State)
}
}
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 {
var errNotFound *iam.ErrProfileNotFound
if errors.As(err, &errNotFound) {
return nil, types.GetUserOutput{}, fmt.Errorf("user not found: %w", err)
}
return nil, types.GetUserOutput{}, fmt.Errorf("get user: %w", err)
}
r.MustAuthorize(ctx, profile.OrganizationID, iam.ActionMembershipProfileGet)
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) {
r.MustAuthorize(ctx, input.OrganizationID, iam.ActionMembershipProfileCreate)
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, &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 {
var errAlreadyExists *iam.ErrUserAlreadyExists
if errors.As(err, &errAlreadyExists) {
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) {
r.MustAuthorize(ctx, input.ProfileID, iam.ActionInvitationCreate)
invitation, err := r.iamSvc.OrganizationService.InviteUser(ctx, &iam.CreateInvitationRequest{
OrganizationID: input.OrganizationID,
ProfileID: input.ProfileID,
})
if err != nil {
var errOrgNotFound *iam.ErrOrganizationNotFound
var errUserExists *iam.ErrUserAlreadyExists
if errors.As(err, &errOrgNotFound) {
return nil, types.InviteUserOutput{}, fmt.Errorf("organization not found: %w", err)
}
if errors.As(err, &errUserExists) {
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) {
r.MustAuthorize(ctx, input.ID, iam.ActionMembershipProfileUpdate)
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) {
r.MustAuthorize(ctx, input.MembershipID, iam.ActionMembershipUpdate)
if input.Role == coredata.MembershipRoleOwner {
r.MustAuthorize(ctx, input.MembershipID, iam.ActionMembershipRoleSetOwner)
}
membership, err := r.iamSvc.OrganizationService.UpdateMempership(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) {
r.MustAuthorize(ctx, input.ProfileID, iam.ActionMembershipProfileDelete)
err := r.iamSvc.OrganizationService.RemoveUser(ctx, input.OrganizationID, input.ProfileID)
if err != nil {
var errManagedBySCIM *iam.ErrUserManagedBySCIM
var errLastOwner *iam.ErrLastActiveOwner
if errors.As(err, &errManagedBySCIM) {
return nil, types.RemoveUserOutput{}, fmt.Errorf("user is managed by SCIM and cannot be removed: %w", err)
}
if errors.As(err, &errLastOwner) {
return nil, types.RemoveUserOutput{}, fmt.Errorf("cannot remove last active owner: %w", err)
}
return nil, types.RemoveUserOutput{}, fmt.Errorf("remove user: %w", err)
}
return nil, types.RemoveUserOutput{DeletedUserID: input.ProfileID}, nil
}
func (r *Resolver) DeleteDataProtectionImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteDataProtectionImpactAssessmentInput) (*mcp.CallToolResult, types.DeleteDataProtectionImpactAssessmentOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.DataProtectionImpactAssessments.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionStatementOfApplicabilityList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionStatementOfApplicabilityGet)
prb := r.ProboService(ctx, input.ID)
soa, err := prb.StatementsOfApplicability.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionStatementOfApplicabilityCreate)
svc := r.ProboService(ctx, input.OrganizationID)
soa, err := svc.StatementsOfApplicability.Create(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionStatementOfApplicabilityUpdate)
svc := r.ProboService(ctx, input.ID)
soa, err := svc.StatementsOfApplicability.Update(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionStatementOfApplicabilityDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.StatementsOfApplicability.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.StatementOfApplicabilityID, probo.ActionApplicabilityStatementList)
prb := r.ProboService(ctx, input.StatementOfApplicabilityID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionApplicabilityStatementGet)
prb := r.ProboService(ctx, input.ID)
stmt, err := prb.StatementsOfApplicability.GetApplicabilityStatement(ctx, 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) {
r.MustAuthorize(ctx, input.StatementOfApplicabilityID, probo.ActionApplicabilityStatementCreate)
svc := r.ProboService(ctx, input.StatementOfApplicabilityID)
stmt, err := svc.StatementsOfApplicability.CreateApplicabilityStatement(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionApplicabilityStatementUpdate)
svc := r.ProboService(ctx, input.ID)
stmt, err := svc.StatementsOfApplicability.UpdateApplicabilityStatement(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionApplicabilityStatementDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.StatementsOfApplicability.DeleteApplicabilityStatement(ctx, 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
}
// ListVendorRiskAssessmentsTool handles the listVendorRiskAssessments tool
// List all risk assessments for a vendor
func (r *Resolver) ListVendorRiskAssessmentsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListVendorRiskAssessmentsInput) (*mcp.CallToolResult, types.ListVendorRiskAssessmentsOutput, error) {
r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorRiskAssessmentList)
prb := r.ProboService(ctx, input.VendorID)
pageOrderBy := page.OrderBy[coredata.VendorRiskAssessmentOrderField]{
Field: coredata.VendorRiskAssessmentOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.VendorRiskAssessmentOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
p, err := prb.Vendors.ListRiskAssessments(ctx, input.VendorID, cursor)
if err != nil {
return nil, types.ListVendorRiskAssessmentsOutput{}, fmt.Errorf("cannot list vendor risk assessments: %w", err)
}
return nil, types.NewListVendorRiskAssessmentsOutput(p), nil
}
// AddVendorRiskAssessmentTool handles the addVendorRiskAssessment tool
// Add a new risk assessment for a vendor
func (r *Resolver) AddVendorRiskAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddVendorRiskAssessmentInput) (*mcp.CallToolResult, types.AddVendorRiskAssessmentOutput, error) {
r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorRiskAssessmentCreate)
prb := r.ProboService(ctx, input.VendorID)
assessment, err := prb.Vendors.CreateRiskAssessment(
ctx,
probo.CreateVendorRiskAssessmentRequest{
VendorID: input.VendorID,
ExpiresAt: input.ExpiresAt,
DataSensitivity: input.DataSensitivity,
BusinessImpact: input.BusinessImpact,
Notes: input.Notes,
},
)
if err != nil {
return nil, types.AddVendorRiskAssessmentOutput{}, fmt.Errorf("failed to create vendor risk assessment: %w", err)
}
return nil, types.NewAddVendorRiskAssessmentOutput(assessment), nil
}
func (r *Resolver) DeleteVendorTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteVendorInput) (*mcp.CallToolResult, types.DeleteVendorOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionVendorDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Vendors.Delete(ctx, input.ID)
if err != nil {
return nil, types.DeleteVendorOutput{}, fmt.Errorf("failed to delete vendor: %w", err)
}
return nil, types.DeleteVendorOutput{
DeletedVendorID: input.ID,
}, nil
}
func (r *Resolver) DeleteFindingTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteFindingInput) (*mcp.CallToolResult, types.DeleteFindingOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionFindingDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Findings.Delete(ctx, input.ID)
if err != nil {
return nil, types.DeleteFindingOutput{}, fmt.Errorf("cannot delete finding: %w", err)
}
return nil, types.DeleteFindingOutput{
DeletedFindingID: input.ID,
}, nil
}
func (r *Resolver) LinkFindingAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.LinkFindingAuditInput) (*mcp.CallToolResult, types.LinkFindingAuditOutput, error) {
r.MustAuthorize(ctx, input.FindingID, probo.ActionFindingAuditMappingCreate)
svc := r.ProboService(ctx, input.FindingID)
finding, audit, err := svc.Findings.CreateAuditMapping(ctx, input.FindingID, input.AuditID, input.ReferenceID)
if err != nil {
return nil, types.LinkFindingAuditOutput{}, fmt.Errorf("cannot link finding to audit: %w", err)
}
return nil, types.LinkFindingAuditOutput{
Finding: types.NewFinding(finding),
Audit: types.NewAudit(audit, nil),
}, nil
}
func (r *Resolver) UnlinkFindingAuditTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnlinkFindingAuditInput) (*mcp.CallToolResult, types.UnlinkFindingAuditOutput, error) {
r.MustAuthorize(ctx, input.FindingID, probo.ActionFindingAuditMappingDelete)
svc := r.ProboService(ctx, input.FindingID)
finding, audit, err := svc.Findings.DeleteAuditMapping(ctx, input.FindingID, input.AuditID)
if err != nil {
return nil, types.UnlinkFindingAuditOutput{}, fmt.Errorf("cannot unlink finding from audit: %w", err)
}
return nil, types.UnlinkFindingAuditOutput{
DeletedFindingID: finding.ID,
DeletedAuditID: audit.ID,
}, nil
}
func (r *Resolver) ListFindingAuditsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListFindingAuditsInput) (*mcp.CallToolResult, types.ListFindingAuditsOutput, error) {
r.MustAuthorize(ctx, input.FindingID, probo.ActionFindingGet)
prb := r.ProboService(ctx, input.FindingID)
pageOrderBy := page.OrderBy[coredata.AuditOrderField]{
Field: coredata.AuditOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.AuditOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
auditPage, err := prb.Audits.ListForFindingID(ctx, input.FindingID, cursor)
if err != nil {
return nil, types.ListFindingAuditsOutput{}, fmt.Errorf("cannot list finding audits: %w", err)
}
return nil, types.NewListFindingAuditsOutput(auditPage), nil
}
// 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAccessReviewCampaignList)
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
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.Campaigns(scope).ListForOrganizationID(ctx, 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 with optional filters
func (r *Resolver) ListAccessEntriesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAccessEntriesInput) (*mcp.CallToolResult, types.ListAccessEntriesOutput, error) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessEntryList)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
pageOrderBy := page.OrderBy[coredata.AccessEntryOrderField]{
Field: coredata.AccessEntryOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.AccessEntryOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
var filter *coredata.AccessEntryFilter
if input.Filter != nil {
filter = &coredata.AccessEntryFilter{
Decision: input.Filter.Decision,
Flag: input.Filter.Flag,
IncrementalTag: input.Filter.IncrementalTag,
IsAdmin: input.Filter.IsAdmin,
AuthMethod: input.Filter.AuthMethod,
}
}
var p *page.Page[*coredata.AccessEntry, coredata.AccessEntryOrderField]
if input.AccessSourceID != nil {
var err error
p, err = r.accessReview.Entries(scope).ListForCampaignIDAndSourceID(
ctx,
input.CampaignID,
*input.AccessSourceID,
cursor,
filter,
)
if err != nil {
panic(fmt.Errorf("cannot list access entries: %w", err))
}
} else {
var err error
p, err = r.accessReview.Entries(scope).ListForCampaignID(ctx, input.CampaignID, cursor, filter)
if err != nil {
panic(fmt.Errorf("cannot list access entries: %w", err))
}
}
return nil, types.NewListAccessEntriesOutput(p), nil
}
// GetAccessReviewCampaignStatisticsTool handles the getAccessReviewCampaignStatistics tool
// Get statistics for an access review campaign
func (r *Resolver) GetAccessReviewCampaignStatisticsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetAccessReviewCampaignStatisticsInput) (*mcp.CallToolResult, types.GetAccessReviewCampaignStatisticsOutput, error) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessReviewCampaignGet)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
stats, err := r.accessReview.Entries(scope).Statistics(ctx, input.CampaignID)
if err != nil {
panic(fmt.Errorf("cannot get campaign statistics: %w", err))
}
return nil, types.GetAccessReviewCampaignStatisticsOutput{
Statistics: types.NewAccessEntryStatistics(stats),
}, nil
}
// RecordAccessEntryDecisionTool handles the recordAccessEntryDecision tool
// Record a decision on an access entry
func (r *Resolver) RecordAccessEntryDecisionTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RecordAccessEntryDecisionInput) (*mcp.CallToolResult, types.RecordAccessEntryDecisionOutput, error) {
r.MustAuthorize(ctx, input.AccessEntryID, probo.ActionAccessEntryDecide)
scope := coredata.NewScopeFromObjectID(input.AccessEntryID)
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, types.RecordAccessEntryDecisionOutput{}, fmt.Errorf("no identity in context")
}
decisionReq := accessreview.RecordAccessEntryDecisionRequest{
EntryID: input.AccessEntryID,
Decision: input.Decision,
DecisionNote: input.DecisionNote,
}
organizationID, err := r.accessReview.ResolveEntryOrganizationID(ctx, input.AccessEntryID)
if err == nil {
profile, err := r.iamSvc.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, organizationID)
if err == nil {
decisionReq.DecidedByID = &profile.ID
}
}
entry, err := r.accessReview.Entries(scope).RecordDecision(ctx, decisionReq)
if err != nil {
return nil, types.RecordAccessEntryDecisionOutput{}, fmt.Errorf("cannot record decision: %w", err)
}
return nil, types.RecordAccessEntryDecisionOutput{
AccessEntry: types.NewAccessEntry(entry),
}, nil
}
// RecordAccessEntryDecisionsTool handles the recordAccessEntryDecisions tool
// Record decisions on multiple access entries in a single batch
func (r *Resolver) RecordAccessEntryDecisionsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RecordAccessEntryDecisionsInput) (*mcp.CallToolResult, types.RecordAccessEntryDecisionsOutput, error) {
if len(input.Decisions) == 0 {
return nil, types.RecordAccessEntryDecisionsOutput{
AccessEntries: []*types.AccessEntry{},
}, nil
}
const maxBatchSize = 100
if len(input.Decisions) > maxBatchSize {
return nil, types.RecordAccessEntryDecisionsOutput{}, 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 {
r.MustAuthorize(ctx, d.AccessEntryID, probo.ActionAccessEntryDecide)
}
scope := coredata.NewScopeFromObjectID(input.Decisions[0].AccessEntryID)
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, types.RecordAccessEntryDecisionsOutput{}, fmt.Errorf("no identity in context")
}
// Cache profile lookups per organization so we resolve the correct
// decidedByID for each entry even when a batch spans multiple orgs.
profileCache := make(map[gid.GID]*gid.GID)
decisions := make([]accessreview.RecordAccessEntryDecisionRequest, len(input.Decisions))
for i, d := range input.Decisions {
var decidedByID *gid.GID
organizationID, err := r.accessReview.ResolveEntryOrganizationID(ctx, d.AccessEntryID)
if err == nil {
if cached, ok := profileCache[organizationID]; ok {
decidedByID = cached
} else {
profile, err := r.iamSvc.OrganizationService.GetProfileForIdentityAndOrganization(ctx, identity.ID, organizationID)
if err == nil {
decidedByID = &profile.ID
}
profileCache[organizationID] = decidedByID
}
}
decisions[i] = accessreview.RecordAccessEntryDecisionRequest{
EntryID: d.AccessEntryID,
Decision: d.Decision,
DecisionNote: d.DecisionNote,
DecidedByID: decidedByID,
}
}
entries, err := r.accessReview.Entries(scope).RecordDecisions(ctx, decisions)
if err != nil {
return nil, types.RecordAccessEntryDecisionsOutput{}, fmt.Errorf("cannot record decisions: %w", err)
}
accessEntries := make([]*types.AccessEntry, len(entries))
for i, e := range entries {
accessEntries[i] = types.NewAccessEntry(e)
}
return nil, types.RecordAccessEntryDecisionsOutput{
AccessEntries: 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) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessReviewCampaignClose)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
campaign, err := r.accessReview.Campaigns(scope).Close(ctx, 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
}
// ListAccessSourcesTool handles the listAccessSources tool
// List access sources for an organization
func (r *Resolver) ListAccessSourcesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListAccessSourcesInput) (*mcp.CallToolResult, types.ListAccessSourcesOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAccessSourceList)
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
pageOrderBy := page.OrderBy[coredata.AccessSourceOrderField]{
Field: coredata.AccessSourceOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.AccessSourceOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
p, err := r.accessReview.Sources(scope).ListForOrganizationID(ctx, input.OrganizationID, cursor)
if err != nil {
panic(fmt.Errorf("cannot list access sources: %w", err))
}
return nil, types.NewListAccessSourcesOutput(p), nil
}
// CreateAccessSourceTool handles the createAccessSource tool
// Create a new access source for an organization
func (r *Resolver) CreateAccessSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateAccessSourceInput) (*mcp.CallToolResult, types.CreateAccessSourceOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAccessSourceCreate)
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
source, err := r.accessReview.Sources(scope).Create(ctx, accessreview.CreateAccessSourceRequest{
OrganizationID: input.OrganizationID,
ConnectorID: input.ConnectorID,
Name: input.Name,
Category: coredata.AccessSourceCategorySaaS,
CsvData: input.CsvData,
})
if err != nil {
return nil, types.CreateAccessSourceOutput{}, fmt.Errorf("cannot create access source: %w", err)
}
return nil, types.CreateAccessSourceOutput{
AccessSource: types.NewAccessSource(source),
}, nil
}
// UpdateAccessSourceTool handles the updateAccessSource tool
// Update an existing access source
func (r *Resolver) UpdateAccessSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateAccessSourceInput) (*mcp.CallToolResult, types.UpdateAccessSourceOutput, error) {
r.MustAuthorize(ctx, input.AccessSourceID, probo.ActionAccessSourceUpdate)
scope := coredata.NewScopeFromObjectID(input.AccessSourceID)
updateReq := accessreview.UpdateAccessSourceRequest{
AccessSourceID: input.AccessSourceID,
Name: input.Name,
}
if rawConnectorID := UnwrapOmittable(input.ConnectorID); rawConnectorID != nil {
if *rawConnectorID != nil {
id, err := gid.ParseGID(**rawConnectorID)
if err != nil {
return nil, types.UpdateAccessSourceOutput{}, 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.Sources(scope).Update(ctx, updateReq)
if err != nil {
return nil, types.UpdateAccessSourceOutput{}, fmt.Errorf("cannot update access source: %w", err)
}
return nil, types.UpdateAccessSourceOutput{
AccessSource: types.NewAccessSource(source),
}, nil
}
// DeleteAccessSourceTool handles the deleteAccessSource tool
// Delete an access source
func (r *Resolver) DeleteAccessSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteAccessSourceInput) (*mcp.CallToolResult, types.DeleteAccessSourceOutput, error) {
r.MustAuthorize(ctx, input.AccessSourceID, probo.ActionAccessSourceDelete)
scope := coredata.NewScopeFromObjectID(input.AccessSourceID)
if err := r.accessReview.Sources(scope).Delete(ctx, input.AccessSourceID); err != nil {
return nil, types.DeleteAccessSourceOutput{}, fmt.Errorf("cannot delete access source: %w", err)
}
return nil, types.DeleteAccessSourceOutput{
DeletedAccessSourceID: input.AccessSourceID,
}, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAccessReviewCampaignCreate)
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
var description string
if input.Description != nil {
description = *input.Description
}
campaign, err := r.accessReview.Campaigns(scope).Create(ctx, accessreview.CreateAccessReviewCampaignRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
Description: description,
FrameworkControls: input.FrameworkControls,
AccessSourceIDs: input.AccessSourceIds,
})
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) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessReviewCampaignUpdate)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
updateReq := accessreview.UpdateAccessReviewCampaignRequest{
CampaignID: input.CampaignID,
Name: input.Name,
Description: input.Description,
}
if rawControls := UnwrapOmittable(input.FrameworkControls); rawControls != nil {
if *rawControls != nil {
controls := make([]string, 0, len(**rawControls))
for _, v := range **rawControls {
if s, ok := v.(string); ok {
controls = append(controls, s)
}
}
updateReq.FrameworkControls = &controls
} else {
empty := []string{}
updateReq.FrameworkControls = &empty
}
}
campaign, err := r.accessReview.Campaigns(scope).Update(ctx, 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) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessReviewCampaignDelete)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
if err := r.accessReview.Campaigns(scope).Delete(ctx, 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) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessReviewCampaignStart)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
campaign, err := r.accessReview.Campaigns(scope).Start(ctx, 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) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessReviewCampaignCancel)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
campaign, err := r.accessReview.Campaigns(scope).Cancel(ctx, 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
}
// AddAccessReviewCampaignScopeSourceTool handles the addAccessReviewCampaignScopeSource tool
// Add an access source to an access review campaign's scope
func (r *Resolver) AddAccessReviewCampaignScopeSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddAccessReviewCampaignScopeSourceInput) (*mcp.CallToolResult, types.AddAccessReviewCampaignScopeSourceOutput, error) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessReviewCampaignAddScopeSource)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
campaign, err := r.accessReview.Campaigns(scope).AddScopeSource(ctx, accessreview.AddCampaignScopeSourceRequest{
CampaignID: input.CampaignID,
AccessSourceID: input.AccessSourceID,
})
if err != nil {
return nil, types.AddAccessReviewCampaignScopeSourceOutput{}, fmt.Errorf("cannot add scope source to access review campaign: %w", err)
}
return nil, types.AddAccessReviewCampaignScopeSourceOutput{
Campaign: types.NewAccessReviewCampaign(campaign),
}, nil
}
// RemoveAccessReviewCampaignScopeSourceTool handles the removeAccessReviewCampaignScopeSource tool
// Remove an access source from an access review campaign's scope
func (r *Resolver) RemoveAccessReviewCampaignScopeSourceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.RemoveAccessReviewCampaignScopeSourceInput) (*mcp.CallToolResult, types.RemoveAccessReviewCampaignScopeSourceOutput, error) {
r.MustAuthorize(ctx, input.CampaignID, probo.ActionAccessReviewCampaignRemoveScopeSource)
scope := coredata.NewScopeFromObjectID(input.CampaignID)
campaign, err := r.accessReview.Campaigns(scope).RemoveScopeSource(ctx, accessreview.RemoveCampaignScopeSourceRequest{
CampaignID: input.CampaignID,
AccessSourceID: input.AccessSourceID,
})
if err != nil {
return nil, types.RemoveAccessReviewCampaignScopeSourceOutput{}, fmt.Errorf("cannot remove scope source from access review campaign: %w", err)
}
return nil, types.RemoveAccessReviewCampaignScopeSourceOutput{
Campaign: types.NewAccessReviewCampaign(campaign),
}, nil
}
// FlagAccessEntryTool handles the flagAccessEntry tool
// Flag an access entry during review
func (r *Resolver) FlagAccessEntryTool(ctx context.Context, req *mcp.CallToolRequest, input *types.FlagAccessEntryInput) (*mcp.CallToolResult, types.FlagAccessEntryOutput, error) {
r.MustAuthorize(ctx, input.AccessEntryID, probo.ActionAccessEntryFlag)
scope := coredata.NewScopeFromObjectID(input.AccessEntryID)
entry, err := r.accessReview.Entries(scope).FlagEntry(ctx, accessreview.FlagAccessEntryRequest{
EntryID: input.AccessEntryID,
Flags: input.Flags,
FlagReasons: input.FlagReasons,
})
if err != nil {
return nil, types.FlagAccessEntryOutput{}, fmt.Errorf("cannot flag access entry: %w", err)
}
return nil, types.FlagAccessEntryOutput{
AccessEntry: types.NewAccessEntry(entry),
}, nil
}
func (r *Resolver) GetAuditReportUrlTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetAuditReportUrlInput) (*mcp.CallToolResult, types.GetAuditReportUrlOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionReportGetReportUrl)
prb := r.ProboService(ctx, input.ID)
url, err := prb.Audits.GenerateReportURL(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentArchive)
svc := r.ProboService(ctx, input.ID)
document, err := svc.Documents.Archive(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentUnarchive)
svc := r.ProboService(ctx, input.ID)
document, err := svc.Documents.Unarchive(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionOrganizationContextGet)
prb := r.ProboService(ctx, input.OrganizationID)
orgContext, err := prb.Organizations.GetContext(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionOrganizationContextUpdate)
prb := r.ProboService(ctx, input.OrganizationID)
orgContext, err := prb.Organizations.UpdateContext(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, iam.ActionAuditLogEntryGet)
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) {
r.MustAuthorize(ctx, input.OrganizationID, iam.ActionAuditLogEntryList)
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) {
r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureGet)
prb := r.ProboService(ctx, input.MeasureID)
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, 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) {
r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionVoidApproval)
svc := r.ProboService(ctx, input.DocumentVersionID)
_, documentVersion, err := svc.DocumentApprovals.VoidApproval(ctx, 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) SendSigningNotificationsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.SendSigningNotificationsInput) (*mcp.CallToolResult, types.SendSigningNotificationsOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDocumentSendSigningNotifications)
svc := r.ProboService(ctx, input.OrganizationID)
err := svc.Documents.SendSigningNotifications(ctx, input.OrganizationID)
if err != nil {
panic(fmt.Errorf("cannot send signing notifications: %w", err))
}
return nil, types.SendSigningNotificationsOutput{
Success: true,
}, nil
}
func (r *Resolver) DeleteDocumentDraftTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteDocumentDraftInput) (*mcp.CallToolResult, types.DeleteDocumentDraftOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentDeleteDraft)
svc := r.ProboService(ctx, input.ID)
document, err := svc.Documents.DeleteDraft(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionStatementOfApplicabilityPublish)
svc := r.ProboService(ctx, input.ID)
document, documentVersion, err := svc.GeneratedDocuments.PublishStatementOfApplicability(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionWebhookSubscriptionList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionWebhookSubscriptionGet)
prb := r.ProboService(ctx, input.ID)
subscription, err := prb.WebhookSubscriptions.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionWebhookSubscriptionCreate)
prb := r.ProboService(ctx, input.OrganizationID)
subscription, err := prb.WebhookSubscriptions.Create(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionWebhookSubscriptionUpdate)
prb := r.ProboService(ctx, input.ID)
subscription, err := prb.WebhookSubscriptions.Update(
ctx,
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionWebhookSubscriptionDelete)
prb := r.ProboService(ctx, input.ID)
err := prb.WebhookSubscriptions.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.WebhookSubscriptionID, probo.ActionWebhookSubscriptionGet)
prb := r.ProboService(ctx, input.WebhookSubscriptionID)
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, 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) {
r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionApprovalList)
svc := r.ProboService(ctx, input.DocumentVersionID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentVersionApprovalList)
svc := r.ProboService(ctx, input.ID)
quorum, err := svc.DocumentApprovals.GetQuorum(ctx, 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) {
r.MustAuthorize(ctx, input.QuorumID, probo.ActionDocumentVersionApprovalList)
svc := r.ProboService(ctx, input.QuorumID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDocumentVersionApprovalList)
svc := r.ProboService(ctx, input.ID)
decision, err := svc.DocumentApprovals.GetDecision(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDatumPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishDataList(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAssetPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishAssetList(ctx, 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
}
// ListVendorContactsTool handles the listVendorContacts tool
// List all contacts for a vendor
func (r *Resolver) ListVendorContactsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListVendorContactsInput) (*mcp.CallToolResult, types.ListVendorContactsOutput, error) {
r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorContactList)
prb := r.ProboService(ctx, input.VendorID)
pageOrderBy := page.OrderBy[coredata.VendorContactOrderField]{
Field: coredata.VendorContactOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.VendorContactOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
p, err := prb.VendorContacts.List(ctx, input.VendorID, cursor)
if err != nil {
return nil, types.ListVendorContactsOutput{}, fmt.Errorf("cannot list vendor contacts: %w", err)
}
return nil, types.NewListVendorContactsOutput(p), nil
}
// AddVendorContactTool handles the addVendorContact tool
// Add a new contact to a vendor
func (r *Resolver) AddVendorContactTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddVendorContactInput) (*mcp.CallToolResult, types.AddVendorContactOutput, error) {
r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorContactCreate)
prb := r.ProboService(ctx, input.VendorID)
emailAddr, err := mail.ParseAddr(input.Email)
if err != nil {
return nil, types.AddVendorContactOutput{}, fmt.Errorf("invalid email address: %w", err)
}
vendorContact, err := prb.VendorContacts.Create(ctx, probo.CreateVendorContactRequest{
VendorID: input.VendorID,
FullName: &input.FullName,
Email: &emailAddr,
Phone: &input.Phone,
Role: &input.Role,
})
if err != nil {
return nil, types.AddVendorContactOutput{}, fmt.Errorf("cannot create vendor contact: %w", err)
}
return nil, types.AddVendorContactOutput{
VendorContact: types.NewVendorContact(vendorContact),
}, nil
}
// UpdateVendorContactTool handles the updateVendorContact tool
// Update an existing vendor contact
func (r *Resolver) UpdateVendorContactTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateVendorContactInput) (*mcp.CallToolResult, types.UpdateVendorContactOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionVendorContactUpdate)
prb := r.ProboService(ctx, input.ID)
updateReq := probo.UpdateVendorContactRequest{
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.UpdateVendorContactOutput{}, 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
}
vendorContact, err := prb.VendorContacts.Update(ctx, updateReq)
if err != nil {
return nil, types.UpdateVendorContactOutput{}, fmt.Errorf("cannot update vendor contact: %w", err)
}
return nil, types.UpdateVendorContactOutput{
VendorContact: types.NewVendorContact(vendorContact),
}, nil
}
// DeleteVendorContactTool handles the deleteVendorContact tool
// Delete a vendor contact
func (r *Resolver) DeleteVendorContactTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteVendorContactInput) (*mcp.CallToolResult, types.DeleteVendorContactOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionVendorContactDelete)
prb := r.ProboService(ctx, input.ID)
err := prb.VendorContacts.Delete(ctx, input.ID)
if err != nil {
return nil, types.DeleteVendorContactOutput{}, fmt.Errorf("cannot delete vendor contact: %w", err)
}
return nil, types.DeleteVendorContactOutput{
DeletedVendorContactID: input.ID,
}, nil
}
// ListVendorServicesTool handles the listVendorServices tool
// List all services for a vendor
func (r *Resolver) ListVendorServicesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListVendorServicesInput) (*mcp.CallToolResult, types.ListVendorServicesOutput, error) {
r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorServiceList)
prb := r.ProboService(ctx, input.VendorID)
pageOrderBy := page.OrderBy[coredata.VendorServiceOrderField]{
Field: coredata.VendorServiceOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.VendorServiceOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
p, err := prb.VendorServices.List(ctx, input.VendorID, cursor)
if err != nil {
return nil, types.ListVendorServicesOutput{}, fmt.Errorf("cannot list vendor services: %w", err)
}
return nil, types.NewListVendorServicesOutput(p), nil
}
// AddVendorServiceTool handles the addVendorService tool
// Add a new service to a vendor
func (r *Resolver) AddVendorServiceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddVendorServiceInput) (*mcp.CallToolResult, types.AddVendorServiceOutput, error) {
r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorServiceCreate)
prb := r.ProboService(ctx, input.VendorID)
vendorService, err := prb.VendorServices.Create(ctx, probo.CreateVendorServiceRequest{
VendorID: input.VendorID,
Name: input.Name,
Description: input.Description,
})
if err != nil {
return nil, types.AddVendorServiceOutput{}, fmt.Errorf("cannot create vendor service: %w", err)
}
return nil, types.AddVendorServiceOutput{
VendorService: types.NewVendorService(vendorService),
}, nil
}
// UpdateVendorServiceTool handles the updateVendorService tool
// Update an existing vendor service
func (r *Resolver) UpdateVendorServiceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateVendorServiceInput) (*mcp.CallToolResult, types.UpdateVendorServiceOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionVendorServiceUpdate)
prb := r.ProboService(ctx, input.ID)
updateReq := probo.UpdateVendorServiceRequest{
ID: input.ID,
}
if input.Name != nil {
updateReq.Name = input.Name
}
if input.Description != nil {
updateReq.Description = &input.Description
}
vendorService, err := prb.VendorServices.Update(ctx, updateReq)
if err != nil {
return nil, types.UpdateVendorServiceOutput{}, fmt.Errorf("cannot update vendor service: %w", err)
}
return nil, types.UpdateVendorServiceOutput{
VendorService: types.NewVendorService(vendorService),
}, nil
}
// DeleteVendorServiceTool handles the deleteVendorService tool
// Delete a vendor service
func (r *Resolver) DeleteVendorServiceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteVendorServiceInput) (*mcp.CallToolResult, types.DeleteVendorServiceOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionVendorServiceDelete)
prb := r.ProboService(ctx, input.ID)
err := prb.VendorServices.Delete(ctx, input.ID)
if err != nil {
return nil, types.DeleteVendorServiceOutput{}, fmt.Errorf("cannot delete vendor service: %w", err)
}
return nil, types.DeleteVendorServiceOutput{
DeletedVendorServiceID: input.ID,
}, nil
}
func (r *Resolver) DeleteAssetTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteAssetInput) (*mcp.CallToolResult, types.DeleteAssetOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionAssetDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Assets.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionDatumDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Data.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionObligationDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Obligations.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionAuditDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.Audits.Delete(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionRightsRequestList)
prb := r.ProboService(ctx, input.OrganizationID)
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, 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) {
r.MustAuthorize(ctx, input.ID, probo.ActionRightsRequestGet)
prb := r.ProboService(ctx, input.ID)
rightsRequest, err := prb.RightsRequests.Get(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionRightsRequestCreate)
svc := r.ProboService(ctx, input.OrganizationID)
rightsRequest, err := svc.RightsRequests.Create(
ctx,
&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) {
r.MustAuthorize(ctx, input.ID, probo.ActionRightsRequestUpdate)
svc := r.ProboService(ctx, input.ID)
var dataSubject **string
if input.DataSubject != nil {
dataSubject = &input.DataSubject
}
rightsRequest, err := svc.RightsRequests.Update(
ctx,
&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) {
r.MustAuthorize(ctx, input.ID, probo.ActionRightsRequestDelete)
svc := r.ProboService(ctx, input.ID)
err := svc.RightsRequests.Delete(ctx, 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
}
// GetTrustCenterTool handles the getTrustCenter tool
// Get the trust center for an organization
func (r *Resolver) GetTrustCenterTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetTrustCenterInput) (*mcp.CallToolResult, types.GetTrustCenterOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionTrustCenterGet)
prb := r.ProboService(ctx, input.OrganizationID)
trustCenter, err := prb.TrustCenters.GetByOrganizationID(ctx, input.OrganizationID)
if err != nil {
return nil, types.GetTrustCenterOutput{}, fmt.Errorf("cannot get trust center: %w", err)
}
tc := types.NewTrustCenter(trustCenter)
logoURL, err := prb.TrustCenters.GenerateLogoURL(ctx, trustCenter.ID, 1*time.Hour)
if err == nil {
tc.LogoFileURL = logoURL
}
darkLogoURL, err := prb.TrustCenters.GenerateDarkLogoURL(ctx, trustCenter.ID, 1*time.Hour)
if err == nil {
tc.DarkLogoFileURL = darkLogoURL
}
ndaFileURL, err := prb.TrustCenters.GenerateNDAFileURL(ctx, trustCenter.ID, 15*time.Minute)
if err == nil {
tc.NdaFileURL = ndaFileURL
}
return nil, types.GetTrustCenterOutput{TrustCenter: tc}, nil
}
// UpdateTrustCenterTool handles the updateTrustCenter tool
// Update the trust center settings
func (r *Resolver) UpdateTrustCenterTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTrustCenterInput) (*mcp.CallToolResult, types.UpdateTrustCenterOutput, error) {
r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionTrustCenterUpdate)
prb := r.ProboService(ctx, input.TrustCenterID)
updateReq := &probo.UpdateTrustCenterRequest{
ID: input.TrustCenterID,
}
if active := UnwrapOmittable(input.Active); active != nil {
updateReq.Active = *active
}
if sei := UnwrapOmittable(input.SearchEngineIndexing); sei != nil {
updateReq.SearchEngineIndexing = *sei
}
trustCenter, _, err := prb.TrustCenters.Update(ctx, updateReq)
if err != nil {
return nil, types.UpdateTrustCenterOutput{}, fmt.Errorf("cannot update trust center: %w", err)
}
return nil, types.UpdateTrustCenterOutput{TrustCenter: types.NewTrustCenter(trustCenter)}, nil
}
// ListTrustCenterReferencesTool handles the listTrustCenterReferences tool
// List all references for a trust center
func (r *Resolver) ListTrustCenterReferencesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListTrustCenterReferencesInput) (*mcp.CallToolResult, types.ListTrustCenterReferencesOutput, error) {
r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionTrustCenterReferenceList)
prb := r.ProboService(ctx, input.TrustCenterID)
pageOrderBy := page.OrderBy[coredata.TrustCenterReferenceOrderField]{
Field: coredata.TrustCenterReferenceOrderFieldRank,
Direction: page.OrderDirectionAsc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.TrustCenterReferenceOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
p, err := prb.TrustCenterReferences.ListForTrustCenterID(ctx, input.TrustCenterID, cursor)
if err != nil {
return nil, types.ListTrustCenterReferencesOutput{}, fmt.Errorf("cannot list trust center references: %w", err)
}
return nil, types.NewListTrustCenterReferencesOutput(p), nil
}
// AddTrustCenterReferenceTool handles the addTrustCenterReference tool
// Add a new reference to the trust center
func (r *Resolver) AddTrustCenterReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddTrustCenterReferenceInput) (*mcp.CallToolResult, types.AddTrustCenterReferenceOutput, error) {
r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionTrustCenterReferenceCreate)
prb := r.ProboService(ctx, input.TrustCenterID)
var websiteURL string
if input.WebsiteURL != nil {
websiteURL = *input.WebsiteURL
}
reference, err := prb.TrustCenterReferences.Create(
ctx,
&probo.CreateTrustCenterReferenceRequest{
TrustCenterID: input.TrustCenterID,
Name: input.Name,
Description: input.Description,
WebsiteURL: websiteURL,
},
)
if err != nil {
return nil, types.AddTrustCenterReferenceOutput{}, fmt.Errorf("cannot add trust center reference: %w", err)
}
return nil, types.AddTrustCenterReferenceOutput{TrustCenterReference: types.NewTrustCenterReference(reference)}, nil
}
// UpdateTrustCenterReferenceTool handles the updateTrustCenterReference tool
// Update a trust center reference
func (r *Resolver) UpdateTrustCenterReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTrustCenterReferenceInput) (*mcp.CallToolResult, types.UpdateTrustCenterReferenceOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterReferenceUpdate)
prb := r.ProboService(ctx, input.ID)
updateRefReq := &probo.UpdateTrustCenterReferenceRequest{
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.TrustCenterReferences.Update(ctx, updateRefReq)
if err != nil {
return nil, types.UpdateTrustCenterReferenceOutput{}, fmt.Errorf("cannot update trust center reference: %w", err)
}
return nil, types.UpdateTrustCenterReferenceOutput{TrustCenterReference: types.NewTrustCenterReference(reference)}, nil
}
// DeleteTrustCenterReferenceTool handles the deleteTrustCenterReference tool
// Delete a trust center reference
func (r *Resolver) DeleteTrustCenterReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteTrustCenterReferenceInput) (*mcp.CallToolResult, types.DeleteTrustCenterReferenceOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterReferenceDelete)
prb := r.ProboService(ctx, input.ID)
err := prb.TrustCenterReferences.Delete(ctx, input.ID)
if err != nil {
return nil, types.DeleteTrustCenterReferenceOutput{}, fmt.Errorf("cannot delete trust center reference: %w", err)
}
return nil, types.DeleteTrustCenterReferenceOutput{DeletedTrustCenterReferenceID: input.ID}, nil
}
// ListTrustCenterFilesTool handles the listTrustCenterFiles tool
// List all files for the trust center
func (r *Resolver) ListTrustCenterFilesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListTrustCenterFilesInput) (*mcp.CallToolResult, types.ListTrustCenterFilesOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionTrustCenterFileList)
prb := r.ProboService(ctx, input.OrganizationID)
pageOrderBy := page.OrderBy[coredata.TrustCenterFileOrderField]{
Field: coredata.TrustCenterFileOrderFieldCreatedAt,
Direction: page.OrderDirectionDesc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.TrustCenterFileOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
filter := coredata.NewTrustCenterFileFilter()
p, err := prb.TrustCenterFiles.ListForOrganizationID(ctx, input.OrganizationID, cursor, filter)
if err != nil {
return nil, types.ListTrustCenterFilesOutput{}, fmt.Errorf("cannot list trust center files: %w", err)
}
files := make([]*types.TrustCenterFile, 0, len(p.Data))
for _, f := range p.Data {
fileURL, err := prb.TrustCenterFiles.GenerateFileURL(ctx, f.ID, 1*time.Hour)
if err != nil {
return nil, types.ListTrustCenterFilesOutput{}, fmt.Errorf("cannot generate file URL: %w", err)
}
files = append(files, types.NewTrustCenterFile(f, fileURL))
}
return nil, types.NewListTrustCenterFilesOutput(files, p), nil
}
// DeleteTrustCenterFileTool handles the deleteTrustCenterFile tool
// Delete a trust center file
func (r *Resolver) DeleteTrustCenterFileTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteTrustCenterFileInput) (*mcp.CallToolResult, types.DeleteTrustCenterFileOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterFileDelete)
prb := r.ProboService(ctx, input.ID)
err := prb.TrustCenterFiles.Delete(ctx, input.ID)
if err != nil {
return nil, types.DeleteTrustCenterFileOutput{}, fmt.Errorf("cannot delete trust center file: %w", err)
}
return nil, types.DeleteTrustCenterFileOutput{DeletedTrustCenterFileID: input.ID}, nil
}
// ListComplianceExternalURLsTool handles the listComplianceExternalURLs tool
// List all external URLs for a trust center
func (r *Resolver) ListComplianceExternalURLsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListComplianceExternalURLsInput) (*mcp.CallToolResult, types.ListComplianceExternalURLsOutput, error) {
r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionComplianceExternalURLList)
prb := r.ProboService(ctx, input.TrustCenterID)
pageOrderBy := page.OrderBy[coredata.ComplianceExternalURLOrderField]{
Field: coredata.ComplianceExternalURLOrderFieldRank,
Direction: page.OrderDirectionAsc,
}
if input.OrderBy != nil {
pageOrderBy = page.OrderBy[coredata.ComplianceExternalURLOrderField]{
Field: input.OrderBy.Field,
Direction: input.OrderBy.Direction,
}
}
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
p, err := prb.ComplianceExternalURLs.List(ctx, input.TrustCenterID, cursor)
if err != nil {
return nil, types.ListComplianceExternalURLsOutput{}, fmt.Errorf("cannot list compliance external URLs: %w", err)
}
return nil, types.NewListComplianceExternalURLsOutput(p), nil
}
// AddComplianceExternalURLTool handles the addComplianceExternalURL tool
// Add a new external URL to the trust center
func (r *Resolver) AddComplianceExternalURLTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddComplianceExternalURLInput) (*mcp.CallToolResult, types.AddComplianceExternalURLOutput, error) {
r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionComplianceExternalURLCreate)
prb := r.ProboService(ctx, input.TrustCenterID)
item, err := prb.ComplianceExternalURLs.Create(
ctx,
&probo.CreateComplianceExternalURLRequest{
TrustCenterID: input.TrustCenterID,
Name: input.Name,
URL: input.URL,
},
)
if err != nil {
return nil, types.AddComplianceExternalURLOutput{}, fmt.Errorf("cannot add compliance external URL: %w", err)
}
return nil, types.AddComplianceExternalURLOutput{ComplianceExternalURL: types.NewComplianceExternalURL(item)}, nil
}
// UpdateComplianceExternalURLTool handles the updateComplianceExternalURL tool
// Update a compliance external URL
func (r *Resolver) UpdateComplianceExternalURLTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateComplianceExternalURLInput) (*mcp.CallToolResult, types.UpdateComplianceExternalURLOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionComplianceExternalURLUpdate)
prb := r.ProboService(ctx, input.ID)
updateURLReq := &probo.UpdateComplianceExternalURLRequest{
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.ComplianceExternalURLs.Update(ctx, updateURLReq)
if err != nil {
return nil, types.UpdateComplianceExternalURLOutput{}, fmt.Errorf("cannot update compliance external URL: %w", err)
}
return nil, types.UpdateComplianceExternalURLOutput{ComplianceExternalURL: types.NewComplianceExternalURL(item)}, nil
}
// DeleteComplianceExternalURLTool handles the deleteComplianceExternalURL tool
// Delete a compliance external URL
func (r *Resolver) DeleteComplianceExternalURLTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteComplianceExternalURLInput) (*mcp.CallToolResult, types.DeleteComplianceExternalURLOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionComplianceExternalURLDelete)
prb := r.ProboService(ctx, input.ID)
err := prb.ComplianceExternalURLs.Delete(
ctx,
&probo.DeleteComplianceExternalURLRequest{
ID: input.ID,
},
)
if err != nil {
return nil, types.DeleteComplianceExternalURLOutput{}, fmt.Errorf("cannot delete compliance external URL: %w", err)
}
return nil, types.DeleteComplianceExternalURLOutput{DeletedComplianceExternalURLID: input.ID}, nil
}
// CreateCustomDomainTool handles the createCustomDomain tool
// Create a custom domain for the organization
func (r *Resolver) CreateCustomDomainTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateCustomDomainInput) (*mcp.CallToolResult, types.CreateCustomDomainOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionCustomDomainCreate)
prb := r.ProboService(ctx, input.OrganizationID)
domain, err := prb.CustomDomains.CreateCustomDomain(
ctx,
probo.CreateCustomDomainRequest{
OrganizationID: input.OrganizationID,
Domain: input.Domain,
},
)
if err != nil {
return nil, types.CreateCustomDomainOutput{}, fmt.Errorf("cannot create custom domain: %w", err)
}
return nil, types.CreateCustomDomainOutput{CustomDomain: types.NewCustomDomain(domain)}, nil
}
// DeleteCustomDomainTool handles the deleteCustomDomain tool
// Delete the custom domain for the organization
func (r *Resolver) DeleteCustomDomainTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCustomDomainInput) (*mcp.CallToolResult, types.DeleteCustomDomainOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionCustomDomainDelete)
prb := r.ProboService(ctx, input.OrganizationID)
domain, err := prb.CustomDomains.GetOrganizationCustomDomain(ctx, input.OrganizationID)
if err != nil {
return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("cannot get custom domain: %w", err)
}
if domain == nil {
return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("organization has no custom domain")
}
deletedDomain := types.NewCustomDomain(domain)
if err := prb.CustomDomains.DeleteCustomDomain(ctx, input.OrganizationID); err != nil {
return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("cannot delete custom domain: %w", err)
}
return nil, types.DeleteCustomDomainOutput{DeletedCustomDomain: deletedDomain}, nil
}
func (r *Resolver) AssessVendorTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AssessVendorInput) (*mcp.CallToolResult, types.AssessVendorOutput, error) {
r.MustAuthorize(ctx, input.ID, probo.ActionVendorAssess)
svc := r.ProboService(ctx, input.ID)
result, err := svc.Vendors.Assess(
ctx,
probo.AssessVendorRequest{
ID: input.ID,
WebsiteURL: input.WebsiteURL,
Procedure: input.Procedure,
},
)
if err != nil {
return nil, types.AssessVendorOutput{}, fmt.Errorf("cannot assess vendor: %w", err)
}
return nil, types.NewAssessVendorOutput(result), nil
}
func (r *Resolver) PublishFindingListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishFindingListInput) (*mcp.CallToolResult, types.PublishFindingListOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFindingPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishFindingList(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionObligationPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishObligationList(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionProcessingActivityPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishProcessingActivityList(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDataProtectionImpactAssessmentPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishDataProtectionImpactAssessmentList(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionTransferImpactAssessmentPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishTransferImpactAssessmentList(ctx, 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) PublishVendorListTool(ctx context.Context, req *mcp.CallToolRequest, input *types.PublishVendorListInput) (*mcp.CallToolResult, types.PublishVendorListOutput, error) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionVendorPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishVendorList(ctx, input.OrganizationID, input.ApproverIds, input.Minor)
if err != nil {
return nil, types.PublishVendorListOutput{}, fmt.Errorf("cannot publish vendor list: %w", err)
}
return nil, types.PublishVendorListOutput{
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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionCookieBannerList)
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieBannerGet)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionCookieBannerCreate)
scope := coredata.NewScopeFromObjectID(input.OrganizationID)
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,
ConsentMode: coredata.CookieConsentMode(input.ConsentMode),
})
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieBannerUpdate)
scope := coredata.NewScopeFromObjectID(input.ID)
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.ConsentMode); v != nil && *v != nil {
mode := coredata.CookieConsentMode(**v)
updateReq.ConsentMode = &mode
}
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieBannerDelete)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieBannerActivate)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieBannerDeactivate)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.CookieBannerID, probo.ActionCookieCategoryList)
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
cursor := types.NewCursor(input.Size, input.Cursor, page.OrderBy[coredata.CookieCategoryOrderField]{Field: coredata.CookieCategoryOrderFieldRank, Direction: page.OrderDirectionAsc})
categories, err := r.cookieBanner.ListCookieCategoriesForBanner(ctx, scope, input.CookieBannerID, cursor)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieCategoryGet)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.CookieBannerID, probo.ActionCookieCategoryCreate)
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieCategoryUpdate)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieCategoryDelete)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieCategoryUpdate)
scope := coredata.NewScopeFromObjectID(input.ID)
_, 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) {
r.MustAuthorize(ctx, input.CookieCategoryID, probo.ActionTrackerPatternList)
scope := coredata.NewScopeFromObjectID(input.CookieCategoryID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTrackerPatternGet)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.CookieCategoryID, probo.ActionTrackerPatternCreate)
scope := coredata.NewScopeFromObjectID(input.CookieCategoryID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTrackerPatternUpdate)
scope := coredata.NewScopeFromObjectID(input.ID)
updateReq := cookiebanner.UpdateTrackerPatternRequest{TrackerPatternID: input.ID}
if v := UnwrapOmittable(input.DisplayName); v != nil && *v != nil {
updateReq.DisplayName = *v
}
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionTrackerPatternDelete)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.TrackerPatternID, probo.ActionTrackerPatternUpdate)
scope := coredata.NewScopeFromObjectID(input.TrackerPatternID)
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) {
r.MustAuthorize(ctx, input.CookieBannerID, probo.ActionCookieBannerVersionPublish)
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
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) ListCookieBannerVersionsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListCookieBannerVersionsInput) (*mcp.CallToolResult, types.ListCookieBannerVersionsOutput, error) {
r.MustAuthorize(ctx, input.CookieBannerID, probo.ActionCookieBannerVersionList)
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
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) {
r.MustAuthorize(ctx, input.CookieBannerID, probo.ActionCookieBannerUpdate)
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
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) {
r.MustAuthorize(ctx, input.CookieBannerID, probo.ActionCookieConsentRecordList)
scope := coredata.NewScopeFromObjectID(input.CookieBannerID)
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) {
r.MustAuthorize(ctx, input.ID, probo.ActionCookieConsentRecordList)
scope := coredata.NewScopeFromObjectID(input.ID)
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) {
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionRiskPublish)
svc := r.ProboService(ctx, input.OrganizationID)
document, documentVersion, err := svc.GeneratedDocuments.PublishRiskList(ctx, 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) {
r.MustAuthorize(ctx, input.OrganizationID, iam.ActionSCIMConfigurationGet)
config, err := r.iamSvc.OrganizationService.GetSCIMConfiguration(ctx, input.OrganizationID)
if err != nil {
var errNotFound *iam.ErrNoSCIMConfigurationFound
if errors.As(err, &errNotFound) {
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) {
r.MustAuthorize(ctx, input.OrganizationID, iam.ActionSCIMConfigurationCreate)
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) {
r.MustAuthorize(ctx, input.OrganizationID, iam.ActionSCIMConfigurationDelete)
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) {
r.MustAuthorize(ctx, input.ScimConfigurationID, iam.ActionSCIMConfigurationUpdate)
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) {
r.MustAuthorize(ctx, input.ID, iam.ActionSCIMBridgeGet)
bridge, err := r.iamSvc.OrganizationService.GetSCIMBridgeByID(ctx, input.ID)
if err != nil {
var errNotFound *iam.ErrSCIMBridgeNotFound
if errors.As(err, &errNotFound) {
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) {
r.MustAuthorize(ctx, input.ScimBridgeID, iam.ActionSCIMBridgeUpdate)
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) {
r.MustAuthorize(ctx, input.ScimConfigurationID, iam.ActionSCIMEventList)
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) {
action := probo.ActionDocumentVersionPublish
if !input.Minor && len(input.ApproverIds) > 0 {
action = probo.ActionDocumentVersionRequestApproval
}
r.MustAuthorize(ctx, input.DocumentID, action)
svc := r.ProboService(ctx, input.DocumentID)
result, err := svc.Documents.PublishVersion(ctx, probo.PublishDocumentRequest{
DocumentID: input.DocumentID,
Minor: input.Minor,
ApproverIDs: input.ApproverIds,
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
}