@okostream/mcp 0.12.9 → 0.12.10

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/server.js +70 -15
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -70499,6 +70499,13 @@ var OKO_CONNECTION_STATUSES = [
70499
70499
  "connected",
70500
70500
  "not_configured",
70501
70501
  "invalid_key",
70502
+ // 🔴 Next to `invalid_key`, not instead of it (A7, `LR3a-2`). The key is
70503
+ // valid and the account behind it is switched off or blocked — the one state
70504
+ // in which "create a fresh key" is not merely unhelpful but impossible, and
70505
+ // the state in which the platform used to give exactly that advice.
70506
+ // A genuinely revoked key still needs the create-a-key step, so the two
70507
+ // states are separate codes with separate steps.
70508
+ "account_inactive",
70502
70509
  "update_required",
70503
70510
  "rate_limited",
70504
70511
  "unavailable"
@@ -70539,6 +70546,18 @@ function nextSteps(status, minimumVersion, latestVersion) {
70539
70546
  label: "Restart or reconnect the MCP server after updating the key."
70540
70547
  }
70541
70548
  ];
70549
+ case "account_inactive":
70550
+ return [
70551
+ {
70552
+ id: "contact_support",
70553
+ label: "Ask OKO support to restore organizer access for this account: the key is valid, the account is switched off or blocked. Creating another key will not help \u2014 key creation needs an active account too.",
70554
+ url: OKO_ONBOARDING_URLS.website
70555
+ },
70556
+ {
70557
+ id: "restart_client",
70558
+ label: "Restart or reconnect the MCP server once access is restored."
70559
+ }
70560
+ ];
70542
70561
  case "update_required":
