Skip to content

Commit 51f7fff

Browse files
Merge pull request #65 from webflow/data-tool-consolidation
Data tool consolidation
2 parents 13ad59b + 791097c commit 51f7fff

File tree

8 files changed

+1433
-1016
lines changed

8 files changed

+1433
-1016
lines changed

README.md

Lines changed: 178 additions & 170 deletions
Large diffs are not rendered by default.

src/tools/cms.ts

Lines changed: 500 additions & 357 deletions
Large diffs are not rendered by default.

src/tools/components.ts

Lines changed: 251 additions & 172 deletions
Large diffs are not rendered by default.

src/tools/pages.ts

Lines changed: 221 additions & 161 deletions
Large diffs are not rendered by default.

src/tools/scripts.ts

Lines changed: 157 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -4,128 +4,184 @@ import { ScriptApplyLocation } from "webflow-api/api/types/ScriptApplyLocation";
44
import { z } from "zod";
55
import { requestOptions } from "../mcp";
66
import { RegisterInlineSiteScriptSchema } from "../schemas";
7-
import { formatErrorResponse, formatResponse, isApiError } from "../utils";
7+
import {
8+
type Content,
9+
formatErrorResponse,
10+
textContent,
11+
toolResponse,
12+
isApiError,
13+
} from "../utils";
814

