@sendinel/mcp-server 1.0.225 → 1.0.227

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/build/tools/org.js +11 -4
  2. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { PLAN_LIMITS as DOMAIN_PLAN_LIMITS, readPlanUsage, readAllRows } from "@sendinel/domain";
1
+ import { PLAN_LIMITS as DOMAIN_PLAN_LIMITS, readPlanUsage, readAiTokenUsage, readAllRows } from "@sendinel/domain";
2
2
  import { z } from 'zod';
3
3
  import { logAudit } from '../audit.js';
4
4
  import { adminDb, db } from '../db.js';
@@ -561,20 +561,24 @@ export function registerOrgTools(server) {
561
561
  idempotentHint: true,
562
562
  openWorldHint: false,
563
563
  },
564
- description: 'Get current plan usage for the project.',
564
+ description: 'Get current plan usage for the project, including the monthly AI token allowance.',
565
565
  inputSchema: {},
566
566
  }, async () => {
567
567
  const projectId = getProjectId();
568
- const { data: project } = await db().from('projects').select('plan').eq('id', projectId).maybeSingle();
568
+ const { data: project } = await db().from('projects').select('plan, compute_path').eq('id', projectId).maybeSingle();
569
569
  const plan = project?.plan ?? 'free';
570
+ // Mirrors the SQL quota check: a missing path is managed, and free is managed unless it is codex_bridge.
571
+ const computePath = project?.compute_path ?? 'managed';
572
+ const aiNotMetered = (plan === 'free' && computePath !== 'codex_bridge' ? 'managed' : computePath) !== 'managed';
570
573
  const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free ?? {};
571
- const [contacts, sends, drafts, { count: sites }] = await Promise.all([
574
+ const [contacts, sends, drafts, aiTokens, { count: sites }] = await Promise.all([
572
575
  readPlanUsage(db(), projectId, "contacts"),
573
576
  readPlanUsage(db(), projectId, "monthly_sends"),
574
577
  checkPlanLimit('ai_drafts').then((result) => ({ data: result, error: null })).catch((error) => ({
575
578
  data: null,
576
579
  error: error instanceof Error ? error.message : 'Unable to read draft usage',
577
580
  })),
581
+ aiNotMetered ? Promise.resolve(null) : readAiTokenUsage(db(), projectId),
578
582
  db().from('sites').select('id', { count: 'exact', head: true }).eq('project_id', projectId),
579
583
  ]);
580
584
  if (contacts.error || sends.error || contacts.data?.error || sends.data?.error || !contacts.data || !sends.data) {
@@ -588,6 +592,9 @@ export function registerOrgTools(server) {
588
592
  ai_drafts: typeof drafts.data?.current === 'number'
589
593
  ? { used: drafts.data.current, limit: limits.ai_drafts ?? null }
590
594
  : { used: null, limit: limits.ai_drafts ?? null, reason: 'Unable to read draft usage' },
595
+ ai_tokens: aiNotMetered
596
+ ? { used: null, limit: null, reason: "Not metered: this project's AI runs on its own compute path, so there is no platform token allowance." }
597
+ : aiTokens ?? { used: null, limit: null, reason: 'Unable to read AI token usage' },
591
598
  log_retention_days: limits.log_retention_days ?? null,
592
599
  });
593
600
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendinel/mcp-server",
3
- "version": "1.0.225",
3
+ "version": "1.0.227",
4
4
  "description": "AI-controlled email operations control plane for campaigns, contacts, segments, analytics, and multi-provider sending via MCP.",
5
5
  "mcpName": "ai.sendinel/mcp-server",
6
6
  "type": "module",