Skip to content

Commit ebcc00a

Browse files
authored
Merge pull request #20 from stape-io/add-version-pagination
Add pagination for version tool
2 parents a4e6d64 + 30d3e2f commit ebcc00a

File tree

5 files changed

+196
-7
lines changed

5 files changed

+196
-7
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "google-tag-manager-mcp-server",
3-
"version": "3.0.2",
3+
"version": "3.0.3",
44
"description": "MCP server for Google Tag Manager",
55
"license": "Apache-2.0",
66
"author": "stape-io",

src/tools/versionActions.ts

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@ import { tagmanager_v2 } from "googleapis";
33
import { z } from "zod";
44
import { McpAgentToolParamsModel } from "../models/McpAgentModel";
55
import { ContainerVersionSchema } from "../schemas/ContainerVersionSchema";
6-
import { createErrorResponse, getTagManagerClient, log } from "../utils";
6+
import {
7+
createErrorResponse,
8+
getTagManagerClient,
9+
ITEMS_PER_PAGE,
10+
log,
11+
processVersionData,
12+
ResourceType,
13+
} from "../utils";
714
import Schema$ContainerVersion = tagmanager_v2.Schema$ContainerVersion;
815

916
const PayloadSchema = ContainerVersionSchema.omit({
@@ -18,7 +25,7 @@ export const versionActions = (
1825
): void => {
1926
server.tool(
2027
"gtm_version",
21-
"Performs all container version operations: get, live, publish, remove, setLatest, undelete, update. Use the 'action' parameter to select the operation.",
28+
`Performs all container version operations: get, live, publish, remove, setLatest, undelete, update. For 'get' and 'live' actions, use 'resourceType' to paginate specific resource arrays (up to ${ITEMS_PER_PAGE} items per page) to avoid response truncation.`,
2229
{
2330
action: z
2431
.enum([
@@ -56,6 +63,44 @@ export const versionActions = (
5663
.describe(
5764
"The fingerprint for optimistic concurrency control. Required for 'publish' and 'update' actions.",
5865
),
66+
resourceType: z
67+
.enum([
68+
"tag",
69+
"trigger",
70+
"variable",
71+
"folder",
72+
"builtInVariable",
73+
"zone",
74+
"customTemplate",
75+
"client",
76+
"gtagConfig",
77+
"transformation",
78+
])
79+
.optional()
80+
.describe(
81+
"Specific resource type to retrieve with pagination (only for 'get' and 'live' actions). If not specified, returns summary with sample items.",
82+
),
83+
page: z
84+
.number()
85+
.min(1)
86+
.default(1)
87+
.describe(
88+
"Page number for pagination (starts from 1). Only used when resourceType is specified.",
89+
),
90+
itemsPerPage: z
91+
.number()
92+
.min(1)
93+
.max(ITEMS_PER_PAGE)
94+
.default(ITEMS_PER_PAGE)
95+
.describe(
96+
`Number of items to return per page (1-${ITEMS_PER_PAGE}). Only used when resourceType is specified.`,
97+
),
98+
includeSummary: z
99+
.boolean()
100+
.default(true)
101+
.describe(
102+
"Include counts and metadata for all resource types. Only used when resourceType is specified.",
103+
),
59104
},
60105
async ({
61106
action,
@@ -64,6 +109,10 @@ export const versionActions = (
64109
containerVersionId,
65110
createOrUpdateConfig,
66111
fingerprint,
112+
resourceType,
113+
page,
114+
itemsPerPage,
115+
includeSummary,
67116
}) => {
68117
log(`Running tool: gtm_version with action ${action}`);
69118

@@ -82,9 +131,17 @@ export const versionActions = (
82131
path: `accounts/${accountId}/containers/${containerId}/versions/${containerVersionId}`,
83132
});
84133

134+
const processedData = processVersionData(
135+
response.data,
136+
resourceType as ResourceType | undefined,
137+
page,
138+
itemsPerPage,
139+
includeSummary,
140+
);
141+
85142
return {
86143
content: [
87-
{ type: "text", text: JSON.stringify(response.data, null, 2) },
144+
{ type: "text", text: JSON.stringify(processedData, null, 2) },
88145
],
89146
};
90147
}
@@ -95,9 +152,17 @@ export const versionActions = (
95152
},
96153
);
97154

155+
const processedData = processVersionData(
156+
response.data,
157+
resourceType as ResourceType | undefined,
158+
page,
159+
itemsPerPage,
160+
includeSummary,
161+
);
162+
98163
return {
99164
content: [
100-
{ type: "text", text: JSON.stringify(response.data, null, 2) },
165+
{ type: "text", text: JSON.stringify(processedData, null, 2) },
101166
],
102167
};
103168
}

src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export * from "./authorizeUtils";
66
export * from "./apisHandler";
77
export * from "./workersOAuthUtils";
88
export * from "./paginationUtils";
9+
export * from "./versionPaginationUtils";
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { tagmanager_v2 } from "googleapis";
2+
import { paginateArray } from "./paginationUtils";
3+
import Schema$ContainerVersion = tagmanager_v2.Schema$ContainerVersion;
4+
5+
export const ITEMS_PER_PAGE = 20;
6+
export const SUMMARY_SAMPLE_SIZE = 5;
7+
8+
export type ResourceType =
9+
| "tag"
10+
| "trigger"
11+
| "variable"
12+
| "folder"
13+
| "builtInVariable"
14+
| "zone"
15+
| "customTemplate"
16+
| "client"
17+
| "gtagConfig"
18+
| "transformation";
19+
20+
export interface ProcessedVersionResponse {
21+
version: Partial<Schema$ContainerVersion>;
22+
summary?: Record<string, number>;
23+
24+
[key: string]: unknown;
25+
}
26+
27+
export function processVersionData(
28+
versionData: Schema$ContainerVersion,
29+
resourceType?: ResourceType,
30+
page?: number,
31+
itemsPerPage?: number,
32+
includeSummary?: boolean,
33+
): ProcessedVersionResponse {
34+
const {
35+
tag,
36+
trigger,
37+
variable,
38+
folder,
39+
builtInVariable,
40+
zone,
41+
customTemplate,
42+
client,
43+
gtagConfig,
44+
transformation,
45+
...baseVersion
46+
} = versionData;
47+
48+
// If no resourceType specified, return summary mode
49+
if (!resourceType) {
50+
const summary = {
51+
tagCount: tag?.length || 0,
52+
triggerCount: trigger?.length || 0,
53+
variableCount: variable?.length || 0,
54+
folderCount: folder?.length || 0,
55+
builtInVariableCount: builtInVariable?.length || 0,
56+
zoneCount: zone?.length || 0,
57+
customTemplateCount: customTemplate?.length || 0,
58+
clientCount: client?.length || 0,
59+
gtagConfigCount: gtagConfig?.length || 0,
60+
transformationCount: transformation?.length || 0,
61+
};
62+
63+
return {
64+
version: baseVersion,
65+
summary,
66+
tagSample: tag?.slice(0, SUMMARY_SAMPLE_SIZE),
67+
triggerSample: trigger?.slice(0, SUMMARY_SAMPLE_SIZE),
68+
variableSample: variable?.slice(0, SUMMARY_SAMPLE_SIZE),
69+
folderSample: folder?.slice(0, SUMMARY_SAMPLE_SIZE),
70+
builtInVariableSample: builtInVariable?.slice(0, SUMMARY_SAMPLE_SIZE),
71+
zoneSample: zone?.slice(0, SUMMARY_SAMPLE_SIZE),
72+
customTemplateSample: customTemplate?.slice(0, SUMMARY_SAMPLE_SIZE),
73+
clientSample: client?.slice(0, SUMMARY_SAMPLE_SIZE),
74+
gtagConfigSample: gtagConfig?.slice(0, SUMMARY_SAMPLE_SIZE),
75+
transformationSample: transformation?.slice(0, SUMMARY_SAMPLE_SIZE),
76+
};
77+
}
78+
79+
// Paginate specific resource type
80+
const resourceMap: Record<ResourceType, unknown[] | undefined> = {
81+
tag,
82+
trigger,
83+
variable,
84+
folder,
85+
builtInVariable,
86+
zone,
87+
customTemplate,
88+
client,
89+
gtagConfig,
90+
transformation,
91+
};
92+
93+
const selectedResource = resourceMap[resourceType] || [];
94+
const paginatedResult = paginateArray(
95+
selectedResource,
96+
page || 1,
97+
itemsPerPage || ITEMS_PER_PAGE,
98+
);
99+
100+
const result: ProcessedVersionResponse = {
101+
version: baseVersion,
102+
[resourceType]: paginatedResult.data,
103+
[`${resourceType}Pagination`]: paginatedResult.pagination,
104+
};
105+
106+
// Add summary if requested
107+
if (includeSummary) {
108+
result.summary = {
109+
tagCount: tag?.length || 0,
110+
triggerCount: trigger?.length || 0,
111+
variableCount: variable?.length || 0,
112+
folderCount: folder?.length || 0,
113+
builtInVariableCount: builtInVariable?.length || 0,
114+
zoneCount: zone?.length || 0,
115+
customTemplateCount: customTemplate?.length || 0,
116+
clientCount: client?.length || 0,
117+
gtagConfigCount: gtagConfig?.length || 0,
118+
transformationCount: transformation?.length || 0,
119+
};
120+
}
121+
122+
return result;
123+
}

0 commit comments

Comments
 (0)