915
export function registerScriptsTools(
1016
server: McpServer,
1117
getClient: () => WebflowClient
1218
) {
13-
// GET https://api.webflow.com/v2/sites/:site_id/registered_scripts
14-
server.tool(
15-
"site_registered_scripts_list",
16-
"List all registered scripts for a site. To apply a script to a site or page, first register it via the Register Script endpoints, then apply it using the relevant Site or Page endpoints.",
17-
{
18-
site_id: z.string().describe("Unique identifier for the site."),
19-
},
20-
async ({ site_id }) => {
21-
try {
22-
const response = await getClient().scripts.list(
23-
site_id,
24-
requestOptions
25-
);
26-
return formatResponse(response);
27-
} catch (error) {
28-
return formatErrorResponse(error);
29-
}
30-
}
31-
);
19+
const listRegisteredScripts = async (arg: { site_id: string }) => {
20+
const response = await getClient().scripts.list(
21+
arg.site_id,
22+
requestOptions
23+
);
24+
return response;
25+
};
3226

33-
// GET https://api.webflow.com/v2/sites/:site_id/custom_code
34-
server.tool(
35-
"site_applied_scripts_list",
36-
"Get all scripts applied to a site by the App. To apply a script to a site or page, first register it via the Register Script endpoints, then apply it using the relevant Site or Page endpoints.",
37-
{
38-
site_id: z.string().describe("Unique identifier for the site."),
39-
},
40-
async ({ site_id }) => {
41-
try {
42-
const response = await getClient().sites.scripts.getCustomCode(
43-
site_id,
44-
requestOptions
45-
);
46-
return formatResponse(response);
47-
} catch (error) {
48-
return formatErrorResponse(error);
49-
}
50-
}
51-
);
27+
const listAppliedScripts = async (arg: { site_id: string }) => {
28+
const response = await getClient().sites.scripts.getCustomCode(
29+
arg.site_id,
30+
requestOptions
31+
);
32+
return response;
33+
};
5234

53-
// POST https://api.webflow.com/v2/sites/:site_id/registered_scripts/inline
54-
server.tool(
55-
"add_inline_site_script",
56-
"Register an inline script for a site. Inline scripts are limited to 2000 characters. ",
57-
{
58-
site_id: z.string().describe("Unique identifier for the site."),
59-
request: RegisterInlineSiteScriptSchema,
60-
},
61-
async ({ site_id, request }) => {
62-
const registerScriptResponse = await getClient().scripts.registerInline(
63-
site_id,
64-
{
65-
sourceCode: request.sourceCode,
66-
version: request.version,
67-
displayName: request.displayName,
68-
canCopy: request.canCopy !== undefined ? request.canCopy : true,
69-
},
35+
const addInlineSiteScript = async (arg: {
36+
site_id: string;
37+
request: {
38+
sourceCode: string;
39+
version: string;
40+
displayName: string;
41+
location?: string;
42+
canCopy?: boolean;
43+
attributes?: Record<string, any>;
44+
};
45+
}) => {
46+
const registerScriptResponse = await getClient().scripts.registerInline(
47+
arg.site_id,
48+
{
49+
sourceCode: arg.request.sourceCode,
50+
version: arg.request.version,
51+
displayName: arg.request.displayName,
52+
canCopy: arg.request.canCopy !== undefined ? arg.request.canCopy : true,
53+
},
54+
requestOptions
55+
);
56+
57+
let existingScripts: any[] = [];
58+
try {
59+
const allScriptsResponse = await getClient().sites.scripts.getCustomCode(
60+
arg.site_id,
7061
requestOptions
7162
);
63+
existingScripts = allScriptsResponse.scripts || [];
64+
} catch (error) {
65+
existingScripts = [];
66+
}
7267

73-
let existingScripts: any[] = [];
74-
try {
75-
const allScriptsResponse =
76-
await getClient().sites.scripts.getCustomCode(
77-
site_id,
78-
requestOptions
79-
);
80-
existingScripts = allScriptsResponse.scripts || [];
81-
} catch (error) {
82-
formatErrorResponse(error);
83-
existingScripts = [];
84-
}
68+
const newScript = {
69+
id: registerScriptResponse.id ?? " ",
70+
location:
71+
arg.request.location === "footer"
72+
? ScriptApplyLocation.Footer
73+
: ScriptApplyLocation.Header,
74+
version: registerScriptResponse.version ?? " ",
75+
attributes: arg.request.attributes,
76+
};
8577

86-
const newScript = {
87-
id: registerScriptResponse.id ?? " ",
88-
location:
89-
request.location === "footer"
90-
? ScriptApplyLocation.Footer
91-
: ScriptApplyLocation.Header,
92-
version: registerScriptResponse.version ?? " ",
93-
attributes: request.attributes,
94-
};
78+
existingScripts.push(newScript);
9579

96-
existingScripts.push(newScript);
80+
await getClient().sites.scripts.upsertCustomCode(
81+
arg.site_id,
82+
{
83+
scripts: existingScripts,
84+
},
85+
requestOptions
86+
);
9787

98-
const addedSiteCustomCoderesponse =
99-
await getClient().sites.scripts.upsertCustomCode(
100-
site_id,
101-
{
102-
scripts: existingScripts,
103-
},
104-
requestOptions
105-
);
88+
return registerScriptResponse;
89+
};
10690

107-
return formatResponse(registerScriptResponse);
91+
const deleteAllSiteScripts = async (arg: { site_id: string }) => {
92+
try {
93+
await getClient().sites.scripts.deleteCustomCode(
94+
arg.site_id,
95+
requestOptions
96+
);
97+
return "Custom Code Deleted";
98+
} catch (error) {
99+
// If it's a 404, we'll try to clear the scripts another way
100+
if (isApiError(error) && error.status === 404) {
101+
return error.message ?? "No custom code found";
102+
}
103+
throw error;
108104
}
109-
);
105+
};
110106

111107
server.tool(
112-
"delete_all_site_scripts",
108+
"data_scripts_tool",
109+
"Data tool - Scripts tool to perform actions like list registered scripts, list applied scripts, add inline site script, and delete all site scripts",
113110
{
114-
site_id: z.string(),
111+
actions: z.array(
112+
z.object({
113+
// GET https://api.webflow.com/v2/sites/:site_id/registered_scripts
114+
list_registered_scripts: z
115+
.object({
116+
site_id: z.string().describe("Unique identifier for the site."),
117+
})
118+
.optional()
119+
.describe(
120+
"List all registered scripts for a site. To apply a script to a site or page, first register it via the Register Script endpoints, then apply it using the relevant Site or Page endpoints."
121+
),
122+
// GET https://api.webflow.com/v2/sites/:site_id/custom_code
123+
list_applied_scripts: z
124+
.object({
125+
site_id: z.string().describe("Unique identifier for the site."),
126+
})
127+
.optional()
128+
.describe(
129+
"Get all scripts applied to a site by the App. To apply a script to a site or page, first register it via the Register Script endpoints, then apply it using the relevant Site or Page endpoints."
130+
),
131+
// POST https://api.webflow.com/v2/sites/:site_id/registered_scripts/inline
132+
add_inline_site_script: z
133+
.object({
134+
site_id: z.string().describe("Unique identifier for the site."),
135+
request: RegisterInlineSiteScriptSchema,
136+
})
137+
.optional()
138+
.describe(
139+
"Register an inline script for a site. Inline scripts are limited to 2000 characters."
140+
),
141+
// DELETE https://api.webflow.com/v2/sites/:site_id/custom_code
142+
delete_all_site_scripts: z
143+
.object({
144+
site_id: z.string().describe("Unique identifier for the site."),
145+
})
146+
.optional()
147+
.describe(
148+
"Delete all custom scripts applied to a site by the App."
149+
),
150+
})
151+
),
115152
},
116-
async ({ site_id }) => {
153+
async ({ actions }) => {
154+
const result: Content[] = [];
117155
try {
118-
const response = await getClient().sites.scripts.deleteCustomCode(
119-
site_id,
120-
requestOptions
121-
);
122-
return formatResponse("Custom Code Deleted");
123-
} catch (error) {
124-
// If it's a 404, we'll try to clear the scripts another way
125-
if (isApiError(error) && error.status === 404) {
126-
return formatResponse(error.message ?? "No custom code found");
156+
for (const action of actions) {
157+
if (action.list_registered_scripts) {
158+
const content = await listRegisteredScripts(
159+
action.list_registered_scripts
160+
);
161+
result.push(textContent(content));
162+
}
163+
if (action.list_applied_scripts) {
164+
const content = await listAppliedScripts(
165+
action.list_applied_scripts
166+
);
167+
result.push(textContent(content));
168+
}
169+
if (action.add_inline_site_script) {
170+
const content = await addInlineSiteScript(
171+
action.add_inline_site_script
172+
);
173+
result.push(textContent(content));
174+
}
175+
if (action.delete_all_site_scripts) {
176+
const content = await deleteAllSiteScripts(
177+
action.delete_all_site_scripts
178+
);
179+
result.push(textContent(content));
180+
}
127181
}
128-
throw error;
182+
return toolResponse(result);
183+
} catch (error) {
184+
return formatErrorResponse(error);
129185
}
130186
}
131187
);

0 commit comments

Comments
 (0)