@genlobe/mcp-server 3.1.8 → 3.3.0

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/dist/index.js +148 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -64,8 +64,13 @@ There are TWO types of authentication contexts:
64
64
  - These endpoints ARE for building end-user frontends
65
65
 
66
66
  ## API Key Types
67
- - \`pk_live_*\`: Public key - safe to expose in frontend code (LIMITED to auth endpoints only)
68
- - \`sk_live_*\`: Secret key - backend only, never expose (FULL API access)
67
+
68
+ - \`pk_live_*\`: Public key safe to expose in frontend code.
69
+ - **By itself** (no JWT) the key only unlocks \`/v1/auth/*\` (register, login, refresh, logout, me, forgot-password, reset-password). These are the seven scopes auto-assigned to public keys.
70
+ - **Combined with an end-user JWT** returned by \`/v1/auth/login\`, the same public key unlocks the full end-user API: \`/v1/user/agents/*\`, \`/v1/entity/records/*\`, \`/v1/plans\`, \`/v1/billing/*\`, \`/v1/users/me\`, etc. Once the JWT is in play, the JWT carries end-user identity and the public key just keeps verifying the tenant context.
71
+ - Restricted by an Origin allowlist (configured per key) and per-IP rate limits.
72
+
73
+ - \`sk_live_*\`: Secret key — backend-only, never expose. Required for server-to-server work that no end-user JWT can cover: defining entity schemas (\`/v1/entity/schemas/*\`), bulk record operations (\`/v1/entity/records/bulk\`, \`/v1/entity/records/search\`), webhooks, batch jobs, and other admin tooling on the tenant's own server.
69
74
 
70
75
  ## API Key Organization Scope (B2B2C)
71
76
 
@@ -102,6 +107,38 @@ If you're building a frontend application for end-users, you should:
102
107
  2. Use the public API key (pk_live_*) for client-side requests
103
108
  3. Include X-API-Key header in ALL requests
104
109
  4. After login, also include Authorization: Bearer <jwt> for authenticated requests
110
+
111
+ ## End-User App Flow (the canonical two-phase pattern)
112
+
113
+ A common confusion: the public key looks restricted to \`/v1/auth/*\`, so developers assume they need to ship the secret key in their frontend to call agents or records. They don't. The pattern is two phases:
114
+
115
+ \`\`\`
116
+ [Tenant's app frontend in the user's browser]
117
+
118
+ │ Phase 1 — auth gateway (public key alone is enough)
119
+ │ X-API-Key: pk_live_xxx
120
+
121
+ POST /v1/auth/register ─┐
122
+ POST /v1/auth/login ├─ returns { access_token (JWT), refresh_token, user }
123
+ POST /v1/auth/refresh ─┘
124
+
125
+ │ Phase 2 — end-user features (public key + JWT)
126
+ │ X-API-Key: pk_live_xxx
127
+ │ Authorization: Bearer <end-user JWT>
128
+
129
+ GET /v1/user/agents/available
130
+ POST /v1/user/agents/{id}/chat
131
+ GET/POST/PUT/DELETE /v1/entity/records/... ← custom-entity records as your app's DB
132
+ GET /v1/plans
133
+ POST /v1/billing/checkout
134
+ GET /v1/users/me
135
+ \`\`\`
136
+
137
+ The \`sk_live_*\` key never reaches the browser. It lives only on the tenant's own server, used for:
138
+ - defining entity schemas (\`/v1/entity/schemas/*\`),
139
+ - bulk record operations (\`/v1/entity/records/bulk\`, \`/search\`),
140
+ - receiving webhooks from the platform,
141
+ - cron jobs and admin tooling.
105
142
  `,
106
143
  base_url: API_URL,
107
144
  documentation_urls: {
@@ -787,7 +824,7 @@ const END_USER_ENDPOINTS = {
787
824
  ]
788
825
  },
