lotux-mcp 0.10.3 → 0.15.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/index.mjs +126 -2
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -52,17 +52,141 @@ const ok = (result) => ({
|
|
|
52
52
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
const server = new McpServer({ name: "lotux", version: "0.
|
|
55
|
+
const server = new McpServer({ name: "lotux", version: "0.15.0" });
|
|
56
56
|
|
|
57
57
|
// ── Reads ─────────────────────────────────────────────────────────────────────
|
|
58
58
|
|
|
59
59
|
server.tool(
|
|
60
60
|
"list_brands",
|
|
61
|
-
"List the LOTUX brands (and the agency) you can access. Use the returned id as account_id for other tools.",
|
|
61
|
+
"List the LOTUX brands (and the agency) you can access, with each brand's slug and client_status (active / archived / internal). Use the returned id as account_id for other tools.",
|
|
62
62
|
{},
|
|
63
63
|
async () => ok(await rpc("list_brands"))
|
|
64
64
|
);
|
|
65
65
|
|
|
66
|
+
// ── Client workspaces (agency team only) ──────────────────────────────────────
|
|
67
|
+
// Where a client's things live for the Cowork editors: Dropbox client folder,
|
|
68
|
+
// raw-footage folders, the agentic workspace folder (01_CLIENTS/<slug>) and the
|
|
69
|
+
// second brain (Kennisbank).
|
|
70
|
+
|
|
71
|
+
server.tool(
|
|
72
|
+
"get_brand",
|
|
73
|
+
"One client's workspace settings: slug, client_status, second brain (Kennisbank id + name, shared with the client or not), workspace_folder, dropbox_client_path, raw_footage_paths, Claude project name, the Claude project kit (instructions text) and the active work claims.",
|
|
74
|
+
{ account_id: z.string().describe("Brand id from list_brands") },
|
|
75
|
+
async (args) => ok(await rpc("get_brand", args))
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
server.tool(
|
|
79
|
+
"update_brand_settings",
|
|
80
|
+
"Change a client's workspace settings. Omitted fields stay as they are. slug is refused once client setup has run (it names the workspace folder). dropbox_client_path follows the Dropbox connection and workspace_folder follows the slug, so neither is set here.",
|
|
81
|
+
{
|
|
82
|
+
account_id: z.string().describe("Brand id from list_brands"),
|
|
83
|
+
client_status: z.enum(["active", "archived", "internal"]).optional(),
|
|
84
|
+
slug: z.string().optional().describe("Lowercase letters, digits and hyphens"),
|
|
85
|
+
kb_workspace_id: z.string().nullable().optional().describe("Kennisbank workspace id (list_kb_workspaces) to link as the second brain"),
|
|
86
|
+
raw_footage_paths: z.array(z.string()).optional().describe("Dropbox paths, e.g. /CLIENTS/Active/Dr. Kegel/01_video/01_raw footage"),
|
|
87
|
+
claude_project_name: z.string().optional(),
|
|
88
|
+
},
|
|
89
|
+
async (args) => ok(await rpc("update_brand_settings", args))
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
server.tool(
|
|
93
|
+
"run_client_setup",
|
|
94
|
+
"Run client setup for a brand: slug, second brain from the template, the agentic workspace folder + CLIENT.md settings block, and (once the brand has connected Dropbox) the linked Dropbox client folder. It already runs by itself when a brand is created and when it connects Dropbox; run it again to fill gaps. Only creates what's missing; running it twice changes nothing. Skipped for clients that aren't active. dry_run: true returns the plan without changing anything. Returns a report per step (created / linked / updated / already there / failed + reason).",
|
|
95
|
+
{
|
|
96
|
+
account_id: z.string().describe("Brand id from list_brands"),
|
|
97
|
+
dry_run: z.boolean().optional(),
|
|
98
|
+
},
|
|
99
|
+
async (args) => ok(await rpc("run_client_setup", args))
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
server.tool(
|
|
103
|
+
"list_kb_folders",
|
|
104
|
+
"The folders of a Kennisbank workspace (id, name, parent_id). Use a folder id as folder_id in create_kb_doc.",
|
|
105
|
+
{ workspace_id: z.string().describe("Workspace id from list_kb_workspaces or get_brand") },
|
|
106
|
+
async (args) => ok(await rpc("list_kb_folders", args))
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
server.tool(
|
|
110
|
+
"create_kb_folder",
|
|
111
|
+
"Create a folder in a Kennisbank workspace (at the root, or inside parent_id). Returns the folder id.",
|
|
112
|
+
{
|
|
113
|
+
workspace_id: z.string(),
|
|
114
|
+
name: z.string(),
|
|
115
|
+
parent_id: z.string().optional().describe("Parent folder id from list_kb_folders"),
|
|
116
|
+
},
|
|
117
|
+
async (args) => ok(await rpc("create_kb_folder", args))
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// ── Work claims ───────────────────────────────────────────────────────────────
|
|
121
|
+
// Several editors work on one client at once, never on the same piece. Claim
|
|
122
|
+
// before you write files; the database decides who's first (Dropbox is too slow
|
|
123
|
+
// for lock files). Claiming again while you hold it renews it.
|
|
124
|
+
|
|
125
|
+
server.tool(
|
|
126
|
+
"claim_work",
|
|
127
|
+
"Claim a piece of work before writing files for it. kind: concept (ref = concept id; prep / edit / revise / re-render one concept; 6 h), inventory (the brand's inventory run; 6 h), brand_shared (files several concepts of the brand use: logos, shared media, shared code; 15 min), house_rules (the shared house rules or style spec, agency-wide; 15 min). Returns {ok: true, claim_id, expires_at} or {ok: false, held_by, since, expires_at} when someone else holds it: then don't write, ask or wait. A concept claim warns when you're not its editor and sets you as editor when it has none.",
|
|
128
|
+
{
|
|
129
|
+
account_id: z.string().describe("Brand id from list_brands (house_rules: any brand of the agency, or the agency)"),
|
|
130
|
+
kind: z.enum(["concept", "inventory", "brand_shared", "house_rules"]),
|
|
131
|
+
ref: z.string().optional().describe("Concept id, for kind concept"),
|
|
132
|
+
note: z.string().optional().describe("What you're doing, e.g. \"render v2 of the 9:16\""),
|
|
133
|
+
},
|
|
134
|
+
async (args) => ok(await rpc("claim_work", args))
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
server.tool(
|
|
138
|
+
"renew_claim",
|
|
139
|
+
"Extend a claim you hold (long renders, long inventory runs). Returns the new expires_at. Fails when it already expired or was released: claim again.",
|
|
140
|
+
{ claim_id: z.string() },
|
|
141
|
+
async (args) => ok(await rpc("renew_claim", args))
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
server.tool(
|
|
145
|
+
"release_work",
|
|
146
|
+
"Release a claim as soon as you're done writing, so the next editor can start.",
|
|
147
|
+
{ claim_id: z.string() },
|
|
148
|
+
async (args) => ok(await rpc("release_work", args))
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
server.tool(
|
|
152
|
+
"list_claims",
|
|
153
|
+
"Active claims: who is working on what right now, since when, until when. With a brand's account_id: that brand plus the agency-wide house_rules claim; empty: every brand.",
|
|
154
|
+
{ account_id: z.string().optional() },
|
|
155
|
+
async (args) => ok(await rpc("list_claims", args))
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// ── Deliverables ──────────────────────────────────────────────────────────────
|
|
159
|
+
// Never guess a file name: LOTUX generates it (the brand's naming convention)
|
|
160
|
+
// and moves the "Concept <code>" folder between stage folders. Versions stay
|
|
161
|
+
// with you: <base_name>.mp4, then <base_name>_v2.mp4, _v3 …; move the previous
|
|
162
|
+
// version into archive_folder. _var<N> is a variation (its own concept), not a version.
|
|
163
|
+
|
|
164
|
+
server.tool(
|
|
165
|
+
"get_deliverable",
|
|
166
|
+
"The file name and folder for one deliverable: base_name (exactly the name LOTUX generates for that hook and language, without extension or version), extension (mp4 for video), folder (the concept's current stage folder in Dropbox, /CLIENTS/Active/<Brand>/01_video/02_deliverables/<stage>/Concept <code>) and archive_folder (folder + /Archive). Name the concept by concept_id, or account_id + code (\"8\" or \"c8\"); variation 2 = the concept's _Var2.",
|
|
167
|
+
{
|
|
168
|
+
concept_id: z.string().optional(),
|
|
169
|
+
account_id: z.string().optional().describe("Brand id, with code"),
|
|
170
|
+
code: z.string().optional().describe("Concept code, e.g. 8 or c8"),
|
|
171
|
+
hook: z.string().describe("h1, h2, h3 … (h for a single hook, \"Hook 2\" works too), b1 for the body-only export"),
|
|
172
|
+
language: z.string().optional().describe("English / en … (default: the concept's base language)"),
|
|
173
|
+
variation: z.number().int().optional().describe("2 for the concept's _Var2"),
|
|
174
|
+
kind: z.enum(["video", "static", "carousel"]).optional().describe("Default video"),
|
|
175
|
+
},
|
|
176
|
+
async (args) => ok(await rpc("get_deliverable", args))
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
server.tool(
|
|
180
|
+
"list_deliverables",
|
|
181
|
+
"Every deliverable name of a concept: base_name per hook and language, for the concept and for each of its variations, each with its folder and archive_folder.",
|
|
182
|
+
{
|
|
183
|
+
concept_id: z.string().optional(),
|
|
184
|
+
account_id: z.string().optional().describe("Brand id, with code"),
|
|
185
|
+
code: z.string().optional(),
|
|
186
|
+
},
|
|
187
|
+
async (args) => ok(await rpc("list_deliverables", args))
|
|
188
|
+
);
|
|
189
|
+
|
|
66
190
|
server.tool(
|
|
67
191
|
"list_entities",
|
|
68
192
|
"List a brand's products, personas, angles, use-cases and offers (the building blocks for a concept). Pass account_id from list_brands.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lotux-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local MCP server that lets Claude create LOTUX concepts (fetch brand-DB entities, create concepts, fill scripts + copy). Talks to the LOTUX app with a personal token; no business logic or secrets live here.",
|
|
6
6
|
"bin": {
|