@okostream/mcp 0.9.3 → 0.10.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.
package/dist/tools.js CHANGED
@@ -1343,7 +1343,7 @@ export function registerTools(server) {
1343
1343
  ],
1344
1344
  returns: "uid, updated field names, and the resulting profile snapshot.",
1345
1345
  examples: ["Use when the organizer asks to change their visible OKO name or timezone."],
1346
- notes: ["This edits only the current organizer's own userProfiles document and does not require extra workspace/event scopes."],
1346
+ notes: ["Edits the organizer profile that owns this key. Requires workspace:write: the key holder is not necessarily the organizer, so a read-only key must not rewrite the owner's name, avatar or timezone."],
1347
1347
  }),
1348
1348
  inputSchema: {
1349
1349
  displayName: profileDisplayNameSchema.optional().describe("Display name, max 40 chars. Null clears it."),
@@ -1352,7 +1352,7 @@ export function registerTools(server) {
1352
1352
  outputSchema: profileOutputSchema,
1353
1353
  annotations: idempotentWriteTool,
1354
1354
  }, async ({ displayName, timezone }) => {
1355
- const { uid } = await authed([]);
1355
+ const { uid } = await authed(["workspace:write"]);
1356
1356
  const patch = { updatedAt: serverTimestamp() };
1357
1357
  if (displayName !== undefined)
1358
1358
  patch.displayName = displayName?.trim() || null;
@@ -1464,11 +1464,17 @@ export function registerTools(server) {
1464
1464
  ]);
1465
1465
  const members = [];
1466
1466
  for (const share of sharesSnap.docs) {
1467
- const profileSnap = await getDoc(doc(firestore, "userProfiles", share.id));
1467
+ // Правила разрешают читать чужой профиль только владельцу платформы,
1468
+ // поэтому на любом рабочем пространстве с участниками это чтение
1469
+ // заканчивается отказом. Без обработки инструмент падал целиком вместо
1470
+ // того, чтобы вернуть состав команды без необязательных профилей.
1471
+ const profile = await getDoc(doc(firestore, "userProfiles", share.id))
1472
+ .then((snap) => (snap.exists() ? serialize(snap.data()) : null))
1473
+ .catch(() => null);
1468
1474
  members.push({
1469
1475
  uid: share.id,
1470
1476
  ...serialize(share.data()),
1471
- profile: profileSnap.exists() ? serialize(profileSnap.data()) : null,
1477
+ profile,
1472
1478
  });
1473
1479
  }
1474
1480
  const invites = invitesSnap.docs.map((invite) => ({ code: invite.id, ...serialize(invite.data()) }));
@@ -1743,9 +1749,12 @@ export function registerTools(server) {
1743
1749
  title: "Update event metadata",
1744
1750
  description: toolDescription({
1745
1751
  summary: "Update safe top-level event/setup metadata fields.",
1746
- args: ["eventId plus any subset of title, videoUrl, eventDate, speakerName, description, pinned."],
1752
+ args: ["eventId plus any subset of title, videoUrl, eventDate, speakerName, description, pinned, sessionMode, durationMinutes."],
1747
1753
  returns: "event id and the list of Firestore fields updated.",
1748
1754
  examples: ["Use for title/date/speaker/video edits; use oko_configure_blocks for blocks and forms."],
1755
+ notes: [
1756
+ "sessionMode 'schedule' makes OKO start and end the analytics session automatically at eventDate for durationMinutes; 'manual' keeps the Start/End buttons and a Telegram reminder 10 minutes before eventDate. This is still an analytics session, not an event status.",
1757
+ ],
1749
1758
  }),
1750
1759
  inputSchema: {
1751
1760
  eventId: eventIdField,
@@ -1755,6 +1764,8 @@ export function registerTools(server) {
1755
1764
  speakerName: z.string().max(160).nullable().optional().describe("New speaker display name, or null to clear."),
1756
1765
  description: z.string().max(3000).nullable().optional().describe("New description, or null to clear."),
1757
1766
  pinned: z.boolean().optional().describe("Whether this event is pinned in the dashboard."),
1767
+ sessionMode: z.enum(["manual", "schedule"]).optional().describe("Analytics session mode: manual Start/End buttons, or automatic start/end on schedule at eventDate."),
1768
+ durationMinutes: z.number().int().min(15).max(1440).optional().describe("Event duration in minutes (15-1440) used by schedule mode to end the session."),
1758
1769
  },
1759
1770
  outputSchema: updateOutputSchema,
1760
1771
  annotations: writeTool,
@@ -1765,7 +1776,9 @@ export function registerTools(server) {
1765
1776
  if (args.videoUrl !== undefined
1766
1777
  || args.eventDate !== undefined
1767
1778
  || args.speakerName !== undefined
1768
- || args.description !== undefined) {
1779
+ || args.description !== undefined
1780
+ || args.sessionMode !== undefined
1781
+ || args.durationMinutes !== undefined) {
1769
1782
  requiredScopes.add("setup:write");
1770
1783
  }
1771
1784
  if (requiredScopes.size === 0)
@@ -1788,6 +1801,10 @@ export function registerTools(server) {
1788
1801
  patch["meta.description"] = args.description?.trim() || null;
1789
1802
  if (args.pinned !== undefined)
1790
1803
  patch.pinned = args.pinned;
1804
+ if (args.sessionMode !== undefined)
1805
+ patch.analyticsSessionMode = args.sessionMode;
1806
+ if (args.durationMinutes !== undefined)
1807
+ patch["meta.durationMinutes"] = args.durationMinutes;
1791
1808
  await updateDoc(doc(firestore, "events", args.eventId), patch);
1792
1809
  return textResult({ id: args.eventId, updated: Object.keys(patch) });
1793
1810
  });
@@ -2328,6 +2345,9 @@ export function registerTools(server) {
2328
2345
  args: ["eventId: event to control.", "block: chat, banner, cta, cards, or placeholder.", "visible: true/false, or null to reset override.", "confirm: must be true."],
2329
2346
  returns: "eventId, block, and effective override value.",
2330
2347
  examples: ["Use visible=false to hide the CTA live; use visible=null to return to setup defaults."],
2348
+ notes: [
2349
+ "block=chat with visible=false PAUSES message input: viewers keep seeing the chat history but cannot send. It does not hide the chat panel.",
2350
+ ],
2331
2351
  }),
2332
2352
  inputSchema: {
2333
2353
  eventId: eventIdField,
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by scripts/generateMcpVersion.mjs from mcp/package.json. Do not edit.
2
- export const OKO_MCP_VERSION = "0.9.3";
2
+ export const OKO_MCP_VERSION = "0.10.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okostream/mcp",
3
- "version": "0.9.3",
3
+ "version": "0.10.0",
4
4
  "description": "Control OKO Stream webinars from Claude, Codex, and other MCP clients.",
5
5
  "license": "UNLICENSED",
6
6
  "author": {
@@ -50,7 +50,7 @@
50
50
  "dotenv": "^17.2.3",
51
51
  "firebase": "^12.16.0",
52
52
  "ipaddr.js": "2.4.0",
53
- "undici": "7.28.0",
53
+ "undici": "7.29.0",
54
54
  "zod": "^3.25.76"
55
55
  },
56
56
  "devDependencies": {