@rolino/mcp 0.6.0 → 0.7.1

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,9 +1,32 @@
1
1
  # @rolino/mcp
2
2
 
3
+ ## 0.7.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @rolino/contracts@0.7.1
8
+ - @rolino/sdk@0.7.1
9
+ - @rolino/local-auth@0.7.1
10
+
11
+ ## 0.7.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 358f37a: Expose additive safe Blog preparation, next-action, and quality summaries through the shared read contracts and existing clients.
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [358f37a]
20
+ - @rolino/contracts@0.7.0
21
+ - @rolino/sdk@0.7.0
22
+ - @rolino/local-auth@0.7.0
23
+
3
24
  ## 0.6.0
4
25
 
5
26
  ### Minor Changes
6
27
 
28
+ - Add nine scoped backlink prospecting tools with correct closed-world and open-world annotations. Rolino does not send email.
29
+
7
30
  - d162f85: Add safe Blog editorial cadence preview and apply operations across contracts, SDK, CLI, and MCP.
8
31
  - 50cb9fc: Add Google Business Profile as a disabled-by-default standard text and single-image publishing destination across shared public clients.
9
32
  - 1ac7ed5: Add signed custom Blog webhook setup, connection testing, one-time secret rotation, and safe idempotent replay parity.
@@ -93,6 +116,10 @@
93
116
 
94
117
  ### Minor Changes
95
118
 
119
+ - Return additive safe Blog preparation and quality state from existing read tools.
120
+
121
+ ### Minor Changes
122
+
96
123
  - Add exact Blog image generation and upload, image review, confirmed
97
124
  exact-bundle approval, scheduling, and schedule cancellation tools with
98
125
  shared contracts, safe errors, and truthful capability and safety annotations.
package/README.md CHANGED
@@ -1,20 +1,24 @@
1
1
  # `@rolino/mcp`
2
2
 
3
- Rolino's Model Context Protocol adapter. The first supported transport is local
4
- stdio and it calls the same public API used by the CLI. Remote Streamable HTTP
5
- remains gated by the OAuth interoperability decision in ADR 0003.
3
+ Rolino's Model Context Protocol adapter. Rolino supports hosted Streamable HTTP
4
+ with client-owned OAuth and local STDIO with the shared CLI OAuth session. The
5
+ hosted route is stateless and does not need this package on the caller's
6
+ computer. This package supplies the local STDIO process and the shared MCP tool
7
+ definitions used by both transports.
6
8
 
7
9
  ## Installation
8
10
 
9
- Local MCP remains a separate, explicit
10
- installation so CLI-only users do not receive MCP runtime dependencies:
11
+ Local STDIO MCP remains a separate, explicit installation so CLI-only and
12
+ remote users do not receive MCP runtime dependencies:
11
13
 
12
14
  ```bash
13
15
  npm install --global @rolino/cli @rolino/mcp
14
16
  ```
15
17
 
16
- The CLI handles standard OAuth Authorization Code with PKCE and writes token-free Codex or Claude
17
- Code configuration that points to this package's installed stdio entry point.
18
+ For hosted Streamable HTTP, run `rolino setup mcp --client codex --transport
19
+ http`, then `codex mcp login rolino`. For local STDIO, the CLI handles standard
20
+ OAuth Authorization Code with PKCE and writes token-free Codex or Claude Code
21
+ configuration that points to this package's installed entry point.
18
22
  Headless operators may install only `@rolino/mcp` and provide a scoped
19
23
  `ROLINO_TOKEN` explicitly.
20
24
 
@@ -41,8 +45,19 @@ Initial tools:
41
45
  - `get_seo_opportunity`
42
46
  - `list_seo_reports`
43
47
  - `get_seo_report`
48
+ - `start_backlink_discovery`
49
+ - `get_backlink_discovery`
50
+ - `list_backlink_prospects`
51
+ - `get_backlink_prospect`
52
+ - `research_backlink_contact`
53
+ - `update_backlink_stage`
54
+ - `update_backlink_outreach`
55
+ - `list_backlink_contacts`
56
+ - `verify_backlink`
44
57
  - `list_calendar_events`
45
58
 
59
+ Backlink tools use independent opt-in scopes. Provider-calling tools are bounded and open-world. Stored reads are closed-world. No tool accepts an arbitrary search query or a user-supplied email. Rolino never sends email.
60
+
46
61
  The media tools discover reusable project assets and stream one explicitly
47
62
  approved local JPEG, PNG, WebP, MP4, or MOV file directly to configured
48
63
  storage. Rolino derives dimensions and video duration from the stored object.
@@ -105,7 +120,7 @@ an unknown outcome, inspect the selected Business Profile before retrying.
105
120
  Integration health is cached and secret-safe, post
106
121
  readiness reuses Rolino's publishing checks, and calendar reads use bounded
107
122
  date windows with cursor pagination. After `rolino auth login`, configure `ROLINO_URL` and
