diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index 7eadcbc24..143b3ea17 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -1312,14 +1312,17 @@ func (r *Resolver) AddTaskTool(ctx context.Context, req *mcp.CallToolRequest, in svc := r.ProboService(ctx, input.OrganizationID) - task, err := svc.Tasks.Create(ctx, probo.CreateTaskRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, - Description: input.Description, - TimeEstimate: input.TimeEstimate, - Deadline: input.Deadline, - AssignedToID: input.AssignedToID, - }) + task, err := svc.Tasks.Create( + ctx, + probo.CreateTaskRequest{ + OrganizationID: input.OrganizationID, + Name: input.Name, + Description: input.Description, + TimeEstimate: input.TimeEstimate, + Deadline: input.Deadline, + AssignedToID: input.AssignedToID, + }, + ) if err != nil { return nil, types.AddTaskOutput{}, fmt.Errorf("failed to create task: %w", err) } @@ -1333,14 +1336,17 @@ func (r *Resolver) UpdateTaskTool(ctx context.Context, req *mcp.CallToolRequest, 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, - TimeEstimate: UnwrapOmittable(input.TimeEstimate), - Deadline: UnwrapOmittable(input.Deadline), - }) + task, err := svc.Tasks.Update( + ctx, + probo.UpdateTaskRequest{ + TaskID: input.ID, + Name: input.Name, + Description: UnwrapOmittable(input.Description), + State: input.State, + TimeEstimate: UnwrapOmittable(input.TimeEstimate), + Deadline: UnwrapOmittable(input.Deadline), + }, + ) if err != nil { return nil, types.UpdateTaskOutput{}, fmt.Errorf("failed to update task: %w", err) } @@ -1377,3 +1383,65 @@ func (r *Resolver) UnassignTaskTool(ctx context.Context, req *mcp.CallToolReques Task: types.NewTask(task), }, nil } + +func (r *Resolver) ListSnapshotsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListSnapshotsInput) (*mcp.CallToolResult, types.ListSnapshotsOutput, error) { + r.MustBeAuthorized(ctx, input.OrganizationID, authz.ActionListSnapshots) + + prb := r.ProboService(ctx, input.OrganizationID) + + pageOrderBy := page.OrderBy[coredata.SnapshotOrderField]{ + Field: coredata.SnapshotOrderFieldCreatedAt, + Direction: page.OrderDirectionDesc, + } + if input.OrderBy != nil { + pageOrderBy = page.OrderBy[coredata.SnapshotOrderField]{ + Field: input.OrderBy.Field, + Direction: input.OrderBy.Direction, + } + } + + cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy) + + page, err := prb.Snapshots.ListForOrganizationID(ctx, input.OrganizationID, cursor) + if err != nil { + panic(fmt.Errorf("cannot list organization snapshots: %w", err)) + } + + return nil, types.NewListSnapshotsOutput(page), nil +} + +func (r *Resolver) GetSnapshotTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetSnapshotInput) (*mcp.CallToolResult, types.GetSnapshotOutput, error) { + r.MustBeAuthorized(ctx, input.ID, authz.ActionGet) + + prb := r.ProboService(ctx, input.ID) + + snapshot, err := prb.Snapshots.Get(ctx, input.ID) + if err != nil { + return nil, types.GetSnapshotOutput{}, fmt.Errorf("failed to get snapshot: %w", err) + } + return nil, types.GetSnapshotOutput{ + Snapshot: types.NewSnapshot(snapshot), + }, nil +} + +func (r *Resolver) TakeSnapshotTool(ctx context.Context, req *mcp.CallToolRequest, input *types.TakeSnapshotInput) (*mcp.CallToolResult, types.TakeSnapshotOutput, error) { + r.MustBeAuthorized(ctx, input.OrganizationID, authz.ActionCreateSnapshot) + + prb := r.ProboService(ctx, input.OrganizationID) + + snapshot, err := prb.Snapshots.Create( + ctx, + &probo.CreateSnapshotRequest{ + OrganizationID: input.OrganizationID, + Name: input.Name, + Description: input.Description, + Type: input.Type, + }, + ) + if err != nil { + return nil, types.TakeSnapshotOutput{}, fmt.Errorf("failed to take snapshot: %w", err) + } + return nil, types.TakeSnapshotOutput{ + Snapshot: types.NewSnapshot(snapshot), + }, nil +} diff --git a/pkg/server/api/mcp/v1/server/server.go b/pkg/server/api/mcp/v1/server/server.go index f6c995b8e..523ac1a2c 100644 --- a/pkg/server/api/mcp/v1/server/server.go +++ b/pkg/server/api/mcp/v1/server/server.go @@ -71,6 +71,9 @@ type ResolverInterface interface { UpdateTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTaskInput) (*mcp.CallToolResult, types.UpdateTaskOutput, error) AssignTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AssignTaskInput) (*mcp.CallToolResult, types.AssignTaskOutput, error) UnassignTaskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UnassignTaskInput) (*mcp.CallToolResult, types.UnassignTaskOutput, error) + ListSnapshotsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListSnapshotsInput) (*mcp.CallToolResult, types.ListSnapshotsOutput, error) + GetSnapshotTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetSnapshotInput) (*mcp.CallToolResult, types.GetSnapshotOutput, error) + TakeSnapshotTool(ctx context.Context, req *mcp.CallToolRequest, input *types.TakeSnapshotInput) (*mcp.CallToolResult, types.TakeSnapshotOutput, error) } // New creates a new MCP server instance with all handlers registered. @@ -700,4 +703,34 @@ func registerToolHandlers(server *mcp.Server, resolver ResolverInterface) { }, resolver.UnassignTaskTool, ) + mcp.AddTool( + server, + &mcp.Tool{ + Name: "listSnapshots", + Description: "List all snapshots for the organization", + InputSchema: types.ListSnapshotsToolInputSchema, + OutputSchema: types.ListSnapshotsToolOutputSchema, + }, + resolver.ListSnapshotsTool, + ) + mcp.AddTool( + server, + &mcp.Tool{ + Name: "getSnapshot", + Description: "Get a snapshot by ID", + InputSchema: types.GetSnapshotToolInputSchema, + OutputSchema: types.GetSnapshotToolOutputSchema, + }, + resolver.GetSnapshotTool, + ) + mcp.AddTool( + server, + &mcp.Tool{ + Name: "takeSnapshot", + Description: "Take a snapshot of a collection of objects (risks, vendors, assets, data, nonconformities, obligations, continual improvements, or processing activities)", + InputSchema: types.TakeSnapshotToolInputSchema, + OutputSchema: types.TakeSnapshotToolOutputSchema, + }, + resolver.TakeSnapshotTool, + ) } diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index 660a19a83..b111bfcc5 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -3063,6 +3063,152 @@ components: task: $ref: "#/components/schemas/Task" + SnapshotsType: + type: string + enum: + - RISKS + - VENDORS + - ASSETS + - DATA + - NONCONFORMITIES + - OBLIGATIONS + - CONTINUAL_IMPROVEMENTS + - PROCESSING_ACTIVITIES + go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.SnapshotsType + + SnapshotOrderField: + type: string + enum: + - CREATED_AT + - NAME + - TYPE + go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.SnapshotOrderField + + SnapshotOrderBy: + type: object + required: + - field + - direction + properties: + field: + $ref: "#/components/schemas/SnapshotOrderField" + description: Snapshot order field + direction: + $ref: "#/components/schemas/OrderDirection" + description: Snapshot order direction + + Snapshot: + type: object + required: + - id + - organization_id + - name + - type + - created_at + properties: + id: + $ref: "#/components/schemas/GID" + description: Snapshot ID + organization_id: + $ref: "#/components/schemas/GID" + description: Organization ID + name: + type: string + description: Snapshot name + description: + anyOf: + - type: string + description: Snapshot description + - type: "null" + description: No description + description: Snapshot description + type: + $ref: "#/components/schemas/SnapshotsType" + description: Snapshot type + created_at: + type: string + format: date-time + description: Creation timestamp + + ListSnapshotsInput: + type: object + required: + - organization_id + properties: + organization_id: + $ref: "#/components/schemas/GID" + description: Organization ID + order_by: + $ref: "#/components/schemas/SnapshotOrderBy" + description: Snapshot order by + size: + type: integer + description: Page size + cursor: + $ref: "#/components/schemas/CursorKey" + description: Page cursor + + ListSnapshotsOutput: + type: object + required: + - snapshots + properties: + snapshots: + type: array + items: + $ref: "#/components/schemas/Snapshot" + description: List of snapshots + next_cursor: + anyOf: + - $ref: "#/components/schemas/CursorKey" + - type: "null" + description: Next page cursor + + GetSnapshotInput: + type: object + required: + - id + properties: + id: + $ref: "#/components/schemas/GID" + description: Snapshot ID + + GetSnapshotOutput: + type: object + required: + - snapshot + properties: + snapshot: + $ref: "#/components/schemas/Snapshot" + + TakeSnapshotInput: + type: object + required: + - organization_id + - name + - type + properties: + organization_id: + $ref: "#/components/schemas/GID" + description: Organization ID + name: + type: string + description: Snapshot name + description: + type: string + description: Snapshot description + type: + $ref: "#/components/schemas/SnapshotsType" + description: Snapshot type (determines which collection to snapshot) + + TakeSnapshotOutput: + type: object + required: + - snapshot + properties: + snapshot: + $ref: "#/components/schemas/Snapshot" + tools: - name: listOrganizations description: List all organizations the user has access to @@ -3491,3 +3637,24 @@ tools: $ref: "#/components/schemas/UnassignTaskInput" outputSchema: $ref: "#/components/schemas/UnassignTaskOutput" + - name: listSnapshots + description: List all snapshots for the organization + readonly: true + inputSchema: + $ref: "#/components/schemas/ListSnapshotsInput" + outputSchema: + $ref: "#/components/schemas/ListSnapshotsOutput" + - name: getSnapshot + description: Get a snapshot by ID + readonly: true + inputSchema: + $ref: "#/components/schemas/GetSnapshotInput" + outputSchema: + $ref: "#/components/schemas/GetSnapshotOutput" + - name: takeSnapshot + description: Take a snapshot of a collection of objects (risks, vendors, assets, data, nonconformities, obligations, continual improvements, or processing activities) + readonly: false + inputSchema: + $ref: "#/components/schemas/TakeSnapshotInput" + outputSchema: + $ref: "#/components/schemas/TakeSnapshotOutput" diff --git a/pkg/server/api/mcp/v1/types/snapshot.go b/pkg/server/api/mcp/v1/types/snapshot.go new file mode 100644 index 000000000..43430dd03 --- /dev/null +++ b/pkg/server/api/mcp/v1/types/snapshot.go @@ -0,0 +1,48 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + +package types + +import ( + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/page" +) + +func NewSnapshot(s *coredata.Snapshot) *Snapshot { + return &Snapshot{ + ID: s.ID, + OrganizationID: s.OrganizationID, + Name: s.Name, + Type: s.Type, + Description: s.Description, + CreatedAt: s.CreatedAt, + } +} + +func NewListSnapshotsOutput(snapshotPage *page.Page[*coredata.Snapshot, coredata.SnapshotOrderField]) ListSnapshotsOutput { + snapshots := make([]*Snapshot, 0, len(snapshotPage.Data)) + for _, s := range snapshotPage.Data { + snapshots = append(snapshots, NewSnapshot(s)) + } + + var nextCursor *page.CursorKey + if len(snapshotPage.Data) > 0 { + cursorKey := snapshotPage.Data[len(snapshotPage.Data)-1].CursorKey(snapshotPage.Cursor.OrderBy.Field) + nextCursor = &cursorKey + } + + return ListSnapshotsOutput{ + NextCursor: nextCursor, + Snapshots: snapshots, + } +} diff --git a/pkg/server/api/mcp/v1/types/types.go b/pkg/server/api/mcp/v1/types/types.go index 4468f4ad7..2c2baae8b 100644 --- a/pkg/server/api/mcp/v1/types/types.go +++ b/pkg/server/api/mcp/v1/types/types.go @@ -62,6 +62,8 @@ var ( GetPeopleToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["people"],"properties":{"people":{"type":"object","required":["id","organization_id","full_name","primary_email_address","additional_email_addresses","kind","created_at","updated_at"],"properties":{"additional_email_addresses":{"type":"array","description":"Additional email addresses","items":{"type":"string"}},"contract_end_date":{"description":"Contract end date","format":"date-time"},"contract_start_date":{"description":"Contract start date","format":"date-time"},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"full_name":{"type":"string","description":"Full name"},"id":{"type":"string","format":"string"},"kind":{"type":"string","enum":["EMPLOYEE","CONTRACTOR","SERVICE_ACCOUNT"]},"organization_id":{"type":"string","format":"string"},"position":{"description":"Position"},"primary_email_address":{"type":"string","description":"Primary email address"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`) GetRiskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"string"}}}`) GetRiskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["risk"],"properties":{"risk":{"type":"object","required":["id","organization_id","name","category","treatment","inherent_likelihood","inherent_impact","inherent_risk_score","residual_likelihood","residual_impact","residual_risk_score","note","created_at","updated_at"],"properties":{"category":{"type":"string","description":"Risk category"},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Risk description"},"id":{"type":"string","format":"string"},"inherent_impact":{"type":"integer","description":"Inherent impact"},"inherent_likelihood":{"type":"integer","description":"Inherent likelihood"},"inherent_risk_score":{"type":"integer","description":"Inherent risk score"},"name":{"type":"string","description":"Risk name"},"note":{"type":"string","description":"Risk note"},"organization_id":{"type":"string","format":"string"},"owner_id":{"anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No owner"}]},"residual_impact":{"type":"integer","description":"Residual impact"},"residual_likelihood":{"type":"integer","description":"Residual likelihood"},"residual_risk_score":{"type":"integer","description":"Residual risk score"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"treatment":{"type":"string","enum":["MITIGATED","ACCEPTED","AVOIDED","TRANSFERRED"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`) + GetSnapshotToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"string"}}}`) + GetSnapshotToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["snapshot"],"properties":{"snapshot":{"type":"object","required":["id","organization_id","name","type","created_at"],"properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Snapshot description","anyOf":[{"type":"string","description":"Snapshot description"},{"type":"null","description":"No description"}]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Snapshot name"},"organization_id":{"type":"string","format":"string"},"type":{"type":"string","enum":["RISKS","VENDORS","ASSETS","DATA","NONCONFORMITIES","OBLIGATIONS","CONTINUAL_IMPROVEMENTS","PROCESSING_ACTIVITIES"]}}}}}`) GetTaskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"string"}}}`) GetTaskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["task"],"properties":{"task":{"type":"object","required":["id","organization_id","name","state","created_at","updated_at"],"properties":{"assigned_to_id":{"description":"Assigned to person ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"Not assigned"}]},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"deadline":{"description":"Deadline","anyOf":[{"type":"string","description":"Deadline","format":"date-time"},{"type":"null","description":"No deadline"}]},"description":{"description":"Task description","anyOf":[{"type":"string","description":"Task description"},{"type":"null","description":"No description"}]},"id":{"type":"string","format":"string"},"measure_id":{"description":"Measure ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No measure"}]},"name":{"type":"string","description":"Task name"},"organization_id":{"type":"string","format":"string"},"state":{"type":"string","enum":["TODO","DONE"]},"time_estimate":{"description":"Time estimate","anyOf":[{"type":"string","description":"A duration"},{"type":"null","description":"No time estimate"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`) LinkControlAuditToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["control_id","audit_id"],"properties":{"audit_id":{"type":"string","format":"string"},"control_id":{"type":"string","format":"string"}}}`) @@ -96,10 +98,14 @@ var ( ListPeopleToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["people"],"properties":{"next_cursor":{"type":"string","format":"string"},"people":{"type":"array","items":{"type":"object","required":["id","organization_id","full_name","primary_email_address","additional_email_addresses","kind","created_at","updated_at"],"properties":{"additional_email_addresses":{"type":"array","description":"Additional email addresses","items":{"type":"string"}},"contract_end_date":{"description":"Contract end date","format":"date-time"},"contract_start_date":{"description":"Contract start date","format":"date-time"},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"full_name":{"type":"string","description":"Full name"},"id":{"type":"string","format":"string"},"kind":{"type":"string","enum":["EMPLOYEE","CONTRACTOR","SERVICE_ACCOUNT"]},"organization_id":{"type":"string","format":"string"},"position":{"description":"Position"},"primary_email_address":{"type":"string","description":"Primary email address"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}}`) ListRisksToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["organization_id"],"properties":{"cursor":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"query":{"type":"string","description":"Search query"},"snapshot_id":{"type":"string","format":"string"}}},"order_by":{"type":"object","required":["field","direction"],"properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","UPDATED_AT","NAME","CATEGORY","TREATMENT","INHERENT_RISK_SCORE","RESIDUAL_RISK_SCORE","OWNER_FULL_NAME"]}}},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}}}`) ListRisksToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["risks"],"properties":{"next_cursor":{"type":"string","format":"string"},"risks":{"type":"array","items":{"type":"object","required":["id","organization_id","name","category","treatment","inherent_likelihood","inherent_impact","inherent_risk_score","residual_likelihood","residual_impact","residual_risk_score","note","created_at","updated_at"],"properties":{"category":{"type":"string","description":"Risk category"},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Risk description"},"id":{"type":"string","format":"string"},"inherent_impact":{"type":"integer","description":"Inherent impact"},"inherent_likelihood":{"type":"integer","description":"Inherent likelihood"},"inherent_risk_score":{"type":"integer","description":"Inherent risk score"},"name":{"type":"string","description":"Risk name"},"note":{"type":"string","description":"Risk note"},"organization_id":{"type":"string","format":"string"},"owner_id":{"anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No owner"}]},"residual_impact":{"type":"integer","description":"Residual impact"},"residual_likelihood":{"type":"integer","description":"Residual likelihood"},"residual_risk_score":{"type":"integer","description":"Residual risk score"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"treatment":{"type":"string","enum":["MITIGATED","ACCEPTED","AVOIDED","TRANSFERRED"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}}`) + ListSnapshotsToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["organization_id"],"properties":{"cursor":{"type":"string","format":"string"},"order_by":{"type":"object","required":["field","direction"],"properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","NAME","TYPE"]}}},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}}}`) + ListSnapshotsToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["snapshots"],"properties":{"next_cursor":{"description":"Next page cursor","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"snapshots":{"type":"array","description":"List of snapshots","items":{"type":"object","required":["id","organization_id","name","type","created_at"],"properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Snapshot description","anyOf":[{"type":"string","description":"Snapshot description"},{"type":"null","description":"No description"}]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Snapshot name"},"organization_id":{"type":"string","format":"string"},"type":{"type":"string","enum":["RISKS","VENDORS","ASSETS","DATA","NONCONFORMITIES","OBLIGATIONS","CONTINUAL_IMPROVEMENTS","PROCESSING_ACTIVITIES"]}}}}}}`) ListTasksToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["organization_id"],"properties":{"cursor":{"type":"string","format":"string"},"measure_id":{"type":"string","format":"string"},"order_by":{"type":"object","required":["field","direction"],"properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT"]}}},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}}}`) ListTasksToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["tasks"],"properties":{"next_cursor":{"description":"Next page cursor","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"tasks":{"type":"array","description":"List of tasks","items":{"type":"object","required":["id","organization_id","name","state","created_at","updated_at"],"properties":{"assigned_to_id":{"description":"Assigned to person ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"Not assigned"}]},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"deadline":{"description":"Deadline","anyOf":[{"type":"string","description":"Deadline","format":"date-time"},{"type":"null","description":"No deadline"}]},"description":{"description":"Task description","anyOf":[{"type":"string","description":"Task description"},{"type":"null","description":"No description"}]},"id":{"type":"string","format":"string"},"measure_id":{"description":"Measure ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No measure"}]},"name":{"type":"string","description":"Task name"},"organization_id":{"type":"string","format":"string"},"state":{"type":"string","enum":["TODO","DONE"]},"time_estimate":{"description":"Time estimate","anyOf":[{"type":"string","description":"A duration"},{"type":"null","description":"No time estimate"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}}`) ListVendorsToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["organization_id"],"properties":{"cursor":{"type":"string","format":"string"},"filter":{"type":"object","properties":{"snapshot_id":{"type":"string","format":"string"}}},"order_by":{"type":"object","required":["field","direction"],"properties":{"direction":{"type":"string","enum":["ASC","DESC"]},"field":{"type":"string","enum":["CREATED_AT","UPDATED_AT","NAME"]}}},"organization_id":{"type":"string","format":"string"},"size":{"type":"integer","description":"Page size"}}}`) ListVendorsToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["vendors"],"properties":{"next_cursor":{"type":"string","format":"string"},"vendors":{"type":"array","items":{"type":"object","required":["id","name","organization_id","created_at","updated_at"],"properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Vendor description"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Vendor name"},"organization_id":{"type":"string","format":"string"},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}}`) + TakeSnapshotToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["organization_id","name","type"],"properties":{"description":{"type":"string","description":"Snapshot description"},"name":{"type":"string","description":"Snapshot name"},"organization_id":{"type":"string","format":"string"},"type":{"type":"string","enum":["RISKS","VENDORS","ASSETS","DATA","NONCONFORMITIES","OBLIGATIONS","CONTINUAL_IMPROVEMENTS","PROCESSING_ACTIVITIES"]}}}`) + TakeSnapshotToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["snapshot"],"properties":{"snapshot":{"type":"object","required":["id","organization_id","name","type","created_at"],"properties":{"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"description":{"description":"Snapshot description","anyOf":[{"type":"string","description":"Snapshot description"},{"type":"null","description":"No description"}]},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Snapshot name"},"organization_id":{"type":"string","format":"string"},"type":{"type":"string","enum":["RISKS","VENDORS","ASSETS","DATA","NONCONFORMITIES","OBLIGATIONS","CONTINUAL_IMPROVEMENTS","PROCESSING_ACTIVITIES"]}}}}}`) UnassignTaskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"string"}}}`) UnassignTaskToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["task"],"properties":{"task":{"type":"object","required":["id","organization_id","name","state","created_at","updated_at"],"properties":{"assigned_to_id":{"description":"Assigned to person ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"Not assigned"}]},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"deadline":{"description":"Deadline","anyOf":[{"type":"string","description":"Deadline","format":"date-time"},{"type":"null","description":"No deadline"}]},"description":{"description":"Task description","anyOf":[{"type":"string","description":"Task description"},{"type":"null","description":"No description"}]},"id":{"type":"string","format":"string"},"measure_id":{"description":"Measure ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No measure"}]},"name":{"type":"string","description":"Task name"},"organization_id":{"type":"string","format":"string"},"state":{"type":"string","enum":["TODO","DONE"]},"time_estimate":{"description":"Time estimate","anyOf":[{"type":"string","description":"A duration"},{"type":"null","description":"No time estimate"}]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`) UnlinkControlAuditToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["control_id","audit_id"],"properties":{"audit_id":{"type":"string","format":"string"},"control_id":{"type":"string","format":"string"}}}`) @@ -757,6 +763,17 @@ type GetRiskOutput struct { Risk *Risk `json:"risk"` } +// GetSnapshotInput represents the schema +type GetSnapshotInput struct { + // Snapshot ID + ID gid.GID `json:"id"` +} + +// GetSnapshotOutput represents the schema +type GetSnapshotOutput struct { + Snapshot *Snapshot `json:"snapshot"` +} + // GetTaskInput represents the schema type GetTaskInput struct { // Task ID @@ -1047,6 +1064,26 @@ type ListRisksOutput struct { Risks []*Risk `json:"risks"` } +// ListSnapshotsInput represents the schema +type ListSnapshotsInput struct { + // Page cursor + Cursor *page.CursorKey `json:"cursor,omitempty"` + // Snapshot order by + OrderBy *SnapshotOrderBy `json:"order_by,omitempty"` + // Organization ID + OrganizationID gid.GID `json:"organization_id"` + // Page size + Size *int `json:"size,omitempty"` +} + +// ListSnapshotsOutput represents the schema +type ListSnapshotsOutput struct { + // Next page cursor + NextCursor *page.CursorKey `json:"next_cursor,omitempty"` + // List of snapshots + Snapshots []*Snapshot `json:"snapshots"` +} + // ListTasksInput represents the schema type ListTasksInput struct { // Page cursor @@ -1292,6 +1329,47 @@ type RiskOrderBy struct { Field coredata.RiskOrderField `json:"field"` } +// Snapshot represents the schema +type Snapshot struct { + // Creation timestamp + CreatedAt time.Time `json:"created_at"` + // Snapshot description + Description *string `json:"description,omitempty"` + // Snapshot ID + ID gid.GID `json:"id"` + // Snapshot name + Name string `json:"name"` + // Organization ID + OrganizationID gid.GID `json:"organization_id"` + // Snapshot type + Type coredata.SnapshotsType `json:"type"` +} + +// SnapshotOrderBy represents the schema +type SnapshotOrderBy struct { + // Snapshot order direction + Direction page.OrderDirection `json:"direction"` + // Snapshot order field + Field coredata.SnapshotOrderField `json:"field"` +} + +// TakeSnapshotInput represents the schema +type TakeSnapshotInput struct { + // Snapshot description + Description *string `json:"description,omitempty"` + // Snapshot name + Name string `json:"name"` + // Organization ID + OrganizationID gid.GID `json:"organization_id"` + // Snapshot type (determines which collection to snapshot) + Type coredata.SnapshotsType `json:"type"` +} + +// TakeSnapshotOutput represents the schema +type TakeSnapshotOutput struct { + Snapshot *Snapshot `json:"snapshot"` +} + // Task represents the schema type Task struct { // Assigned to person ID