From 4570e9b70b99378cc365687d8ba3d7828fa2f1c7 Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro Date: Thu, 7 May 2026 22:01:20 -0300 Subject: [PATCH] feat: add monthly quota to API response body Add monthlyQuotaRemaining/monthlyQuotaLimit fields to QRResponseDto populated from X-Quota-* headers set by rate limiter. MCP server now displays quota in tool result text instead of web credits. Co-Authored-By: Claude Sonnet 4.6 --- Controllers/QRManagerController.cs | 8 ++++++++ Models/DTOs/QRResponseDto.cs | 6 ++++++ mcp-server/index.mjs | 4 +++- mcp-server/server-http.mjs | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Controllers/QRManagerController.cs b/Controllers/QRManagerController.cs index 96dd03b..e5383ac 100644 --- a/Controllers/QRManagerController.cs +++ b/Controllers/QRManagerController.cs @@ -114,6 +114,14 @@ namespace QRRapidoApp.Controllers }; } + // Inject monthly quota from response headers (set by ApiKeyAuthorizeAttribute) + if (HttpContext.Response.Headers.TryGetValue("X-Quota-Remaining", out var qr) && + int.TryParse(qr, out var quotaRemaining)) + result.MonthlyQuotaRemaining = quotaRemaining; + if (HttpContext.Response.Headers.TryGetValue("X-Quota-Limit", out var ql) && + int.TryParse(ql, out var quotaLimit)) + result.MonthlyQuotaLimit = quotaLimit; + // Map format and mimeType into the response result.Format = format; result.MimeType = format switch diff --git a/Models/DTOs/QRResponseDto.cs b/Models/DTOs/QRResponseDto.cs index 75ddf7d..99b4a0c 100644 --- a/Models/DTOs/QRResponseDto.cs +++ b/Models/DTOs/QRResponseDto.cs @@ -18,5 +18,11 @@ namespace QRRapidoApp.Models.DTOs /// MIME type of the encoded image (e.g. "image/png", "image/webp"). public string MimeType { get; set; } = "image/png"; + + /// Monthly API quota remaining (from rate limiter). -1 = unlimited. + public int MonthlyQuotaRemaining { get; set; } = -1; + + /// Monthly API quota limit. -1 = unlimited. + public int MonthlyQuotaLimit { get; set; } = -1; } } \ No newline at end of file diff --git a/mcp-server/index.mjs b/mcp-server/index.mjs index d70d571..9720607 100644 --- a/mcp-server/index.mjs +++ b/mcp-server/index.mjs @@ -109,7 +109,9 @@ function successContent(data, label = "qr") { file ? `๐Ÿ–ผ Aberto em: ${file}` : "", `โฑ ${data.generationTimeMs}ms`, `๐Ÿ’พ Cache: ${data.fromCache ? "hit" : "miss"}`, - `๐Ÿ“Š Crรฉditos restantes: ${data.remainingCredits ?? "N/A"}` + data.monthlyQuotaLimit >= 0 + ? `๐Ÿ“Š Quota mensal: ${data.monthlyQuotaRemaining}/${data.monthlyQuotaLimit}` + : `๐Ÿ“Š Quota mensal: ilimitada` ].filter(Boolean).join("\n") } ] diff --git a/mcp-server/server-http.mjs b/mcp-server/server-http.mjs index 5e639b3..cce07e9 100644 --- a/mcp-server/server-http.mjs +++ b/mcp-server/server-http.mjs @@ -164,7 +164,7 @@ function createMcpServer(apiKey) { return { content: [ { type: "image", data: data.qrCodeBase64, mimeType: data.mimeType || "image/png" }, - { type: "text", text: `โœ… QR gerado (${type})\nโฑ ${data.generationTimeMs}ms\n๐Ÿ’พ cache: ${data.fromCache ? "hit" : "miss"}` } + { type: "text", text: `โœ… QR gerado (${type})\nโฑ ${data.generationTimeMs}ms\n๐Ÿ’พ cache: ${data.fromCache ? "hit" : "miss"}\n๐Ÿ“Š quota: ${data.monthlyQuotaRemaining >= 0 ? `${data.monthlyQuotaRemaining}/${data.monthlyQuotaLimit}` : "ilimitada"}` } ] }; }