789
826
  billing: {
790
- description: "Billing operations - checkout, plan changes, cancellation. All endpoints require SECRET key (sk_live_*) only.",
827
+ description: "Billing operations. Two flavors:\n\n- **Tier 1 (legacy / platform-level)**: endpoints under /v1/billing/* use the platform's Stripe and a SECRET key (sk_live_*) only. They were originally for Genlobe → Tenant billing and a since-superseded Tier 2 prototype; keep using them for tenant-internal flows.\n\n- **Tier 3 (Organization → end-user, Epic #209)**: each Organization runs its OWN Stripe (BYO key). End-users subscribe via /v1/organizations/{org_id}/billing/* (api key + JWT + active OrganizationMember). The Org's plan catalog is read via the public /v1/organizations/{org_id}/plans (api key only — no JWT). See the master spec at specs/features/billing/three-tier-billing.spec.md.",
791
828
  endpoints: [
792
829
  {
793
830
  method: "GET",
@@ -880,6 +917,91 @@ const END_USER_ENDPOINTS = {
880
917
  total_invoices: "number"
881
918
  },
882
919
  note: "Returns 404 if organization not found or doesn't belong to tenant."
920
+ },
921
+ // ---------------------------------------------------------------
922
+ // Tier 3 endpoints (Epic #209). Each Organization runs its OWN
923
+ // Stripe (BYO key). These run against the org's Stripe, not the
924
+ // platform's, and require an active OrganizationMember of the path's
925
+ // org. Plans are sold by the Organization to its end-users.
926
+ // ---------------------------------------------------------------
927
+ {
928
+ method: "GET",
929
+ path: "/v1/organizations/{organization_id}/plans",
930
+ summary: "List the Organization's active plans (Tier 3) — public to anonymous visitors of the org's app",
931
+ auth: { api_key: "pk_live_* or sk_live_*", jwt: false },
932
+ response: {
933
+ items: "array of OrganizationPlan: id (uuid), organization_id (uuid), name (string), slug (string), description (string | null), price_amount (decimal), currency (ISO-4217), billing_interval ('month' | 'year'), stripe_product_id (string | null), stripe_price_id (string | null), stripe_price_id_yearly (string | null), features (array of strings), limits (object<string, int | null>), is_active (boolean), created_at (ISO datetime), updated_at (ISO datetime)",
934
+ total: "number"
935
+ },
936
+ note: "Tenant-scoped: returns 404 if the Organization doesn't belong to the API key's tenant (no existence leak across tenants). Only plans with is_active=true and stripe_price_id != null are returned — use one of those plan ids when calling /billing/checkout-session.",
937
+ example_request: `GET /v1/organizations/660e8400-e29b-41d4-a716-446655440001/plans`
938
+ },
939
+ {
940
+ method: "POST",
941
+ path: "/v1/organizations/{organization_id}/billing/checkout-session",
942
+ summary: "Start a Stripe Checkout subscription flow for the calling end-user against an Org plan (Tier 3)",
943
+ auth: { api_key: "pk_live_* or sk_live_*", jwt: true },
944
+ request_body: {
945
+ plan_id: "uuid (required) — OrganizationPlan id (NOT a Stripe price id). Get it from /v1/organizations/{organization_id}/plans.",
946
+ success_url: "string url (required) — Stripe redirects here on success.",
947
+ cancel_url: "string url (required) — Stripe redirects here if the user cancels."
948
+ },
949
+ response: {
950
+ checkout_url: "string — Stripe-hosted Checkout URL (redirect the user here).",
951
+ session_id: "string — Stripe Checkout session id (cs_*)."
952
+ },
953
+ errors: {
954
+ "403": "Caller is not an active OrganizationMember of the path's org.",
955
+ "404": "Plan not found / belongs to a different org / inactive (collapsed to the same 404 to avoid cross-org existence leaks).",
956
+ "409": "Plan has no stripe_price_id yet OR the Organization has no Stripe configured (the Org Owner must finish setup first)."
957
+ },
958
+ note: "The caller becomes the end-user customer in the Organization's Stripe account, not in the platform's. The actual Subscription row is created by the webhook handler after Stripe fires checkout.session.completed.",
959
+ example_request: `{
960
+ "plan_id": "770e8400-e29b-41d4-a716-446655440002",
961
+ "success_url": "https://claude.example.com/billing/success?cs={CHECKOUT_SESSION_ID}",
962
+ "cancel_url": "https://claude.example.com/pricing"
963
+ }`
964
+ },
965
+ {
966
+ method: "POST",
967
+ path: "/v1/organizations/{organization_id}/billing/customer-portal-session",
968
+ summary: "Open a Stripe Customer Portal session for the calling end-user (Tier 3, manage / cancel)",
969
+ auth: { api_key: "pk_live_* or sk_live_*", jwt: true },
970
+ request_body: {
971
+ return_url: "string url (required) — Stripe redirects here when the user closes the Portal."
972
+ },
973
+ response: {
974
+ portal_url: "string — Stripe-hosted Customer Portal URL."
975
+ },
976
+ errors: {
977
+ "403": "Caller is not an active OrganizationMember of the path's org.",
978
+ "409": "Caller has no Subscription / no Stripe customer for this Organization yet, OR the Organization has no Stripe configured."
979
+ },
980
+ note: "Portal allowed actions (cancel / update payment method / etc.) are configured by the Organization Owner in their own Stripe Dashboard."
981
+ },
982
+ {
983
+ method: "GET",
984
+ path: "/v1/organizations/{organization_id}/billing/subscription",
985
+ summary: "Read the calling end-user's current subscription in this Organization (Tier 3)",
986
+ auth: { api_key: "pk_live_* or sk_live_*", jwt: true },
987
+ response: {
988
+ id: "uuid",
989
+ organization_id: "uuid",
990
+ user_id: "uuid",
991
+ plan_id: "uuid | null",
992
+ status: "string | null — Stripe Subscription.status (active, past_due, canceled, …)",
993
+ billing_cycle: "string — 'monthly' or 'yearly'",
994
+ current_period_start: "ISO datetime | null",
995
+ current_period_end: "ISO datetime | null",
996
+ cancel_at_period_end: "boolean",
997
+ canceled_at: "ISO datetime | null",
998
+ trial_start: "ISO datetime | null",
999
+ trial_end: "ISO datetime | null"
1000
+ },
1001
+ errors: {
1002
+ "403": "Caller is not an active OrganizationMember of the path's org.",
1003
+ "404": "Caller has no Subscription for this Organization yet."
1004
+ }
883
1005
  }
884
1006
  ]
885
1007
  },
