@rolino/mcp 0.5.0-beta.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @rolino/mcp
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4f9e790: Add the optional `blog:manage` capability and synchronized agent-first Blog
8
+ setup, import, cadence planning, plan review, article creation, confirmed
9
+ connection provisioning, and safe verification operations.
10
+ - 1edd1e7: Add published Blog Studio delivery contracts and the server-only Next.js 16 Blog Studio package.
11
+ - 74a13ea: Expose immediate versus scheduled delivery and destination lifecycle stages,
12
+ preserve YouTube visibility for immediate publishing, and clarify remote
13
+ schedule confirmation across public clients.
14
+ - 4af607d: Add independent exact-bundle Blog approval, reviewed image upload and generation,
15
+ confirmed publication scheduling and cancellation, and the complete authorized
16
+ agent workflow without widening existing credentials.
17
+ - 4a893dd: Add provider-neutral Blog publishing destinations, safe delivery inspection,
18
+ and exact destination binding across public agent interfaces.
19
+ - 843a1db: Add the exact optional `seo:read` capability and bounded read-only SEO
20
+ opportunity and weekly-report parity across public agent contracts, clients,
21
+ CLI commands, and closed-world MCP tools. SEO reads now use the version 3 task
22
+ contract with the exact Ready, Research, or Rejected decision, selected format,
23
+ complete deliverables, bounded evidence, safe URLs, limitations, and no-publish
24
+ rules. Public output uses readable topic names and separate topic-relevance and
25
+ action-readiness confidence. Research tasks compare all supported formats and
26
+ must validate or reject the finding before a separate draft action is allowed.
27
+
28
+ ### Patch Changes
29
+
30
+ - Updated dependencies [4f9e790]
31
+ - Updated dependencies [1edd1e7]
32
+ - Updated dependencies [74a13ea]
33
+ - Updated dependencies [4af607d]
34
+ - Updated dependencies [4a893dd]
35
+ - Updated dependencies [843a1db]
36
+ - @rolino/contracts@0.5.0
37
+ - @rolino/sdk@0.5.0
38
+ - @rolino/local-auth@0.5.0
39
+
3
40
  ## 0.5.0-beta.0
4
41
 
5
42
  ### Minor Changes
@@ -37,6 +74,9 @@
37
74
 
38
75
  ### Minor Changes
39
76
 
77
+ - Add exact Blog image generation and upload, image review, confirmed
78
+ exact-bundle approval, scheduling, and schedule cancellation tools with
79
+ shared contracts, safe errors, and truthful capability and safety annotations.
40
80
  - Add safe Blog provider, destination, and delivery tools plus destination-bound publication inputs.
41
81
 
42
82
  ## 0.4.0
package/README.md CHANGED
@@ -153,24 +153,37 @@ issues through the repository's
153
153
  `@rolino/mcp` is available under the MIT License.
154
154
  ## Agent-first Blog Studio tools
155
155
 
156
- The local stdio server exposes Blog readiness, import, cadence planning,
157
- plan-item evidence and state, editable article creation, connection status,
158
- confirmed provisioning, signed revalidation testing, and these provider-neutral
159
- publishing reads:
160
-
161
- - `list_blog_publishing_providers` requires `blog:manage` and returns only
162
- enabled providers, safe capabilities, and official documentation.
163
- - `list_blog_publishing_destinations` requires `blog:read` and returns safe
164
- connection readiness without credentials or private provider data.
165
- - `list_blog_delivery_attempts` requires `blog:read`, accepts an optional exact
166
- article ID, and returns safe delivery states, retry times, error codes, and
167
- remote URLs.
168
-
169
- These three tools are closed-world reads. They do not contact a provider or
170
- change content. They do not return draft content, prompts, evidence, secrets,
171
- or raw provider responses. Setup requires the
172
- independent optional `blog:manage` capability; it is never inferred from
173
- `blog:write` or `blog:publish` and is not added to existing credentials.
156
+ The local stdio server exposes Blog readiness, import, cadence planning,
157
+ plan-item evidence and state, editable article creation, connection status,
158
+ confirmed provisioning, signed revalidation testing, and these provider-neutral
159
+ publishing reads:
160
+
161
+ - `list_blog_publishing_providers` requires `blog:manage` and returns only
162
+ enabled providers, safe capabilities, and official documentation.
163
+ - `list_blog_publishing_destinations` requires `blog:read` and returns safe
164
+ connection readiness without credentials or private provider data.
165
+ - `list_blog_delivery_attempts` requires `blog:read`, accepts an optional exact
166
+ article ID, and returns safe delivery states, retry times, error codes, and
167
+ remote URLs.
168
+ - `generate_blog_image`, `upload_blog_image`, and `review_blog_image` require
169
+ `blog:write`. They cannot approve an article or publish it. Upload reads only
170
+ the exact local JPEG, PNG, or WebP path supplied to the tool.
171
+ - `preview_blog_revision_approval` and `execute_blog_revision_approval` require
172
+ the independent `blog:approve` capability. Execution makes the confirmed
173
+ exact bundle eligible for a separate publication operation; it cannot
174
+ publish.
175
+ - `preview_blog_schedule`, `execute_blog_schedule`,
176
+ `preview_blog_schedule_cancellation`, and
177
+ `execute_blog_schedule_cancellation` require the independent `blog:publish`
178
+ capability. Scheduling causes future external publication but does not grant
179
+ approval. Cancellation removes only the confirmed future schedule and never
180
+ unpublishes a live article.
181
+
182
+ The three publishing-read tools are closed-world reads. They do not contact a provider or
183
+ change content. They do not return draft content, prompts, evidence, secrets,
184
+ or raw provider responses. Setup requires the
185
+ independent optional `blog:manage` capability; it is never inferred from
186
+ `blog:write` or `blog:publish` and is not added to existing credentials.
174
187
 
