From 89af9f806aac3906933df7ad801c511c50a1ac12 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Wed, 26 Nov 2025 09:11:45 +0100 Subject: [PATCH] Add updatePeople tool Signed-off-by: Bryan Frimin --- pkg/server/api/mcp/v1/schema.resolvers.go | 27 +++++++++++ pkg/server/api/mcp/v1/server/server.go | 11 +++++ pkg/server/api/mcp/v1/specification.yaml | 56 +++++++++++++++++++++++ pkg/server/api/mcp/v1/types/types.go | 27 +++++++++++ 4 files changed, 121 insertions(+) diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index 906e4e876..f06694bd4 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -193,6 +193,33 @@ func (r *Resolver) AddPeopleTool(ctx context.Context, req *mcp.CallToolRequest, }, nil } +func (r *Resolver) UpdatePeopleTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdatePeopleInput) (*mcp.CallToolResult, types.UpdatePeopleOutput, error) { + r.MustBeAuthorized(ctx, input.ID, authz.ActionUpdatePeople) + + svc := r.ProboService(ctx, input.ID) + + people, err := svc.Peoples.Update( + ctx, + probo.UpdatePeopleRequest{ + ID: input.ID, + FullName: input.FullName, + PrimaryEmailAddress: input.PrimaryEmailAddress, + AdditionalEmailAddresses: input.AdditionalEmailAddresses, + Kind: input.Kind, + Position: UnwrapOmittable(input.Position), + ContractStartDate: UnwrapOmittable(input.ContractStartDate), + ContractEndDate: UnwrapOmittable(input.ContractEndDate), + }, + ) + if err != nil { + panic(fmt.Errorf("cannot update people: %w", err)) + } + + return nil, types.UpdatePeopleOutput{ + People: types.NewPeople(people), + }, nil +} + func (r *Resolver) ListRisksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRisksInput) (*mcp.CallToolResult, types.ListRisksOutput, error) { r.MustBeAuthorized(ctx, input.OrganizationID, authz.ActionListRisks) diff --git a/pkg/server/api/mcp/v1/server/server.go b/pkg/server/api/mcp/v1/server/server.go index 12473315e..d6fde4eec 100644 --- a/pkg/server/api/mcp/v1/server/server.go +++ b/pkg/server/api/mcp/v1/server/server.go @@ -17,6 +17,7 @@ type ResolverInterface interface { UpdateVendorTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateVendorInput) (*mcp.CallToolResult, types.UpdateVendorOutput, error) GetPeopleTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetPeopleInput) (*mcp.CallToolResult, types.GetPeopleOutput, error) AddPeopleTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddPeopleInput) (*mcp.CallToolResult, types.AddPeopleOutput, error) + UpdatePeopleTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdatePeopleInput) (*mcp.CallToolResult, types.UpdatePeopleOutput, error) ListRisksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListRisksInput) (*mcp.CallToolResult, types.ListRisksOutput, error) GetRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetRiskInput) (*mcp.CallToolResult, types.GetRiskOutput, error) AddRiskTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddRiskInput) (*mcp.CallToolResult, types.AddRiskOutput, error) @@ -194,6 +195,16 @@ func registerToolHandlers(server *mcp.Server, resolver ResolverInterface) { }, resolver.AddPeopleTool, ) + mcp.AddTool( + server, + &mcp.Tool{ + Name: "updatePeople", + Description: "Update an existing people", + InputSchema: types.UpdatePeopleToolInputSchema, + OutputSchema: types.UpdatePeopleToolOutputSchema, + }, + resolver.UpdatePeopleTool, + ) mcp.AddTool( server, &mcp.Tool{ diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index 15e36acfb..6fe856650 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -402,6 +402,54 @@ components: people: $ref: "#/components/schemas/People" + UpdatePeopleInput: + type: object + required: + - id + properties: + id: + $ref: "#/components/schemas/GID" + description: People ID + full_name: + type: string + description: Full name + primary_email_address: + type: string + description: Primary email address + additional_email_addresses: + anyOf: + - type: array + items: + type: string + - type: "null" + description: No additional email addresses + description: Additional email addresses + kind: + $ref: "#/components/schemas/PeopleKind" + description: People kind + position: + type: ["string", "null"] + description: Position + go.probo.inc/mcpgen/omittable: true + contract_start_date: + type: ["string", "null"] + format: date-time + description: Contract start date + go.probo.inc/mcpgen/omittable: true + contract_end_date: + type: ["string", "null"] + format: date-time + description: Contract end date + go.probo.inc/mcpgen/omittable: true + + UpdatePeopleOutput: + type: object + required: + - people + properties: + people: + $ref: "#/components/schemas/People" + RiskOrderField: type: string enum: @@ -3892,6 +3940,14 @@ tools: $ref: "#/components/schemas/AddPeopleInput" outputSchema: $ref: "#/components/schemas/AddPeopleOutput" + - name: updatePeople + description: Update an existing people + hints: + readonly: false + inputSchema: + $ref: "#/components/schemas/UpdatePeopleInput" + outputSchema: + $ref: "#/components/schemas/UpdatePeopleOutput" - name: listRisks description: List all risks for the organization hints: diff --git a/pkg/server/api/mcp/v1/types/types.go b/pkg/server/api/mcp/v1/types/types.go index b0a07f10f..5aa6a54c6 100644 --- a/pkg/server/api/mcp/v1/types/types.go +++ b/pkg/server/api/mcp/v1/types/types.go @@ -164,6 +164,8 @@ var ( UpdateNonconformityToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["nonconformity"],"properties":{"nonconformity":{"type":"object","required":["id","organization_id","reference_id","audit_id","root_cause","owner_id","status","created_at","updated_at"],"properties":{"audit_id":{"type":"string","format":"string"},"corrective_action":{"description":"Corrective action"},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"date_identified":{"description":"Date identified","format":"date-time"},"description":{"description":"Description"},"due_date":{"description":"Due date","format":"date-time"},"effectiveness_check":{"description":"Effectiveness check"},"id":{"type":"string","format":"string"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"reference_id":{"type":"string","description":"Reference ID"},"root_cause":{"type":"string","description":"Root cause"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"status":{"type":"string","enum":["OPEN","IN_PROGRESS","CLOSED"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`) UpdateObligationToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"actions_to_be_implemented":{"description":"Actions to be implemented"},"area":{"description":"Area"},"due_date":{"description":"Due date","format":"date-time"},"id":{"type":"string","format":"string"},"last_review_date":{"description":"Last review date","format":"date-time"},"owner_id":{"description":"Owner ID","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"regulator":{"description":"Regulator"},"requirement":{"description":"Requirement"},"source":{"description":"Source"},"status":{"description":"Status","anyOf":[{"type":"string","enum":["NON_COMPLIANT","PARTIALLY_COMPLIANT","COMPLIANT"]},{"type":"null","description":"No status"}]}}}`) UpdateObligationToolOutputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["obligation"],"properties":{"obligation":{"type":"object","required":["id","organization_id","owner_id","status","created_at","updated_at"],"properties":{"actions_to_be_implemented":{"description":"Actions to be implemented"},"area":{"description":"Area"},"created_at":{"type":"string","description":"Creation timestamp","format":"date-time"},"due_date":{"description":"Due date","format":"date-time"},"id":{"type":"string","format":"string"},"last_review_date":{"description":"Last review date","format":"date-time"},"organization_id":{"type":"string","format":"string"},"owner_id":{"type":"string","format":"string"},"regulator":{"description":"Regulator"},"requirement":{"description":"Requirement"},"snapshot_id":{"description":"Snapshot ID","anyOf":[{"type":"string","format":"string"},{"type":"null","description":"No snapshot"}]},"source":{"description":"Source"},"source_id":{"description":"Source ID"},"status":{"type":"string","enum":["NON_COMPLIANT","PARTIALLY_COMPLIANT","COMPLIANT"]},"updated_at":{"type":"string","description":"Update timestamp","format":"date-time"}}}}}`) + UpdatePeopleToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"additional_email_addresses":{"description":"Additional email addresses","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null","description":"No additional email addresses"}]},"contract_end_date":{"description":"Contract end date","format":"date-time"},"contract_start_date":{"description":"Contract start date","format":"date-time"},"full_name":{"type":"string","description":"Full name"},"id":{"type":"string","format":"string"},"kind":{"type":"string","enum":["EMPLOYEE","CONTRACTOR","SERVICE_ACCOUNT"]},"position":{"description":"Position"},"primary_email_address":{"type":"string","description":"Primary email address"}}}`) + UpdatePeopleToolOutputSchema = 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"}}}}}`) UpdateRiskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"category":{"type":"string","description":"Risk category"},"description":{"description":"Risk description"},"id":{"type":"string","format":"string"},"inherent_impact":{"type":"integer","description":"Inherent impact"},"inherent_likelihood":{"type":"integer","description":"Inherent likelihood"},"name":{"type":"string","description":"Risk name"},"note":{"type":"string","description":"Risk note"},"owner_id":{"description":"Owner ID","anyOf":[{"type":"string","format":"string"},{"type":"null"}]},"residual_impact":{"type":"integer","description":"Residual impact"},"residual_likelihood":{"type":"integer","description":"Residual likelihood"},"treatment":{"type":"string","enum":["MITIGATED","ACCEPTED","AVOIDED","TRANSFERRED"]}}}`) UpdateRiskToolOutputSchema = 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"}}}}}`) UpdateTaskToolInputSchema = mcp.MustUnmarshalSchema(`{"type":"object","required":["id"],"properties":{"deadline":{"description":"Deadline","anyOf":[{"type":"string","description":"Deadline","format":"date-time"},{"type":"null","description":"No deadline"}]},"description":{"description":"Task description"},"id":{"type":"string","format":"string"},"name":{"type":"string","description":"Task name"},"state":{"description":"Task state","anyOf":[{"type":"string","enum":["TODO","DONE"]},{"type":"null","description":"No state"}]},"time_estimate":{"description":"Time estimate","anyOf":[{"type":"string","description":"A duration"},{"type":"null","description":"No time estimate"}]}}}`) @@ -2020,6 +2022,31 @@ type UpdateObligationOutput struct { Obligation *Obligation `json:"obligation"` } +// UpdatePeopleInput represents the schema +type UpdatePeopleInput struct { + // Additional email addresses + AdditionalEmailAddresses *[]string `json:"additional_email_addresses,omitempty"` + // Contract end date + ContractEndDate mcp.Omittable[*time.Time] `json:"contract_end_date,omitempty"` + // Contract start date + ContractStartDate mcp.Omittable[*time.Time] `json:"contract_start_date,omitempty"` + // Full name + FullName *string `json:"full_name,omitempty"` + // People ID + ID gid.GID `json:"id"` + // People kind + Kind *coredata.PeopleKind `json:"kind,omitempty"` + // Position + Position mcp.Omittable[*string] `json:"position,omitempty"` + // Primary email address + PrimaryEmailAddress *string `json:"primary_email_address,omitempty"` +} + +// UpdatePeopleOutput represents the schema +type UpdatePeopleOutput struct { + People *People `json:"people"` +} + // UpdateRiskInput represents the schema type UpdateRiskInput struct { // Risk category