lotux-mcp 0.10.3 → 0.16.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 +131 -7
- 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.16.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 (an \"Agentic workspace\" page plus Client Feedback and Basic Rules folders in its \"Exposed to MCP\" section), 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 in a Kennisbank workspace's \"Exposed to MCP\" section, the only part of a second brain the MCP can see (id, name, parent_id, path; parent_id null = directly in the section). 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's \"Exposed to MCP\" section (at its top level, 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.",
|
|
@@ -412,28 +536,28 @@ server.tool(
|
|
|
412
536
|
|
|
413
537
|
server.tool(
|
|
414
538
|
"list_kb_workspaces",
|
|
415
|
-
"List the Kennisbank (knowledge base) workspaces you can access — markdown docs the team and AI share. Returns id, name, visibility. Use a workspace id with list_kb_docs / create_kb_doc.",
|
|
539
|
+
"List the Kennisbank (knowledge base) workspaces you can access — markdown docs the team and AI share. Returns id, name, visibility. Use a workspace id with list_kb_docs / create_kb_doc. Only each workspace's \"Exposed to MCP\" section is visible to the MCP; the rest is the team's own notes.",
|
|
416
540
|
{},
|
|
417
541
|
async () => ok(await rpc("list_kb_workspaces"))
|
|
418
542
|
);
|
|
419
543
|
|
|
420
544
|
server.tool(
|
|
421
545
|
"list_kb_docs",
|
|
422
|
-
"List the pages in a Kennisbank workspace (id, title, folder path). Use a doc id with get_kb_doc.",
|
|
546
|
+
"List the pages in a Kennisbank workspace's \"Exposed to MCP\" section (id, title, folder path inside the section; \"\" = its top level). Pages outside the section are not listed. Use a doc id with get_kb_doc.",
|
|
423
547
|
{ workspace_id: z.string().describe("Workspace id from list_kb_workspaces") },
|
|
424
548
|
async ({ workspace_id }) => ok(await rpc("list_kb_docs", { workspace_id }))
|
|
425
549
|
);
|
|
426
550
|
|
|
427
551
|
server.tool(
|
|
428
552
|
"get_kb_doc",
|
|
429
|
-
"Read one Kennisbank page's full markdown content by id.",
|
|
553
|
+
"Read one Kennisbank page's full markdown content by id. Only pages in the \"Exposed to MCP\" section can be read.",
|
|
430
554
|
{ doc_id: z.string() },
|
|
431
555
|
async ({ doc_id }) => ok(await rpc("get_kb_doc", { doc_id }))
|
|
432
556
|
);
|
|
433
557
|
|
|
434
558
|
server.tool(
|
|
435
559
|
"create_kb_doc",
|
|
436
|
-
"Create a new markdown page in a Kennisbank workspace. Returns the new doc id. content is markdown; folder_id is optional (
|
|
560
|
+
"Create a new markdown page in a Kennisbank workspace's \"Exposed to MCP\" section. Returns the new doc id. content is markdown; folder_id is optional (top of the section if omitted) and must be a folder from list_kb_folders.",
|
|
437
561
|
{
|
|
438
562
|
workspace_id: z.string().describe("Workspace id from list_kb_workspaces"),
|
|
439
563
|
title: z.string(),
|
|
@@ -445,7 +569,7 @@ server.tool(
|
|
|
445
569
|
|
|
446
570
|
server.tool(
|
|
447
571
|
"update_kb_doc",
|
|
448
|
-
"Update a Kennisbank page's title and/or markdown content. Omitted fields are left unchanged.",
|
|
572
|
+
"Update a Kennisbank page's title and/or markdown content (pages in the \"Exposed to MCP\" section only). Omitted fields are left unchanged.",
|
|
449
573
|
{
|
|
450
574
|
doc_id: z.string(),
|
|
451
575
|
title: z.string().optional(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lotux-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.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": {
|