@jclvsh/dropspace 2.43.0 → 2.48.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/README.md +12 -0
- package/dist/commands/account.js +42 -0
- package/dist/server.js +6 -0
- package/dist/tool-policy.js +3 -0
- package/dist/tools/reports.d.ts +5 -0
- package/dist/tools/reports.js +63 -0
- package/dist/tools/trial-reels.js +11 -1
- package/dist/workflows.d.ts +15 -0
- package/dist/workflows.js +50 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -382,6 +382,18 @@ Reddit engagement (drafted comments in other communities) is paused: its tools a
|
|
|
382
382
|
| `scan_trial_reels` | Scan an account's reels again and queue the strong ones (local package only) |
|
|
383
383
|
| `update_trial_reel` | Approve, hold, re-caption, or remove a waiting reel, or approve all (send scope to approve; local package only) |
|
|
384
384
|
|
|
385
|
+
### Reports and workflows
|
|
386
|
+
|
|
387
|
+
| Tool | Description |
|
|
388
|
+
| ---- | ----------- |
|
|
389
|
+
| `save_report` | Save a markdown report to the user's reports page (local package only) |
|
|
390
|
+
| `list_reports` | Saved reports, newest first, without bodies (local package only) |
|
|
391
|
+
| `get_report` | One report with its markdown body (local package only) |
|
|
392
|
+
|
|
393
|
+
Prompts (local package only): `instagram_audit`, `best_times_plan`, `winners_report`. Each tells the AI app which tools to call and ends with `save_report`.
|
|
394
|
+
|
|
395
|
+
CLI: `dropspace reports list|get|delete`.
|
|
396
|
+
|
|
385
397
|
#### `get_audience` Parameters
|
|
386
398
|
|
|
387
399
|
| Parameter | Type | Required | Description |
|
package/dist/commands/account.js
CHANGED
|
@@ -39,4 +39,46 @@ export function registerAccountCommands(program, client) {
|
|
|
39
39
|
handleError(error);
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
|
+
const reports = program.command("reports").description("your saved reports (from the MCP workflows or the API)");
|
|
43
|
+
reports
|
|
44
|
+
.command("list")
|
|
45
|
+
.description("saved reports, newest first, without their bodies")
|
|
46
|
+
.option("--page <n>", "page number")
|
|
47
|
+
.option("--page-size <n>", "reports per page (max 100)")
|
|
48
|
+
.action(async (options) => {
|
|
49
|
+
try {
|
|
50
|
+
const params = {};
|
|
51
|
+
if (options.page)
|
|
52
|
+
params.page = options.page;
|
|
53
|
+
if (options.pageSize)
|
|
54
|
+
params.page_size = options.pageSize;
|
|
55
|
+
formatOutput(await client.get("/reports", params), getFormat(program.opts()));
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
handleError(error);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
reports
|
|
62
|
+
.command("get <id>")
|
|
63
|
+
.description("one report with its markdown body")
|
|
64
|
+
.action(async (id) => {
|
|
65
|
+
try {
|
|
66
|
+
formatOutput(await client.get(`/reports/${id}`), getFormat(program.opts()));
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
handleError(error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
reports
|
|
73
|
+
.command("delete <id>")
|
|
74
|
+
.description("delete a saved report")
|
|
75
|
+
.action(async (id) => {
|
|
76
|
+
try {
|
|
77
|
+
await client.delete(`/reports/${id}`);
|
|
78
|
+
formatOutput({ data: { id, deleted: true } }, getFormat(program.opts()));
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
handleError(error);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
42
84
|
}
|
package/dist/server.js
CHANGED
|
@@ -18,6 +18,7 @@ import { registerAudienceTools } from "./tools/audience.js";
|
|
|
18
18
|
import { registerCommentTools } from "./tools/comments.js";
|
|
19
19
|
import { registerAccountTools } from "./tools/account.js";
|
|
20
20
|
import { registerTrialReelTools } from "./tools/trial-reels.js";
|
|
21
|
+
import { registerReportTools, registerWorkflowPrompts } from "./tools/reports.js";
|
|
21
22
|
/** Drops tools whose feature is paused before the policy registrar sees them (see PAUSED_TOOLS). */
|
|
22
23
|
function skipPausedTools(registrar) {
|
|
23
24
|
return {
|
|
@@ -48,5 +49,10 @@ export function createDropspaceServer({ client, version, profile }) {
|
|
|
48
49
|
registerCommentTools(registrar, client);
|
|
49
50
|
registerAccountTools(registrar, client);
|
|
50
51
|
registerTrialReelTools(registrar, client);
|
|
52
|
+
registerReportTools(registrar, client);
|
|
53
|
+
// Prompts are not tools, so the policy registrar does not filter them: the hosted profile
|
|
54
|
+
// (frozen for the Meta review) gets none.
|
|
55
|
+
if (profile === "full")
|
|
56
|
+
registerWorkflowPrompts(server);
|
|
51
57
|
return server;
|
|
52
58
|
}
|
package/dist/tool-policy.js
CHANGED
|
@@ -133,6 +133,9 @@ const FULL_TOOL_POLICY = {
|
|
|
133
133
|
update_trial_reel_program: localOnly("audience", "sensitive"),
|
|
134
134
|
scan_trial_reels: localOnly("audience", "write"),
|
|
135
135
|
update_trial_reel: localOnly("audience", "sensitive"),
|
|
136
|
+
save_report: localOnly("account", "write"),
|
|
137
|
+
list_reports: localOnly("account", "read"),
|
|
138
|
+
get_report: localOnly("account", "read"),
|
|
136
139
|
get_usage: hosted("usage", "read"),
|
|
137
140
|
get_changelog: hosted("usage", "read"),
|
|
138
141
|
get_dropspace_status: hosted("dropspace", "read"),
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { DropspaceClient } from "../client.js";
|
|
3
|
+
/** The workflow prompts (Instagram audit, best-times plan, winners report). Local package only. */
|
|
4
|
+
export declare function registerWorkflowPrompts(server: McpServer): void;
|
|
5
|
+
export declare function registerReportTools(server: McpServer, client: DropspaceClient): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { WORKFLOWS } from "../workflows.js";
|
|
3
|
+
function text(result) {
|
|
4
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5
|
+
}
|
|
6
|
+
function fail(error) {
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: "text", text: `error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
9
|
+
isError: true,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** The workflow prompts (Instagram audit, best-times plan, winners report). Local package only. */
|
|
13
|
+
export function registerWorkflowPrompts(server) {
|
|
14
|
+
for (const workflow of WORKFLOWS) {
|
|
15
|
+
server.registerPrompt(workflow.name, { title: workflow.title, description: workflow.description }, () => ({
|
|
16
|
+
description: workflow.description,
|
|
17
|
+
messages: [{ role: "user", content: { type: "text", text: workflow.prompt } }],
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function registerReportTools(server, client) {
|
|
22
|
+
server.tool("save_report", "save a markdown report to the user's dropspace reports (the reports page in the app): the end step of the instagram_audit, best_times_plan, and winners_report workflows. title up to 200 characters, body up to 100,000. at most 200 saved reports; past that the save is refused and the user deletes some first. returns the saved report with its id.", {
|
|
23
|
+
title: z.string().min(1).max(200).describe("report title, e.g. 'Instagram audit - 10/29/2026'"),
|
|
24
|
+
body: z.string().min(1).max(100_000).describe("the report in markdown"),
|
|
25
|
+
kind: z.enum(["audit", "best_times", "winners", "other"]).optional().describe("which workflow made it"),
|
|
26
|
+
}, async ({ title, body, kind }) => {
|
|
27
|
+
try {
|
|
28
|
+
return text(await client.post("/reports", {
|
|
29
|
+
title,
|
|
30
|
+
body,
|
|
31
|
+
kind: kind ?? "other",
|
|
32
|
+
source: "mcp",
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return fail(error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
server.tool("list_reports", "the user's saved reports, newest first, without their bodies: id, title, kind (audit, best_times, winners, other), source (mcp or api), created_at. read one with get_report.", {
|
|
40
|
+
page: z.number().int().min(1).optional(),
|
|
41
|
+
page_size: z.number().int().min(1).max(100).optional(),
|
|
42
|
+
}, async ({ page, page_size }) => {
|
|
43
|
+
try {
|
|
44
|
+
const params = {};
|
|
45
|
+
if (page)
|
|
46
|
+
params.page = String(page);
|
|
47
|
+
if (page_size)
|
|
48
|
+
params.page_size = String(page_size);
|
|
49
|
+
return text(await client.get("/reports", params));
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return fail(error);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
server.tool("get_report", "one saved report with its markdown body.", { id: z.string().uuid().describe("report id from list_reports or save_report") }, async ({ id }) => {
|
|
56
|
+
try {
|
|
57
|
+
return text(await client.get(`/reports/${id}`));
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return fail(error);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -28,6 +28,11 @@ export function registerTrialReelTools(server, client) {
|
|
|
28
28
|
.optional()
|
|
29
29
|
.describe("never queue a reel whose caption contains one of these"),
|
|
30
30
|
timezone: z.string().optional().describe("IANA timezone for posting hours, e.g. America/New_York"),
|
|
31
|
+
edit_kinds: z
|
|
32
|
+
.array(z.enum(["reshare", "background", "subtitles", "hook", "sticker"]))
|
|
33
|
+
.min(1)
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("kinds new reels take in turn: reshare (the original video), background (on a colored background), subtitles (burned-in; only reels with speech and no captions on screen), hook (a strong line from later in the reel played first), or sticker (a reply-to-comment card with a comment claude writes)"),
|
|
31
36
|
}, async ({ connection_id, ...settings }) => {
|
|
32
37
|
try {
|
|
33
38
|
return text(await client.put(`/trial-reels/programs/${connection_id}`, settings));
|
|
@@ -48,13 +53,17 @@ export function registerTrialReelTools(server, client) {
|
|
|
48
53
|
id: z.string().uuid().optional().describe("item id from list_trial_reels (not needed with approve_all)"),
|
|
49
54
|
approved: z.boolean().optional(),
|
|
50
55
|
caption: z.string().max(2200).optional(),
|
|
56
|
+
kind: z
|
|
57
|
+
.enum(["reshare", "background", "subtitles", "hook", "sticker"])
|
|
58
|
+
.optional()
|
|
59
|
+
.describe("post the original (reshare) or an edited version (background, subtitles, hook, sticker); a new kind holds the reel"),
|
|
51
60
|
remove: z.boolean().optional(),
|
|
52
61
|
approve_all: z
|
|
53
62
|
.string()
|
|
54
63
|
.uuid()
|
|
55
64
|
.optional()
|
|
56
65
|
.describe("instead of one item: a connection_id whose waiting reels with captions are all approved"),
|
|
57
|
-
}, async ({ id, approved, caption, remove, approve_all }) => {
|
|
66
|
+
}, async ({ id, approved, caption, kind, remove, approve_all }) => {
|
|
58
67
|
try {
|
|
59
68
|
if (approve_all) {
|
|
60
69
|
return text(await client.post(`/trial-reels/programs/${approve_all}/approve-all`));
|
|
@@ -68,6 +77,7 @@ export function registerTrialReelTools(server, client) {
|
|
|
68
77
|
return text(await client.patch(`/trial-reels/items/${id}`, {
|
|
69
78
|
...(approved !== undefined ? { approved } : {}),
|
|
70
79
|
...(caption !== undefined ? { caption } : {}),
|
|
80
|
+
...(kind !== undefined ? { kind } : {}),
|
|
71
81
|
}));
|
|
72
82
|
}
|
|
73
83
|
catch (error) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow prompts: ready-made instructions an AI app (Claude, ChatGPT, any MCP client) runs
|
|
3
|
+
* against the dropspace MCP tools, ending with save_report. The MCP server serves them as MCP
|
|
4
|
+
* prompts, and the docs page imports this file (@jclvsh/dropspace/workflows) to show the same text.
|
|
5
|
+
*/
|
|
6
|
+
export interface Workflow {
|
|
7
|
+
/** MCP prompt name. */
|
|
8
|
+
name: string;
|
|
9
|
+
title: string;
|
|
10
|
+
description: string;
|
|
11
|
+
/** The report kind save_report is asked to use. */
|
|
12
|
+
kind: "audit" | "best_times" | "winners";
|
|
13
|
+
prompt: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const WORKFLOWS: Workflow[];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow prompts: ready-made instructions an AI app (Claude, ChatGPT, any MCP client) runs
|
|
3
|
+
* against the dropspace MCP tools, ending with save_report. The MCP server serves them as MCP
|
|
4
|
+
* prompts, and the docs page imports this file (@jclvsh/dropspace/workflows) to show the same text.
|
|
5
|
+
*/
|
|
6
|
+
export const WORKFLOWS = [
|
|
7
|
+
{
|
|
8
|
+
name: "instagram_audit",
|
|
9
|
+
title: "Instagram audit",
|
|
10
|
+
description: "where the account stands: growth, who it reaches, what its reels have in common, what to fix first",
|
|
11
|
+
kind: "audit",
|
|
12
|
+
prompt: [
|
|
13
|
+
"Audit my Instagram account using the dropspace tools.",
|
|
14
|
+
"1. Call get_audience with include_instagram_insights true and window_days 30: followers, net growth per day, follows vs unfollows, and the share of reach from non-followers.",
|
|
15
|
+
"2. Call get_audience_demographics: who follows and who engages (age, gender, top countries and cities).",
|
|
16
|
+
"3. Call get_reels_read; if there is no read from the last 7 days, call generate_reels_read. Use its findings on what the strong and weak reels share.",
|
|
17
|
+
"4. Call get_best_posting_hours for when followers are online.",
|
|
18
|
+
"Write the audit in markdown with these sections: Where the account stands (numbers, with dates), Who it reaches, What works, What doesn't, The three changes to make this week. Quote numbers exactly as the tools returned them and say when a tool had no data.",
|
|
19
|
+
'Then call save_report with kind "audit" and a title like "Instagram audit - <today\'s date>".',
|
|
20
|
+
].join("\n"),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "best_times_plan",
|
|
24
|
+
title: "Best-times plan",
|
|
25
|
+
description: "a weekly posting schedule built from when the followers are online",
|
|
26
|
+
kind: "best_times",
|
|
27
|
+
prompt: [
|
|
28
|
+
"Build my weekly Instagram posting plan using the dropspace tools.",
|
|
29
|
+
"1. Call get_best_posting_hours with my timezone: the hourly averages, the weekday-by-hour grid, and the busiest hours.",
|
|
30
|
+
"2. Call get_autopilot to see the posting times autopilot uses now, if it is set up.",
|
|
31
|
+
"3. Call list_launches for the last 30 days to see when I actually posted.",
|
|
32
|
+
"Write the plan in markdown: a table of days and times (at most 2 a day, at least 2 hours apart), why each time was picked (followers online at that hour), and what to change from the current schedule. Say plainly if Instagram had no online-followers numbers (accounts under 100 followers) and fall back to 9 am, 1 pm, and 6 pm.",
|
|
33
|
+
'Then call save_report with kind "best_times" and a title like "Posting plan - week of <date>".',
|
|
34
|
+
].join("\n"),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "winners_report",
|
|
38
|
+
title: "Winners report",
|
|
39
|
+
description: "the posts and trial reels that won lately, what they share, and what to make next",
|
|
40
|
+
kind: "winners",
|
|
41
|
+
prompt: [
|
|
42
|
+
"Find my recent winners using the dropspace tools.",
|
|
43
|
+
"1. Call list_launches for the last 30 days, then get_launch_analytics on the posted ones to get views, likes, comments, shares, and saves.",
|
|
44
|
+
"2. Call get_trial_reel_analytics and list_trial_reels for trial reels and their 1, 3, and 7-day results (won or retired).",
|
|
45
|
+
"3. Call get_reels_read for the latest read of the account's reels.",
|
|
46
|
+
"Rank posts by views relative to the account's usual (the median of the posts you read). Write the report in markdown: the top five with their numbers and links, what they share (topic, hook, format, length, posting time), the bottom three and what they share, and three posts to make next. Use only the numbers the tools returned.",
|
|
47
|
+
'Then call save_report with kind "winners" and a title like "Winners - <month>".',
|
|
48
|
+
].join("\n"),
|
|
49
|
+
},
|
|
50
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jclvsh/dropspace",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.48.0",
|
|
4
4
|
"description": "MCP server and CLI for the Dropspace API",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"types": "./dist/tool-policy.d.ts",
|
|
28
28
|
"default": "./dist/tool-policy.js"
|
|
29
29
|
},
|
|
30
|
+
"./workflows": {
|
|
31
|
+
"types": "./dist/workflows.d.ts",
|
|
32
|
+
"default": "./dist/workflows.js"
|
|
33
|
+
},
|
|
30
34
|
"./package.json": "./package.json"
|
|
31
35
|
},
|
|
32
36
|
"bin": {
|