108
- the server automatically obtains and refreshes the API-resource OAuth token saved for
123
+ the server automatically obtains and refreshes the API-resource OAuth token saved for
109
124
  that exact host. `ROLINO_TOKEN` remains an explicit override for CI and other
110
125
  headless environments. `ROLINO_CONFIG_DIR` can override the portable credential
111
126
  directory, and `ROLINO_TIMEOUT` is optional. Stdout is reserved for MCP
@@ -206,9 +221,9 @@ Read tools are closed-world. The signed revalidation test is accurately marked
206
221
  as an open-world write. Connection execute is confirmed, destructive, and
207
222
  idempotent; its first success may return one-time values that must be written
208
223
  only to server-side environment configuration. Errors and replays never reveal
209
- those values. These tools remain available over local stdio. The remote profile
210
- omits both caller-local media and Blog image uploads, and the hosted route stays hidden while its
211
- deployment gate is off. Publication still requires a user-approved exact revision and the
224
+ those values. These tools remain available over local stdio. The remote profile
225
+ omits both caller-local media and Blog image uploads, and the hosted route stays hidden while its
226
+ deployment gate is off. Publication still requires a user-approved exact revision and the
212
227
  separate publish preview/execute tools.
213
228
 
214
229
  Use the Blog tools in this order: read setup and current article or plan state;
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.6.0",
55
+ version: "0.7.1",
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/server": "2.0.0",
114
- "@rolino/contracts": "0.6.0",
115
- "@rolino/local-auth": "0.6.0",
116
- "@rolino/sdk": "0.6.0",
114
+ "@rolino/contracts": "0.7.1",
115
+ "@rolino/local-auth": "0.7.1",
116
+ "@rolino/sdk": "0.7.1",
117
117
  zod: "^4.4.3"
118
118
  },
