@crypto512/jicon-mcp 1.3.0 → 2.0.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 +68 -85
- package/TOOL_LIST.md +704 -87
- package/dist/config/constants.d.ts +18 -7
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +21 -8
- package/dist/config/constants.js.map +1 -1
- package/dist/config/loader.d.ts +11 -11
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +53 -93
- package/dist/config/loader.js.map +1 -1
- package/dist/config/types.d.ts +3 -6
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +2 -4
- package/dist/config/types.js.map +1 -1
- package/dist/confluence/formatters.js +1 -1
- package/dist/confluence/formatters.js.map +1 -1
- package/dist/confluence/tools.d.ts +4 -0
- package/dist/confluence/tools.d.ts.map +1 -1
- package/dist/confluence/tools.js +180 -125
- package/dist/confluence/tools.js.map +1 -1
- package/dist/index.js +17 -26
- package/dist/index.js.map +1 -1
- package/dist/jira/formatters.d.ts +1 -0
- package/dist/jira/formatters.d.ts.map +1 -1
- package/dist/jira/formatters.js +13 -12
- package/dist/jira/formatters.js.map +1 -1
- package/dist/jira/tools.d.ts +4 -0
- package/dist/jira/tools.d.ts.map +1 -1
- package/dist/jira/tools.js +189 -50
- package/dist/jira/tools.js.map +1 -1
- package/dist/permissions/tool-registry.d.ts +2 -2
- package/dist/permissions/tool-registry.d.ts.map +1 -1
- package/dist/permissions/tool-registry.js +4 -2
- package/dist/permissions/tool-registry.js.map +1 -1
- package/dist/permissions/write-home-validator.d.ts.map +1 -1
- package/dist/permissions/write-home-validator.js +13 -3
- package/dist/permissions/write-home-validator.js.map +1 -1
- package/dist/tempo/defaults.d.ts +17 -0
- package/dist/tempo/defaults.d.ts.map +1 -0
- package/dist/tempo/defaults.js +26 -0
- package/dist/tempo/defaults.js.map +1 -0
- package/dist/tempo/tools.d.ts +5 -0
- package/dist/tempo/tools.d.ts.map +1 -1
- package/dist/tempo/tools.js +108 -34
- package/dist/tempo/tools.js.map +1 -1
- package/dist/utils/buffer-pipeline/index.d.ts +30 -0
- package/dist/utils/buffer-pipeline/index.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/index.js +317 -0
- package/dist/utils/buffer-pipeline/index.js.map +1 -0
- package/dist/utils/buffer-pipeline/output/csv.d.ts +20 -0
- package/dist/utils/buffer-pipeline/output/csv.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/output/csv.js +117 -0
- package/dist/utils/buffer-pipeline/output/csv.js.map +1 -0
- package/dist/utils/buffer-pipeline/output/json.d.ts +16 -0
- package/dist/utils/buffer-pipeline/output/json.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/output/json.js +48 -0
- package/dist/utils/buffer-pipeline/output/json.js.map +1 -0
- package/dist/utils/buffer-pipeline/output/markdown.d.ts +15 -0
- package/dist/utils/buffer-pipeline/output/markdown.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/output/markdown.js +105 -0
- package/dist/utils/buffer-pipeline/output/markdown.js.map +1 -0
- package/dist/utils/buffer-pipeline/output/xhtml-list.d.ts +16 -0
- package/dist/utils/buffer-pipeline/output/xhtml-list.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/output/xhtml-list.js +81 -0
- package/dist/utils/buffer-pipeline/output/xhtml-list.js.map +1 -0
- package/dist/utils/buffer-pipeline/output/xhtml-table.d.ts +15 -0
- package/dist/utils/buffer-pipeline/output/xhtml-table.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/output/xhtml-table.js +176 -0
- package/dist/utils/buffer-pipeline/output/xhtml-table.js.map +1 -0
- package/dist/utils/buffer-pipeline/schema.d.ts +1878 -0
- package/dist/utils/buffer-pipeline/schema.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/schema.js +168 -0
- package/dist/utils/buffer-pipeline/schema.js.map +1 -0
- package/dist/utils/buffer-pipeline/stages/filter.d.ts +32 -0
- package/dist/utils/buffer-pipeline/stages/filter.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/stages/filter.js +208 -0
- package/dist/utils/buffer-pipeline/stages/filter.js.map +1 -0
- package/dist/utils/buffer-pipeline/stages/format.d.ts +45 -0
- package/dist/utils/buffer-pipeline/stages/format.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/stages/format.js +160 -0
- package/dist/utils/buffer-pipeline/stages/format.js.map +1 -0
- package/dist/utils/buffer-pipeline/stages/group-by.d.ts +25 -0
- package/dist/utils/buffer-pipeline/stages/group-by.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/stages/group-by.js +190 -0
- package/dist/utils/buffer-pipeline/stages/group-by.js.map +1 -0
- package/dist/utils/buffer-pipeline/stages/select.d.ts +54 -0
- package/dist/utils/buffer-pipeline/stages/select.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/stages/select.js +228 -0
- package/dist/utils/buffer-pipeline/stages/select.js.map +1 -0
- package/dist/utils/buffer-pipeline/stages/sort.d.ts +20 -0
- package/dist/utils/buffer-pipeline/stages/sort.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/stages/sort.js +96 -0
- package/dist/utils/buffer-pipeline/stages/sort.js.map +1 -0
- package/dist/utils/buffer-pipeline/types.d.ts +277 -0
- package/dist/utils/buffer-pipeline/types.d.ts.map +1 -0
- package/dist/utils/buffer-pipeline/types.js +8 -0
- package/dist/utils/buffer-pipeline/types.js.map +1 -0
- package/dist/utils/buffer-tools.d.ts +749 -19
- package/dist/utils/buffer-tools.d.ts.map +1 -1
- package/dist/utils/buffer-tools.js +738 -491
- package/dist/utils/buffer-tools.js.map +1 -1
- package/dist/utils/content-buffer.d.ts +55 -4
- package/dist/utils/content-buffer.d.ts.map +1 -1
- package/dist/utils/content-buffer.js +107 -9
- package/dist/utils/content-buffer.js.map +1 -1
- package/dist/utils/jicon-help.d.ts +1 -1
- package/dist/utils/jicon-help.d.ts.map +1 -1
- package/dist/utils/jicon-help.js +253 -28
- package/dist/utils/jicon-help.js.map +1 -1
- package/dist/utils/json-structure.d.ts +121 -0
- package/dist/utils/json-structure.d.ts.map +1 -0
- package/dist/utils/json-structure.js +637 -0
- package/dist/utils/json-structure.js.map +1 -0
- package/dist/utils/plantuml/include-expander.d.ts +31 -30
- package/dist/utils/plantuml/include-expander.d.ts.map +1 -1
- package/dist/utils/plantuml/include-expander.js +167 -133
- package/dist/utils/plantuml/include-expander.js.map +1 -1
- package/dist/utils/plantuml/index.d.ts +3 -3
- package/dist/utils/plantuml/index.d.ts.map +1 -1
- package/dist/utils/plantuml/index.js +4 -4
- package/dist/utils/plantuml/index.js.map +1 -1
- package/dist/utils/plantuml/service.d.ts +13 -24
- package/dist/utils/plantuml/service.d.ts.map +1 -1
- package/dist/utils/plantuml/service.js +49 -99
- package/dist/utils/plantuml/service.js.map +1 -1
- package/dist/utils/plantuml/tools.d.ts.map +1 -1
- package/dist/utils/plantuml/tools.js +33 -72
- package/dist/utils/plantuml/tools.js.map +1 -1
- package/dist/utils/plantuml/types.d.ts +1 -35
- package/dist/utils/plantuml/types.d.ts.map +1 -1
- package/dist/utils/plantuml/types.js +1 -11
- package/dist/utils/plantuml/types.js.map +1 -1
- package/dist/utils/plantuml/validation-helper.d.ts +1 -1
- package/dist/utils/plantuml/validation-helper.js +12 -12
- package/dist/utils/plantuml/validation-helper.js.map +1 -1
- package/dist/utils/response-formatter.d.ts +61 -6
- package/dist/utils/response-formatter.d.ts.map +1 -1
- package/dist/utils/response-formatter.js +174 -91
- package/dist/utils/response-formatter.js.map +1 -1
- package/dist/utils/url-tools.d.ts.map +1 -1
- package/dist/utils/url-tools.js +22 -0
- package/dist/utils/url-tools.js.map +1 -1
- package/dist/utils/xhtml/error-locator.js +2 -2
- package/dist/utils/xhtml/error-locator.js.map +1 -1
- package/dist/utils/xhtml/index.d.ts +1 -1
- package/dist/utils/xhtml/index.d.ts.map +1 -1
- package/dist/utils/xhtml/index.js +1 -1
- package/dist/utils/xhtml/index.js.map +1 -1
- package/dist/utils/xhtml/parser.d.ts +34 -5
- package/dist/utils/xhtml/parser.d.ts.map +1 -1
- package/dist/utils/xhtml/parser.js +66 -11
- package/dist/utils/xhtml/parser.js.map +1 -1
- package/dist/utils/xhtml/plantuml.d.ts.map +1 -1
- package/dist/utils/xhtml/plantuml.js +5 -3
- package/dist/utils/xhtml/plantuml.js.map +1 -1
- package/dist/utils/xhtml/serializer.d.ts.map +1 -1
- package/dist/utils/xhtml/serializer.js +12 -15
- package/dist/utils/xhtml/serializer.js.map +1 -1
- package/package.json +12 -4
- package/crypto512-jicon-mcp-1.3.0.tgz +0 -0
package/dist/confluence/tools.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Confluence MCP Tools
|
|
3
3
|
*/
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { formatSuccess,
|
|
5
|
+
import { formatSuccess, formatSuccessJson, formatSuccessXhtml, formatError, isApiError } from "../utils/response-formatter.js";
|
|
6
6
|
import { contentBuffer } from "../utils/content-buffer.js";
|
|
7
7
|
import { formatPageMetadata } from "./formatters.js";
|
|
8
|
-
import { validateXhtmlAsync, parseXhtml,
|
|
8
|
+
import { validateXhtmlAsync, parseXhtml, enhanceXhtmlError } from "../utils/xhtml/index.js";
|
|
9
9
|
import { detectRawPlantUml, detectDiagramType } from "../utils/xhtml/plantuml.js";
|
|
10
|
-
import {
|
|
10
|
+
import { convertPlantUmlIncludesInXhtml, IncludeConversionError } from "../utils/plantuml/index.js";
|
|
11
11
|
import { parseUrl } from "../utils/url-tools.js";
|
|
12
12
|
import { DEFAULT_PAGE_EXPAND } from "./defaults.js";
|
|
13
13
|
/**
|
|
@@ -136,30 +136,20 @@ async function validateContentForWrite(content, bufferId) {
|
|
|
136
136
|
}
|
|
137
137
|
return null; // Valid content
|
|
138
138
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Store XHTML content in buffer with element IDs for structured editing.
|
|
141
|
-
* Parses XHTML, assigns data-jicon-id attributes, and stores with structure.
|
|
142
|
-
* Content is validated before Confluence writes, so parsing always succeeds.
|
|
143
|
-
*/
|
|
144
|
-
function storeXhtmlWithStructure(content, metadata) {
|
|
145
|
-
const parseResult = parseXhtml(content);
|
|
146
|
-
const structureResult = parseStructure(parseResult.document);
|
|
147
|
-
const contentWithIds = serializeXhtml(parseResult.document);
|
|
148
|
-
const bufferId = contentBuffer.storeWithStructure(contentWithIds, structureResult.structure, structureResult.nextId, metadata);
|
|
149
|
-
return { bufferId, structure: structureResult.structure };
|
|
150
|
-
}
|
|
151
139
|
export function createConfluenceTools(client) {
|
|
152
140
|
return {
|
|
153
141
|
confluence_search_content: {
|
|
154
|
-
description: `Search Confluence content using CQL. Auto-fetches all results.
|
|
142
|
+
description: `Search Confluence content using CQL. Auto-fetches all results (up to 5000).
|
|
155
143
|
|
|
156
|
-
|
|
144
|
+
Entry point for finding Confluence pages by content, title, or metadata.
|
|
157
145
|
|
|
158
|
-
|
|
146
|
+
REQUIRES: Valid CQL query (see help(topic="cql") for syntax)
|
|
147
|
+
RETURNS: bufferId (JSON array), itemCount with page IDs and titles
|
|
148
|
+
NEXT: confluence_get_page (to load), buffer_pipeline (for reports), buffer_grep (to search results)
|
|
159
149
|
|
|
160
|
-
Example: type=page AND space=DOCS AND text~
|
|
150
|
+
Example: confluence_search_content(cql="type=page AND space=DOCS AND text~'API'")
|
|
161
151
|
|
|
162
|
-
WARNING: Use text~
|
|
152
|
+
WARNING: Use text~ not content~. Use space KEY not name.`,
|
|
163
153
|
inputSchema: z.object({
|
|
164
154
|
cql: z.string().describe("CQL query string"),
|
|
165
155
|
expand: z.array(z.string()).optional().describe("Additional data to expand"),
|
|
@@ -167,7 +157,7 @@ WARNING: Use text~ (not content~ or body~). Use space KEY (not name).`,
|
|
|
167
157
|
handler: async (args) => {
|
|
168
158
|
try {
|
|
169
159
|
const result = await client.searchContentAll(args.cql, args.expand);
|
|
170
|
-
return
|
|
160
|
+
return formatSuccessJson(result, {
|
|
171
161
|
resourceType: "confluence_search",
|
|
172
162
|
title: `CQL: ${args.cql.substring(0, 100)}${args.cql.length > 100 ? "..." : ""}`,
|
|
173
163
|
});
|
|
@@ -239,18 +229,19 @@ Use buffer_edit(bufferId, after=ID, content/plantuml/fromBufferId) to add conten
|
|
|
239
229
|
handler: async (args) => {
|
|
240
230
|
try {
|
|
241
231
|
const result = await client.getPage(args.pageId, args.expand);
|
|
242
|
-
const
|
|
243
|
-
// Collapse expanded includes back to !include directives
|
|
244
|
-
const content = collapseExpandedIncludesInXhtml(rawContent);
|
|
232
|
+
const content = result.body?.storage?.value || "";
|
|
245
233
|
// Store content with element IDs for structured editing
|
|
246
|
-
const
|
|
234
|
+
const xhtmlResult = formatSuccessXhtml(content, {
|
|
247
235
|
resourceType: "confluence_page",
|
|
248
236
|
resourceId: String(result.id),
|
|
249
|
-
contentType: "xhtml",
|
|
250
237
|
version: result.version?.number,
|
|
251
238
|
spaceKey: result.space?.key,
|
|
252
|
-
title: result.title,
|
|
239
|
+
title: result.title || args.pageId,
|
|
253
240
|
});
|
|
241
|
+
if ("errorResult" in xhtmlResult) {
|
|
242
|
+
return xhtmlResult.errorResult;
|
|
243
|
+
}
|
|
244
|
+
const { bufferId, structure } = xhtmlResult;
|
|
254
245
|
return formatSuccess({
|
|
255
246
|
...formatPageMetadata(result),
|
|
256
247
|
pageId: result.id,
|
|
@@ -288,18 +279,19 @@ Use buffer_edit(bufferId, after=ID, content/plantuml/fromBufferId) to add conten
|
|
|
288
279
|
statusCode: 404,
|
|
289
280
|
});
|
|
290
281
|
}
|
|
291
|
-
const
|
|
292
|
-
// Collapse expanded includes back to !include directives
|
|
293
|
-
const content = collapseExpandedIncludesInXhtml(rawContent);
|
|
282
|
+
const content = result.body?.storage?.value || "";
|
|
294
283
|
// Store content with element IDs for structured editing
|
|
295
|
-
const
|
|
284
|
+
const xhtmlResult = formatSuccessXhtml(content, {
|
|
296
285
|
resourceType: "confluence_page",
|
|
297
286
|
resourceId: String(result.id),
|
|
298
|
-
contentType: "xhtml",
|
|
299
287
|
version: result.version?.number,
|
|
300
288
|
spaceKey: result.space?.key,
|
|
301
|
-
title: result.title,
|
|
289
|
+
title: result.title || args.title,
|
|
302
290
|
});
|
|
291
|
+
if ("errorResult" in xhtmlResult) {
|
|
292
|
+
return xhtmlResult.errorResult;
|
|
293
|
+
}
|
|
294
|
+
const { bufferId, structure } = xhtmlResult;
|
|
303
295
|
return formatSuccess({
|
|
304
296
|
...formatPageMetadata(result),
|
|
305
297
|
pageId: result.id,
|
|
@@ -316,27 +308,11 @@ Use buffer_edit(bufferId, after=ID, content/plantuml/fromBufferId) to add conten
|
|
|
316
308
|
},
|
|
317
309
|
},
|
|
318
310
|
confluence_edit: {
|
|
319
|
-
description: `
|
|
311
|
+
description: `Load page/draft for editing. Returns bufferId, structure (element IDs), pageId, version.
|
|
320
312
|
|
|
321
|
-
ACCEPTS
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
- Full URL: https://confluence.example.com/display/SPACE/Page+Title
|
|
325
|
-
- Page ID: "123456"
|
|
326
|
-
- Draft ID: "draft:123456" (prefix with "draft:")
|
|
327
|
-
- Space/Title: "DOCS/API Guide"
|
|
328
|
-
|
|
329
|
-
SMART BEHAVIOR:
|
|
330
|
-
- URLs are parsed automatically to extract pageId or draftId
|
|
331
|
-
- Draft IDs: tries to load draft; if 404 (published), finds page by title
|
|
332
|
-
- Returns bufferId + structure + pageId for editing
|
|
333
|
-
|
|
334
|
-
WORKFLOW:
|
|
335
|
-
1. confluence_edit(input) → bufferId, structure, pageId
|
|
336
|
-
2. buffer_edit(bufferId, ...) → modify content
|
|
337
|
-
3. confluence_draft_create(pageId=..., bufferId=...) → draft linked to original page
|
|
338
|
-
4. User publishes via Confluence UI (updates original page)
|
|
339
|
-
5. For more edits: confluence_edit(same URL or "SPACE/Title") → auto-resolves`,
|
|
313
|
+
ACCEPTS: URL | pageId | "draft:ID" | "SPACE/Title"
|
|
314
|
+
RETURNS: bufferId, structure, pageId, version
|
|
315
|
+
NEXT: buffer_edit → confluence_draft_create → confluence_review_publish`,
|
|
340
316
|
inputSchema: z.object({
|
|
341
317
|
input: z.string().describe('URL, pageId, "draft:ID", or "SPACE/Title"'),
|
|
342
318
|
}),
|
|
@@ -351,16 +327,18 @@ WORKFLOW:
|
|
|
351
327
|
}
|
|
352
328
|
// Helper to load page content and return formatted result
|
|
353
329
|
const loadPageContent = async (pageResult) => {
|
|
354
|
-
const
|
|
355
|
-
const
|
|
356
|
-
const { bufferId, structure } = storeXhtmlWithStructure(content, {
|
|
330
|
+
const content = pageResult.body?.storage?.value || "";
|
|
331
|
+
const xhtmlResult = formatSuccessXhtml(content, {
|
|
357
332
|
resourceType: "confluence_page",
|
|
358
333
|
resourceId: String(pageResult.id),
|
|
359
|
-
contentType: "xhtml",
|
|
360
334
|
version: pageResult.version?.number,
|
|
361
335
|
spaceKey: pageResult.space?.key,
|
|
362
336
|
title: pageResult.title,
|
|
363
337
|
});
|
|
338
|
+
if ("errorResult" in xhtmlResult) {
|
|
339
|
+
throw new Error("Failed to parse XHTML content");
|
|
340
|
+
}
|
|
341
|
+
const { bufferId, structure } = xhtmlResult;
|
|
364
342
|
return {
|
|
365
343
|
pageId: pageResult.id,
|
|
366
344
|
spaceKey: pageResult.space?.key,
|
|
@@ -375,16 +353,18 @@ WORKFLOW:
|
|
|
375
353
|
// Helper to load draft content
|
|
376
354
|
const loadDraftContent = async (draftId) => {
|
|
377
355
|
const result = await client.getDraft(draftId);
|
|
378
|
-
const
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
resourceType: "confluence_page",
|
|
356
|
+
const content = result.body?.storage?.value || "";
|
|
357
|
+
const xhtmlResult = formatSuccessXhtml(content, {
|
|
358
|
+
resourceType: "confluence_draft",
|
|
382
359
|
resourceId: String(result.id),
|
|
383
|
-
contentType: "xhtml",
|
|
384
360
|
spaceKey: result.space?.key,
|
|
385
361
|
title: result.title,
|
|
386
362
|
isDraft: true,
|
|
387
363
|
});
|
|
364
|
+
if ("errorResult" in xhtmlResult) {
|
|
365
|
+
throw new Error("Failed to parse XHTML content");
|
|
366
|
+
}
|
|
367
|
+
const { bufferId, structure } = xhtmlResult;
|
|
388
368
|
return {
|
|
389
369
|
draftId: result.id,
|
|
390
370
|
spaceKey: result.space?.key,
|
|
@@ -508,7 +488,15 @@ WORKFLOW:
|
|
|
508
488
|
// - New pages: confluence_draft_create → user publishes
|
|
509
489
|
// - Existing pages: confluence_get_page → buffer_edit → confluence_draft_create → user publishes
|
|
510
490
|
confluence_delete_page: {
|
|
511
|
-
description:
|
|
491
|
+
description: `Delete a Confluence page permanently.
|
|
492
|
+
|
|
493
|
+
Page is moved to trash. Use with caution.
|
|
494
|
+
|
|
495
|
+
REQUIRES: pageId
|
|
496
|
+
RETURNS: Success confirmation
|
|
497
|
+
NEXT: None
|
|
498
|
+
|
|
499
|
+
Example: confluence_delete_page(pageId="123456")`,
|
|
512
500
|
inputSchema: z.object({
|
|
513
501
|
pageId: z.coerce.string().describe("Page ID (accepts string or number)"),
|
|
514
502
|
}),
|
|
@@ -533,7 +521,13 @@ WORKFLOW:
|
|
|
533
521
|
confluence_list_spaces: {
|
|
534
522
|
description: `List all accessible Confluence spaces.
|
|
535
523
|
|
|
536
|
-
|
|
524
|
+
Discover available spaces and their keys for use in CQL queries.
|
|
525
|
+
|
|
526
|
+
REQUIRES: None (optional type filter)
|
|
527
|
+
RETURNS: bufferId with spaces array (key, name, type)
|
|
528
|
+
NEXT: confluence_get_space (for details), confluence_search_content (to query space)
|
|
529
|
+
|
|
530
|
+
Example: confluence_list_spaces(type="global")`,
|
|
537
531
|
inputSchema: z.object({
|
|
538
532
|
type: z
|
|
539
533
|
.enum(["global", "personal"])
|
|
@@ -543,7 +537,7 @@ Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
|
543
537
|
handler: async (args) => {
|
|
544
538
|
try {
|
|
545
539
|
const result = await client.listSpaces(args.type);
|
|
546
|
-
return
|
|
540
|
+
return formatSuccessJson(result, {
|
|
547
541
|
resourceType: "confluence_spaces",
|
|
548
542
|
title: args.type ? `${args.type} spaces` : "All Spaces",
|
|
549
543
|
});
|
|
@@ -554,9 +548,15 @@ Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
|
554
548
|
},
|
|
555
549
|
},
|
|
556
550
|
confluence_get_space: {
|
|
557
|
-
description: `Get detailed information about a space.
|
|
551
|
+
description: `Get detailed information about a Confluence space.
|
|
558
552
|
|
|
559
|
-
|
|
553
|
+
View space configuration, homepage, and description.
|
|
554
|
+
|
|
555
|
+
REQUIRES: spaceKey (short code like 'DOCS')
|
|
556
|
+
RETURNS: bufferId with space details (name, homepage, description)
|
|
557
|
+
NEXT: confluence_search_content (to query space), confluence_get_page (homepage)
|
|
558
|
+
|
|
559
|
+
Example: confluence_get_space(spaceKey="DOCS")`,
|
|
560
560
|
inputSchema: z.object({
|
|
561
561
|
spaceKey: z.string().describe("Space key"),
|
|
562
562
|
expand: z.array(z.string()).optional().describe("Additional data to expand"),
|
|
@@ -564,7 +564,7 @@ Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
|
564
564
|
handler: async (args) => {
|
|
565
565
|
try {
|
|
566
566
|
const result = await client.getSpace(args.spaceKey, args.expand);
|
|
567
|
-
return
|
|
567
|
+
return formatSuccessJson(result, {
|
|
568
568
|
resourceType: "confluence_space",
|
|
569
569
|
title: result.name || args.spaceKey,
|
|
570
570
|
spaceKey: args.spaceKey,
|
|
@@ -586,7 +586,7 @@ Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
|
586
586
|
handler: async (args) => {
|
|
587
587
|
try {
|
|
588
588
|
const result = await client.getPageChildren(args.pageId, args.expand);
|
|
589
|
-
return
|
|
589
|
+
return formatSuccessJson(result, {
|
|
590
590
|
resourceType: "confluence_page_children",
|
|
591
591
|
title: `Page ${args.pageId} children`,
|
|
592
592
|
pageId: args.pageId,
|
|
@@ -623,7 +623,7 @@ Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
|
623
623
|
handler: async (args) => {
|
|
624
624
|
try {
|
|
625
625
|
const result = await client.getComments(args.pageId);
|
|
626
|
-
return
|
|
626
|
+
return formatSuccessJson(result, {
|
|
627
627
|
resourceType: "confluence_comments",
|
|
628
628
|
title: `Page ${args.pageId} comments`,
|
|
629
629
|
pageId: args.pageId,
|
|
@@ -661,7 +661,7 @@ Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
|
661
661
|
handler: async (args) => {
|
|
662
662
|
try {
|
|
663
663
|
const result = await client.listAttachments(args.pageId);
|
|
664
|
-
return
|
|
664
|
+
return formatSuccessJson(result, {
|
|
665
665
|
resourceType: "confluence_attachments",
|
|
666
666
|
title: `Page ${args.pageId} attachments`,
|
|
667
667
|
pageId: args.pageId,
|
|
@@ -673,14 +673,8 @@ Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
|
673
673
|
},
|
|
674
674
|
},
|
|
675
675
|
confluence_get_current_user_space: {
|
|
676
|
-
description: `Get the current user's personal
|
|
677
|
-
|
|
678
|
-
Use this tool when the user asks about:
|
|
679
|
-
- "my space", "my home space", "my personal space"
|
|
680
|
-
- "confluence home", "home space"
|
|
681
|
-
- "where can I write", "my confluence area"
|
|
682
|
-
|
|
683
|
-
Returns the user's personal space key and details. Use this to verify your personal space before write operations when write-home restriction is enabled.`,
|
|
676
|
+
description: `Get the current user's personal Confluence space. Returns spaceKey and homePageId.
|
|
677
|
+
Use to verify personal space before write operations when write-home restriction is enabled.`,
|
|
684
678
|
inputSchema: z.object({}),
|
|
685
679
|
handler: async () => {
|
|
686
680
|
try {
|
|
@@ -712,30 +706,16 @@ Returns the user's personal space key and details. Use this to verify your perso
|
|
|
712
706
|
// Note: Confluence drafts cannot be updated via API, only created, read, or deleted.
|
|
713
707
|
// The workflow is: create draft → edit locally in buffer → save (delete+recreate) → publish
|
|
714
708
|
confluence_draft_create: {
|
|
715
|
-
description: `Create
|
|
709
|
+
description: `Create draft for user review. Requires bufferId with valid XHTML.
|
|
716
710
|
|
|
717
|
-
|
|
711
|
+
NEW page: confluence_draft_create(spaceKey, title, bufferId)
|
|
712
|
+
EDIT page: confluence_edit → buffer_edit → confluence_draft_create(pageId, bufferId)
|
|
718
713
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
3. buffer_edit(bufferId, replace=elementId, content="...") → fix errors if any
|
|
723
|
-
4. confluence_draft_create(spaceKey, title, bufferId) → creates draft for review
|
|
724
|
-
|
|
725
|
-
Workflow for EDITING existing page:
|
|
726
|
-
1. confluence_get_page(pageId) or confluence_edit(input) → bufferId, structure
|
|
727
|
-
2. buffer_edit(bufferId, after=ID, content/plantuml) → modify content
|
|
728
|
-
3. buffer_validate_xhtml(bufferId) → check for errors
|
|
729
|
-
4. confluence_draft_create(pageId, bufferId) → creates "[jicon-mcp REVIEW] Title" draft
|
|
730
|
-
5. User reviews in Confluence UI
|
|
731
|
-
6. confluence_review_publish(draftId) → applies changes to original page
|
|
732
|
-
|
|
733
|
-
On validation error: returns bufferId + errorElementId for surgical fix with buffer_edit.
|
|
734
|
-
|
|
735
|
-
IMPORTANT: Call help(topic="storage") for XHTML syntax (HTML vs XHTML differences).
|
|
736
|
-
IMPORTANT: Call help(topic="plantuml") for diagram syntax.`,
|
|
714
|
+
Draft title auto-prefixed with "[jicon-mcp REVIEW]" when editing existing pages.
|
|
715
|
+
RETURNS: draftId, bufferId, structure, url. On XHTML error: errorElementId for buffer_edit fix.
|
|
716
|
+
WARNING: pageId must be a PAGE ID, not a draft ID. Use confluence_draft_open for existing drafts.`,
|
|
737
717
|
inputSchema: z.object({
|
|
738
|
-
pageId: z.coerce.string().optional().describe("Existing
|
|
718
|
+
pageId: z.coerce.string().optional().describe("Existing PAGE ID to edit (NOT a draft ID). Get from confluence_get_page or confluence_edit. When provided, bufferId must come from that page."),
|
|
739
719
|
spaceKey: z.string().optional().describe("Space key (required for new pages, auto-populated when pageId is provided)"),
|
|
740
720
|
title: z.string().optional().describe("Page title (required for new pages, auto-populated when pageId is provided)"),
|
|
741
721
|
bufferId: z.string().describe("Buffer ID containing XHTML content (from buffer_create or confluence_get_page)"),
|
|
@@ -773,7 +753,7 @@ IMPORTANT: Call help(topic="plantuml") for diagram syntax.`,
|
|
|
773
753
|
});
|
|
774
754
|
}
|
|
775
755
|
// Get full content from buffer
|
|
776
|
-
const fullContent = contentBuffer.getChunk(args.bufferId, 0, bufferInfo.
|
|
756
|
+
const fullContent = contentBuffer.getChunk(args.bufferId, 0, bufferInfo.bufferSizeBytes);
|
|
777
757
|
if (!fullContent) {
|
|
778
758
|
return formatError({
|
|
779
759
|
error: true,
|
|
@@ -817,10 +797,18 @@ IMPORTANT: Call help(topic="plantuml") for diagram syntax.`,
|
|
|
817
797
|
}
|
|
818
798
|
}
|
|
819
799
|
catch (error) {
|
|
800
|
+
// Provide helpful hint if they might have passed a draftId instead of pageId
|
|
801
|
+
const errorMessage = isApiError(error) ? error.message :
|
|
802
|
+
error instanceof Error ? error.message : String(error);
|
|
820
803
|
return formatError({
|
|
821
804
|
error: true,
|
|
822
|
-
message: `
|
|
805
|
+
message: `Page '${args.pageId}' not found. If this is a draft ID (from confluence_draft_create), use confluence_draft_open to continue editing instead.`,
|
|
823
806
|
statusCode: 404,
|
|
807
|
+
details: {
|
|
808
|
+
originalError: errorMessage,
|
|
809
|
+
hint: "For existing drafts: confluence_draft_open(draftId) → buffer_edit → confluence_draft_save. For new drafts from existing pages: confluence_edit(pageId) → buffer_edit → confluence_draft_create(pageId, bufferId)",
|
|
810
|
+
pageIdProvided: args.pageId,
|
|
811
|
+
},
|
|
824
812
|
});
|
|
825
813
|
}
|
|
826
814
|
}
|
|
@@ -852,8 +840,26 @@ IMPORTANT: Call help(topic="plantuml") for diagram syntax.`,
|
|
|
852
840
|
if (validationError) {
|
|
853
841
|
return validationError;
|
|
854
842
|
}
|
|
855
|
-
//
|
|
856
|
-
|
|
843
|
+
// Convert PlantUML !include URLs to stdlib syntax before sending to Confluence
|
|
844
|
+
let expandedContent;
|
|
845
|
+
try {
|
|
846
|
+
expandedContent = convertPlantUmlIncludesInXhtml(content);
|
|
847
|
+
}
|
|
848
|
+
catch (error) {
|
|
849
|
+
if (error instanceof IncludeConversionError) {
|
|
850
|
+
return formatError({
|
|
851
|
+
error: true,
|
|
852
|
+
message: error.message,
|
|
853
|
+
statusCode: 400,
|
|
854
|
+
details: {
|
|
855
|
+
url: error.url,
|
|
856
|
+
suggestion: error.suggestion,
|
|
857
|
+
hint: "Replace the HTTP URL with the suggested stdlib syntax in your PlantUML diagram",
|
|
858
|
+
},
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
throw error;
|
|
862
|
+
}
|
|
857
863
|
try {
|
|
858
864
|
// Constants for review workflow
|
|
859
865
|
const REVIEW_PREFIX = '[jicon-mcp REVIEW] ';
|
|
@@ -915,16 +921,19 @@ IMPORTANT: Call help(topic="plantuml") for diagram syntax.`,
|
|
|
915
921
|
}
|
|
916
922
|
// Store content with element IDs for structured editing
|
|
917
923
|
// Track originalPageId in metadata so we can link the draft to its source
|
|
918
|
-
const
|
|
919
|
-
resourceType: "
|
|
924
|
+
const xhtmlResult = formatSuccessXhtml(content, {
|
|
925
|
+
resourceType: "confluence_draft",
|
|
920
926
|
resourceId: result.id,
|
|
921
|
-
contentType: "xhtml",
|
|
922
927
|
spaceKey: result.space?.key,
|
|
923
928
|
title: result.title,
|
|
924
929
|
isDraft: true,
|
|
925
930
|
originalPageId: originalPageId,
|
|
926
931
|
originalPageVersion: originalPageVersion,
|
|
927
932
|
});
|
|
933
|
+
if ("errorResult" in xhtmlResult) {
|
|
934
|
+
return xhtmlResult.errorResult;
|
|
935
|
+
}
|
|
936
|
+
const newBufferId = xhtmlResult.bufferId;
|
|
928
937
|
// Build the draft edit URL (drafts use resumedraft.action, not the webui link)
|
|
929
938
|
const baseUrl = client.getBaseUrl();
|
|
930
939
|
const draftUrl = `${baseUrl}/pages/resumedraft.action?draftId=${result.id}`;
|
|
@@ -1000,18 +1009,19 @@ Use buffer_edit(bufferId, after=ID, content/plantuml/fromBufferId) to modify, th
|
|
|
1000
1009
|
handler: async (args) => {
|
|
1001
1010
|
try {
|
|
1002
1011
|
const result = await client.getDraft(args.draftId);
|
|
1003
|
-
const
|
|
1004
|
-
// Collapse expanded includes back to !include directives
|
|
1005
|
-
const content = collapseExpandedIncludesInXhtml(rawContent);
|
|
1012
|
+
const content = result.body?.storage?.value || "";
|
|
1006
1013
|
// Store content with element IDs for structured editing
|
|
1007
|
-
const
|
|
1008
|
-
resourceType: "
|
|
1014
|
+
const xhtmlResult = formatSuccessXhtml(content, {
|
|
1015
|
+
resourceType: "confluence_draft",
|
|
1009
1016
|
resourceId: result.id,
|
|
1010
|
-
contentType: "xhtml",
|
|
1011
1017
|
spaceKey: result.space?.key,
|
|
1012
1018
|
title: result.title,
|
|
1013
1019
|
isDraft: true,
|
|
1014
1020
|
});
|
|
1021
|
+
if ("errorResult" in xhtmlResult) {
|
|
1022
|
+
return xhtmlResult.errorResult;
|
|
1023
|
+
}
|
|
1024
|
+
const { bufferId, structure } = xhtmlResult;
|
|
1015
1025
|
// Build the draft edit URL
|
|
1016
1026
|
const baseUrl = client.getBaseUrl();
|
|
1017
1027
|
const draftUrl = `${baseUrl}/pages/resumedraft.action?draftId=${result.id}`;
|
|
@@ -1053,7 +1063,7 @@ Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
|
1053
1063
|
created: page.version?.when || "",
|
|
1054
1064
|
url: `${baseUrl}/pages/resumedraft.action?draftId=${page.id}`,
|
|
1055
1065
|
}));
|
|
1056
|
-
return
|
|
1066
|
+
return formatSuccessJson({
|
|
1057
1067
|
drafts,
|
|
1058
1068
|
total: result.totalSize,
|
|
1059
1069
|
}, {
|
|
@@ -1099,7 +1109,7 @@ Returns new draftId, bufferId, structure (element IDs), and URL. Always use the
|
|
|
1099
1109
|
});
|
|
1100
1110
|
}
|
|
1101
1111
|
// Get full content from buffer
|
|
1102
|
-
const fullContent = contentBuffer.getChunk(args.bufferId, 0, bufferChunk.
|
|
1112
|
+
const fullContent = contentBuffer.getChunk(args.bufferId, 0, bufferChunk.bufferSizeBytes);
|
|
1103
1113
|
if (!fullContent) {
|
|
1104
1114
|
return formatError({
|
|
1105
1115
|
error: true,
|
|
@@ -1126,8 +1136,26 @@ Returns new draftId, bufferId, structure (element IDs), and URL. Always use the
|
|
|
1126
1136
|
if (validationError) {
|
|
1127
1137
|
return validationError;
|
|
1128
1138
|
}
|
|
1129
|
-
//
|
|
1130
|
-
|
|
1139
|
+
// Convert PlantUML !include URLs to stdlib syntax before sending to Confluence
|
|
1140
|
+
let expandedContent;
|
|
1141
|
+
try {
|
|
1142
|
+
expandedContent = convertPlantUmlIncludesInXhtml(savedContent);
|
|
1143
|
+
}
|
|
1144
|
+
catch (error) {
|
|
1145
|
+
if (error instanceof IncludeConversionError) {
|
|
1146
|
+
return formatError({
|
|
1147
|
+
error: true,
|
|
1148
|
+
message: error.message,
|
|
1149
|
+
statusCode: 400,
|
|
1150
|
+
details: {
|
|
1151
|
+
url: error.url,
|
|
1152
|
+
suggestion: error.suggestion,
|
|
1153
|
+
hint: "Replace the HTTP URL with the suggested stdlib syntax in your PlantUML diagram",
|
|
1154
|
+
},
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
throw error;
|
|
1158
|
+
}
|
|
1131
1159
|
const title = args.title || existingDraft.title;
|
|
1132
1160
|
// Delete old draft before creating new one
|
|
1133
1161
|
// NOTE: Confluence Data Center does NOT support updating drafts directly.
|
|
@@ -1158,18 +1186,21 @@ Returns new draftId, bufferId, structure (element IDs), and URL. Always use the
|
|
|
1158
1186
|
});
|
|
1159
1187
|
// Update buffer metadata with new draft ID
|
|
1160
1188
|
contentBuffer.invalidateByMetadata({
|
|
1161
|
-
resourceType: "
|
|
1189
|
+
resourceType: "confluence_draft",
|
|
1162
1190
|
resourceId: args.draftId,
|
|
1163
1191
|
});
|
|
1164
1192
|
// Store content with element IDs for structured editing
|
|
1165
|
-
const
|
|
1166
|
-
resourceType: "
|
|
1193
|
+
const xhtmlResult = formatSuccessXhtml(savedContent, {
|
|
1194
|
+
resourceType: "confluence_draft",
|
|
1167
1195
|
resourceId: newDraft.id,
|
|
1168
|
-
contentType: "xhtml",
|
|
1169
1196
|
spaceKey: newDraft.space?.key,
|
|
1170
1197
|
title: newDraft.title,
|
|
1171
1198
|
isDraft: true,
|
|
1172
1199
|
});
|
|
1200
|
+
if ("errorResult" in xhtmlResult) {
|
|
1201
|
+
return xhtmlResult.errorResult;
|
|
1202
|
+
}
|
|
1203
|
+
const { bufferId: newBufferId, structure } = xhtmlResult;
|
|
1173
1204
|
// Build the draft edit URL
|
|
1174
1205
|
const baseUrl = client.getBaseUrl();
|
|
1175
1206
|
const draftUrl = `${baseUrl}/pages/resumedraft.action?draftId=${newDraft.id}`;
|
|
@@ -1230,14 +1261,24 @@ Drafts are NOT sent to trash - they are permanently deleted.`,
|
|
|
1230
1261
|
confluence_review_publish: {
|
|
1231
1262
|
description: `Publish a review draft to apply changes to the original page.
|
|
1232
1263
|
|
|
1264
|
+
Apply changes from "[jicon-mcp REVIEW]" draft to the original page.
|
|
1265
|
+
|
|
1266
|
+
REQUIRES: reviewDraftId (from confluence_draft_create with pageId)
|
|
1267
|
+
RETURNS: Updated page info with new version number
|
|
1268
|
+
NEXT: confluence_get_page (to verify), confluence_edit (for more changes)
|
|
1269
|
+
|
|
1233
1270
|
This tool:
|
|
1234
1271
|
1. Validates the draft is a "[jicon-mcp REVIEW]" draft with proper label
|
|
1235
1272
|
2. Copies the draft content to the original page (creates new version)
|
|
1236
1273
|
3. Deletes the review draft
|
|
1237
1274
|
|
|
1238
|
-
|
|
1275
|
+
Example: confluence_review_publish(reviewDraftId="123456")`,
|
|
1239
1276
|
inputSchema: z.object({
|
|
1240
1277
|
reviewDraftId: z.coerce.string().describe("ID of the [jicon-mcp REVIEW] draft to publish"),
|
|
1278
|
+
autoRetry: z
|
|
1279
|
+
.boolean()
|
|
1280
|
+
.optional()
|
|
1281
|
+
.describe("Auto-retry once on 409 conflict (refetches page version)"),
|
|
1241
1282
|
}),
|
|
1242
1283
|
handler: async (args) => {
|
|
1243
1284
|
const REVIEW_PREFIX = '[jicon-mcp REVIEW] ';
|
|
@@ -1294,9 +1335,23 @@ Use this after user has reviewed the draft in Confluence UI.`,
|
|
|
1294
1335
|
// 5. Get the review draft content
|
|
1295
1336
|
const reviewContent = reviewDraft.body?.storage?.value || "";
|
|
1296
1337
|
// 6. Update original page with review content
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1338
|
+
let updatedPage;
|
|
1339
|
+
try {
|
|
1340
|
+
updatedPage = await client.updatePage(originalPageId, originalPage.version?.number || 1, originalPage.title, // Keep original title (not the REVIEW prefix)
|
|
1341
|
+
reviewContent, false // Not a minor edit
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
catch (updateError) {
|
|
1345
|
+
// Handle version conflicts with optional auto-retry
|
|
1346
|
+
if (isApiError(updateError) && updateError.statusCode === 409 && args.autoRetry) {
|
|
1347
|
+
// Re-fetch page to get current version and retry
|
|
1348
|
+
const refreshedPage = await client.getPage(originalPageId, ["version"]);
|
|
1349
|
+
updatedPage = await client.updatePage(originalPageId, refreshedPage.version?.number || 1, originalPage.title, reviewContent, false);
|
|
1350
|
+
}
|
|
1351
|
+
else {
|
|
1352
|
+
throw updateError;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1300
1355
|
// 7. Delete review draft
|
|
1301
1356
|
await client.deleteDraft(args.reviewDraftId);
|
|
1302
1357
|
// 8. Invalidate buffers
|