lotux-mcp 0.15.0 → 0.17.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 +2 -0
- package/index.mjs +108 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,6 +66,8 @@ Restart Claude, then try: *"list my LOTUX brands"*.
|
|
|
66
66
|
| `content_options` / `create_flywheel` / `update_flywheel` / `list_flywheels` / `get_flywheel` | Content flywheels (Marketing → Content, agency-only): one long-form video. Start with `content_options`; give flywheels a `key` so re-runs reuse them |
|
|
67
67
|
| `push_assets` / `add_asset` / `get_asset` / `list_assets` / `update_asset` / `set_asset_status` / `add_comment` / `delete_asset` | Content assets, upserted on their `key`. Statuses: scripting → production → ready_for_post → post_production → to_review → revisions → approved → live → testing → scaling → turned_off. Content you write lands in `to_review`; Claude can't set revisions, approve, or set live / testing / scaling / turned_off; deleting signed-off work needs `force`. Each asset carries `raw_footage_url` (raw files folder) and `final_asset_url` (the export — a change sends it to review), plus its content ID (`code`) and `name` = `"<code> - <title>"`; pass `code` instead of `asset_id` anywhere |
|
|
68
68
|
| `get_setup_checks` / `set_setup_check` | A flywheel's setup checklist (Instagram auto-replies, setter replies, reel covers, YouTube, Klaviyo flow) — tick a step by `check_key` after doing it |
|
|
69
|
+
| `list_team` / `get_team_member` / `update_team_member` | HR (agency-only, needs HR access): the team — role, lead, status, dates, KPIs, archive/restore. No pay, no delete, no invites (app only) |
|
|
70
|
+
| `list_job_roles` / `get_job_role` / `update_job_role` / `create_job_role` | HR → Responsibilities: role templates (responsibilities, KPIs, capacity, owned columns). Lists are replaced whole |
|
|
69
71
|
|
|
70
72
|
Beats (`add_beat`, `update_beat`, `delete_beat`, `set_beat_translation`, `add_language`) were
|
|
71
73
|
retired in Sep 2026 — scripts are documents now. Calling one returns a message pointing at the
|
package/index.mjs
CHANGED
|
@@ -52,7 +52,7 @@ 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.17.0" });
|
|
56
56
|
|
|
57
57
|
// ── Reads ─────────────────────────────────────────────────────────────────────
|
|
58
58
|
|
|
@@ -91,7 +91,7 @@ server.tool(
|
|
|
91
91
|
|
|
92
92
|
server.tool(
|
|
93
93
|
"run_client_setup",
|
|
94
|
-
"Run client setup for a brand: slug, second brain
|
|
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
95
|
{
|
|
96
96
|
account_id: z.string().describe("Brand id from list_brands"),
|
|
97
97
|
dry_run: z.boolean().optional(),
|
|
@@ -101,14 +101,14 @@ server.tool(
|
|
|
101
101
|
|
|
102
102
|
server.tool(
|
|
103
103
|
"list_kb_folders",
|
|
104
|
-
"The 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
105
|
{ workspace_id: z.string().describe("Workspace id from list_kb_workspaces or get_brand") },
|
|
106
106
|
async (args) => ok(await rpc("list_kb_folders", args))
|
|
107
107
|
);
|
|
108
108
|
|
|
109
109
|
server.tool(
|
|
110
110
|
"create_kb_folder",
|
|
111
|
-
"Create a folder in a Kennisbank workspace (at
|
|
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
112
|
{
|
|
113
113
|
workspace_id: z.string(),
|
|
114
114
|
name: z.string(),
|
|
@@ -536,28 +536,28 @@ server.tool(
|
|
|
536
536
|
|
|
537
537
|
server.tool(
|
|
538
538
|
"list_kb_workspaces",
|
|
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.",
|
|
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.",
|
|
540
540
|
{},
|
|
541
541
|
async () => ok(await rpc("list_kb_workspaces"))
|
|
542
542
|
);
|
|
543
543
|
|
|
544
544
|
server.tool(
|
|
545
545
|
"list_kb_docs",
|
|
546
|
-
"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.",
|
|
547
547
|
{ workspace_id: z.string().describe("Workspace id from list_kb_workspaces") },
|
|
548
548
|
async ({ workspace_id }) => ok(await rpc("list_kb_docs", { workspace_id }))
|
|
549
549
|
);
|
|
550
550
|
|
|
551
551
|
server.tool(
|
|
552
552
|
"get_kb_doc",
|
|
553
|
-
"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.",
|
|
554
554
|
{ doc_id: z.string() },
|
|
555
555
|
async ({ doc_id }) => ok(await rpc("get_kb_doc", { doc_id }))
|
|
556
556
|
);
|
|
557
557
|
|
|
558
558
|
server.tool(
|
|
559
559
|
"create_kb_doc",
|
|
560
|
-
"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.",
|
|
561
561
|
{
|
|
562
562
|
workspace_id: z.string().describe("Workspace id from list_kb_workspaces"),
|
|
563
563
|
title: z.string(),
|
|
@@ -569,7 +569,7 @@ server.tool(
|
|
|
569
569
|
|
|
570
570
|
server.tool(
|
|
571
571
|
"update_kb_doc",
|
|
572
|
-
"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.",
|
|
573
573
|
{
|
|
574
574
|
doc_id: z.string(),
|
|
575
575
|
title: z.string().optional(),
|
|
@@ -817,6 +817,105 @@ server.tool(
|
|
|
817
817
|
async (args) => ok(await rpc("set_setup_check", args))
|
|
818
818
|
);
|
|
819
819
|
|
|
820
|
+
// ---------------------------------------------------------------------------
|
|
821
|
+
// HR (agency only): the team and the role templates (Responsibilities).
|
|
822
|
+
// Needs HR access in LOTUX. Pay, contracts, documents, deleting people and
|
|
823
|
+
// invites stay in the app on purpose.
|
|
824
|
+
// ---------------------------------------------------------------------------
|
|
825
|
+
|
|
826
|
+
const kpiShape = z.object({
|
|
827
|
+
label: z.string(),
|
|
828
|
+
target: z.string().nullable().optional(),
|
|
829
|
+
source: z.string().nullable().optional(),
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
server.tool(
|
|
833
|
+
"list_team",
|
|
834
|
+
"Everyone at the agency in HR: name, job role, lead, is_lead, status (onboarding / active / left), employment, start/end date, LOTUX login yes/no. Archived and left people only with include_archived. No pay.",
|
|
835
|
+
{ include_archived: z.boolean().optional(), account_id: z.string().optional().describe("Agency id; omit for your own agency") },
|
|
836
|
+
async (args) => ok(await rpc("list_team", args))
|
|
837
|
+
);
|
|
838
|
+
|
|
839
|
+
server.tool(
|
|
840
|
+
"get_team_member",
|
|
841
|
+
"One person in HR: role, lead, who they lead, contact fields, their own KPIs (else the role's apply), access checklist and their last 20 notes. No pay.",
|
|
842
|
+
{ member: z.string().describe("Person id or (part of) their name"), account_id: z.string().optional() },
|
|
843
|
+
async (args) => ok(await rpc("get_team_member", args))
|
|
844
|
+
);
|
|
845
|
+
|
|
846
|
+
server.tool(
|
|
847
|
+
"update_team_member",
|
|
848
|
+
"Change a person in HR. Only the fields you send change. role and lead take a name or id (null clears). archived true hides them from HR lists, the lead picker and payroll (data kept); false restores. kpis replaces their own KPI list ([] = use the role's KPIs). Can't change pay, delete people or send invites — do that in the app.",
|
|
849
|
+
{
|
|
850
|
+
member: z.string().describe("Person id or name"),
|
|
851
|
+
name: z.string().optional(),
|
|
852
|
+
role: z.string().nullable().optional().describe("Job role name or id (list_job_roles)"),
|
|
853
|
+
lead: z.string().nullable().optional().describe("Lead's name or id"),
|
|
854
|
+
is_lead: z.boolean().optional(),
|
|
855
|
+
status: z.enum(["onboarding", "active", "left"]).optional(),
|
|
856
|
+
employment: z.enum(["employee", "freelance"]).nullable().optional(),
|
|
857
|
+
start_date: z.string().nullable().optional().describe("YYYY-MM-DD"),
|
|
858
|
+
end_date: z.string().nullable().optional().describe("YYYY-MM-DD"),
|
|
859
|
+
lotux_email: z.string().nullable().optional(),
|
|
860
|
+
personal_email: z.string().nullable().optional(),
|
|
861
|
+
phone: z.string().nullable().optional(),
|
|
862
|
+
archived: z.boolean().optional(),
|
|
863
|
+
kpis: z.array(kpiShape).optional(),
|
|
864
|
+
account_id: z.string().optional(),
|
|
865
|
+
},
|
|
866
|
+
async (args) => ok(await rpc("update_team_member", args))
|
|
867
|
+
);
|
|
868
|
+
|
|
869
|
+
server.tool(
|
|
870
|
+
"list_job_roles",
|
|
871
|
+
"The role templates in HR → Responsibilities: id, name, one-line summary and how many people have the role.",
|
|
872
|
+
{ account_id: z.string().optional() },
|
|
873
|
+
async (args) => ok(await rpc("list_job_roles", args))
|
|
874
|
+
);
|
|
875
|
+
|
|
876
|
+
server.tool(
|
|
877
|
+
"get_job_role",
|
|
878
|
+
"One role template in full: title, one-liner, what they obsess over, who they work with, what failure looks like, what they're not responsible for, responsibilities, KPIs, capacity, the LOTUX columns they own, and who has the role.",
|
|
879
|
+
{ role: z.string().describe("Role id or exact name"), account_id: z.string().optional() },
|
|
880
|
+
async (args) => ok(await rpc("get_job_role", args))
|
|
881
|
+
);
|
|
882
|
+
|
|
883
|
+
const roleFields = {
|
|
884
|
+
role_label: z.string().nullable().optional(),
|
|
885
|
+
title: z.string().nullable().optional(),
|
|
886
|
+
one_line: z.string().nullable().optional(),
|
|
887
|
+
obsess_over: z.string().nullable().optional(),
|
|
888
|
+
works_with: z.string().nullable().optional(),
|
|
889
|
+
failure_looks_like: z.string().nullable().optional(),
|
|
890
|
+
not_responsible_for: z.string().nullable().optional(),
|
|
891
|
+
kpi_headline: z.string().nullable().optional(),
|
|
892
|
+
kpi_detail: z.string().nullable().optional(),
|
|
893
|
+
capacity_count: z.number().int().nonnegative().nullable().optional(),
|
|
894
|
+
capacity_unit: z.enum(["clients", "accounts", "brands"]).nullable().optional(),
|
|
895
|
+
software_columns: z.array(z.string()).optional().describe("LOTUX columns this role owns"),
|
|
896
|
+
responsibilities: z.array(z.string()).optional().describe("Replaces the whole list, in order"),
|
|
897
|
+
kpis: z.array(kpiShape).optional().describe("Replaces the whole list, in order"),
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
server.tool(
|
|
901
|
+
"update_job_role",
|
|
902
|
+
"Change a role template (HR → Responsibilities). Only the fields you send change; responsibilities and kpis replace the whole list, so send the full list. new_name renames the role.",
|
|
903
|
+
{
|
|
904
|
+
role: z.string().describe("Role id or exact name"),
|
|
905
|
+
new_name: z.string().optional(),
|
|
906
|
+
...roleFields,
|
|
907
|
+
account_id: z.string().optional(),
|
|
908
|
+
},
|
|
909
|
+
async (args) => ok(await rpc("update_job_role", args))
|
|
910
|
+
);
|
|
911
|
+
|
|
912
|
+
server.tool(
|
|
913
|
+
"create_job_role",
|
|
914
|
+
"Create a role template (starts with the standard Start here flow) and fill it in one go. An existing role with the same name is returned (and updated with the fields you send) instead of a duplicate.",
|
|
915
|
+
{ name: z.string(), ...roleFields, account_id: z.string().optional() },
|
|
916
|
+
async (args) => ok(await rpc("create_job_role", args))
|
|
917
|
+
);
|
|
918
|
+
|
|
820
919
|
async function main() {
|
|
821
920
|
const transport = new StdioServerTransport();
|
|
822
921
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lotux-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.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": {
|