Added MCp support
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Communications;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
/// <summary>
|
||||
/// MCP tools proxying Communications, Onboarding Invites & Notification Services (Module M25, Recipient Onboarding M03).
|
||||
/// </summary>
|
||||
[McpServerToolType]
|
||||
public class CommunicationsMcpTools(ICommunicationsService service)
|
||||
{
|
||||
[McpServerTool(Name = "communications_get_notifications", Title = "Get Organisation Notifications", ReadOnly = true)]
|
||||
[Description("Retrieves notifications and alerts dispatched to an organisation.")]
|
||||
public async Task<Records<Notification[]>> GetNotificationsAsync([Description("Organisation hash identifier")] string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetNotificationsAsync(organisationIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "communications_get_user_notifications", Title = "Get User Notifications", ReadOnly = true)]
|
||||
[Description("Retrieves pending notifications and task reminders for a specific user.")]
|
||||
public async Task<Records<Notification[]>> GetUserNotificationsAsync([Description("Target user identifier")] Guid userId, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetUserNotificationsAsync(userId, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "communications_create_notification", Title = "Dispatch Notification", Destructive = false)]
|
||||
[Description("Creates and queues a system, in-app, or email notification for delivery (FR-M25-001).")]
|
||||
public async Task<McpToolResult> CreateNotificationAsync([Description("Notification creation request")] CreateNotificationRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateNotificationAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Notification successfully created and queued for delivery.");
|
||||
|
||||
[McpServerTool(Name = "communications_update_notification", Title = "Update Notification Status", Destructive = false)]
|
||||
[Description("Updates the delivery or read status of a notification.")]
|
||||
public async Task<McpToolResult> UpdateNotificationAsync([Description("Notification update request")] UpdateNotificationRequest request, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateNotificationAsync(request, cancellationToken)).ToMcpResult("Notification status successfully updated.");
|
||||
|
||||
[McpServerTool(Name = "communications_send_invite", Title = "Send Onboarding Invite", Destructive = false)]
|
||||
[Description("Sends an invitation email and onboarding link to an external grantee or partner organisation user (Module M03).")]
|
||||
public async Task<Records<Invite>> SendInviteAsync([Description("Invite request parameters")] InviteRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.SendInviteAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "communications_get_invites", Title = "Get Onboarding Invites", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of sent onboarding invitations and their verification states.")]
|
||||
public async Task<Records<Invite[]>> GetInvitesAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetInvitesAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "communications_get_applicant_data", Title = "Get Applicant Intake Data", ReadOnly = true)]
|
||||
[Description("Retrieves captured applicant and grantee profile data for onboarding validation.")]
|
||||
public async Task<Records<ApplicantData[]>> GetApplicantDataAsync([Description("Applicant user identifier")] Guid applicantUserId, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetApplicantDataAsync(applicantUserId, cancellationToken)).ToMcpResult();
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Evidence;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
/// <summary>
|
||||
/// MCP tools proxying Evidence, Indicators & Verification Services (BR-004 Evidence-Based Performance, M07 Milestones, M08 M&E Indicators).
|
||||
/// </summary>
|
||||
[McpServerToolType]
|
||||
public class EvidenceMcpTools(IEvidenceService service)
|
||||
{
|
||||
[McpServerTool(Name = "evidence_get_files", Title = "Get Uploaded Evidence Records", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of uploaded evidence documents and audit artifacts (BR-004, Module M07).")]
|
||||
public async Task<Records<Evidence[]>> GetEvidenceFilesAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetEvidenceFilesAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "evidence_get_evidence", Title = "Get Evidence by ID", ReadOnly = true)]
|
||||
[Description("Retrieves metadata, verification status, and hash verification for an evidence document.")]
|
||||
public async Task<Records<Evidence>> GetEvidenceAsync([Description("Evidence hash identifier")] string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetEvidenceAsync(evidenceIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "evidence_get_milestone_evidence", Title = "Get Milestone Evidence", ReadOnly = true)]
|
||||
[Description("Retrieves all evidence documents uploaded to substantiate a specific milestone.")]
|
||||
public async Task<Records<Evidence[]>> GetMilestoneEvidenceAsync([Description("Milestone hash identifier")] string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetMilestoneEvidencesAsync(milestoneIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "evidence_get_project_evidence", Title = "Get Project Evidence", ReadOnly = true)]
|
||||
[Description("Retrieves all evidence documents associated with a project across all its milestones and indicators.")]
|
||||
public async Task<Records<Evidence[]>> GetProjectEvidenceAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProjectEvidencesAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "evidence_get_url", Title = "Get Evidence Document URL", ReadOnly = true)]
|
||||
[Description("Generates a secure presigned download URL for an uploaded evidence artifact in object storage.")]
|
||||
public async Task<Records<string>> GetEvidenceUrlAsync([Description("Evidence hash identifier")] string evidenceIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetEvidenceUrlAsync(evidenceIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "evidence_get_indicators", Title = "Get M&E Indicators", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of M&E indicators measuring project results hierarchy (Module M08, BR-008, BR-009).")]
|
||||
public async Task<Records<Indicator[]>> GetIndicatorsAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetIndicatorsAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "evidence_get_indicator", Title = "Get Indicator by ID", ReadOnly = true)]
|
||||
[Description("Retrieves baseline, target, actual values, and variance calculation for an indicator (BR-009).")]
|
||||
public async Task<Records<Indicator>> GetIndicatorAsync([Description("Indicator hash identifier")] string indicatorIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetIndicatorAsync(indicatorIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "evidence_create_indicator", Title = "Create Performance Indicator", Destructive = false)]
|
||||
[Description("Creates an M&E indicator measuring Output, Outcome, or Impact with baseline and targets (Module M08, BR-008).")]
|
||||
public async Task<McpToolResult> CreateIndicatorAsync([Description("Indicator creation request")] CreateIndicatorRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateIndicatorAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Indicator successfully created.");
|
||||
|
||||
[McpServerTool(Name = "evidence_record_actual_amount", Title = "Record Indicator Actual Value", Destructive = false)]
|
||||
[Description("Records achieved actual metric and cost for an indicator, recalculating variance against target (BR-009).")]
|
||||
public async Task<McpToolResult> RecordIndicatorActualAmountAsync([Description("Indicator hash identifier")] string indicatorIdHash, [Description("Actual numerical value achieved")] decimal amount, [Description("Optional actual financial cost incurred")] decimal? actualCost = null,
|
||||
[Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.RecordIndicatorActualAmountAsync(indicatorIdHash, amount, actualCost, userId ?? SystemUser, cancellationToken)).ToMcpResult("Indicator actual value successfully recorded.");
|
||||
|
||||
[McpServerTool(Name = "evidence_create_milestone", Title = "Create Milestone with Gating Criteria", Destructive = false)]
|
||||
[Description("Defines a project milestone with verification evidence rules gating tranche disbursements (Module M07, BR-003).")]
|
||||
public async Task<McpToolResult> CreateMilestoneAsync([Description("Milestone creation request")] CreateMilestoneRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateMilestoneAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Milestone successfully created.");
|
||||
|
||||
[McpServerTool(Name = "evidence_update_evidence", Title = "Update Evidence Metadata", Destructive = false)]
|
||||
[Description("Updates verification status, review notes, or metadata for an evidence submission.")]
|
||||
public async Task<McpToolResult> UpdateEvidenceAsync([Description("Evidence update request")] UpdateEvidenceRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateEvidenceAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Evidence metadata successfully updated.");
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Execution;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
/// <summary>
|
||||
/// MCP tools proxying Execution Services (M06 Disbursement Control, M09 Risk Management, Gating Rules BR-003).
|
||||
/// </summary>
|
||||
[McpServerToolType]
|
||||
public class ExecutionMcpTools(IExecutionService service)
|
||||
{
|
||||
[McpServerTool(Name = "execution_get_disbursements", Title = "Get Disbursements", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of disbursement tranche and drawdown records (Module M06).")]
|
||||
public async Task<Records<Disbursement[]>> GetDisbursementsAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetDisbursementsAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "execution_get_disbursement", Title = "Get Disbursement by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a disbursement request by its hash identifier.")]
|
||||
public async Task<Records<Disbursement>> GetDisbursementAsync([Description("Disbursement hash identifier")] string disbursementIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetDisbursementAsync(disbursementIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "execution_create_disbursement", Title = "Create Disbursement Request", Destructive = false)]
|
||||
[Description("Submits a drawdown / payment disbursement request linked to a satisfied milestone (BR-003, Module M06).")]
|
||||
public async Task<McpToolResult> CreateDisbursementAsync([Description("Disbursement request details")] CreateDisbursementRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateDisbursementAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Disbursement request successfully created.");
|
||||
|
||||
[McpServerTool(Name = "execution_approve_disbursement", Title = "Approve Disbursement", Destructive = false)]
|
||||
[Description("Formally approves release of funds for a disbursement tranche after verifying milestone evidence and conditions precedent (BR-003, AT-03).")]
|
||||
public async Task<McpToolResult> ApproveDisbursementAsync([Description("Disbursement hash identifier")] string disbursementIdHash, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.ApproveDisbursementAsync(disbursementIdHash, userId ?? SystemUser, cancellationToken)).ToMcpResult("Disbursement tranche successfully approved for release.");
|
||||
|
||||
[McpServerTool(Name = "execution_update_disbursement", Title = "Update Disbursement", Destructive = false)]
|
||||
[Description("Updates metadata, bank payment references, or status of a disbursement tranche.")]
|
||||
public async Task<McpToolResult> UpdateDisbursementAsync([Description("Disbursement update request")] UpdateDisbursementRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateDisbursementAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Disbursement record successfully updated.");
|
||||
|
||||
[McpServerTool(Name = "execution_get_risks", Title = "Get Risk Register", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of risks identified across portfolio projects (Module M09).")]
|
||||
public async Task<Records<Risk[]>> GetRisksAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetRisksAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "execution_get_risk", Title = "Get Risk by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a project risk, including likelihood, impact, score, and mitigations.")]
|
||||
public async Task<Records<Risk>> GetRiskAsync([Description("Risk hash identifier")] string riskIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetRiskAsync(riskIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "execution_create_risk", Title = "Log Risk", Destructive = false)]
|
||||
[Description("Logs a new risk event with likelihood, severity, residual risk, and mitigation action plan (Module M09).")]
|
||||
public async Task<McpToolResult> CreateRiskAsync([Description("Risk log request")] CreateRiskRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateRiskAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Risk record successfully created.");
|
||||
|
||||
[McpServerTool(Name = "execution_update_risk", Title = "Update Risk & Mitigation", Destructive = false)]
|
||||
[Description("Updates a risk's assessment score, status, or mitigation progress.")]
|
||||
public async Task<McpToolResult> UpdateRiskAsync([Description("Risk update parameters")] UpdateRiskRequest request, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateRiskAsync(request, cancellationToken)).ToMcpResult("Risk record successfully updated.");
|
||||
|
||||
[McpServerTool(Name = "execution_get_rules", Title = "Get Gating Rules", ReadOnly = true)]
|
||||
[Description("Retrieves configurable gating and compliance validation rules (Module M06 / BR-003).")]
|
||||
public async Task<Records<Rule[]>> GetRulesAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetRulesAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "execution_get_rule", Title = "Get Rule by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a gating validation rule by hash identifier.")]
|
||||
public async Task<Records<Rule>> GetRuleAsync([Description("Rule hash identifier")] string ruleIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetRuleAsync(ruleIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "execution_create_rule", Title = "Create Gating Rule", Destructive = false)]
|
||||
[Description("Defines a new business or compliance gating rule governing disbursement release.")]
|
||||
public async Task<McpToolResult> CreateRuleAsync([Description("Rule creation request")] CreateRuleRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateRuleAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Gating rule successfully created.");
|
||||
|
||||
[McpServerTool(Name = "execution_update_rule", Title = "Update Gating Rule", Destructive = false)]
|
||||
[Description("Updates the logic or parameters of an existing gating rule.")]
|
||||
public async Task<McpToolResult> UpdateRuleAsync([Description("Rule update request")] UpdateRuleRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateRuleAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Gating rule successfully updated.");
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Governance;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
/// <summary>
|
||||
/// MCP tools proxying Governance Services (Portfolios, Organisations, Multi-Tenancy, Funding Instruments, Executive Dashboards).
|
||||
/// </summary>
|
||||
[McpServerToolType]
|
||||
public class GovernanceMcpTools(IGovernanceService service)
|
||||
{
|
||||
[McpServerTool(Name = "governance_get_dashboard", Title = "Get Portfolio Executive Dashboard", ReadOnly = true)]
|
||||
[Description("Retrieves aggregated executive portfolio statistics, project counts, financial totals, and risk overviews (Modules M20 & M22).")]
|
||||
public async Task<Records<Dashboard>> GetDashboardAsync(CancellationToken cancellationToken = default) =>
|
||||
(await service.GetDashboardAsync(cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_get_organisations", Title = "Get Master Organisations", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of recipient, partner, and donor organisations (BR-005 Single Source of Truth).")]
|
||||
public async Task<Records<Organisation[]>> GetOrganisationsAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetOrganisationsAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_get_organisation", Title = "Get Organisation by ID", ReadOnly = true)]
|
||||
[Description("Retrieves full master data and KYC details for an organisation by hash identifier.")]
|
||||
public async Task<Records<Organisation>> GetOrganisationAsync([Description("Organisation hash identifier")] string organisationIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetOrganisationAsync(organisationIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_create_organisation", Title = "Register Organisation", Destructive = false)]
|
||||
[Description("Registers a new recipient organisation, donor, or implementation partner (Module M03).")]
|
||||
public async Task<McpToolResult> CreateOrganisationAsync([Description("Organisation creation details")] CreateOrganisationRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateOrganisationAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Organisation successfully registered.");
|
||||
|
||||
[McpServerTool(Name = "governance_update_organisation", Title = "Update Organisation", Destructive = false)]
|
||||
[Description("Updates organisation profile, contact details, registration, or tax status.")]
|
||||
public async Task<Records<Organisation>> UpdateOrganisationAsync([Description("Organisation update request")] UpdateOrganisationRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await service.UpdateOrganisationAsync(request, userId ?? SystemUser, cancellationToken);
|
||||
|
||||
return result.ToMcpResult();
|
||||
}
|
||||
|
||||
[McpServerTool(Name = "governance_get_portfolios", Title = "Get Portfolios", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of top-level investment and grant portfolios.")]
|
||||
public async Task<Records<Portfolio[]>> GetPortfoliosAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetPorfoliosAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_get_portfolio", Title = "Get Portfolio by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a portfolio by hash identifier.")]
|
||||
public async Task<Records<Portfolio>> GetPortfolioAsync([Description("Portfolio hash identifier")] string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetPortfolioAsync(portfolioIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_create_portfolio", Title = "Create Portfolio", Destructive = false)]
|
||||
[Description("Creates an overarching investment or grant portfolio governing programmes.")]
|
||||
public async Task<McpToolResult> CreatePortfolioAsync([Description("Portfolio creation parameters")] CreatePortfolioRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreatePortfolioAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Portfolio successfully created.");
|
||||
|
||||
[McpServerTool(Name = "governance_update_portfolio", Title = "Update Portfolio", Destructive = false)]
|
||||
[Description("Updates portfolio objectives, dates, or metadata.")]
|
||||
public async Task<McpToolResult> UpdatePortfolioAsync([Description("Portfolio update request")] UpdatePortfolioRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdatePortfolioAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Portfolio successfully updated.");
|
||||
|
||||
[McpServerTool(Name = "governance_get_instruments", Title = "Get Funding Instruments", ReadOnly = true)]
|
||||
[Description("Retrieves configured funding instruments (Grant, Debt, Impact, Blended Finance, etc.) under a programme (BR-006).")]
|
||||
public async Task<Records<Instrument[]>> GetInstrumentsAsync([Description("Programme hash identifier")] string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetInstrumentsAsync(programmeIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_create_instrument", Title = "Define Funding Instrument", Destructive = false)]
|
||||
[Description("Configures a funding instrument with custom milestone rules, KPIs, and disbursement criteria (BR-006).")]
|
||||
public async Task<McpToolResult> CreateInstrumentAsync([Description("Instrument creation request")] CreateInstrumentRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateInstrumentAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Funding instrument successfully defined.");
|
||||
|
||||
[McpServerTool(Name = "governance_get_tenants", Title = "Get Tenants", ReadOnly = true)]
|
||||
[Description("Retrieves registered tenant partitions in the multi-tenant architecture.")]
|
||||
public async Task<Records<Tenant[]>> GetTenantsAsync(CancellationToken cancellationToken = default) =>
|
||||
(await service.GetTenantsAsync(cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_get_tenant", Title = "Get Tenant by ID", ReadOnly = true)]
|
||||
[Description("Retrieves tenant profile and isolation partition details.")]
|
||||
public async Task<Records<Tenant>> GetTenantAsync([Description("Tenant hash identifier")] string tenantIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetTenantAsync(tenantIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_create_tenant", Title = "Create Tenant", Destructive = false)]
|
||||
[Description("Provisions a new tenant boundary in the platform.")]
|
||||
public async Task<McpToolResult> CreateTenantAsync([Description("Tenant creation parameters")] CreateTenantRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateTenantAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Tenant successfully created.");
|
||||
|
||||
[McpServerTool(Name = "governance_get_portfolio_value", Title = "Calculate Portfolio Monetary Value", ReadOnly = true)]
|
||||
[Description("Computes aggregated total commitment and monetary allocation across all projects in a portfolio (BR-010).")]
|
||||
public async Task<Records<decimal>> GetPortfolioValueAsync([Description("Portfolio hash identifier")] string portfolioIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetPorfolioValueAsync(portfolioIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "governance_get_programme_value", Title = "Calculate Programme Monetary Value", ReadOnly = true)]
|
||||
[Description("Computes aggregated total commitment across all projects in a programme (BR-010).")]
|
||||
public async Task<Records<decimal>> GetProgrammeValueAsync([Description("Programme hash identifier")] string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProgrammeValueAsync(programmeIdHash, cancellationToken)).ToMcpResult();
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Grants;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
/// <summary>
|
||||
/// MCP tools proxying Grants & Award Services (M01 Award Intake, M02 Contract Management, M05 Budgeting).
|
||||
/// </summary>
|
||||
[McpServerToolType]
|
||||
public class GrantsMcpTools(IGrantsService service)
|
||||
{
|
||||
[McpServerTool(Name = "grants_get_awards", Title = "Get Approved Funding Awards", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of approved funding awards (Module M01).")]
|
||||
public async Task<Records<Award[]>> GetAwardsAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetAwardsAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "grants_get_award", Title = "Get Award by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of an approved funding award by its hash identifier.")]
|
||||
public async Task<Records<Award>> GetAwardAsync([Description("Award hash identifier")] string awardIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetAwardAsync(awardIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "grants_create_award", Title = "Register Approved Award", Destructive = false)]
|
||||
[Description("Registers an approved funding award from upstream committee sanction (BR-001/BR-002, M01). Automatically transitions into contract generation.")]
|
||||
public async Task<McpToolResult> CreateAwardAsync([Description("Award creation details")] CreateAwardRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateAwardAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Award record successfully created and transitioned to contract generation.");
|
||||
|
||||
[McpServerTool(Name = "grants_update_award", Title = "Update Award Record", Destructive = false)]
|
||||
[Description("Updates an existing funding award's metadata and parameters.")]
|
||||
public async Task<McpToolResult> UpdateAwardAsync([Description("Award update parameters")] UpdateAwardRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateAwardAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Award record successfully updated.");
|
||||
|
||||
[McpServerTool(Name = "grants_get_contracts", Title = "Get Contracts", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of legal grant contracts and agreements (Module M02).")]
|
||||
public async Task<Records<Contract[]>> GetContractsAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetContractsAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "grants_get_contract", Title = "Get Contract by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a contract agreement by its hash identifier.")]
|
||||
public async Task<Records<Contract>> GetContractAsync([Description("Contract hash identifier")] string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetContractAsync(contractIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "grants_create_contract", Title = "Create Draft Contract", Destructive = false)]
|
||||
[Description("Creates a new draft contract or agreement associated with an approved award (Module M02).")]
|
||||
public async Task<McpToolResult> CreateContractAsync([Description("Contract creation request")] CreateContractRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateContractAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Draft contract agreement successfully created.");
|
||||
|
||||
[McpServerTool(Name = "grants_update_contract", Title = "Update Contract Agreement", Destructive = false)]
|
||||
[Description("Updates terms and metadata of a contract in DRAFT or UNDER_REVIEW state.")]
|
||||
public async Task<McpToolResult> UpdateContractAsync([Description("Contract update request")] UpdateContractRequest request, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateContractAsync(request, cancellationToken)).ToMcpResult("Contract agreement successfully updated.");
|
||||
|
||||
[McpServerTool(Name = "grants_execute_contract", Title = "Formally Execute Contract", Destructive = false)]
|
||||
[Description("Formally executes and locks a contract agreement once all parties have signed and effective date is established (FR-M02-020).")]
|
||||
public async Task<McpToolResult> ExecuteContractAsync([Description("Contract execution request")] ExecuteContractRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.ExecuteContractAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Contract agreement successfully executed and locked.");
|
||||
|
||||
[McpServerTool(Name = "grants_get_contract_url", Title = "Get Contract Download URL", ReadOnly = true)]
|
||||
[Description("Retrieves a presigned download URL for the authoritative executed contract document.")]
|
||||
public async Task<Records<string>> GetContractUrlAsync([Description("Contract hash identifier")] string contractIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetContractUrlAsync(contractIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "grants_get_budgets", Title = "Get Budgets", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of project budgets and allocations (Module M05).")]
|
||||
public async Task<Records<Budget[]>> GetBudgetsAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetBudgetsAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "grants_get_budget", Title = "Get Budget by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a project budget allocation by hash identifier.")]
|
||||
public async Task<Records<Budget>> GetBudgetAsync([Description("Budget hash identifier")] string budgetIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetBudgetAsync(budgetIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "grants_create_budget", Title = "Create Budget Allocation", Destructive = false)]
|
||||
[Description("Creates a new project budget line and category allocation (Module M05).")]
|
||||
public async Task<McpToolResult> CreateBudgetAsync([Description("Budget creation request")] CreateBudgetRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateBudgetAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Budget allocation successfully created.");
|
||||
|
||||
[McpServerTool(Name = "grants_update_budget", Title = "Update Budget Allocation", Destructive = false)]
|
||||
[Description("Updates an existing project budget allocation with audit tracking.")]
|
||||
public async Task<McpToolResult> UpdateBudgetAsync([Description("Budget update request")] UpdateBudgetRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateBudgetAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Budget allocation successfully updated.");
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
using PostFundManagement.Application.Abstractions.Mcp;
|
||||
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
public class InAppMcpClient : IInAppMcpClient
|
||||
{
|
||||
private static bool initialized;
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly ILoggerFactory loggerFactory;
|
||||
|
||||
private static readonly ConcurrentDictionary<string, ToolMethodInfo> ToolRegistry = new(StringComparer.OrdinalIgnoreCase);
|
||||
private static readonly List<McpToolDefinition> ToolDefinitions = [];
|
||||
private static readonly Lock InitLock = new();
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
public static readonly Type[] ToolTypes =
|
||||
[
|
||||
typeof(GrantsMcpTools),
|
||||
typeof(ProjectsMcpTools),
|
||||
typeof(ExecutionMcpTools),
|
||||
typeof(GovernanceMcpTools),
|
||||
typeof(EvidenceMcpTools),
|
||||
typeof(CommunicationsMcpTools),
|
||||
typeof(UsersMcpTools)
|
||||
];
|
||||
|
||||
public InAppMcpClient(IServiceProvider serviceProvider, ILoggerFactory loggerFactory)
|
||||
{
|
||||
this.serviceProvider = serviceProvider;
|
||||
this.loggerFactory = loggerFactory;
|
||||
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
if (initialized) return;
|
||||
|
||||
lock (InitLock)
|
||||
{
|
||||
if (initialized) return;
|
||||
|
||||
foreach (var toolType in ToolTypes)
|
||||
{
|
||||
var groupName = toolType.Name.Replace("McpTools", string.Empty);
|
||||
|
||||
foreach (var method in toolType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
var toolAttr = method.GetCustomAttribute<McpServerToolAttribute>();
|
||||
|
||||
if (toolAttr == null) continue;
|
||||
|
||||
var toolName = !string.IsNullOrWhiteSpace(toolAttr.Name) ? toolAttr.Name : method.Name;
|
||||
var title = !string.IsNullOrWhiteSpace(toolAttr.Title) ? toolAttr.Title : toolName;
|
||||
var descAttr = method.GetCustomAttribute<DescriptionAttribute>();
|
||||
var description = descAttr?.Description ?? title;
|
||||
|
||||
var parameters = new List<McpToolParameter>();
|
||||
var methodParams = method.GetParameters();
|
||||
|
||||
foreach (var p in methodParams)
|
||||
{
|
||||
if (p.ParameterType == typeof(CancellationToken)) continue;
|
||||
|
||||
var pDescAttr = p.GetCustomAttribute<DescriptionAttribute>();
|
||||
|
||||
parameters.Add(new McpToolParameter(Name: p.Name ?? "param", Type: p.ParameterType.Name, Description: pDescAttr?.Description ?? string.Empty,
|
||||
IsRequired: !p.HasDefaultValue && !IsNullable(p.ParameterType), DefaultValue: p.HasDefaultValue ? p.DefaultValue : null));
|
||||
}
|
||||
|
||||
var toolDef = new McpToolDefinition(Name: toolName, Title: title, Description: description, Group: groupName,
|
||||
ReadOnly: toolAttr.ReadOnly, Parameters: parameters);
|
||||
|
||||
ToolDefinitions.Add(toolDef);
|
||||
|
||||
ToolRegistry[toolName] = new ToolMethodInfo(toolType, method, methodParams);
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<McpToolDefinition> GetAvailableTools() => ToolDefinitions;
|
||||
|
||||
public async Task<McpToolExecutionResult> ExecuteToolAsync(string toolName, IReadOnlyDictionary<string, object?>? arguments = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!ToolRegistry.TryGetValue(toolName, out var toolMethod))
|
||||
return McpToolExecutionResult.Fail($"MCP tool '{toolName}' is not recognized.");
|
||||
|
||||
try
|
||||
{
|
||||
var targetInstance = serviceProvider.GetRequiredService(toolMethod.TargetType);
|
||||
var args = BindArguments(toolMethod.Parameters, arguments, cancellationToken);
|
||||
|
||||
var invokeResult = toolMethod.Method.Invoke(targetInstance, args);
|
||||
|
||||
if (invokeResult is Task task)
|
||||
{
|
||||
await task.ConfigureAwait(false);
|
||||
|
||||
var resultProperty = task.GetType().GetProperty("Result");
|
||||
var value = resultProperty?.GetValue(task);
|
||||
|
||||
return McpToolExecutionResult.Ok(value);
|
||||
}
|
||||
|
||||
return McpToolExecutionResult.Ok(invokeResult);
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
var inner = ex.InnerException ?? ex;
|
||||
|
||||
return McpToolExecutionResult.Fail($"Execution of tool '{toolName}' failed: {inner.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return McpToolExecutionResult.Fail($"Execution of tool '{toolName}' failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<McpClient> CreateProtocolClientAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
var serverToClient = new Pipe();
|
||||
var clientToServer = new Pipe();
|
||||
|
||||
var serverIn = clientToServer.Reader.AsStream();
|
||||
var serverOut = serverToClient.Writer.AsStream();
|
||||
|
||||
var clientIn = serverToClient.Reader.AsStream();
|
||||
var clientOut = clientToServer.Writer.AsStream();
|
||||
|
||||
var inMemoryServices = new ServiceCollection();
|
||||
inMemoryServices.AddLogging();
|
||||
|
||||
foreach (var t in ToolTypes)
|
||||
inMemoryServices.AddScoped(t, _ => serviceProvider.GetRequiredService(t));
|
||||
|
||||
var mcpBuilder = inMemoryServices.AddMcpServer();
|
||||
|
||||
foreach (var t in ToolTypes)
|
||||
mcpBuilder.WithTools(t, (JsonSerializerOptions?)null);
|
||||
|
||||
mcpBuilder.WithStreamServerTransport(serverIn, serverOut);
|
||||
|
||||
var inMemoryProvider = inMemoryServices.BuildServiceProvider();
|
||||
var hostedServices = inMemoryProvider.GetServices<IHostedService>();
|
||||
|
||||
foreach (var hs in hostedServices)
|
||||
_ = hs.StartAsync(cancellationToken);
|
||||
|
||||
var clientTransport = new StreamClientTransport(serverInput: clientOut, serverOutput: clientIn, loggerFactory);
|
||||
|
||||
return await McpClient.CreateAsync(clientTransport, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
private static object?[] BindArguments(ParameterInfo[] parameters, IReadOnlyDictionary<string, object?>? arguments, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new object?[parameters.Length];
|
||||
var args = arguments ?? new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var p = parameters[i];
|
||||
|
||||
if (p.ParameterType == typeof(CancellationToken))
|
||||
{
|
||||
result[i] = cancellationToken;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var matchKey = args.Keys.FirstOrDefault(k => string.Equals(k, p.Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (matchKey != null && args.TryGetValue(matchKey, out var val) && val != null)
|
||||
result[i] = ConvertValue(val, p.ParameterType);
|
||||
else if (p.HasDefaultValue)
|
||||
result[i] = p.DefaultValue;
|
||||
else if (p.ParameterType == typeof(Guid) && p.Name?.Contains("userId", StringComparison.OrdinalIgnoreCase) == true)
|
||||
result[i] = SystemUser;
|
||||
else if (IsNullable(p.ParameterType))
|
||||
result[i] = null;
|
||||
else
|
||||
result[i] = p.ParameterType.IsValueType ? Activator.CreateInstance(p.ParameterType) : null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static object? ConvertValue(object val, Type targetType)
|
||||
{
|
||||
if (val == null) return null;
|
||||
|
||||
var underlying = Nullable.GetUnderlyingType(targetType) ?? targetType;
|
||||
|
||||
if (underlying.IsInstanceOfType(val)) return val;
|
||||
|
||||
if (val is JsonElement jsonElement)
|
||||
return JsonSerializer.Deserialize(jsonElement.GetRawText(), targetType, JsonOptions);
|
||||
|
||||
var str = val.ToString();
|
||||
|
||||
if (str == null) return null;
|
||||
|
||||
if (underlying == typeof(Guid)) return Guid.Parse(str);
|
||||
|
||||
if (underlying.IsEnum) return Enum.Parse(underlying, str, true);
|
||||
|
||||
if (underlying.IsPrimitive || underlying == typeof(decimal) || underlying == typeof(string) || underlying == typeof(DateTime))
|
||||
return Convert.ChangeType(val, underlying, CultureInfo.InvariantCulture);
|
||||
|
||||
return JsonSerializer.Deserialize(JsonSerializer.Serialize(val), targetType, JsonOptions);
|
||||
}
|
||||
|
||||
private static bool IsNullable(Type type) =>
|
||||
!type.IsValueType || Nullable.GetUnderlyingType(type) != null;
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Projects;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
/// <summary>
|
||||
/// MCP tools proxying Project & Programme Management Services (M04 WBS/Activities, M07 Milestones, M10 Compliance, M13 Beneficiaries, M15 Change Control, M16 Issues, M17 Site Visits).
|
||||
/// </summary>
|
||||
[McpServerToolType]
|
||||
public class ProjectsMcpTools(IProjectService service)
|
||||
{
|
||||
[McpServerTool(Name = "projects_get_projects", Title = "Get Projects", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of funded projects (Module M04).")]
|
||||
public async Task<Records<Project[]>> GetProjectsAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProjectsAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_project", Title = "Get Project by ID", ReadOnly = true)]
|
||||
[Description("Retrieves comprehensive details of a project by its hash identifier.")]
|
||||
public async Task<Records<Project>> GetProjectAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProjectAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_create_project", Title = "Create Project", Destructive = false)]
|
||||
[Description("Creates and initializes a funded project under an active award/programme (Module M04).")]
|
||||
public async Task<McpToolResult> CreateProjectAsync([Description("Project creation request")] CreateProjectRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateProjectAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Project successfully created.");
|
||||
|
||||
[McpServerTool(Name = "projects_update_project", Title = "Update Project", Destructive = false)]
|
||||
[Description("Updates project baseline configuration, scope, and objectives.")]
|
||||
public async Task<McpToolResult> UpdateProjectAsync([Description("Project update request")] UpdateProjectRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateProjectAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Project details successfully updated.");
|
||||
|
||||
[McpServerTool(Name = "projects_update_project_status", Title = "Update Project Status", Destructive = false)]
|
||||
[Description("Transitions a project's lifecycle status (e.g. Inception, Active, Under Review, Closeout, Completed).")]
|
||||
public async Task<McpToolResult> UpdateProjectStatusAsync([Description("Status update request")] UpdateProjectStatusRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateProjectStatusAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult("Project status successfully updated.");
|
||||
|
||||
[McpServerTool(Name = "projects_get_programmes", Title = "Get Funding Programmes", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of overarching funding programmes.")]
|
||||
public async Task<Records<Programme[]>> GetProgrammesAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProgrammesAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_programme", Title = "Get Programme by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a funding programme by its hash identifier.")]
|
||||
public async Task<Records<Programme>> GetProgrammeAsync([Description("Programme hash identifier")] string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProgrammeAsync(programmeIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_create_programme", Title = "Create Programme", Destructive = false)]
|
||||
[Description("Creates a new funding programme governing awards and portfolios.")]
|
||||
public async Task<McpToolResult> CreateProgrammeAsync([Description("Programme creation parameters")] CreateProgrammeRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateProgrammeAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_update_programme", Title = "Update Programme", Destructive = false)]
|
||||
[Description("Updates details of an existing funding programme.")]
|
||||
public async Task<McpToolResult> UpdateProgrammeAsync([Description("Programme update parameters")] UpdateProgrammeRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateProgrammeAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_programme_projects", Title = "Get Projects by Programme", ReadOnly = true)]
|
||||
[Description("Retrieves all projects associated with a given funding programme.")]
|
||||
public async Task<Records<Project[]>> GetProgrammeProjectsAsync([Description("Programme hash identifier")] string programmeIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProgrammeProjectsAsync(programmeIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_activities", Title = "Get Project Activities", ReadOnly = true)]
|
||||
[Description("Retrieves the work breakdown structure (WBS) activities for a project.")]
|
||||
public async Task<Records<Domain.Models.Activity[]>> GetActivitiesAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetActivitiesAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_activity", Title = "Get Activity by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a project activity by its hash identifier.")]
|
||||
public async Task<Records<Domain.Models.Activity>> GetActivityAsync([Description("Activity hash identifier")] string activityIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetActivityAsync(activityIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_create_activity", Title = "Create Project Activity", Destructive = false)]
|
||||
[Description("Creates a new work breakdown structure (WBS) activity under a project.")]
|
||||
public async Task<McpToolResult> CreateActivityAsync([Description("Activity creation request")] CreateActivityRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateActivityAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_update_activity", Title = "Update Project Activity", Destructive = false)]
|
||||
[Description("Updates progress, timeline, and status of a project activity.")]
|
||||
public async Task<McpToolResult> UpdateActivityAsync([Description("Activity update request")] UpdateActivityRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateActivityAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_project_milestones", Title = "Get Project Milestones", ReadOnly = true)]
|
||||
[Description("Retrieves all delivery and disbursement gating milestones for a project (Module M07).")]
|
||||
public async Task<Records<Milestone[]>> GetProjectMilestonesAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProjectMilestonesAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_milestones", Title = "Get All Milestones", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated list of milestones across the portfolio.")]
|
||||
public async Task<Records<Milestone[]>> GetMilestonesAsync([Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetMilestonesAsync(new Pagination(page, pageSize), cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_milestone", Title = "Get Milestone by ID", ReadOnly = true)]
|
||||
[Description("Retrieves details of a project milestone by its hash identifier.")]
|
||||
public async Task<Records<Milestone>> GetMilestoneAsync([Description("Milestone hash identifier")] string milestoneIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetMilestoneAsync(milestoneIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_update_milestone", Title = "Update Milestone", Destructive = false)]
|
||||
[Description("Updates milestone progress, delivery dates, verification status, and completion state.")]
|
||||
public async Task<McpToolResult> UpdateMilestoneAsync([Description("Milestone update request")] UpdateMilestoneRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateMilestoneAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_project_risks", Title = "Get Project Risks", ReadOnly = true)]
|
||||
[Description("Retrieves risk register items specifically identified for a project.")]
|
||||
public async Task<Records<Risk[]>> GetProjectRisksAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProjectRisksAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_project_indicators", Title = "Get Project Indicators", ReadOnly = true)]
|
||||
[Description("Retrieves M&E performance indicators configured for a project (Module M08).")]
|
||||
public async Task<Records<Indicator[]>> GetProjectIndicatorsAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetProjectIndicatorsAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_beneficiaries", Title = "Get Beneficiaries", ReadOnly = true)]
|
||||
[Description("Retrieves POPIA-compliant beneficiary demographic records for a project (Module M13).")]
|
||||
public async Task<Records<Beneficiary[]>> GetBeneficiariesAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetBeneficiariesAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_create_beneficiary", Title = "Register Beneficiary Group", Destructive = false)]
|
||||
[Description("Registers reach and demographic beneficiary data for a project (Module M13).")]
|
||||
public async Task<McpToolResult> CreateBeneficiaryAsync([Description("Beneficiary registration request")] CreateBeneficiaryRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateBeneficiaryAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_change_requests", Title = "Get Change Requests", ReadOnly = true)]
|
||||
[Description("Retrieves project scope, timeline, and budget change requests (Module M15).")]
|
||||
public async Task<Records<ChangeRequest[]>> GetChangeRequestsAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetChangeRequestsAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_create_change_request", Title = "Submit Change Request", Destructive = false)]
|
||||
[Description("Submits a formal change request for project scope, budget, or timeline amendment.")]
|
||||
public async Task<McpToolResult> CreateChangeRequestAsync([Description("Change request details")] CreateChangeRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateChangeRequestAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_compliance_items", Title = "Get Compliance Items", ReadOnly = true)]
|
||||
[Description("Retrieves statutory, tax, and ESG compliance checklist items for a project (Module M10).")]
|
||||
public async Task<Records<ComplianceItem[]>> GetComplianceItemsAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetComplianceItemsAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_create_compliance_item", Title = "Create Compliance Item", Destructive = false)]
|
||||
[Description("Creates a compliance or statutory requirement item for monitoring.")]
|
||||
public async Task<McpToolResult> CreateComplianceItemAsync([Description("Compliance item details")] CreateComplianceItemRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateComplianceItemAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_issues", Title = "Get Project Issues", ReadOnly = true)]
|
||||
[Description("Retrieves operational issue log items and blockers for a project (Module M16).")]
|
||||
public async Task<Records<Issue[]>> GetIssuesAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetIssuesAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_create_issue", Title = "Log Issue", Destructive = false)]
|
||||
[Description("Logs an operational issue or bottleneck against a project for management tracking.")]
|
||||
public async Task<McpToolResult> CreateIssueAsync([Description("Issue log request")] CreateIssueRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateIssueAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_get_site_visits", Title = "Get Site Visits", ReadOnly = true)]
|
||||
[Description("Retrieves scheduled and completed physical or virtual monitoring site visits (Module M17).")]
|
||||
public async Task<Records<SiteVisit[]>> GetSiteVisitsAsync([Description("Project hash identifier")] string projectIdHash, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetSiteVisitsAsync(projectIdHash, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "projects_create_site_visit", Title = "Schedule Site Visit", Destructive = false)]
|
||||
[Description("Schedules an in-person or remote monitoring site inspection for milestone verification.")]
|
||||
public async Task<McpToolResult> CreateSiteVisitAsync([Description("Site visit schedule request")] CreateSiteVisitRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateSiteVisitAsync(request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
/// <summary>
|
||||
/// Token-optimized standardized tool response wrapper for MCP tool execution.
|
||||
/// </summary>
|
||||
public record Records<T>(bool Success, T? Data = default, string? Message = null, IReadOnlyList<string>? Errors = null)
|
||||
{
|
||||
public static Records<T> Ok(T data, string? message = null) => new(true, data, message, null);
|
||||
|
||||
public static Records<T> Fail(string error, IReadOnlyList<string>? errors = null) => new(false, default, error, errors);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Token-optimized standardized non-generic tool response wrapper for MCP tool execution.
|
||||
/// </summary>
|
||||
public record McpToolResult(bool Success, string Message, IReadOnlyList<string>? Errors = null)
|
||||
{
|
||||
public static McpToolResult Ok(string message = "Operation completed successfully.") => new(true, message);
|
||||
|
||||
public static McpToolResult Fail(string error, IReadOnlyList<string>? errors = null) => new(false, error, errors);
|
||||
}
|
||||
|
||||
public sealed record McpToolDefinition(string Name, string Title, string Description, string Group, bool ReadOnly, IReadOnlyList<McpToolParameter> Parameters);
|
||||
|
||||
public sealed record McpToolParameter(string Name, string Type, string Description, bool IsRequired, object? DefaultValue);
|
||||
|
||||
public sealed record McpToolExecutionResult(bool Success, object? Data, string? Error, string? SerializedResult)
|
||||
{
|
||||
public static McpToolExecutionResult Ok(object? data, JsonSerializerOptions? options = null) =>
|
||||
new(true, data, null, data != null ? JsonSerializer.Serialize(data, options ?? DefaultJsonOptions) : null);
|
||||
|
||||
public static McpToolExecutionResult Fail(string error) =>
|
||||
new(false, null, error, null);
|
||||
|
||||
private static readonly JsonSerializerOptions DefaultJsonOptions = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = false
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record ToolMethodInfo(Type TargetType, MethodInfo Method, ParameterInfo[] Parameters);
|
||||
@@ -0,0 +1,66 @@
|
||||
using PostFundManagement.Application.Abstractions.Services;
|
||||
using PostFundManagement.Application.Extensions;
|
||||
using PostFundManagement.Application.Services.Users;
|
||||
using PostFundManagement.Domain;
|
||||
using PostFundManagement.Domain.Models;
|
||||
using PostFundManagement.Domain.Models.Security;
|
||||
using Role = PostFundManagement.Domain.Models.Security.Role;
|
||||
|
||||
namespace PostFundManagement.Application.Mcp;
|
||||
|
||||
/// <summary>
|
||||
/// MCP tools proxying Identity & User Administration Services (RBAC Roles, Claims, Account Provisioning).
|
||||
/// </summary>
|
||||
[McpServerToolType]
|
||||
public class UsersMcpTools(IUserService service)
|
||||
{
|
||||
[McpServerTool(Name = "users_get_users", Title = "Get User Directory", ReadOnly = true)]
|
||||
[Description("Retrieves a paginated and filtered list of user accounts across tenant partitions.")]
|
||||
public async Task<Records<User[]>> GetUsersAsync([Description("User search and filtering parameters")] UserFilterRequest filter, [Description("Page index (1-based)")] int page = 1, [Description("Page size (1-100)")] int pageSize = 50, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetUsersAsync(new Pagination(page, pageSize), filter, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_get_user", Title = "Get User by ID", ReadOnly = true)]
|
||||
[Description("Retrieves account profile and security claims for a specific user.")]
|
||||
public async Task<Records<User>> GetUserAsync([Description("Target user identifier")] Guid userId, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetUserAsync(userId, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_create_user", Title = "Create User Account", Destructive = false)]
|
||||
[Description("Provisions a new user account within a tenant organization.")]
|
||||
public async Task<McpToolResult> CreateUserAsync([Description("Tenant hash identifier")] string tenantIdHash, [Description("Hashed ID number or passport")] string idNumberHash, [Description("User account creation parameters")] CreateUserRequest request, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.CreateUserAsync(tenantIdHash, idNumberHash, request, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_update_status", Title = "Update User Account Status", Destructive = false)]
|
||||
[Description("Updates active, suspended, or archived state of a user account.")]
|
||||
public async Task<McpToolResult> UpdateUserStatusAsync([Description("Target user identifier")] Guid userId, [Description("New activity status")] ActivityStatus status, CancellationToken cancellationToken = default) =>
|
||||
(await service.UpdateUserStatusAsync(userId, status, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_get_system_roles", Title = "Get System Roles", ReadOnly = true)]
|
||||
[Description("Retrieves system-wide security and governance roles.")]
|
||||
public async Task<Records<Role[]>> GetSystemRolesAsync([Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetSystemRolesAsync(userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_get_user_roles", Title = "Get User Roles", ReadOnly = true)]
|
||||
[Description("Retrieves assigned RBAC roles for a specific user.")]
|
||||
public async Task<Records<Role[]>> GetUserRolesAsync([Description("Target user identifier")] Guid targetUserId, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetUserRolesAsync(targetUserId, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_add_role", Title = "Assign Role to User", Destructive = false)]
|
||||
[Description("Assigns a security role to a user account.")]
|
||||
public async Task<McpToolResult> AddUserRoleAsync([Description("Target user identifier")] Guid targetUserId, [Description("Role identifier to assign")] Guid roleId, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.AddUserRoleAsync(targetUserId, roleId, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_delete_role", Title = "Revoke Role from User", Destructive = false)]
|
||||
[Description("Revokes an assigned security role from a user account.")]
|
||||
public async Task<McpToolResult> DeleteUserRoleAsync([Description("Target user identifier")] Guid targetUserId, [Description("Role identifier to revoke")] Guid roleId, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.DeleteUserRoleAsync(targetUserId, roleId, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_get_user_claims", Title = "Get User Claims", ReadOnly = true)]
|
||||
[Description("Retrieves specific identity and authorization claims associated with a user.")]
|
||||
public async Task<Records<Domain.Models.Security.Claim[]>> GetUserClaimsAsync([Description("Target user identifier")] Guid targetUserId, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.GetUserClaimsAsync(targetUserId, userId ?? SystemUser, cancellationToken)).ToMcpResult();
|
||||
|
||||
[McpServerTool(Name = "users_set_lockout", Title = "Set User Lockout", Destructive = false)]
|
||||
[Description("Locks or unlocks a user account from authenticating into the platform.")]
|
||||
public async Task<McpToolResult> SetUserLockoutAsync([Description("Target user identifier")] Guid targetUserId, [Description("True to lockout/disable account, false to re-enable")] bool disable, [Description("Optional acting user ID; defaults to System user if omitted")] Guid? userId = null, CancellationToken cancellationToken = default) =>
|
||||
(await service.SetUserLockoutAsync(targetUserId, userId ?? SystemUser, disable, cancellationToken)).ToMcpResult();
|
||||
}
|
||||
Reference in New Issue
Block a user