@@ -1026,6 +1148,29 @@ const END_USER_ENDPOINTS = {
1026
1148
  error: "string | null"
1027
1149
  },
1028
1150
  note: "Returns 402 Payment Required if usage limits exceeded."
1151
+ },
1152
+ {
1153
+ method: "GET",
1154
+ path: "/v1/organizations/{organization_id}/usage",
1155
+ summary: "Get aggregate usage for one Organization in the queried period",
1156
+ auth: { api_key: "pk_live_* or sk_live_*", jwt: true },
1157
+ query_params: {
1158
+ period_start: "ISO datetime (optional) - Inclusive start of the aggregation window (UTC). Defaults to the current calendar month.",
1159
+ period_end: "ISO datetime (optional) - Exclusive end of the aggregation window (UTC). Must be supplied together with period_start.",
1160
+ },
1161
+ response: {
1162
+ organization_id: "uuid",
1163
+ organization_name: "string | null - Human-readable name from organizations row, null if the org row was deleted",
1164
+ organization_slug: "string | null",
1165
+ period_start: "ISO datetime - resolved window start",
1166
+ period_end: "ISO datetime - resolved window end",
1167
+ messages_count: "number - Sum of messages_count across plan_usages rows for the org in the period",
1168
+ tokens_count: "number - Sum of tokens_count (input + output)",
1169
+ input_tokens_count: "number",
1170
+ output_tokens_count: "number",
1171
+ cost_usd: "string - Decimal as string (e.g. '12.345600')",
1172
+ },
1173
+ note: "Auth requires the caller to be an active OrganizationMember of the path's org. Returns a zero row when the org had no activity in the period, so callers can always render a header without a 404 fallback. Read-only — does not consume usage.",
1029
1174
  }
1030
1175
  ]
1031
1176
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genlobe/mcp-server",
3
- "version": "3.1.8",
3
+ "version": "3.3.0",
4
4
  "description": "MCP Server for GenLobe SaaS API - Provides AI assistants with comprehensive API documentation for building frontend applications",
5
5
  "main": "dist/index.js",
6
6
  "bin": {