175
188
  Read tools are closed-world. The signed revalidation test is accurately marked
176
189
  as an open-world write. Connection execute is confirmed, destructive, and
@@ -179,3 +192,15 @@ only to server-side environment configuration. Errors and replays never reveal
179
192
  those values. These are local stdio tools—Rolino does not expose hosted remote
180
193
  MCP. Publication still requires a user-approved exact revision and the
181
194
  separate publish preview/execute tools.
195
+
196
+ Use the Blog tools in this order: read setup and current article or plan state;
197
+ ask for a missing website, cadence, destination, or access level; import and
198
+ plan through polled durable jobs; present evidence before bounded plan
199
+ acceptance; create one immutable revision with catalog-backed links; generate
200
+ or upload and review one image with alt text; stop for user approval when
201
+ `blog:approve` is missing; otherwise preview and execute exact-bundle approval
202
+ with its confirmation token and a stable idempotency key; stop after approval
203
+ when `blog:publish` is missing; otherwise preview and execute unchanged
204
+ publication or scheduling; poll delivery and verify the live URL; and restart
205
+ from approval preview after any content or image change. Existing credentials
206
+ do not gain `blog:approve`, and a queued delivery is not published.
package/dist/bin.cjs CHANGED
@@ -52,7 +52,7 @@ var z = __toESM(require("zod/v4"), 1);
52
52
  // package.json