119
119
  devDependencies: {
@@ -250,6 +250,8 @@ var readOnlyAnnotations = {
250
250
  idempotentHint: true,
251
251
  openWorldHint: false
252
252
  };
253
+ var backlinkOpenWorldAnnotations = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true };
254
+ var backlinkWriteAnnotations = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
253
255
  var blogPublicationWeekdaysSchema = z.array(z.number().int().min(0).max(6)).min(1).max(7).superRefine((weekdays, context) => {
254
256
  if (new Set(weekdays).size !== weekdays.length) {
255
257
  context.addIssue({ code: "custom", message: "Weekdays must be unique." });
@@ -800,6 +802,73 @@ function createRolinoMcpServer(options = {}) {
800
802
  return errorResult(error);
801
803
  }
802
804
  });
805
+ const backlinkApi = () => {
806
+ if (!api.backlinks) throw new TypeError("This Rolino client does not support backlink prospecting.");
807
+ return api.backlinks;
808
+ };
809
+ server.registerTool("start_backlink_discovery", { title: "Start bounded backlink discovery", description: "Queue one bounded backlink opportunity discovery for an exact Rolino project. This can contact the configured web research provider. It does not accept an arbitrary query and Rolino never sends email.", inputSchema: z.object({ projectId: import_contracts.SeoEntityIdSchema, limit: z.number().int().min(1).max(20).default(20), idempotencyKey: z.string().min(1).max(128) }), outputSchema: import_contracts.BacklinkDiscoveryRunSchema, annotations: backlinkOpenWorldAnnotations }, async ({ projectId, limit, idempotencyKey }) => {
810
+ try {
811
+ return jsonResult(await backlinkApi().discoveries.start(projectId, { limit }, idempotencyKey));
812
+ } catch (error) {
813
+ return errorResult(error);
814
+ }
815
+ });
816
+ server.registerTool("get_backlink_discovery", { title: "Get backlink discovery", description: "Read one stored backlink discovery run. This closed-world tool does not contact providers or send email.", inputSchema: z.object({ projectId: import_contracts.SeoEntityIdSchema, runId: import_contracts.SeoEntityIdSchema }), outputSchema: import_contracts.BacklinkDiscoveryRunSchema, annotations: readOnlyAnnotations }, async ({ projectId, runId }) => {
817
+ try {
818
+ return jsonResult(await backlinkApi().discoveries.get(projectId, runId));
819
+ } catch (error) {
820
+ return errorResult(error);
821
+ }
822
+ });
823
+ server.registerTool("list_backlink_prospects", { title: "List backlink prospects", description: "Read bounded, safe backlink prospect summaries for one project. This closed-world tool omits emails and draft bodies and never sends email.", inputSchema: import_contracts.BacklinkProspectListQuerySchema.extend({ projectId: import_contracts.SeoEntityIdSchema }), outputSchema: import_contracts.BacklinkProspectListDataSchema, annotations: readOnlyAnnotations }, async ({ projectId, ...options2 }) => {
824
+ try {
825
+ return jsonResult(await backlinkApi().prospects.list(projectId, options2));
826
+ } catch (error) {
827
+ return errorResult(error);
828
+ }
829
+ });
830
+ server.registerTool("get_backlink_prospect", { title: "Get backlink prospect", description: "Read one safe stored backlink prospect and its canonical next action. It omits emails and drafts and never sends email.", inputSchema: z.object({ projectId: import_contracts.SeoEntityIdSchema, prospectId: import_contracts.SeoEntityIdSchema }), outputSchema: import_contracts.BacklinkProspectSchema, annotations: readOnlyAnnotations }, async ({ projectId, prospectId }) => {
831
+ try {
832
+ return jsonResult(await backlinkApi().prospects.get(projectId, prospectId));
833
+ } catch (error) {
834
+ return errorResult(error);
835
+ }
836
+ });
837
+ server.registerTool("research_backlink_contact", { title: "Research a public backlink contact", description: "Queue bounded public contact research for one approved stored prospect. This can contact the configured web provider. The tool cannot accept an email and Rolino never sends email.", inputSchema: z.object({ projectId: import_contracts.SeoEntityIdSchema, prospectId: import_contracts.SeoEntityIdSchema, idempotencyKey: z.string().min(1).max(128) }), outputSchema: import_contracts.BacklinkQueueResponseSchema.shape.data, annotations: backlinkOpenWorldAnnotations }, async ({ projectId, prospectId, idempotencyKey }) => {
838
+ try {
839
+ return jsonResult(await backlinkApi().prospects.researchContact(projectId, prospectId, idempotencyKey));
840
+ } catch (error) {
841
+ return errorResult(error);
842
+ }
843
+ });
844
+ server.registerTool("update_backlink_stage", { title: "Update backlink stage", description: "Apply one allowed optimistic stage change to a stored prospect. This cannot send email.", inputSchema: import_contracts.BacklinkStageUpdateInputSchema.extend({ projectId: import_contracts.SeoEntityIdSchema, prospectId: import_contracts.SeoEntityIdSchema, idempotencyKey: z.string().min(1).max(128) }), outputSchema: import_contracts.BacklinkProspectSchema, annotations: backlinkWriteAnnotations }, async ({ projectId, prospectId, stage, expectedVersion, idempotencyKey }) => {
845
+ try {
846
+ return jsonResult(await backlinkApi().prospects.updateStage(projectId, prospectId, { stage, expectedVersion }, idempotencyKey));
847
+ } catch (error) {
848
+ return errorResult(error);
849
+ }
850
+ });
851
+ server.registerTool("update_backlink_outreach", { title: "Update backlink outreach draft", description: "Save an edited stored outreach draft with an optimistic version. This tool only edits a draft. Rolino never sends email.", inputSchema: import_contracts.BacklinkOutreachUpdateInputSchema.extend({ projectId: import_contracts.SeoEntityIdSchema, prospectId: import_contracts.SeoEntityIdSchema, idempotencyKey: z.string().min(1).max(128) }), outputSchema: import_contracts.BacklinkOutreachDraftSchema, annotations: backlinkWriteAnnotations }, async ({ projectId, prospectId, idempotencyKey, ...input }) => {
852
+ try {
853
+ return jsonResult(await backlinkApi().prospects.updateOutreach(projectId, prospectId, input, idempotencyKey));
854
+ } catch (error) {
855
+ return errorResult(error);
856
+ }
857
+ });
858
+ server.registerTool("list_backlink_contacts", { title: "List approved public backlink contacts", description: "Read bounded, non-stale public contacts and editable drafts. This requires explicit contact access. Rolino never sends email.", inputSchema: import_contracts.BacklinkContactListQuerySchema.extend({ projectId: import_contracts.SeoEntityIdSchema }), outputSchema: import_contracts.BacklinkContactListDataSchema, annotations: readOnlyAnnotations }, async ({ projectId, ...options2 }) => {
859
+ try {
860
+ return jsonResult(await backlinkApi().contacts.list(projectId, options2));
861
+ } catch (error) {
862
+ return errorResult(error);
863
+ }
864
+ });
865
+ server.registerTool("verify_backlink", { title: "Verify an exact backlink", description: "Queue a bounded public fetch of a claimed page and check for the exact selected owned target URL. This contacts the configured web provider and never sends email.", inputSchema: import_contracts.BacklinkVerificationInputSchema.extend({ projectId: import_contracts.SeoEntityIdSchema, prospectId: import_contracts.SeoEntityIdSchema, idempotencyKey: z.string().min(1).max(128) }), outputSchema: import_contracts.BacklinkVerificationSchema, annotations: backlinkOpenWorldAnnotations }, async ({ projectId, prospectId, idempotencyKey, ...input }) => {
866
+ try {
867
+ return jsonResult(await backlinkApi().prospects.verify(projectId, prospectId, input, idempotencyKey));
868
+ } catch (error) {
869
+ return errorResult(error);
870
+ }
871
+ });
803
872
  server.registerTool("list_blog_plans", {
804
873
  title: "List Blog Studio plans",
805
874
  description: "Read the bounded 30-day Blog Studio plans for one exact project. This does not read the social calendar.",