@burdenoff/mcp-libs 2026.511.1
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 +76 -0
- package/dist/chunk-4GBVJ4OY.js +847 -0
- package/dist/chunk-4GBVJ4OY.js.map +1 -0
- package/dist/chunk-H2OYWLOA.js +919 -0
- package/dist/chunk-H2OYWLOA.js.map +1 -0
- package/dist/chunk-JFEQYSWM.js +174 -0
- package/dist/chunk-JFEQYSWM.js.map +1 -0
- package/dist/chunk-WWFVD7BO.js +273 -0
- package/dist/chunk-WWFVD7BO.js.map +1 -0
- package/dist/context-1jV4NsLv.d.cts +138 -0
- package/dist/context-1jV4NsLv.d.ts +138 -0
- package/dist/core/index.cjs +953 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +59 -0
- package/dist/core/index.d.ts +59 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/http-BP4c721D.d.cts +22 -0
- package/dist/http-DXTeCD5r.d.ts +22 -0
- package/dist/index.cjs +1013 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/module-DBcfA-i3.d.ts +67 -0
- package/dist/module-DFQBZNK6.d.cts +67 -0
- package/dist/modules/auth/index.cjs +533 -0
- package/dist/modules/auth/index.cjs.map +1 -0
- package/dist/modules/auth/index.d.cts +51 -0
- package/dist/modules/auth/index.d.ts +51 -0
- package/dist/modules/auth/index.js +159 -0
- package/dist/modules/auth/index.js.map +1 -0
- package/dist/modules/billing/index.cjs +655 -0
- package/dist/modules/billing/index.cjs.map +1 -0
- package/dist/modules/billing/index.d.cts +8 -0
- package/dist/modules/billing/index.d.ts +8 -0
- package/dist/modules/billing/index.js +606 -0
- package/dist/modules/billing/index.js.map +1 -0
- package/dist/modules/channels/index.cjs +443 -0
- package/dist/modules/channels/index.cjs.map +1 -0
- package/dist/modules/channels/index.d.cts +8 -0
- package/dist/modules/channels/index.d.ts +8 -0
- package/dist/modules/channels/index.js +394 -0
- package/dist/modules/channels/index.js.map +1 -0
- package/dist/modules/conversations/index.cjs +288 -0
- package/dist/modules/conversations/index.cjs.map +1 -0
- package/dist/modules/conversations/index.d.cts +8 -0
- package/dist/modules/conversations/index.d.ts +8 -0
- package/dist/modules/conversations/index.js +239 -0
- package/dist/modules/conversations/index.js.map +1 -0
- package/dist/modules/devportal/index.cjs +796 -0
- package/dist/modules/devportal/index.cjs.map +1 -0
- package/dist/modules/devportal/index.d.cts +8 -0
- package/dist/modules/devportal/index.d.ts +8 -0
- package/dist/modules/devportal/index.js +747 -0
- package/dist/modules/devportal/index.js.map +1 -0
- package/dist/modules/export/index.cjs +333 -0
- package/dist/modules/export/index.cjs.map +1 -0
- package/dist/modules/export/index.d.cts +8 -0
- package/dist/modules/export/index.d.ts +8 -0
- package/dist/modules/export/index.js +284 -0
- package/dist/modules/export/index.js.map +1 -0
- package/dist/modules/files/index.cjs +278 -0
- package/dist/modules/files/index.cjs.map +1 -0
- package/dist/modules/files/index.d.cts +8 -0
- package/dist/modules/files/index.d.ts +8 -0
- package/dist/modules/files/index.js +229 -0
- package/dist/modules/files/index.js.map +1 -0
- package/dist/modules/groups/index.cjs +451 -0
- package/dist/modules/groups/index.cjs.map +1 -0
- package/dist/modules/groups/index.d.cts +8 -0
- package/dist/modules/groups/index.d.ts +8 -0
- package/dist/modules/groups/index.js +402 -0
- package/dist/modules/groups/index.js.map +1 -0
- package/dist/modules/health/index.cjs +159 -0
- package/dist/modules/health/index.cjs.map +1 -0
- package/dist/modules/health/index.d.cts +8 -0
- package/dist/modules/health/index.d.ts +8 -0
- package/dist/modules/health/index.js +36 -0
- package/dist/modules/health/index.js.map +1 -0
- package/dist/modules/integrations/index.cjs +316 -0
- package/dist/modules/integrations/index.cjs.map +1 -0
- package/dist/modules/integrations/index.d.cts +8 -0
- package/dist/modules/integrations/index.d.ts +8 -0
- package/dist/modules/integrations/index.js +267 -0
- package/dist/modules/integrations/index.js.map +1 -0
- package/dist/modules/notifications/index.cjs +222 -0
- package/dist/modules/notifications/index.cjs.map +1 -0
- package/dist/modules/notifications/index.d.cts +8 -0
- package/dist/modules/notifications/index.d.ts +8 -0
- package/dist/modules/notifications/index.js +173 -0
- package/dist/modules/notifications/index.js.map +1 -0
- package/dist/modules/organizations/index.cjs +267 -0
- package/dist/modules/organizations/index.cjs.map +1 -0
- package/dist/modules/organizations/index.d.cts +8 -0
- package/dist/modules/organizations/index.d.ts +8 -0
- package/dist/modules/organizations/index.js +218 -0
- package/dist/modules/organizations/index.js.map +1 -0
- package/dist/modules/products/index.cjs +736 -0
- package/dist/modules/products/index.cjs.map +1 -0
- package/dist/modules/products/index.d.cts +8 -0
- package/dist/modules/products/index.d.ts +8 -0
- package/dist/modules/products/index.js +687 -0
- package/dist/modules/products/index.js.map +1 -0
- package/dist/modules/rbac/index.cjs +378 -0
- package/dist/modules/rbac/index.cjs.map +1 -0
- package/dist/modules/rbac/index.d.cts +8 -0
- package/dist/modules/rbac/index.d.ts +8 -0
- package/dist/modules/rbac/index.js +329 -0
- package/dist/modules/rbac/index.js.map +1 -0
- package/dist/modules/sandbox/index.cjs +318 -0
- package/dist/modules/sandbox/index.cjs.map +1 -0
- package/dist/modules/sandbox/index.d.cts +8 -0
- package/dist/modules/sandbox/index.d.ts +8 -0
- package/dist/modules/sandbox/index.js +225 -0
- package/dist/modules/sandbox/index.js.map +1 -0
- package/dist/modules/scheduler/index.cjs +267 -0
- package/dist/modules/scheduler/index.cjs.map +1 -0
- package/dist/modules/scheduler/index.d.cts +8 -0
- package/dist/modules/scheduler/index.d.ts +8 -0
- package/dist/modules/scheduler/index.js +218 -0
- package/dist/modules/scheduler/index.js.map +1 -0
- package/dist/modules/security/index.cjs +529 -0
- package/dist/modules/security/index.cjs.map +1 -0
- package/dist/modules/security/index.d.cts +8 -0
- package/dist/modules/security/index.d.ts +8 -0
- package/dist/modules/security/index.js +480 -0
- package/dist/modules/security/index.js.map +1 -0
- package/dist/modules/store/index.cjs +450 -0
- package/dist/modules/store/index.cjs.map +1 -0
- package/dist/modules/store/index.d.cts +8 -0
- package/dist/modules/store/index.d.ts +8 -0
- package/dist/modules/store/index.js +401 -0
- package/dist/modules/store/index.js.map +1 -0
- package/dist/modules/support/index.cjs +285 -0
- package/dist/modules/support/index.cjs.map +1 -0
- package/dist/modules/support/index.d.cts +8 -0
- package/dist/modules/support/index.d.ts +8 -0
- package/dist/modules/support/index.js +236 -0
- package/dist/modules/support/index.js.map +1 -0
- package/dist/modules/tags/index.cjs +421 -0
- package/dist/modules/tags/index.cjs.map +1 -0
- package/dist/modules/tags/index.d.cts +8 -0
- package/dist/modules/tags/index.d.ts +8 -0
- package/dist/modules/tags/index.js +372 -0
- package/dist/modules/tags/index.js.map +1 -0
- package/dist/modules/tours/index.cjs +225 -0
- package/dist/modules/tours/index.cjs.map +1 -0
- package/dist/modules/tours/index.d.cts +8 -0
- package/dist/modules/tours/index.d.ts +8 -0
- package/dist/modules/tours/index.js +176 -0
- package/dist/modules/tours/index.js.map +1 -0
- package/dist/modules/vibecontrols/index.cjs +5551 -0
- package/dist/modules/vibecontrols/index.cjs.map +1 -0
- package/dist/modules/vibecontrols/index.d.cts +8 -0
- package/dist/modules/vibecontrols/index.d.ts +8 -0
- package/dist/modules/vibecontrols/index.js +4380 -0
- package/dist/modules/vibecontrols/index.js.map +1 -0
- package/dist/modules/workspaces/index.cjs +552 -0
- package/dist/modules/workspaces/index.cjs.map +1 -0
- package/dist/modules/workspaces/index.d.cts +8 -0
- package/dist/modules/workspaces/index.d.ts +8 -0
- package/dist/modules/workspaces/index.js +503 -0
- package/dist/modules/workspaces/index.js.map +1 -0
- package/dist/tool-name-CQf_IqAj.d.cts +47 -0
- package/dist/tool-name-DlnrBsZ6.d.ts +47 -0
- package/dist/transports/index.cjs +183 -0
- package/dist/transports/index.cjs.map +1 -0
- package/dist/transports/index.d.cts +13 -0
- package/dist/transports/index.d.ts +13 -0
- package/dist/transports/index.js +3 -0
- package/dist/transports/index.js.map +1 -0
- package/package.json +125 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { mcpToolName, jsonResult, errorResult } from '../../chunk-H2OYWLOA.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
// src/modules/tags/operations.ts
|
|
5
|
+
var LIST_TAGS = `
|
|
6
|
+
query TagsList($filter: TagFilterInput, $pagination: TagsPaginationInput) {
|
|
7
|
+
getTags(filter: $filter, pagination: $pagination) {
|
|
8
|
+
items { id key label description scope displayOrder }
|
|
9
|
+
total hasMore
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
`;
|
|
13
|
+
var GET_TAG = `
|
|
14
|
+
query GetTag($id: ID!) {
|
|
15
|
+
getTag(id: $id) {
|
|
16
|
+
id key label description color icon scope vocabularyId parentId
|
|
17
|
+
displayOrder assignmentCount usageCount hierarchyLevel hierarchyPath
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
var CREATE_TAG = `
|
|
22
|
+
mutation CreateTag($input: CreateTagInput!) {
|
|
23
|
+
createTag(input: $input) {
|
|
24
|
+
id key label description scope displayOrder createdAt
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
var UPDATE_TAG = `
|
|
29
|
+
mutation UpdateTag($id: ID!, $input: UpdateTagInput!) {
|
|
30
|
+
updateTag(id: $id, input: $input) {
|
|
31
|
+
id label description color icon parentId displayOrder updatedAt
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
var DELETE_TAG = `
|
|
36
|
+
mutation DeleteTag($id: ID!) {
|
|
37
|
+
deleteTag(id: $id)
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
var TAG_ANALYTICS = `
|
|
41
|
+
query TagAnalytics($tagId: ID!, $startDate: DateTime!, $endDate: DateTime!) {
|
|
42
|
+
getTagAnalytics(tagId: $tagId, startDate: $startDate, endDate: $endDate) {
|
|
43
|
+
assignmentCount date entityTypeBreakdown uniqueUsers uniqueEntities
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
var TAG_RELATIONS = `
|
|
48
|
+
query GetRelatedTags($tagId: ID!) {
|
|
49
|
+
getRelatedTags(tagId: $tagId) {
|
|
50
|
+
tag { id label }
|
|
51
|
+
relationType
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
var CREATE_TAG_RELATION = `
|
|
56
|
+
mutation CreateTagRelation($input: CreateTagRelationInput!) {
|
|
57
|
+
createTagRelation(input: $input) {
|
|
58
|
+
id fromTagId toTagId relationType bidirectional
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
var DELETE_TAG_RELATION = `
|
|
63
|
+
mutation DeleteTagRelation($id: ID!) {
|
|
64
|
+
deleteTagRelation(id: $id)
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
// src/modules/tags/tools.ts
|
|
69
|
+
var TagScopeEnum = z.enum(["WORKSPACE", "GLOBAL", "VIBE"]).describe("Visibility scope of the tag");
|
|
70
|
+
var TagRelationTypeEnum = z.enum(["SYNONYM", "ANTONYM", "BROADER", "NARROWER", "RELATED", "IMPLIES", "EXCLUDES"]).describe(
|
|
71
|
+
"Semantic relationship between two tags (SYNONYM = same-meaning, BROADER/NARROWER = hierarchy, IMPLIES/EXCLUDES = behaviour, RELATED = generic)"
|
|
72
|
+
);
|
|
73
|
+
function resolveWorkspaceContext(ctx) {
|
|
74
|
+
const auth = ctx.auth.read();
|
|
75
|
+
const workspaceId = auth?.workspaceId;
|
|
76
|
+
if (!workspaceId) {
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
error: errorResult(
|
|
80
|
+
"No workspace selected. Bind one with <product>_auth_select_workspace before calling tag tools."
|
|
81
|
+
)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return { ok: true, ctx: { workspaceId } };
|
|
85
|
+
}
|
|
86
|
+
function registerTagsTools(server, ctx, track) {
|
|
87
|
+
server.registerTool(
|
|
88
|
+
track(mcpToolName(ctx.productName, "tags_list")),
|
|
89
|
+
{
|
|
90
|
+
title: "List Tags",
|
|
91
|
+
description: "List tags in the currently-bound workspace, with optional scope/search filters and pagination. Returns { items, total, hasMore }.",
|
|
92
|
+
inputSchema: {
|
|
93
|
+
scope: TagScopeEnum.optional().describe("Filter by scope"),
|
|
94
|
+
search: z.string().optional().describe("Free-text search across key/label/description"),
|
|
95
|
+
limit: z.number().optional().describe("Page size (default 100)"),
|
|
96
|
+
offset: z.number().optional().describe("Pagination offset (default 0)")
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
async ({ scope, search, limit, offset }) => {
|
|
100
|
+
try {
|
|
101
|
+
const wctx = resolveWorkspaceContext(ctx);
|
|
102
|
+
if (!wctx.ok) return wctx.error;
|
|
103
|
+
const filter = { workspaceId: wctx.ctx.workspaceId };
|
|
104
|
+
if (scope !== void 0) filter.scope = scope;
|
|
105
|
+
if (search !== void 0) filter.search = search;
|
|
106
|
+
const data = await ctx.gql.workspace.request(LIST_TAGS, {
|
|
107
|
+
filter,
|
|
108
|
+
pagination: { limit: limit ?? 100, offset: offset ?? 0 }
|
|
109
|
+
});
|
|
110
|
+
return jsonResult(data.getTags);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
ctx.logger.error("tags_list failed", { error: String(error) });
|
|
113
|
+
return errorResult(
|
|
114
|
+
`Failed to list tags: ${error instanceof Error ? error.message : String(error)}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
server.registerTool(
|
|
120
|
+
track(mcpToolName(ctx.productName, "tags_get")),
|
|
121
|
+
{
|
|
122
|
+
title: "Get Tag",
|
|
123
|
+
description: "Fetch a single tag by ID. Returns the full detail shape (color, icon, hierarchy, usage counters).",
|
|
124
|
+
inputSchema: { id: z.string().describe("Tag ID") }
|
|
125
|
+
},
|
|
126
|
+
async ({ id }) => {
|
|
127
|
+
try {
|
|
128
|
+
const data = await ctx.gql.workspace.request(GET_TAG, {
|
|
129
|
+
id
|
|
130
|
+
});
|
|
131
|
+
if (!data.getTag) {
|
|
132
|
+
return errorResult(`Tag ${id} not found`);
|
|
133
|
+
}
|
|
134
|
+
return jsonResult(data.getTag);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
ctx.logger.error("tags_get failed", { error: String(error) });
|
|
137
|
+
return errorResult(
|
|
138
|
+
`Failed to get tag: ${error instanceof Error ? error.message : String(error)}`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
server.registerTool(
|
|
144
|
+
track(mcpToolName(ctx.productName, "tags_create")),
|
|
145
|
+
{
|
|
146
|
+
title: "Create Tag",
|
|
147
|
+
description: "Create a tag in the currently-bound workspace. `key` must be unique within the (workspace, scope) tuple; `label` is the human-readable display name.",
|
|
148
|
+
inputSchema: {
|
|
149
|
+
key: z.string().min(1).describe("Stable identifier (kebab-case recommended); unique within workspace+scope"),
|
|
150
|
+
label: z.string().min(1).describe("Human-readable display name"),
|
|
151
|
+
description: z.string().optional().describe("Free-form description"),
|
|
152
|
+
color: z.string().optional().describe("Hex color (e.g. #ff8800) \u2014 must be a semantic theme token in UI"),
|
|
153
|
+
icon: z.string().optional().describe("Icon name (lucide-react identifier)"),
|
|
154
|
+
scope: TagScopeEnum.optional().describe("Tag scope (default WORKSPACE)"),
|
|
155
|
+
parentId: z.string().optional().describe("Parent tag ID for hierarchical taxonomies")
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
async ({ key, label, description, color, icon, scope, parentId }) => {
|
|
159
|
+
try {
|
|
160
|
+
const wctx = resolveWorkspaceContext(ctx);
|
|
161
|
+
if (!wctx.ok) return wctx.error;
|
|
162
|
+
const input = {
|
|
163
|
+
context: wctx.ctx,
|
|
164
|
+
key,
|
|
165
|
+
label,
|
|
166
|
+
scope: scope ?? "WORKSPACE"
|
|
167
|
+
};
|
|
168
|
+
if (description !== void 0) input.description = description;
|
|
169
|
+
if (color !== void 0) input.color = color;
|
|
170
|
+
if (icon !== void 0) input.icon = icon;
|
|
171
|
+
if (parentId !== void 0) input.parentId = parentId;
|
|
172
|
+
const data = await ctx.gql.workspace.request(CREATE_TAG, {
|
|
173
|
+
input
|
|
174
|
+
});
|
|
175
|
+
return jsonResult(data.createTag);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
ctx.logger.error("tags_create failed", { error: String(error) });
|
|
178
|
+
return errorResult(
|
|
179
|
+
`Failed to create tag: ${error instanceof Error ? error.message : String(error)}`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
server.registerTool(
|
|
185
|
+
track(mcpToolName(ctx.productName, "tags_update")),
|
|
186
|
+
{
|
|
187
|
+
title: "Update Tag",
|
|
188
|
+
description: "Update a tag. At least one mutable field (label / description / color / icon / parentId / displayOrder) must be provided. The workspace context is implicit.",
|
|
189
|
+
inputSchema: {
|
|
190
|
+
id: z.string().describe("Tag ID"),
|
|
191
|
+
label: z.string().optional().describe("Updated display name"),
|
|
192
|
+
description: z.string().optional().describe("Updated description (pass empty string to clear)"),
|
|
193
|
+
color: z.string().optional().describe("Updated hex color"),
|
|
194
|
+
icon: z.string().optional().describe("Updated icon name"),
|
|
195
|
+
parentId: z.string().optional().describe("Updated parent tag ID"),
|
|
196
|
+
displayOrder: z.number().int().optional().describe("Updated display order within parent (lower sorts first)")
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
async ({ id, label, description, color, icon, parentId, displayOrder }) => {
|
|
200
|
+
try {
|
|
201
|
+
const wctx = resolveWorkspaceContext(ctx);
|
|
202
|
+
if (!wctx.ok) return wctx.error;
|
|
203
|
+
const input = { context: wctx.ctx };
|
|
204
|
+
if (label !== void 0) input.label = label;
|
|
205
|
+
if (description !== void 0) input.description = description;
|
|
206
|
+
if (color !== void 0) input.color = color;
|
|
207
|
+
if (icon !== void 0) input.icon = icon;
|
|
208
|
+
if (parentId !== void 0) input.parentId = parentId;
|
|
209
|
+
if (displayOrder !== void 0) input.displayOrder = displayOrder;
|
|
210
|
+
if (Object.keys(input).length === 1) {
|
|
211
|
+
return errorResult(
|
|
212
|
+
"No updates specified \u2014 provide at least one of label/description/color/icon/parentId/displayOrder"
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
const data = await ctx.gql.workspace.request(UPDATE_TAG, {
|
|
216
|
+
id,
|
|
217
|
+
input
|
|
218
|
+
});
|
|
219
|
+
return jsonResult(data.updateTag);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
ctx.logger.error("tags_update failed", { error: String(error) });
|
|
222
|
+
return errorResult(
|
|
223
|
+
`Failed to update tag: ${error instanceof Error ? error.message : String(error)}`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
server.registerTool(
|
|
229
|
+
track(mcpToolName(ctx.productName, "tags_delete")),
|
|
230
|
+
{
|
|
231
|
+
title: "Delete Tag",
|
|
232
|
+
description: "Permanently delete a tag and all its assignments. This is destructive \u2014 there is no soft-delete on the tags service.",
|
|
233
|
+
inputSchema: { id: z.string().describe("Tag ID to delete") }
|
|
234
|
+
},
|
|
235
|
+
async ({ id }) => {
|
|
236
|
+
try {
|
|
237
|
+
const data = await ctx.gql.workspace.request(DELETE_TAG, {
|
|
238
|
+
id
|
|
239
|
+
});
|
|
240
|
+
return jsonResult({ deleted: data.deleteTag, tagId: id });
|
|
241
|
+
} catch (error) {
|
|
242
|
+
ctx.logger.error("tags_delete failed", { error: String(error) });
|
|
243
|
+
return errorResult(
|
|
244
|
+
`Failed to delete tag: ${error instanceof Error ? error.message : String(error)}`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
server.registerTool(
|
|
250
|
+
track(mcpToolName(ctx.productName, "tags_analytics")),
|
|
251
|
+
{
|
|
252
|
+
title: "Tag Usage Analytics",
|
|
253
|
+
description: "Time-bucketed analytics for a tag: assignmentCount, uniqueUsers, uniqueEntities, and entityType breakdown over the [from, to] window.",
|
|
254
|
+
inputSchema: {
|
|
255
|
+
tagId: z.string().describe("Tag ID to analyse"),
|
|
256
|
+
from: z.string().describe("Start of the window in ISO-8601 (DateTime)"),
|
|
257
|
+
to: z.string().describe("End of the window in ISO-8601 (DateTime)")
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
async ({ tagId, from, to }) => {
|
|
261
|
+
try {
|
|
262
|
+
const data = await ctx.gql.workspace.request(TAG_ANALYTICS, { tagId, startDate: from, endDate: to });
|
|
263
|
+
return jsonResult(data.getTagAnalytics);
|
|
264
|
+
} catch (error) {
|
|
265
|
+
ctx.logger.error("tags_analytics failed", { error: String(error) });
|
|
266
|
+
return errorResult(
|
|
267
|
+
`Failed to get tag analytics: ${error instanceof Error ? error.message : String(error)}`
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
server.registerTool(
|
|
273
|
+
track(mcpToolName(ctx.productName, "tags_permissions_list")),
|
|
274
|
+
{
|
|
275
|
+
title: "List Tag Relations",
|
|
276
|
+
description: "List all tag relations originating from the given tag (synonyms, hierarchy, implies/excludes, etc.).",
|
|
277
|
+
inputSchema: { tagId: z.string().describe("Tag ID") }
|
|
278
|
+
},
|
|
279
|
+
async ({ tagId }) => {
|
|
280
|
+
try {
|
|
281
|
+
const data = await ctx.gql.workspace.request(
|
|
282
|
+
TAG_RELATIONS,
|
|
283
|
+
{ tagId }
|
|
284
|
+
);
|
|
285
|
+
return jsonResult(data.getRelatedTags);
|
|
286
|
+
} catch (error) {
|
|
287
|
+
ctx.logger.error("tags_permissions_list failed", { error: String(error) });
|
|
288
|
+
return errorResult(
|
|
289
|
+
`Failed to list tag relations: ${error instanceof Error ? error.message : String(error)}`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
server.registerTool(
|
|
295
|
+
track(mcpToolName(ctx.productName, "tags_permissions_grant")),
|
|
296
|
+
{
|
|
297
|
+
title: "Create Tag Relation",
|
|
298
|
+
description: "Create a typed relation between two tags. Set bidirectional=true to mirror the relation in both directions (only meaningful for symmetric types like SYNONYM, ANTONYM, RELATED).",
|
|
299
|
+
inputSchema: {
|
|
300
|
+
fromTagId: z.string().describe("Source tag ID"),
|
|
301
|
+
toTagId: z.string().describe("Target tag ID"),
|
|
302
|
+
relationType: TagRelationTypeEnum.describe("Relation type"),
|
|
303
|
+
bidirectional: z.boolean().optional().describe("Mirror the relation in the reverse direction (default false)")
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
async ({ fromTagId, toTagId, relationType, bidirectional }) => {
|
|
307
|
+
try {
|
|
308
|
+
const wctx = resolveWorkspaceContext(ctx);
|
|
309
|
+
if (!wctx.ok) return wctx.error;
|
|
310
|
+
const input = {
|
|
311
|
+
context: wctx.ctx,
|
|
312
|
+
fromTagId,
|
|
313
|
+
toTagId,
|
|
314
|
+
relationType,
|
|
315
|
+
bidirectional: bidirectional ?? false
|
|
316
|
+
};
|
|
317
|
+
const data = await ctx.gql.workspace.request(CREATE_TAG_RELATION, { input });
|
|
318
|
+
return jsonResult(data.createTagRelation);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
ctx.logger.error("tags_permissions_grant failed", { error: String(error) });
|
|
321
|
+
return errorResult(
|
|
322
|
+
`Failed to create tag relation: ${error instanceof Error ? error.message : String(error)}`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
);
|
|
327
|
+
server.registerTool(
|
|
328
|
+
track(mcpToolName(ctx.productName, "tags_permissions_revoke")),
|
|
329
|
+
{
|
|
330
|
+
title: "Delete Tag Relation",
|
|
331
|
+
description: "Delete a tag relation by its relation ID.",
|
|
332
|
+
inputSchema: { relationId: z.string().describe("Relation ID to delete") }
|
|
333
|
+
},
|
|
334
|
+
async ({ relationId }) => {
|
|
335
|
+
try {
|
|
336
|
+
const data = await ctx.gql.workspace.request(
|
|
337
|
+
DELETE_TAG_RELATION,
|
|
338
|
+
{ id: relationId }
|
|
339
|
+
);
|
|
340
|
+
return jsonResult({ deleted: data.deleteTagRelation, relationId });
|
|
341
|
+
} catch (error) {
|
|
342
|
+
ctx.logger.error("tags_permissions_revoke failed", { error: String(error) });
|
|
343
|
+
return errorResult(
|
|
344
|
+
`Failed to delete tag relation: ${error instanceof Error ? error.message : String(error)}`
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/modules/tags/index.ts
|
|
352
|
+
var tagsModule = {
|
|
353
|
+
id: "tags",
|
|
354
|
+
version: "0.0.1",
|
|
355
|
+
displayName: "Tags",
|
|
356
|
+
dependsOn: ["auth"],
|
|
357
|
+
capabilities: { tools: {} },
|
|
358
|
+
register(server, ctx) {
|
|
359
|
+
const tools = [];
|
|
360
|
+
const track = (n) => {
|
|
361
|
+
tools.push(n);
|
|
362
|
+
return n;
|
|
363
|
+
};
|
|
364
|
+
registerTagsTools(server, ctx, track);
|
|
365
|
+
return { tools, resources: [], prompts: [] };
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
var tags_default = tagsModule;
|
|
369
|
+
|
|
370
|
+
export { tags_default as default };
|
|
371
|
+
//# sourceMappingURL=index.js.map
|
|
372
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/tags/operations.ts","../../../src/modules/tags/tools.ts","../../../src/modules/tags/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Tags module GraphQL operations — CRUD + analytics + relations.\n * Ported verbatim from cli-sdk/src/modules/tags/operations.ts.\n *\n * Backend: ~/products/wspace/tags/wspace-tags-svc/.\n * Hive service name: `tags` (boundary prefix + `-svc` suffix stripped).\n */\n\nexport const LIST_TAGS = `\n query TagsList($filter: TagFilterInput, $pagination: TagsPaginationInput) {\n getTags(filter: $filter, pagination: $pagination) {\n items { id key label description scope displayOrder }\n total hasMore\n }\n }\n`;\n\nexport const GET_TAG = `\n query GetTag($id: ID!) {\n getTag(id: $id) {\n id key label description color icon scope vocabularyId parentId\n displayOrder assignmentCount usageCount hierarchyLevel hierarchyPath\n }\n }\n`;\n\nexport const CREATE_TAG = `\n mutation CreateTag($input: CreateTagInput!) {\n createTag(input: $input) {\n id key label description scope displayOrder createdAt\n }\n }\n`;\n\nexport const UPDATE_TAG = `\n mutation UpdateTag($id: ID!, $input: UpdateTagInput!) {\n updateTag(id: $id, input: $input) {\n id label description color icon parentId displayOrder updatedAt\n }\n }\n`;\n\nexport const DELETE_TAG = `\n mutation DeleteTag($id: ID!) {\n deleteTag(id: $id)\n }\n`;\n\nexport const TAG_ANALYTICS = `\n query TagAnalytics($tagId: ID!, $startDate: DateTime!, $endDate: DateTime!) {\n getTagAnalytics(tagId: $tagId, startDate: $startDate, endDate: $endDate) {\n assignmentCount date entityTypeBreakdown uniqueUsers uniqueEntities\n }\n }\n`;\n\nexport const TAG_RELATIONS = `\n query GetRelatedTags($tagId: ID!) {\n getRelatedTags(tagId: $tagId) {\n tag { id label }\n relationType\n }\n }\n`;\n\nexport const CREATE_TAG_RELATION = `\n mutation CreateTagRelation($input: CreateTagRelationInput!) {\n createTagRelation(input: $input) {\n id fromTagId toTagId relationType bidirectional\n }\n }\n`;\n\nexport const DELETE_TAG_RELATION = `\n mutation DeleteTagRelation($id: ID!) {\n deleteTagRelation(id: $id)\n }\n`;\n","/**\n * Tags MCP tools — CANONICAL reference module per CLAUDE.md.\n *\n * Surface (6 tools + 3 relation tools = 9): CRUD + analytics + relations.{list,grant,revoke}.\n * Mirrors cli-sdk/src/modules/tags/commands.ts (\"tags permissions\" Commander group ↔\n * the relation tools below — the underlying mutations are the same; \"permissions\"\n * is the user-facing surface name on the CLI side).\n *\n * Quality bar:\n * - Tight zod enums for every backend enum (TagScope, TagRelationType)\n * - Descriptive title + description on every tool (Claude Desktop renders these)\n * - Detailed `.describe()` on every input field for tool-call grounding\n * - Workspace-context guard surfaces a precise re-auth hint via errorResult\n * - Strict types: no `any`; `unknown` + cast only at request boundaries\n */\n\nimport { z } from 'zod';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { jsonResult, errorResult, mcpToolName, type McpContext } from '../../core/index.js';\nimport * as ops from './operations.js';\n\ninterface TagRow {\n id: string;\n key: string;\n label: string;\n description?: string | null;\n scope?: string;\n displayOrder?: number;\n}\n\ninterface TagDetail extends TagRow {\n color?: string | null;\n icon?: string | null;\n vocabularyId?: string | null;\n parentId?: string | null;\n assignmentCount?: number;\n usageCount?: number;\n hierarchyLevel?: number;\n hierarchyPath?: string[];\n}\n\ninterface RelatedTag {\n tag: { id: string; label: string };\n relationType: string;\n}\n\nconst TagScopeEnum = z\n .enum(['WORKSPACE', 'GLOBAL', 'VIBE'])\n .describe('Visibility scope of the tag');\n\nconst TagRelationTypeEnum = z\n .enum(['SYNONYM', 'ANTONYM', 'BROADER', 'NARROWER', 'RELATED', 'IMPLIES', 'EXCLUDES'])\n .describe(\n 'Semantic relationship between two tags (SYNONYM = same-meaning, BROADER/NARROWER = hierarchy, IMPLIES/EXCLUDES = behaviour, RELATED = generic)',\n );\n\ninterface WorkspaceCtx {\n workspaceId: string;\n}\n\n/**\n * Resolve the bound workspace context from the auth store. The tags service\n * requires `context.workspaceId` on every mutation input.\n *\n * Returns `errorResult` shape via the `error` channel when no workspace is\n * bound — the caller MUST short-circuit on that signal.\n */\nfunction resolveWorkspaceContext(\n ctx: McpContext,\n): { ok: true; ctx: WorkspaceCtx } | { ok: false; error: ReturnType<typeof errorResult> } {\n const auth = ctx.auth.read();\n const workspaceId = auth?.workspaceId;\n if (!workspaceId) {\n return {\n ok: false,\n error: errorResult(\n 'No workspace selected. Bind one with <product>_auth_select_workspace before calling tag tools.',\n ),\n };\n }\n return { ok: true, ctx: { workspaceId } };\n}\n\nexport function registerTagsTools(\n server: McpServer,\n ctx: McpContext,\n track: (n: string) => string,\n): void {\n // ── CRUD ────────────────────────────────────────────────────────────────\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_list')),\n {\n title: 'List Tags',\n description:\n 'List tags in the currently-bound workspace, with optional scope/search filters and pagination. Returns { items, total, hasMore }.',\n inputSchema: {\n scope: TagScopeEnum.optional().describe('Filter by scope'),\n search: z.string().optional().describe('Free-text search across key/label/description'),\n limit: z.number().optional().describe('Page size (default 100)'),\n offset: z.number().optional().describe('Pagination offset (default 0)'),\n },\n },\n async ({ scope, search, limit, offset }) => {\n try {\n const wctx = resolveWorkspaceContext(ctx);\n if (!wctx.ok) return wctx.error;\n\n const filter: Record<string, unknown> = { workspaceId: wctx.ctx.workspaceId };\n if (scope !== undefined) filter.scope = scope;\n if (search !== undefined) filter.search = search;\n\n const data = await ctx.gql.workspace.request<{\n getTags: { items: TagRow[]; total: number; hasMore: boolean };\n }>(ops.LIST_TAGS, {\n filter,\n pagination: { limit: limit ?? 100, offset: offset ?? 0 },\n });\n return jsonResult(data.getTags);\n } catch (error) {\n ctx.logger.error('tags_list failed', { error: String(error) });\n return errorResult(\n `Failed to list tags: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_get')),\n {\n title: 'Get Tag',\n description:\n 'Fetch a single tag by ID. Returns the full detail shape (color, icon, hierarchy, usage counters).',\n inputSchema: { id: z.string().describe('Tag ID') },\n },\n async ({ id }) => {\n try {\n const data = await ctx.gql.workspace.request<{ getTag: TagDetail | null }>(ops.GET_TAG, {\n id,\n });\n if (!data.getTag) {\n return errorResult(`Tag ${id} not found`);\n }\n return jsonResult(data.getTag);\n } catch (error) {\n ctx.logger.error('tags_get failed', { error: String(error) });\n return errorResult(\n `Failed to get tag: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_create')),\n {\n title: 'Create Tag',\n description:\n 'Create a tag in the currently-bound workspace. `key` must be unique within the (workspace, scope) tuple; `label` is the human-readable display name.',\n inputSchema: {\n key: z\n .string()\n .min(1)\n .describe('Stable identifier (kebab-case recommended); unique within workspace+scope'),\n label: z.string().min(1).describe('Human-readable display name'),\n description: z.string().optional().describe('Free-form description'),\n color: z\n .string()\n .optional()\n .describe('Hex color (e.g. #ff8800) — must be a semantic theme token in UI'),\n icon: z.string().optional().describe('Icon name (lucide-react identifier)'),\n scope: TagScopeEnum.optional().describe('Tag scope (default WORKSPACE)'),\n parentId: z.string().optional().describe('Parent tag ID for hierarchical taxonomies'),\n },\n },\n async ({ key, label, description, color, icon, scope, parentId }) => {\n try {\n const wctx = resolveWorkspaceContext(ctx);\n if (!wctx.ok) return wctx.error;\n\n const input: Record<string, unknown> = {\n context: wctx.ctx,\n key,\n label,\n scope: scope ?? 'WORKSPACE',\n };\n if (description !== undefined) input.description = description;\n if (color !== undefined) input.color = color;\n if (icon !== undefined) input.icon = icon;\n if (parentId !== undefined) input.parentId = parentId;\n\n const data = await ctx.gql.workspace.request<{ createTag: TagRow }>(ops.CREATE_TAG, {\n input,\n });\n return jsonResult(data.createTag);\n } catch (error) {\n ctx.logger.error('tags_create failed', { error: String(error) });\n return errorResult(\n `Failed to create tag: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_update')),\n {\n title: 'Update Tag',\n description:\n 'Update a tag. At least one mutable field (label / description / color / icon / parentId / displayOrder) must be provided. The workspace context is implicit.',\n inputSchema: {\n id: z.string().describe('Tag ID'),\n label: z.string().optional().describe('Updated display name'),\n description: z\n .string()\n .optional()\n .describe('Updated description (pass empty string to clear)'),\n color: z.string().optional().describe('Updated hex color'),\n icon: z.string().optional().describe('Updated icon name'),\n parentId: z.string().optional().describe('Updated parent tag ID'),\n displayOrder: z\n .number()\n .int()\n .optional()\n .describe('Updated display order within parent (lower sorts first)'),\n },\n },\n async ({ id, label, description, color, icon, parentId, displayOrder }) => {\n try {\n const wctx = resolveWorkspaceContext(ctx);\n if (!wctx.ok) return wctx.error;\n\n const input: Record<string, unknown> = { context: wctx.ctx };\n if (label !== undefined) input.label = label;\n if (description !== undefined) input.description = description;\n if (color !== undefined) input.color = color;\n if (icon !== undefined) input.icon = icon;\n if (parentId !== undefined) input.parentId = parentId;\n if (displayOrder !== undefined) input.displayOrder = displayOrder;\n\n // `context` is always present so length === 1 means no real updates.\n if (Object.keys(input).length === 1) {\n return errorResult(\n 'No updates specified — provide at least one of label/description/color/icon/parentId/displayOrder',\n );\n }\n\n const data = await ctx.gql.workspace.request<{ updateTag: TagRow }>(ops.UPDATE_TAG, {\n id,\n input,\n });\n return jsonResult(data.updateTag);\n } catch (error) {\n ctx.logger.error('tags_update failed', { error: String(error) });\n return errorResult(\n `Failed to update tag: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_delete')),\n {\n title: 'Delete Tag',\n description:\n 'Permanently delete a tag and all its assignments. This is destructive — there is no soft-delete on the tags service.',\n inputSchema: { id: z.string().describe('Tag ID to delete') },\n },\n async ({ id }) => {\n try {\n const data = await ctx.gql.workspace.request<{ deleteTag: boolean }>(ops.DELETE_TAG, {\n id,\n });\n return jsonResult({ deleted: data.deleteTag, tagId: id });\n } catch (error) {\n ctx.logger.error('tags_delete failed', { error: String(error) });\n return errorResult(\n `Failed to delete tag: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n // ── Analytics ───────────────────────────────────────────────────────────\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_analytics')),\n {\n title: 'Tag Usage Analytics',\n description:\n 'Time-bucketed analytics for a tag: assignmentCount, uniqueUsers, uniqueEntities, and entityType breakdown over the [from, to] window.',\n inputSchema: {\n tagId: z.string().describe('Tag ID to analyse'),\n from: z.string().describe('Start of the window in ISO-8601 (DateTime)'),\n to: z.string().describe('End of the window in ISO-8601 (DateTime)'),\n },\n },\n async ({ tagId, from, to }) => {\n try {\n const data = await ctx.gql.workspace.request<{\n getTagAnalytics: Record<string, unknown>;\n }>(ops.TAG_ANALYTICS, { tagId, startDate: from, endDate: to });\n return jsonResult(data.getTagAnalytics);\n } catch (error) {\n ctx.logger.error('tags_analytics failed', { error: String(error) });\n return errorResult(\n `Failed to get tag analytics: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n // ── Relations (CLI's \"permissions\" group is named for the user-facing\n // semantic — under the hood these are tag-relation mutations) ──────────\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_permissions_list')),\n {\n title: 'List Tag Relations',\n description:\n 'List all tag relations originating from the given tag (synonyms, hierarchy, implies/excludes, etc.).',\n inputSchema: { tagId: z.string().describe('Tag ID') },\n },\n async ({ tagId }) => {\n try {\n const data = await ctx.gql.workspace.request<{ getRelatedTags: RelatedTag[] }>(\n ops.TAG_RELATIONS,\n { tagId },\n );\n return jsonResult(data.getRelatedTags);\n } catch (error) {\n ctx.logger.error('tags_permissions_list failed', { error: String(error) });\n return errorResult(\n `Failed to list tag relations: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_permissions_grant')),\n {\n title: 'Create Tag Relation',\n description:\n 'Create a typed relation between two tags. Set bidirectional=true to mirror the relation in both directions (only meaningful for symmetric types like SYNONYM, ANTONYM, RELATED).',\n inputSchema: {\n fromTagId: z.string().describe('Source tag ID'),\n toTagId: z.string().describe('Target tag ID'),\n relationType: TagRelationTypeEnum.describe('Relation type'),\n bidirectional: z\n .boolean()\n .optional()\n .describe('Mirror the relation in the reverse direction (default false)'),\n },\n },\n async ({ fromTagId, toTagId, relationType, bidirectional }) => {\n try {\n const wctx = resolveWorkspaceContext(ctx);\n if (!wctx.ok) return wctx.error;\n\n const input: Record<string, unknown> = {\n context: wctx.ctx,\n fromTagId,\n toTagId,\n relationType,\n bidirectional: bidirectional ?? false,\n };\n const data = await ctx.gql.workspace.request<{\n createTagRelation: Record<string, unknown>;\n }>(ops.CREATE_TAG_RELATION, { input });\n return jsonResult(data.createTagRelation);\n } catch (error) {\n ctx.logger.error('tags_permissions_grant failed', { error: String(error) });\n return errorResult(\n `Failed to create tag relation: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'tags_permissions_revoke')),\n {\n title: 'Delete Tag Relation',\n description: 'Delete a tag relation by its relation ID.',\n inputSchema: { relationId: z.string().describe('Relation ID to delete') },\n },\n async ({ relationId }) => {\n try {\n const data = await ctx.gql.workspace.request<{ deleteTagRelation: boolean }>(\n ops.DELETE_TAG_RELATION,\n { id: relationId },\n );\n return jsonResult({ deleted: data.deleteTagRelation, relationId });\n } catch (error) {\n ctx.logger.error('tags_permissions_revoke failed', { error: String(error) });\n return errorResult(\n `Failed to delete tag relation: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n}\n","/**\n * Tags module — CANONICAL reference module per CLAUDE.md.\n *\n * Tools: <product>_tags_{list,get,create,update,delete,analytics} +\n * <product>_tags_relations_{list,grant,revoke}.\n *\n * Backend: ~/products/wspace/tags/wspace-tags-svc/.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { McpContext, McpModule, ModuleRegistration } from '../../core/index.js';\nimport { registerTagsTools } from './tools.js';\n\nconst tagsModule: McpModule = {\n id: 'tags',\n version: '0.0.1',\n displayName: 'Tags',\n dependsOn: ['auth'],\n capabilities: { tools: {} },\n register(server: McpServer, ctx: McpContext): ModuleRegistration {\n const tools: string[] = [];\n const track = (n: string): string => {\n tools.push(n);\n return n;\n };\n registerTagsTools(server, ctx, track);\n return { tools, resources: [], prompts: [] };\n },\n};\n\nexport default tagsModule;\n"]}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
require('graphql-request');
|
|
5
|
+
require('cross-fetch');
|
|
6
|
+
require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
7
|
+
require('@modelcontextprotocol/sdk/types.js');
|
|
8
|
+
|
|
9
|
+
// src/modules/tours/tools.ts
|
|
10
|
+
|
|
11
|
+
// src/core/errors.ts
|
|
12
|
+
var McpInternalError = class extends Error {
|
|
13
|
+
cause;
|
|
14
|
+
constructor(message, cause) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "McpInternalError";
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/core/result.ts
|
|
22
|
+
function jsonResult(data, structured) {
|
|
23
|
+
const result = {
|
|
24
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
25
|
+
};
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
function errorResult(message, hint) {
|
|
29
|
+
const text = hint ? `${message}
|
|
30
|
+
|
|
31
|
+
Hint: ${hint}` : message;
|
|
32
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/core/tool-name.ts
|
|
36
|
+
var MAX_TOOL_NAME_LENGTH = 63;
|
|
37
|
+
function assertSafeName(name, kind) {
|
|
38
|
+
if (name.length > MAX_TOOL_NAME_LENGTH) {
|
|
39
|
+
throw new McpInternalError(
|
|
40
|
+
`Tool name '${name}' exceeds ${MAX_TOOL_NAME_LENGTH} characters (some MCP clients truncate at 64).`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return name;
|
|
44
|
+
}
|
|
45
|
+
function mcpToolName(productName, ...parts) {
|
|
46
|
+
if (!productName) {
|
|
47
|
+
throw new McpInternalError("mcpToolName: productName is required");
|
|
48
|
+
}
|
|
49
|
+
const name = [productName, ...parts].filter(Boolean).join("_");
|
|
50
|
+
return assertSafeName(name);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/modules/tours/operations.ts
|
|
54
|
+
var LIST_TOURS = `
|
|
55
|
+
query ListTours($filters: TourFilters, $pagination: TourPagination) {
|
|
56
|
+
tours(filters: $filters, pagination: $pagination) {
|
|
57
|
+
tours {
|
|
58
|
+
id
|
|
59
|
+
name
|
|
60
|
+
slug
|
|
61
|
+
description
|
|
62
|
+
status
|
|
63
|
+
isActive
|
|
64
|
+
productId
|
|
65
|
+
moduleId
|
|
66
|
+
priority
|
|
67
|
+
displayOrder
|
|
68
|
+
createdAt
|
|
69
|
+
updatedAt
|
|
70
|
+
}
|
|
71
|
+
total
|
|
72
|
+
hasMore
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
var GET_USER_TOUR_PROGRESS = `
|
|
77
|
+
query GetUserTourProgress($userId: ID, $pagination: TourPagination) {
|
|
78
|
+
userTourProgresses(userId: $userId, pagination: $pagination) {
|
|
79
|
+
id
|
|
80
|
+
tourId
|
|
81
|
+
userId
|
|
82
|
+
status
|
|
83
|
+
currentStepId
|
|
84
|
+
currentStepOrder
|
|
85
|
+
completedSteps
|
|
86
|
+
skippedSteps
|
|
87
|
+
startedAt
|
|
88
|
+
completedAt
|
|
89
|
+
lastViewedAt
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
var RESET_TOUR_PROGRESS = `
|
|
94
|
+
mutation ResetTourProgress($tourId: ID!, $userId: ID!) {
|
|
95
|
+
resetTourProgress(tourId: $tourId, userId: $userId) {
|
|
96
|
+
id
|
|
97
|
+
tourId
|
|
98
|
+
status
|
|
99
|
+
currentStepId
|
|
100
|
+
currentStepOrder
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
104
|
+
|
|
105
|
+
// src/modules/tours/tools.ts
|
|
106
|
+
function registerToursTools(server, ctx, track) {
|
|
107
|
+
server.registerTool(
|
|
108
|
+
track(mcpToolName(ctx.productName, "tours_list")),
|
|
109
|
+
{
|
|
110
|
+
title: "List Tours",
|
|
111
|
+
description: "List available product tours.",
|
|
112
|
+
inputSchema: {
|
|
113
|
+
productId: zod.z.string().optional().describe("Filter by productId"),
|
|
114
|
+
moduleId: zod.z.string().optional().describe("Filter by moduleId"),
|
|
115
|
+
status: zod.z.string().optional().describe("Filter by status"),
|
|
116
|
+
isActive: zod.z.boolean().optional().describe("Only active tours"),
|
|
117
|
+
limit: zod.z.number().optional().describe("Page size"),
|
|
118
|
+
offset: zod.z.number().optional().describe("Offset for pagination")
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
async ({ productId, moduleId, status, isActive, limit, offset }) => {
|
|
122
|
+
try {
|
|
123
|
+
const filters = {};
|
|
124
|
+
if (productId !== void 0) filters.productId = productId;
|
|
125
|
+
if (moduleId !== void 0) filters.moduleId = moduleId;
|
|
126
|
+
if (status !== void 0) filters.status = status.toUpperCase();
|
|
127
|
+
if (isActive !== void 0) filters.isActive = isActive;
|
|
128
|
+
const data = await ctx.gql.global.request(LIST_TOURS, {
|
|
129
|
+
filters: Object.keys(filters).length ? filters : void 0,
|
|
130
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0 }
|
|
131
|
+
});
|
|
132
|
+
return jsonResult(data.tours);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
ctx.logger.error("tours_list failed", { error: String(error) });
|
|
135
|
+
return errorResult(
|
|
136
|
+
`Failed to list tours: ${error instanceof Error ? error.message : String(error)}`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
server.registerTool(
|
|
142
|
+
track(mcpToolName(ctx.productName, "tours_progress_get")),
|
|
143
|
+
{
|
|
144
|
+
title: "Get Tour Progress",
|
|
145
|
+
description: "Get the current user's tour progress, optionally filtered by user id.",
|
|
146
|
+
inputSchema: {
|
|
147
|
+
userId: zod.z.string().optional().describe("User ID (defaults to current actor)"),
|
|
148
|
+
limit: zod.z.number().optional().describe("Page size"),
|
|
149
|
+
offset: zod.z.number().optional().describe("Offset for pagination")
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
async ({ userId, limit, offset }) => {
|
|
153
|
+
try {
|
|
154
|
+
const data = await ctx.gql.global.request(
|
|
155
|
+
GET_USER_TOUR_PROGRESS,
|
|
156
|
+
{
|
|
157
|
+
userId,
|
|
158
|
+
pagination: { limit: limit ?? 50, offset: offset ?? 0 }
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
return jsonResult(data.userTourProgresses);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
ctx.logger.error("tours_progress_get failed", { error: String(error) });
|
|
164
|
+
return errorResult(
|
|
165
|
+
`Failed to get tour progress: ${error instanceof Error ? error.message : String(error)}`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
server.registerTool(
|
|
171
|
+
track(mcpToolName(ctx.productName, "tours_progress_reset")),
|
|
172
|
+
{
|
|
173
|
+
title: "Reset Tour Progress",
|
|
174
|
+
description: "Reset tour progress for the given user (defaults to the current actor).",
|
|
175
|
+
inputSchema: {
|
|
176
|
+
tourId: zod.z.string().describe("Tour ID"),
|
|
177
|
+
userId: zod.z.string().optional().describe("User ID (defaults to current actor)")
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
async ({ tourId, userId }) => {
|
|
181
|
+
try {
|
|
182
|
+
const auth = ctx.auth.read();
|
|
183
|
+
const resolvedUserId = userId ?? auth?.workspaceId;
|
|
184
|
+
if (!resolvedUserId) {
|
|
185
|
+
return errorResult(
|
|
186
|
+
"Unable to resolve user; pass userId or authenticate to a workspace first."
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
const data = await ctx.gql.global.request(
|
|
190
|
+
RESET_TOUR_PROGRESS,
|
|
191
|
+
{ tourId, userId: resolvedUserId }
|
|
192
|
+
);
|
|
193
|
+
return jsonResult(data.resetTourProgress);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
ctx.logger.error("tours_progress_reset failed", { error: String(error) });
|
|
196
|
+
return errorResult(
|
|
197
|
+
`Failed to reset tour progress: ${error instanceof Error ? error.message : String(error)}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/modules/tours/index.ts
|
|
205
|
+
var toursModule = {
|
|
206
|
+
id: "tours",
|
|
207
|
+
version: "0.0.1",
|
|
208
|
+
displayName: "Tours",
|
|
209
|
+
dependsOn: ["auth"],
|
|
210
|
+
capabilities: { tools: {} },
|
|
211
|
+
register(server, ctx) {
|
|
212
|
+
const tools = [];
|
|
213
|
+
const track = (n) => {
|
|
214
|
+
tools.push(n);
|
|
215
|
+
return n;
|
|
216
|
+
};
|
|
217
|
+
registerToursTools(server, ctx, track);
|
|
218
|
+
return { tools, resources: [], prompts: [] };
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
var tours_default = toursModule;
|
|
222
|
+
|
|
223
|
+
module.exports = tours_default;
|
|
224
|
+
//# sourceMappingURL=index.cjs.map
|
|
225
|
+
//# sourceMappingURL=index.cjs.map
|