Skip to content

Commit 13626ba

Browse files
Apply MCP token review feedback fixes
Agent-Logs-Url: https://github.com/IntelliTect/EssentialCSharp.Web/sessions/1309ce59-f673-4f1a-b124-e849af2f4737 Co-authored-by: BenjaminMichaelis <22186029+BenjaminMichaelis@users.noreply.github.com>
1 parent 2d3ffbe commit 13626ba

5 files changed

Lines changed: 17 additions & 11 deletions

File tree

EssentialCSharp.Web.Tests/McpApiTokenServiceTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ public async Task CreateTokenAsync_WithExpiryBeyondSixMonths_Throws()
4545

4646
using var scope = factory.Services.CreateScope();
4747
var tokenService = scope.ServiceProvider.GetRequiredService<McpApiTokenService>();
48-
DateTime requestedExpiry = McpApiTokenService.GetDefaultExpirationUtc(DateTime.UtcNow).AddDays(1);
48+
DateTime requestedExpiry = McpApiTokenService.GetDefaultExpirationUtc(DateTime.UtcNow).AddDays(2);
4949

5050
await Assert.That(() => tokenService.CreateTokenAsync(userId, "too-long", requestedExpiry))
5151
.Throws<ArgumentOutOfRangeException>()
52-
.WithMessageContaining("6 months");
52+
.WithMessageContaining(McpApiTokenService.MaxExpiryValidationMessage);
5353
}
5454
}

EssentialCSharp.Web/Areas/Identity/Pages/Account/Manage/McpAccess.cshtml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@page
22
@model McpAccessModel
33
@using EssentialCSharp.Web.Models
4+
@using EssentialCSharp.Web.Services
45
@{
56
ViewData["Title"] = "MCP Access";
67
ViewData["ActivePage"] = ManageNavPages.McpAccess;
@@ -61,7 +62,7 @@
6162
<label asp-for="ExpiresOn" class="form-label">Expiry Date</label>
6263
<input asp-for="ExpiresOn" type="date" class="form-control" max="@Model.MaxExpiresOn.ToString("yyyy-MM-dd")" />
6364
<span asp-validation-for="ExpiresOn" class="text-danger"></span>
64-
<div class="form-text">MCP tokens default to 6 months and cannot exceed 6 months from today. The token expires at end of day (23:59:59) UTC on the selected date.</div>
65+
<div class="form-text">MCP tokens default to @McpApiTokenService.DefaultLifetimeMonths months and cannot exceed @McpApiTokenService.DefaultLifetimeMonths months from today. The token expires at end of day (UTC) on the selected date.</div>
6566
</div>
6667
<button type="submit" class="btn btn-primary">Create Token</button>
6768
</form>

EssentialCSharp.Web/Areas/Identity/Pages/Account/Manage/McpAccess.cshtml.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public class McpAccessModel(
3333
public async Task<IActionResult> OnGetAsync()
3434
{
3535
DisableCaching();
36-
InitializeExpiryBounds();
36+
DateTime nowUtc = DateTime.UtcNow;
37+
InitializeExpiryBounds(nowUtc);
3738
ApplyDefaultExpiryIfMissing();
3839
string? userId = userManager.GetUserId(User);
3940
if (userId is null) return Challenge();
@@ -44,7 +45,9 @@ public async Task<IActionResult> OnGetAsync()
4445
public async Task<IActionResult> OnPostCreateAsync()
4546
{
4647
DisableCaching();
47-
InitializeExpiryBounds();
48+
DateTime nowUtc = DateTime.UtcNow;
49+
DateOnly todayUtc = DateOnly.FromDateTime(nowUtc);
50+
InitializeExpiryBounds(nowUtc);
4851
ApplyDefaultExpiryIfMissing();
4952
string? userId = userManager.GetUserId(User);
5053
if (userId is null) return Challenge();
@@ -54,7 +57,7 @@ public async Task<IActionResult> OnPostCreateAsync()
5457

5558
if (ExpiresOn.HasValue)
5659
{
57-
if (ExpiresOn.Value < DateOnly.FromDateTime(DateTime.UtcNow))
60+
if (ExpiresOn.Value < todayUtc)
5861
ModelState.AddModelError(nameof(ExpiresOn), "Expiry date must be today or in the future.");
5962
if (ExpiresOn.Value > MaxExpiresOn)
6063
ModelState.AddModelError(nameof(ExpiresOn), McpApiTokenService.MaxExpiryValidationMessage);
@@ -97,9 +100,9 @@ private void DisableCaching()
97100
Response.Headers.Expires = "0";
98101
}
99102

100-
private void InitializeExpiryBounds()
103+
private void InitializeExpiryBounds(DateTime nowUtc)
101104
{
102-
MaxExpiresOn = McpApiTokenService.GetDefaultExpiryDate();
105+
MaxExpiresOn = McpApiTokenService.GetDefaultExpiryDate(nowUtc);
103106
}
104107

105108
private void ApplyDefaultExpiryIfMissing()

EssentialCSharp.Web/Controllers/McpTokenController.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ public async Task<IActionResult> CreateToken(
2626
if (name.Length > 256)
2727
return BadRequest(new { Error = "Token name must be 256 characters or fewer." });
2828

29+
DateTime nowUtc = DateTime.UtcNow;
30+
DateOnly todayUtc = DateOnly.FromDateTime(nowUtc);
2931
DateTime? expiresAt = null;
30-
DateOnly maxExpiresOn = McpApiTokenService.GetDefaultExpiryDate();
32+
DateOnly maxExpiresOn = McpApiTokenService.GetDefaultExpiryDate(nowUtc);
3133
if (request?.ExpiresOn is DateOnly expiresOn)
3234
{
33-
if (expiresOn < DateOnly.FromDateTime(DateTime.UtcNow))
35+
if (expiresOn < todayUtc)
3436
return BadRequest(new { Error = "ExpiresOn must be today or in the future." });
3537
if (expiresOn > maxExpiresOn)
3638
return BadRequest(new { Error = McpApiTokenService.MaxExpiryValidationMessage });

EssentialCSharp.Web/Services/McpApiTokenService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace EssentialCSharp.Web.Services;
1010
public class McpApiTokenService(EssentialCSharpWebContext db)
1111
{
1212
public const int DefaultLifetimeMonths = 6;
13-
public const string MaxExpiryValidationMessage = "MCP tokens can expire at most 6 months from today.";
13+
public static string MaxExpiryValidationMessage => $"MCP tokens can expire at most {DefaultLifetimeMonths} months from today.";
1414

1515
public sealed record ResolvedMcpApiToken(Guid TokenId, string UserId);
1616

0 commit comments

Comments
 (0)