53
53
  var package_default = {
54
54
  name: "@rolino/mcp",
55
- version: "0.5.0-beta.0",
55
+ version: "0.5.0",
56
56
  description: "Model Context Protocol server for Rolino",
57
57
  type: "module",
58
58
  license: "MIT",
@@ -111,9 +111,9 @@ var package_default = {
111
111
  dependencies: {
112
112
  "@hono/node-server": "2.0.12",
113
113
  "@modelcontextprotocol/sdk": "^1.30.0",
114
- "@rolino/contracts": "0.5.0-beta.0",
115
- "@rolino/local-auth": "0.5.0-beta.0",
116
- "@rolino/sdk": "0.5.0-beta.0",
114
+ "@rolino/contracts": "0.5.0",
115
+ "@rolino/local-auth": "0.5.0",
116
+ "@rolino/sdk": "0.5.0",
117
117
  zod: "^4.4.3"
118
118
  },
119
119
  devDependencies: {
@@ -318,6 +318,30 @@ var revalidationTestAnnotations = {
318
318
  idempotentHint: true,
319
319
  openWorldHint: true
320
320
  };
321
+ var blogImageWriteAnnotations = {
322
+ readOnlyHint: false,
323
+ destructiveHint: false,
324
+ idempotentHint: true,
325
+ openWorldHint: false
326
+ };
327
+ var blogConfirmationPreviewAnnotations = {
328
+ readOnlyHint: false,
329
+ destructiveHint: false,
330
+ idempotentHint: false,
331
+ openWorldHint: false
332
+ };
333
+ var blogConfirmedWriteAnnotations = {
334
+ readOnlyHint: false,
335
+ destructiveHint: false,
336
+ idempotentHint: true,
337
+ openWorldHint: false
338
+ };
339
+ var blogScheduleExecuteAnnotations = {
340
+ readOnlyHint: false,
341
+ destructiveHint: false,
342
+ idempotentHint: true,
343
+ openWorldHint: true
344
+ };
321
345
  function defaultClient(options) {
322
346
  return new import_sdk2.RolinoClient({
323
347
  baseUrl: options.baseUrl ?? "https://getrolino.com",
@@ -1029,6 +1053,169 @@ function createRolinoMcpServer(options = {}) {
1029
1053
  return errorResult(error);
1030
1054
  }
1031
1055
  });
1056
+ server.registerTool("generate_blog_image", {
1057
+ title: "Generate a Blog image candidate",
1058
+ description: "Requires blog:write. Queue a bounded featured-image candidate for one exact article revision. This cannot approve an image or article and cannot publish.",
1059
+ inputSchema: {
1060
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1061
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID."),
1062
+ ...import_contracts.AgentBlogImageGenerateRequestSchema.shape
1063
+ },
1064
+ outputSchema: import_contracts.AgentBlogImageGenerationResponseSchema.shape.data,
1065
+ annotations: blogImageWriteAnnotations
1066
+ }, async ({ projectId, articleId, ...input }) => {
1067
+ try {
1068
+ return jsonResult(await blogApi().articles.generateImage(projectId, articleId, input));
1069
+ } catch (error) {
1070
+ return errorResult(error);
1071
+ }
1072
+ });
1073
+ server.registerTool("upload_blog_image", {
1074
+ title: "Upload a local Blog image candidate",
1075
+ description: "Requires blog:write. Read only one exact caller-supplied local JPEG, PNG, or WebP path and upload it for one exact article revision. This cannot approve an image or article and cannot publish.",
1076
+ inputSchema: {
1077
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1078
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID."),
1079
+ revisionId: import_contracts.AgentBlogImageUploadPrepareRequestSchema.shape.revisionId,
1080
+ filePath: z.string().min(1).describe("Exact local path of the user-approved Blog image."),
1081
+ altText: import_contracts.AgentBlogImageUploadCompleteRequestSchema.shape.altText
1082
+ },
1083
+ outputSchema: import_contracts.AgentBlogImageSchema,
1084
+ annotations: blogImageWriteAnnotations
1085
+ }, async ({ projectId, articleId, revisionId, filePath, altText }) => {
1086
+ try {
1087
+ const absolutePath = (0, import_node_path.resolve)(filePath);
1088
+ const details = await (0, import_promises.stat)(absolutePath).catch(() => null);
1089
+ if (!details?.isFile()) throw new TypeError("The Blog image path must point to a readable file.");
1090
+ const contentTypes = { ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".png": "image/png", ".webp": "image/webp" };
1091
+ const extension = (0, import_node_path.extname)(absolutePath).toLowerCase();
1092
+ const contentType = contentTypes[extension];
1093
+ if (!contentType) throw new TypeError("Use a JPEG, PNG, or WebP Blog image.");
1094
+ const body = await (0, import_node_fs.openAsBlob)(absolutePath, { type: contentType });
1095
+ return jsonResult(await blogApi().articles.uploadImage(projectId, articleId, { revisionId, fileName: (0, import_node_path.basename)(absolutePath), contentType, fileSize: details.size, altText, body }));
1096
+ } catch (error) {
1097
+ return errorResult(error);
1098
+ }
1099
+ });
1100
+ server.registerTool("review_blog_image", {
1101
+ title: "Review a Blog image candidate",
1102
+ description: "Requires blog:write. Approve or reject one exact image version with reviewable alt text and idempotency. This does not approve the article and cannot publish.",
1103
+ inputSchema: {
1104
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1105
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID."),
1106
+ imageId: import_contracts.SeoEntityIdSchema.describe("Exact Blog image ID."),
1107
+ ...import_contracts.AgentBlogImageReviewRequestSchema.shape
1108
+ },
1109
+ outputSchema: import_contracts.AgentBlogImageSchema,
1110
+ annotations: blogImageWriteAnnotations
1111
+ }, async ({ projectId, articleId, imageId, ...input }) => {
1112
+ try {
1113
+ return jsonResult(await blogApi().articles.reviewImage(projectId, articleId, imageId, input));
1114
+ } catch (error) {
1115
+ return errorResult(error);
1116
+ }
1117
+ });
1118
+ server.registerTool("preview_blog_revision_approval", {
1119
+ title: "Preview exact Blog revision approval",
1120
+ description: "Requires blog:approve. Validate one exact revision, its approved image bundle, live links, warnings, and bundle hash, then create a short-lived confirmation. This cannot publish.",
1121
+ inputSchema: {
1122
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1123
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID."),
1124
+ ...import_contracts.AgentBlogApprovalPreviewRequestSchema.shape
1125
+ },
1126
+ outputSchema: import_contracts.AgentBlogApprovalPreviewSchema,
1127
+ annotations: blogConfirmationPreviewAnnotations
1128
+ }, async ({ projectId, articleId, ...input }) => {
1129
+ try {
1130
+ return jsonResult(await blogApi().articles.previewApproval(projectId, articleId, input));
1131
+ } catch (error) {
1132
+ return errorResult(error);
1133
+ }
1134
+ });
1135
+ server.registerTool("execute_blog_revision_approval", {
1136
+ title: "Approve an exact Blog revision bundle",
1137
+ description: "Requires blog:approve. Consume the matching confirmation and idempotently approve the exact revision and image bundle, which makes that bundle eligible for a separate publication operation. This cannot publish.",
1138
+ inputSchema: {
1139
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1140
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID."),
1141
+ ...import_contracts.AgentBlogApprovalExecuteRequestSchema.shape
1142
+ },
1143
+ outputSchema: import_contracts.AgentBlogApprovalExecuteSchema,
1144
+ annotations: blogConfirmedWriteAnnotations
1145
+ }, async ({ projectId, articleId, ...input }) => {
1146
+ try {
1147
+ return jsonResult(await blogApi().articles.executeApproval(projectId, articleId, input));
1148
+ } catch (error) {
1149
+ return errorResult(error);
1150
+ }
1151
+ });
1152
+ server.registerTool("preview_blog_schedule", {
1153
+ title: "Preview an exact Blog schedule",
1154
+ description: "Requires blog:publish. Bind one already-approved exact bundle, future instant, IANA timezone, and destination set to a short-lived confirmation. This does not grant approval or publish now.",
1155
+ inputSchema: {
1156
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1157
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID."),
1158
+ ...import_contracts.AgentBlogSchedulePreviewRequestSchema.shape
1159
+ },
1160
+ outputSchema: import_contracts.AgentBlogSchedulePreviewSchema,
1161
+ annotations: blogConfirmationPreviewAnnotations
1162
+ }, async ({ projectId, articleId, ...input }) => {
1163
+ try {
1164
+ return jsonResult(await blogApi().articles.previewSchedule(projectId, articleId, input));
1165
+ } catch (error) {
1166
+ return errorResult(error);
1167
+ }
1168
+ });
1169
+ server.registerTool("execute_blog_schedule", {
1170
+ title: "Schedule an exact approved Blog bundle",
1171
+ description: "Requires blog:publish. Consume the matching confirmation and idempotently schedule or reschedule one already-approved exact bundle for future external publication. This does not grant approval.",
1172
+ inputSchema: {
1173
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1174
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID."),
1175
+ ...import_contracts.AgentBlogScheduleExecuteRequestSchema.shape
1176
+ },
1177
+ outputSchema: import_contracts.AgentBlogScheduleExecuteSchema,
1178
+ annotations: blogScheduleExecuteAnnotations
1179
+ }, async ({ projectId, articleId, ...input }) => {
1180
+ try {
1181
+ return jsonResult(await blogApi().articles.executeSchedule(projectId, articleId, input));
1182
+ } catch (error) {
1183
+ return errorResult(error);
1184
+ }
1185
+ });
1186
+ server.registerTool("preview_blog_schedule_cancellation", {
1187
+ title: "Preview Blog schedule cancellation",
1188
+ description: "Requires blog:publish. Bind the exact current future schedule to a short-lived cancellation confirmation. This does not unpublish a live article and does not grant approval.",
1189
+ inputSchema: {
1190
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1191
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID.")
1192
+ },
1193
+ outputSchema: import_contracts.AgentBlogScheduleCancelPreviewSchema,
1194
+ annotations: blogConfirmationPreviewAnnotations
1195
+ }, async ({ projectId, articleId }) => {
1196
+ try {
1197
+ return jsonResult(await blogApi().articles.previewScheduleCancellation(projectId, articleId));
1198
+ } catch (error) {
1199
+ return errorResult(error);
1200
+ }
1201
+ });
1202
+ server.registerTool("execute_blog_schedule_cancellation", {
1203
+ title: "Cancel an exact future Blog schedule",
1204
+ description: "Requires blog:publish. Consume the matching confirmation and idempotently cancel the exact future schedule. This is destructive, but it never unpublishes a live article and does not grant approval.",
1205
+ inputSchema: {
1206
+ projectId: import_contracts.SeoEntityIdSchema.describe("Exact Rolino project ID."),
1207
+ articleId: import_contracts.SeoEntityIdSchema.describe("Exact Blog article ID."),
1208
+ ...import_contracts.AgentBlogScheduleCancelExecuteRequestSchema.shape
1209
+ },
1210
+ outputSchema: import_contracts.AgentBlogScheduleCancelExecuteSchema,
1211
+ annotations: destructiveIdempotentAnnotations
1212
+ }, async ({ projectId, articleId, ...input }) => {
1213
+ try {
1214
+ return jsonResult(await blogApi().articles.executeScheduleCancellation(projectId, articleId, input));
1215
+ } catch (error) {
1216
+ return errorResult(error);
1217
+ }
1218
+ });
1032
1219
  server.registerTool("get_blog_job", {
1033
1220
  title: "Read one Blog job",
1034
1221
  description: "Read truthful durable job state without exposing prompts, provider details, or secrets.",