70543
70562
  return [
70544
70563
  {
@@ -70566,7 +70585,7 @@ function nextSteps(status, minimumVersion, latestVersion) {
70566
70585
  function buildConnectionStatus(status, options2 = {}) {
70567
70586
  const connected = status === "connected";
70568
70587
  const errorCode = connected ? null : status === "update_required" ? "CLIENT_UPGRADE_REQUIRED" : status === "rate_limited" ? "RATE_LIMITED" : status === "unavailable" ? "SERVICE_UNAVAILABLE" : "AUTH_REQUIRED";
70569
- const message = connected ? "OKO MCP is connected to an active organizer account." : status === "not_configured" ? "OKO MCP is installed, but OKO_API_KEY is not configured." : status === "invalid_key" ? "OKO MCP is installed, but the configured API key is invalid or revoked." : status === "update_required" ? options2.serverMessage ?? "This OKO MCP client version is no longer supported." : status === "rate_limited" ? "OKO temporarily rate-limited the connection attempt." : "OKO MCP could not verify the organizer connection.";
70588
+ const message = connected ? "OKO MCP is connected to an active organizer account." : status === "not_configured" ? "OKO MCP is installed, but OKO_API_KEY is not configured." : status === "invalid_key" ? "OKO MCP is installed, but the configured API key is invalid or revoked." : status === "account_inactive" ? options2.serverMessage ?? "The OKO API key is valid, but the organizer account behind it is switched off or blocked." : status === "update_required" ? options2.serverMessage ?? "This OKO MCP client version is no longer supported." : status === "rate_limited" ? "OKO temporarily rate-limited the connection attempt." : "OKO MCP could not verify the organizer connection.";
70570
70589
  return {
70571
70590
  connected,
70572
70591
  status,
@@ -116272,7 +116291,7 @@ function sanitizeScopes(scopes) {
116272
116291
  }
116273
116292
 
116274
116293
  // build/version.js
116275
- var OKO_MCP_VERSION = "0.12.9";
116294
+ var OKO_MCP_VERSION = "0.12.10";
116276
116295
 
116277
116296
  // build/auth.js
116278
116297
  var state = null;
@@ -116345,6 +116364,17 @@ var OkoAuthError = class extends Error {
116345
116364
  function versionField(value) {
116346
116365
  return typeof value === "string" && parseVersion(value) ? value.trim() : void 0;
116347
116366
  }
116367
+ function inactiveOrganizerError(body) {
116368
+ const parsed = body && typeof body === "object" ? body : {};
116369
+ if (parsed.error !== "organizer_inactive")
116370
+ return null;
116371
+ const serverMessage = typeof parsed.message === "string" && parsed.message.trim() ? parsed.message.trim() : void 0;
116372
+ return new OkoAuthError("account_inactive", serverMessage ?? "The OKO API key is valid, but the organizer account behind it is switched off or blocked. Creating another key will not help \u2014 contact OKO support to restore access.", { serverMessage });
116373
+ }
116374
+ function serverRefusalNote(body) {
116375
+ const parsed = body && typeof body === "object" ? body : {};
116376
+ return typeof parsed.message === "string" && parsed.message.trim() ? parsed.message.trim() : void 0;
116377
+ }
116348
116378
  function upgradeRequiredError(body) {
116349
116379
  const parsed = body && typeof body === "object" ? body : {};
116350
116380
  const minimumVersion = versionField(parsed.minimumVersion);
@@ -116379,7 +116409,16 @@ async function exchangeApiKey() {
116379
116409
  if (status === 429) {
116380
116410
  throw new OkoAuthError("rate_limited", "OKO API key exchange is temporarily rate-limited. Wait one minute, then restart the MCP client.");
116381
116411
  }
116382
- throw status === 401 ? new OkoAuthError("invalid_key", "OKO API key is invalid or revoked. Create a fresh key in the OKO MCP install center and replace OKO_API_KEY.") : new OkoAuthError("unavailable", `OKO organizer authentication failed with HTTP ${status}. Check your connection and try again.`);
116412
+ if (status === 401) {
116413
+ const inactive = inactiveOrganizerError(errorBody);
116414
+ if (inactive)
116415
+ throw inactive;
116416
+ }
116417
+ throw status === 401 ? new OkoAuthError("invalid_key", "OKO API key is invalid or revoked. Create a fresh key in the OKO MCP install center and replace OKO_API_KEY.") : new OkoAuthError("unavailable", [
116418
+ `OKO organizer authentication failed with HTTP ${status}.`,
116419
+ serverRefusalNote(errorBody),
116420
+ "Check your connection and try again."
116421
+ ].filter(Boolean).join(" "));
116383
116422
  }
116384
116423
  const data = await response.json();
116385
116424
  if (typeof data.customToken !== "string") {
@@ -116611,17 +116650,19 @@ async function readEventAccess(eventId, uid, mode) {
116611
116650
  return null;
116612
116651
  })
116613
116652
  ]);
116614
- if (!snap.exists())
116615
- throw new Error("Event not found.");
116616
- const data = snap.data();
116617
- const allowed = grant === null ? legacyEventAllowsMode(data, uid, mode) : data.ownerId === uid || grant.exists() && grantAllowsMode(grant.data(), mode);
116618
- return { data, allowed };
116653
+ const data = snap.data() ?? {};
116654
+ const holds = (wanted) => grant === null ? legacyEventAllowsMode(data, uid, wanted) : data.ownerId === uid || grant.exists() && grantAllowsMode(grant.data(), wanted);
116655
+ return { data, exists: snap.exists(), visible: holds("read"), allowed: holds(mode) };
116619
116656
  }
116620
116657
  async function eventGrantsMode(eventId, uid, mode) {
116621
116658
  return (await readEventAccess(eventId, uid, mode)).allowed;
116622
116659
  }
116660
+ var EVENT_NOT_FOUND_MESSAGE = "Event not found.";
116623
116661
  async function readEvent(eventId, uid, mode = "read") {
116624
- const { data, allowed } = await readEventAccess(eventId, uid, mode);
116662
+ const { data, exists, visible, allowed } = await readEventAccess(eventId, uid, mode);
116663
+ if (!visible || !exists) {
116664
+ throw new Error(EVENT_NOT_FOUND_MESSAGE);
116665
+ }
116625
116666
  if (!allowed) {
116626
116667
  throw new Error(`Event does not grant ${mode} access to this organizer.`);
116627
116668
  }
@@ -119676,14 +119717,18 @@ function registerLifecycleTools(server2) {
119676
119717
  }
119677
119718
 
119678
119719
  // build/tools/live.js
119720
+ var CHAT_LIVE_SETTINGS = ["mode", "slowModeMs", "automodEnabled", "allowViewerLinks"];
119679
119721
  function registerLiveTools(server2) {
119680
119722
  server2.registerTool("oko_get_live_state", {
119681
119723
  title: "Get live state",
119682
119724
  description: toolDescription({
119683
119725
  summary: "Read main RTDB live controls, aggregate analytics, and chat settings for an event.",
119684
119726
  args: ["eventId: event to inspect."],
119685
- returns: "eventId, agg metrics, ctrl live overrides, and chat settings.",
119686
- examples: ["Use during a webinar before changing live block visibility or starting/ending sessions."]
119727
+ returns: "eventId, agg metrics, ctrl live overrides, and chat settings (mode, slowModeMs, automodEnabled, allowViewerLinks).",
119728
+ examples: ["Use during a webinar before changing live block visibility or starting/ending sessions."],
119729
+ notes: [
119730
+ "Live state does not carry the event team: to see who has access to an event and with which permissions, use oko_list_workspace_access on the event's workspace."
119731
+ ]
119687
119732
  }),
119688
119733
  inputSchema: { eventId: eventIdField },
119689
119734
  outputSchema: liveStateOutputSchema,
@@ -119691,12 +119736,18 @@ function registerLiveTools(server2) {
119691
119736
  }, async ({ eventId }) => {
119692
119737
  const { uid } = await authed(["analytics:read"]);
119693
119738
  await readEvent(eventId, uid, "analytics");
119694
- const [aggSnap, ctrlSnap, chatSettingsSnap] = await Promise.all([
119739
+ const [aggSnap, ctrlSnap, ...chatSnaps] = await Promise.all([
119695
119740
  get(ref(rtdb, `events/${eventId}/agg`)),
119696
119741
  get(ref(rtdb, `events/${eventId}/ctrl`)),
119697
- get(ref(chatRtdb, `settings/${eventId}`))
119742
+ ...CHAT_LIVE_SETTINGS.map((field2) => get(ref(chatRtdb, `settings/${eventId}/${field2}`)))
119698
119743
  ]);
119699
- return textResult({ eventId, agg: aggSnap.val() ?? {}, ctrl: ctrlSnap.val() ?? {}, chat: chatSettingsSnap.val() ?? {} });
119744
+ const chat = {};
119745
+ CHAT_LIVE_SETTINGS.forEach((field2, index) => {
119746
+ const value = chatSnaps[index]?.val();
119747
+ if (value !== null && value !== void 0)
119748
+ chat[field2] = value;
119749
+ });
119750
+ return textResult({ eventId, agg: aggSnap.val() ?? {}, ctrl: ctrlSnap.val() ?? {}, chat });
119700
119751
  });
119701
119752
  server2.registerTool("oko_set_block_visibility", {
119702
119753
  title: "Set live block visibility",
@@ -120831,7 +120882,11 @@ function registerWorkspaceTools(server2) {
120831
120882
  "workspaceId: workspace owned by the authenticated organizer.",
120832
120883
  "code: optional invite code, 16-64 chars; omitted means generated (recommended).",
120833
120884
  "email: optional intended recipient email.",
120834
- "permissions: optional whitelist of workspace permission booleans.",
120885
+ // The schema is `workspacePermissionsSchema`: nine booleans, all
120886
+ // required, no extra keys. "optional whitelist" read as "send the
120887
+ // ones you want", and every such call was rejected by validation
120888
+ // before it reached the platform.
120889
+ "permissions: required object of all nine workspace permission booleans (createEvents, editSetup, deleteEvents, controlLive, moderateChat, startSession, viewAnalytics, downloadReports, sendNotifications) \u2014 every key must be present, extra keys are rejected; set false for the ones the invitee should not get.",
120835
120890
  "confirm: must be true."
120836
120891
  ],
120837
120892
  returns: "workspaceId, invite code, inviteUrl, and created=true.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okostream/mcp",
3
- "version": "0.12.9",
3
+ "version": "0.12.10",
4
4
  "description": "Control OKO Stream webinars from Claude, Codex, and other MCP clients.",
5
5
  "license": "UNLICENSED",
6
6
  "author": {