@rolino/mcp 0.1.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/index.cjs ADDED
@@ -0,0 +1,646 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ROLINO_MCP_VERSION: () => ROLINO_MCP_VERSION,
34
+ createRolinoMcpServer: () => createRolinoMcpServer,
35
+ resolveMcpConfiguration: () => resolveMcpConfiguration,
36
+ startStdioServer: () => startStdioServer
37
+ });
38
+ module.exports = __toCommonJS(index_exports);
39
+ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
40
+ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
41
+ var import_promises = require("fs/promises");
42
+ var import_node_path = require("path");
43
+ var import_contracts = require("@rolino/contracts");
44
+ var import_sdk2 = require("@rolino/sdk");
45
+ var z = __toESM(require("zod/v4"), 1);
46
+
47
+ // package.json
48
+ var package_default = {
49
+ name: "@rolino/mcp",
50
+ version: "0.1.0",
51
+ description: "Model Context Protocol server for Rolino",
52
+ type: "module",
53
+ license: "MIT",
54
+ keywords: [
55
+ "rolino",
56
+ "mcp",
57
+ "model-context-protocol",
58
+ "social-media",
59
+ "ai-agent"
60
+ ],
61
+ repository: {
62
+ type: "git",
63
+ url: "git+https://github.com/deifos/rolino.git",
64
+ directory: "packages/mcp"
65
+ },
66
+ homepage: "https://github.com/deifos/rolino/tree/main/packages/mcp#readme",
67
+ bugs: {
68
+ url: "https://github.com/deifos/rolino/issues"
69
+ },
70
+ main: "./dist/index.cjs",
71
+ module: "./dist/index.js",
72
+ types: "./dist/index.d.ts",
73
+ bin: {
74
+ "rolino-mcp": "./dist/bin.js"
75
+ },
76
+ exports: {
77
+ ".": {
78
+ import: {
79
+ types: "./dist/index.d.ts",
80
+ default: "./dist/index.js"
81
+ },
82
+ require: {
83
+ types: "./dist/index.d.cts",
84
+ default: "./dist/index.cjs"
85
+ }
86
+ }
87
+ },
88
+ files: [
89
+ "dist/**/*.js",
90
+ "dist/**/*.cjs",
91
+ "dist/**/*.map",
92
+ "dist/**/*.d.ts",
93
+ "dist/**/*.d.cts",
94
+ "README.md",
95
+ "CHANGELOG.md",
96
+ "LICENSE"
97
+ ],
98
+ publishConfig: {
99
+ access: "public"
100
+ },
101
+ scripts: {
102
+ build: "tsup src/index.ts src/bin.ts --format esm,cjs --dts --sourcemap --clean",
103
+ typecheck: "tsc --noEmit",
104
+ dev: "tsx src/bin.ts"
105
+ },
106
+ dependencies: {
107
+ "@hono/node-server": "2.0.12",
108
+ "@modelcontextprotocol/sdk": "^1.30.0",
109
+ "@rolino/contracts": "0.1.0",
110
+ "@rolino/local-auth": "0.1.0",
111
+ "@rolino/sdk": "0.1.0",
112
+ zod: "^4.4.3"
113
+ },
114
+ devDependencies: {
115
+ tsx: "^4.21.0"
116
+ },
117
+ engines: {
118
+ node: ">=20.19.0"
119
+ }
120
+ };
121
+
122
+ // src/configuration.ts
123
+ var import_local_auth = require("@rolino/local-auth");
124
+ var import_sdk = require("@rolino/sdk");
125
+ function resolveMcpConfiguration(env = process.env) {
126
+ const baseUrl = (0, import_sdk.normalizeRolinoBaseUrl)(
127
+ env.ROLINO_URL ?? "https://getrolino.com"
128
+ );
129
+ const credential = (0, import_local_auth.resolveCredential)(baseUrl, env);
130
+ return {
131
+ baseUrl,
132
+ token: credential.token ?? void 0,
133
+ timeoutMs: env.ROLINO_TIMEOUT ? (0, import_sdk.parseRolinoTimeout)(env.ROLINO_TIMEOUT) : void 0,
134
+ credentialSource: credential.source
135
+ };
136
+ }
137
+
138
+ // src/index.ts
139
+ var ROLINO_MCP_VERSION = package_default.version;
140
+ var mcpDraftInputShape = {
141
+ ...import_contracts.DraftPostInputSchema.shape,
142
+ platforms: import_contracts.DraftPostInputSchema.shape.platforms,
143
+ mediaAssetIds: import_contracts.DraftPostInputSchema.shape.mediaAssetIds.describe(
144
+ "Existing project media asset IDs. YouTube requires exactly one stored video; Bluesky accepts up to four stored JPEG, PNG, or WebP images."
145
+ ),
146
+ captionOverrides: import_contracts.DraftPostInputSchema.shape.captionOverrides.describe(
147
+ "Optional destination text. YOUTUBE is the video description and BLUESKY is limited to 300 graphemes; when omitted, Rolino uses the shared caption."
148
+ ),
149
+ youtubeSettings: import_contracts.DraftPostInputSchema.shape.youtubeSettings.describe(
150
+ "Required with YOUTUBE: explicit title, numeric categoryId, privacyStatus, madeForKids declaration, synthetic-media disclosure, subscriber-notification choice, and tags. Unaudited Google API projects may be restricted to Private uploads."
151
+ )
152
+ };
153
+ var mcpScheduleExecuteOutputSchema = z.object({
154
+ status: z.union([import_contracts.PostSchema.shape.status, z.literal("PENDING")]),
155
+ id: import_contracts.PostSchema.shape.id.optional(),
156
+ postId: import_contracts.PostSchedulePendingSchema.shape.postId.optional(),
157
+ provider: import_contracts.PostSchedulePendingSchema.shape.provider.optional(),
158
+ mutationId: import_contracts.PostSchedulePendingSchema.shape.mutationId.optional(),
159
+ operation: import_contracts.PostSchedulePendingSchema.shape.operation.optional(),
160
+ message: import_contracts.PostSchedulePendingSchema.shape.message.optional()
161
+ }).passthrough();
162
+ function jsonResult(structuredContent) {
163
+ return {
164
+ content: [{ type: "text", text: JSON.stringify(structuredContent) }],
165
+ structuredContent
166
+ };
167
+ }
168
+ function errorResult(error) {
169
+ let body;
170
+ if (error instanceof import_sdk2.RolinoApiError) {
171
+ body = {
172
+ error: {
173
+ code: error.code,
174
+ message: error.message,
175
+ ...error.requestId ? { requestId: error.requestId } : {},
176
+ ...error.retryAfterSeconds === null ? {} : { retryAfterSeconds: error.retryAfterSeconds }
177
+ }
178
+ };
179
+ } else if (error instanceof import_sdk2.RolinoNetworkError) {
180
+ body = { error: { code: error.kind, message: error.message } };
181
+ } else if (error instanceof TypeError) {
182
+ body = { error: { code: "VALIDATION_ERROR", message: error.message } };
183
+ } else {
184
+ body = {
185
+ error: {
186
+ code: "INTERNAL_ERROR",
187
+ message: "Rolino could not complete the tool call."
188
+ }
189
+ };
190
+ }
191
+ return {
192
+ content: [{ type: "text", text: JSON.stringify(body) }],
193
+ isError: true
194
+ };
195
+ }
196
+ var readOnlyAnnotations = {
197
+ readOnlyHint: true,
198
+ destructiveHint: false,
199
+ idempotentHint: true,
200
+ openWorldHint: false
201
+ };
202
+ var createDraftAnnotations = {
203
+ readOnlyHint: false,
204
+ destructiveHint: false,
205
+ idempotentHint: true,
206
+ openWorldHint: false
207
+ };
208
+ var createProjectAnnotations = {
209
+ readOnlyHint: false,
210
+ destructiveHint: false,
211
+ idempotentHint: true,
212
+ openWorldHint: false
213
+ };
214
+ var uploadMediaAnnotations = {
215
+ readOnlyHint: false,
216
+ destructiveHint: false,
217
+ idempotentHint: false,
218
+ openWorldHint: true
219
+ };
220
+ var ProjectCreateToolInputSchema = import_contracts.ProjectCreateInputSchema.safeExtend({
221
+ idempotencyKey: z.string().min(1).max(200).describe("Stable caller-generated retry key for this exact creation.")
222
+ });
223
+ var updateDraftAnnotations = {
224
+ readOnlyHint: false,
225
+ destructiveHint: true,
226
+ idempotentHint: true,
227
+ openWorldHint: false
228
+ };
229
+ var schedulePreviewAnnotations = {
230
+ readOnlyHint: false,
231
+ destructiveHint: false,
232
+ idempotentHint: false,
233
+ openWorldHint: true
234
+ };
235
+ var scheduleExecuteAnnotations = {
236
+ readOnlyHint: false,
237
+ destructiveHint: true,
238
+ idempotentHint: true,
239
+ openWorldHint: true
240
+ };
241
+ var publishPreviewAnnotations = {
242
+ readOnlyHint: false,
243
+ destructiveHint: false,
244
+ idempotentHint: false,
245
+ openWorldHint: true
246
+ };
247
+ var publishExecuteAnnotations = {
248
+ readOnlyHint: false,
249
+ destructiveHint: true,
250
+ idempotentHint: true,
251
+ openWorldHint: true
252
+ };
253
+ function defaultClient(options) {
254
+ return new import_sdk2.RolinoClient({
255
+ baseUrl: options.baseUrl ?? "https://getrolino.com",
256
+ token: options.token,
257
+ timeoutMs: options.timeoutMs,
258
+ fetch: options.fetch
259
+ });
260
+ }
261
+ function createRolinoMcpServer(options = {}) {
262
+ const api = options.client ?? defaultClient(options);
263
+ const server = new import_mcp.McpServer({
264
+ name: "rolino",
265
+ version: ROLINO_MCP_VERSION,
266
+ description: "Read Rolino workspace and publishing state, prepare drafts, and schedule posts through an exact server-confirmed two-step workflow."
267
+ });
268
+ server.registerTool("whoami", {
269
+ title: "Show Rolino identity",
270
+ description: "Use this before project tools to identify the authenticated Rolino user, organization, and granted capabilities. This tool never changes Rolino data.",
271
+ inputSchema: {},
272
+ outputSchema: import_contracts.ActorSchema,
273
+ annotations: readOnlyAnnotations
274
+ }, async () => {
275
+ try {
276
+ return jsonResult(await api.whoami());
277
+ } catch (error) {
278
+ return errorResult(error);
279
+ }
280
+ });
281
+ server.registerTool("list_projects", {
282
+ title: "List Rolino projects",
283
+ description: "List projects visible to the authenticated Rolino organization. Use the returned IDs with get_project; paginate with nextCursor when present. This tool never changes Rolino data.",
284
+ inputSchema: {
285
+ limit: z.number().int().min(1).max(100).default(50).describe("Maximum number of projects to return, from 1 to 100."),
286
+ cursor: z.string().min(1).optional().describe("Project cursor returned by a previous list_projects call.")
287
+ },
288
+ outputSchema: import_contracts.ProjectListDataSchema,
289
+ annotations: readOnlyAnnotations
290
+ }, async ({ limit, cursor }) => {
291
+ try {
292
+ return jsonResult(await api.projects.list({ limit, cursor }));
293
+ } catch (error) {
294
+ return errorResult(error);
295
+ }
296
+ });
297
+ server.registerTool("get_project", {
298
+ title: "Get a Rolino project",
299
+ description: "Get one Rolino project by its exact ID after discovering it with list_projects. This tool never changes Rolino data.",
300
+ inputSchema: {
301
+ projectId: z.string().min(1).describe("Exact Rolino project ID.")
302
+ },
303
+ outputSchema: import_contracts.ProjectSchema,
304
+ annotations: readOnlyAnnotations
305
+ }, async ({ projectId }) => {
306
+ try {
307
+ return jsonResult(await api.projects.get(projectId));
308
+ } catch (error) {
309
+ return errorResult(error);
310
+ }
311
+ });
312
+ server.registerTool("create_project", {
313
+ title: "Create a Rolino project",
314
+ description: "Create and save one paired Rolino project and brand. This requires projects:write and changes Rolino data, but it does not research a website, connect providers, schedule, or publish. Supply a stable idempotency key so retrying the same input cannot create a duplicate; returned website URLs are normalized and may differ from the submitted string.",
315
+ inputSchema: ProjectCreateToolInputSchema,
316
+ outputSchema: import_contracts.ProjectSchema,
317
+ annotations: createProjectAnnotations
318
+ }, async ({ idempotencyKey, ...input }) => {
319
+ try {
320
+ return jsonResult(await api.projects.create(input, {
321
+ idempotencyKey
322
+ }));
323
+ } catch (error) {
324
+ return errorResult(error);
325
+ }
326
+ });
327
+ server.registerTool("list_media_assets", {
328
+ title: "List Rolino media assets",
329
+ description: "List reusable images and videos in one exact project. Use this before uploading to avoid duplicates and pass returned asset IDs when creating or updating drafts. This tool never changes Rolino data.",
330
+ inputSchema: {
331
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
332
+ limit: z.number().int().min(1).max(100).default(50),
333
+ cursor: z.string().min(1).optional(),
334
+ type: z.enum(["IMAGE", "VIDEO"]).optional(),
335
+ query: z.string().trim().min(1).max(100).optional()
336
+ },
337
+ outputSchema: import_contracts.MediaAssetListDataSchema,
338
+ annotations: readOnlyAnnotations
339
+ }, async ({ projectId, limit, cursor, type, query }) => {
340
+ try {
341
+ if (!api.media) throw new TypeError("This Rolino client does not support media operations.");
342
+ return jsonResult(await api.media.list(projectId, { limit, cursor, type, query }));
343
+ } catch (error) {
344
+ return errorResult(error);
345
+ }
346
+ });
347
+ server.registerTool("upload_media_asset", {
348
+ title: "Upload local media to Rolino",
349
+ description: "Upload one explicitly approved local JPEG, PNG, WebP, MP4, or MOV file into an exact project's reusable media library. Read only the exact path supplied for this workflow. This changes Rolino data but never creates, schedules, or publishes a post. Return the asset ID for a later draft operation.",
350
+ inputSchema: {
351
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
352
+ filePath: z.string().min(1).describe("Exact local path of the user-approved media file.")
353
+ },
354
+ outputSchema: import_contracts.MediaAssetSchema,
355
+ annotations: uploadMediaAnnotations
356
+ }, async ({ projectId, filePath }) => {
357
+ try {
358
+ if (!api.media) throw new TypeError("This Rolino client does not support media operations.");
359
+ const absolutePath = (0, import_node_path.resolve)(filePath);
360
+ const details = await (0, import_promises.stat)(absolutePath).catch(() => null);
361
+ if (!details?.isFile()) throw new TypeError("The media path must point to a readable file.");
362
+ const contentTypes = { ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".webp": "image/webp", ".mp4": "video/mp4", ".mov": "video/quicktime" };
363
+ const contentType = contentTypes[(0, import_node_path.extname)(absolutePath).toLowerCase()];
364
+ if (!contentType) throw new TypeError("Use a JPEG, PNG, WebP, MP4, or MOV file.");
365
+ const bytes = await (0, import_promises.readFile)(absolutePath);
366
+ return jsonResult(await api.media.upload(projectId, { fileName: (0, import_node_path.basename)(absolutePath), contentType, fileSize: details.size, body: new Blob([bytes], { type: contentType }) }));
367
+ } catch (error) {
368
+ return errorResult(error);
369
+ }
370
+ });
371
+ server.registerTool("list_posts", {
372
+ title: "List Rolino posts",
373
+ description: "List posts in an exact Rolino project. Discover project IDs with list_projects, filter by status when useful, and paginate with nextCursor. This tool never changes Rolino data.",
374
+ inputSchema: {
375
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
376
+ limit: z.number().int().min(1).max(100).default(50).describe("Maximum number of posts to return, from 1 to 100."),
377
+ cursor: z.string().min(1).optional().describe("Post cursor returned by a previous list_posts call."),
378
+ status: z.enum([
379
+ "DRAFT",
380
+ "SCHEDULED",
381
+ "ACTION_REQUIRED",
382
+ "PUBLISHING",
383
+ "PUBLISHED",
384
+ "PARTIALLY_PUBLISHED",
385
+ "FAILED"
386
+ ]).optional().describe("Optional exact post status filter.")
387
+ },
388
+ outputSchema: import_contracts.PostListDataSchema,
389
+ annotations: readOnlyAnnotations
390
+ }, async ({ projectId, limit, cursor, status }) => {
391
+ try {
392
+ return jsonResult(await api.posts.list(projectId, {
393
+ limit,
394
+ cursor,
395
+ status
396
+ }));
397
+ } catch (error) {
398
+ return errorResult(error);
399
+ }
400
+ });
401
+ server.registerTool("get_post", {
402
+ title: "Get a Rolino post",
403
+ description: "Get one Rolino post, including its ordered media and publication-destination status, by exact project and post IDs. This tool never changes Rolino data.",
404
+ inputSchema: {
405
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
406
+ postId: z.string().min(1).describe("Exact Rolino post ID.")
407
+ },
408
+ outputSchema: import_contracts.PostSchema,
409
+ annotations: readOnlyAnnotations
410
+ }, async ({ projectId, postId }) => {
411
+ try {
412
+ return jsonResult(await api.posts.get(projectId, postId));
413
+ } catch (error) {
414
+ return errorResult(error);
415
+ }
416
+ });
417
+ server.registerTool("create_draft_post", {
418
+ title: "Create Rolino draft post",
419
+ description: "Create a draft in one exact project. This changes Rolino data but never schedules or publishes. A YouTube draft requires exactly one stored video plus explicit title, category, visibility, audience, disclosure, notification, and tag settings; its description uses the YOUTUBE caption override or shared caption. Unaudited Google API projects may be limited to Private uploads. Supply a stable idempotency key so retrying the same input cannot create a duplicate.",
420
+ inputSchema: {
421
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
422
+ idempotencyKey: z.string().min(1).max(200).describe("Stable caller-generated retry key for this exact creation."),
423
+ ...mcpDraftInputShape
424
+ },
425
+ outputSchema: import_contracts.PostSchema,
426
+ annotations: createDraftAnnotations
427
+ }, async ({ projectId, idempotencyKey, ...input }) => {
428
+ try {
429
+ const draft = import_contracts.DraftPostInputSchema.parse(input);
430
+ return jsonResult(await api.posts.create(projectId, draft, {
431
+ idempotencyKey
432
+ }));
433
+ } catch (error) {
434
+ return errorResult(error);
435
+ }
436
+ });
437
+ server.registerTool("update_draft_post", {
438
+ title: "Update Rolino draft post",
439
+ description: "Replace a draft's caption, destinations, media, and provider settings without scheduling or publishing it. YouTube still requires exactly one stored video and every explicit metadata declaration; its description uses the YOUTUBE caption override or shared caption. Read the post first and pass its current version; stale versions fail instead of overwriting another change. A stable idempotency key makes exact retries safe.",
440
+ inputSchema: {
441
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
442
+ postId: z.string().min(1).describe("Exact Rolino draft post ID."),
443
+ expectedVersion: z.number().int().positive().describe("Current version returned by get_post."),
444
+ idempotencyKey: z.string().min(1).max(200).describe("Stable caller-generated retry key for this exact update."),
445
+ ...mcpDraftInputShape
446
+ },
447
+ outputSchema: import_contracts.PostSchema,
448
+ annotations: updateDraftAnnotations
449
+ }, async ({
450
+ projectId,
451
+ postId,
452
+ expectedVersion,
453
+ idempotencyKey,
454
+ ...input
455
+ }) => {
456
+ try {
457
+ const draft = import_contracts.DraftPostInputSchema.parse(input);
458
+ return jsonResult(await api.posts.update(projectId, postId, draft, {
459
+ expectedVersion,
460
+ idempotencyKey
461
+ }));
462
+ } catch (error) {
463
+ return errorResult(error);
464
+ }
465
+ });
466
+ server.registerTool("get_post_readiness", {
467
+ title: "Get Rolino post readiness",
468
+ description: "Evaluate one saved post against its destinations, media, captions, settings, permissions, token timing, and cached provider health. YouTube checks cover one stored video, explicit metadata and declarations, description limits, Private-only audit restrictions, and queue-aware lead time. This is a read-only evaluation and does not refresh providers or publish content.",
469
+ inputSchema: {
470
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
471
+ postId: z.string().min(1).describe("Exact Rolino post ID.")
472
+ },
473
+ outputSchema: import_contracts.PostReadinessSchema,
474
+ annotations: readOnlyAnnotations
475
+ }, async ({ projectId, postId }) => {
476
+ try {
477
+ return jsonResult(await api.posts.readiness(projectId, postId));
478
+ } catch (error) {
479
+ return errorResult(error);
480
+ }
481
+ });
482
+ server.registerTool("preview_post_schedule", {
483
+ title: "Preview a Rolino post schedule",
484
+ description: "Validate one exact future schedule against the current post version and live provider health. A YouTube schedule must target Public and its preview explains that confirmed execution starts a private upload immediately for early processing. This contacts configured providers and creates a five-minute, single-use confirmation, but does not schedule or publish the post. Inspect the complete result before calling execute_post_schedule with identical values.",
485
+ inputSchema: {
486
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
487
+ postId: z.string().min(1).describe("Exact Rolino post ID."),
488
+ expectedVersion: z.number().int().positive().describe("Current version returned by get_post."),
489
+ ...import_contracts.PostScheduleInputSchema.shape
490
+ },
491
+ outputSchema: import_contracts.PostSchedulePreviewSchema,
492
+ annotations: schedulePreviewAnnotations
493
+ }, async ({ projectId, postId, expectedVersion, ...input }) => {
494
+ try {
495
+ return jsonResult(await api.posts.previewSchedule(
496
+ projectId,
497
+ postId,
498
+ input,
499
+ { expectedVersion }
500
+ ));
501
+ } catch (error) {
502
+ return errorResult(error);
503
+ }
504
+ });
505
+ server.registerTool("execute_post_schedule", {
506
+ title: "Execute a confirmed Rolino post schedule",
507
+ description: "Schedule a post only after preview_post_schedule. Pass the unchanged time, timezone, post version, and returned one-time confirmation token. For YouTube, confirmed execution begins or resumes the private upload immediately and may return PENDING until a remote schedule change is confirmed; it never means the video already published. Rolino rechecks readiness and provider health, rejects stale or mismatched confirmation, and uses the stable idempotency key for safe retries. Scheduling causes future external publishing and is consequential.",
508
+ inputSchema: {
509
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
510
+ postId: z.string().min(1).describe("Exact Rolino post ID."),
511
+ expectedVersion: z.number().int().positive().describe("Same post version used by preview_post_schedule."),
512
+ idempotencyKey: z.string().min(1).max(200).describe("Stable caller-generated retry key for this exact execution."),
513
+ confirmationToken: z.string().min(1).max(200).describe("Single-use token returned by preview_post_schedule."),
514
+ ...import_contracts.PostScheduleInputSchema.shape
515
+ },
516
+ outputSchema: mcpScheduleExecuteOutputSchema,
517
+ annotations: scheduleExecuteAnnotations
518
+ }, async ({
519
+ projectId,
520
+ postId,
521
+ expectedVersion,
522
+ idempotencyKey,
523
+ confirmationToken,
524
+ ...input
525
+ }) => {
526
+ try {
527
+ return jsonResult(await api.posts.executeSchedule(
528
+ projectId,
529
+ postId,
530
+ { ...input, confirmationToken },
531
+ { expectedVersion, idempotencyKey }
532
+ ));
533
+ } catch (error) {
534
+ return errorResult(error);
535
+ }
536
+ });
537
+ server.registerTool("preview_post_publish", {
538
+ title: "Preview immediate Rolino post publishing",
539
+ description: "Validate exact destinations against the current post version, safe retry state, readiness, and live provider health. YouTube readiness requires one stored video and explicit metadata; the configured visibility is exact, while unaudited Google API projects may be restricted to Private. This contacts configured providers and creates a five-minute, single-use confirmation, but does not publish. Inspect the complete result before calling execute_post_publish with identical destinations.",
540
+ inputSchema: {
541
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
542
+ postId: z.string().min(1).describe("Exact Rolino post ID."),
543
+ expectedVersion: z.number().int().positive().describe("Current version returned by get_post."),
544
+ destinations: import_contracts.PostPublishInputSchema.shape.destinations.describe("Exact Instagram, TikTok, YouTube, and/or Bluesky destinations to publish now.")
545
+ },
546
+ outputSchema: import_contracts.PostPublishPreviewSchema,
547
+ annotations: publishPreviewAnnotations
548
+ }, async ({ projectId, postId, expectedVersion, destinations }) => {
549
+ try {
550
+ return jsonResult(await api.posts.previewPublish(
551
+ projectId,
552
+ postId,
553
+ { destinations },
554
+ { expectedVersion }
555
+ ));
556
+ } catch (error) {
557
+ return errorResult(error);
558
+ }
559
+ });
560
+ server.registerTool("execute_post_publish", {
561
+ title: "Execute confirmed immediate Rolino post publishing",
562
+ description: "Begin external publishing only after preview_post_publish. Pass the unchanged destinations, post version, and returned one-time confirmation token. YouTube execution starts a resumable upload and remains PREPARING until provider-confirmed upload and processing complete; no queued or local state is reported as published. Rolino rechecks readiness and safe retry state, durably queues the exact destinations, rejects ambiguous prior outcomes, and uses the stable idempotency key to prevent duplicate execution. This is immediately consequential.",
563
+ inputSchema: {
564
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
565
+ postId: z.string().min(1).describe("Exact Rolino post ID."),
566
+ expectedVersion: z.number().int().positive().describe("Same post version used by preview_post_publish."),
567
+ idempotencyKey: z.string().min(1).max(200).describe("Stable caller-generated retry key for this exact execution."),
568
+ confirmationToken: z.string().min(1).max(200).describe("Single-use token returned by preview_post_publish."),
569
+ destinations: import_contracts.PostPublishInputSchema.shape.destinations.describe("Exact unchanged destinations returned by preview_post_publish.")
570
+ },
571
+ outputSchema: import_contracts.PostSchema,
572
+ annotations: publishExecuteAnnotations
573
+ }, async ({
574
+ projectId,
575
+ postId,
576
+ expectedVersion,
577
+ idempotencyKey,
578
+ confirmationToken,
579
+ destinations
580
+ }) => {
581
+ try {
582
+ return jsonResult(await api.posts.executePublish(
583
+ projectId,
584
+ postId,
585
+ { destinations, confirmationToken },
586
+ { expectedVersion, idempotencyKey }
587
+ ));
588
+ } catch (error) {
589
+ return errorResult(error);
590
+ }
591
+ });
592
+ server.registerTool("list_integration_health", {
593
+ title: "List Rolino publishing integration health",
594
+ description: "List secret-safe cached health for every enabled publishing connection (Instagram, TikTok, YouTube, or Bluesky) in one exact project. This tool does not contact external providers or reveal social credentials.",
595
+ inputSchema: {
596
+ projectId: z.string().min(1).describe("Exact Rolino project ID.")
597
+ },
598
+ outputSchema: import_contracts.IntegrationHealthListDataSchema,
599
+ annotations: readOnlyAnnotations
600
+ }, async ({ projectId }) => {
601
+ try {
602
+ return jsonResult(await api.integrations.health(projectId));
603
+ } catch (error) {
604
+ return errorResult(error);
605
+ }
606
+ });
607
+ server.registerTool("list_calendar_events", {
608
+ title: "List Rolino calendar events",
609
+ description: "List scheduled posts and their enabled destinations in one exact project, including YouTube posts whose private early preparation has started. By default the bounded window spans 30 days in the past through 90 days ahead; provide both from and to for another range and paginate with nextCursor.",
610
+ inputSchema: {
611
+ projectId: z.string().min(1).describe("Exact Rolino project ID."),
612
+ limit: z.number().int().min(1).max(100).default(50).describe("Maximum number of calendar events to return, from 1 to 100."),
613
+ cursor: z.string().min(1).optional().describe("Opaque cursor returned by a previous list_calendar_events call."),
614
+ from: z.iso.datetime().optional().describe("Inclusive ISO-8601 window start; provide together with to."),
615
+ to: z.iso.datetime().optional().describe("Exclusive ISO-8601 window end; provide together with from.")
616
+ },
617
+ outputSchema: import_contracts.CalendarListDataSchema,
618
+ annotations: readOnlyAnnotations
619
+ }, async ({ projectId, limit, cursor, from, to }) => {
620
+ try {
621
+ return jsonResult(await api.calendar.list(projectId, {
622
+ limit,
623
+ cursor,
624
+ from,
625
+ to
626
+ }));
627
+ } catch (error) {
628
+ return errorResult(error);
629
+ }
630
+ });
631
+ return server;
632
+ }
633
+ async function startStdioServer(options = {}) {
634
+ const server = createRolinoMcpServer(options);
635
+ const transport = new import_stdio.StdioServerTransport();
636
+ await server.connect(transport);
637
+ return server;
638
+ }
639
+ // Annotate the CommonJS export names for ESM import in node:
640
+ 0 && (module.exports = {
641
+ ROLINO_MCP_VERSION,
642
+ createRolinoMcpServer,
643
+ resolveMcpConfiguration,
644
+ startStdioServer
645
+ });
646
+ //# sourceMappingURL=index.cjs.map