@crypto512/jicon-mcp 1.2.0 → 1.3.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 +23 -0
- package/TOOL_LIST.md +95 -60
- package/crypto512-jicon-mcp-1.3.0.tgz +0 -0
- package/dist/confluence/tools.d.ts +4 -12
- package/dist/confluence/tools.d.ts.map +1 -1
- package/dist/confluence/tools.js +137 -140
- package/dist/confluence/tools.js.map +1 -1
- package/dist/jira/tools.d.ts.map +1 -1
- package/dist/jira/tools.js +76 -25
- package/dist/jira/tools.js.map +1 -1
- package/dist/tempo/tools.d.ts.map +1 -1
- package/dist/tempo/tools.js +74 -22
- package/dist/tempo/tools.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 +93 -72
- package/dist/utils/jicon-help.js.map +1 -1
- package/dist/utils/response-formatter.d.ts +13 -0
- package/dist/utils/response-formatter.d.ts.map +1 -1
- package/dist/utils/response-formatter.js +25 -0
- package/dist/utils/response-formatter.js.map +1 -1
- package/dist/utils/xhtml/types.d.ts +1 -0
- package/dist/utils/xhtml/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/confluence/tools.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Confluence MCP Tools
|
|
3
3
|
*/
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { formatSuccess, formatError, isApiError } from "../utils/response-formatter.js";
|
|
5
|
+
import { formatSuccess, formatSuccessBuffered, formatError, isApiError } from "../utils/response-formatter.js";
|
|
6
6
|
import { contentBuffer } from "../utils/content-buffer.js";
|
|
7
7
|
import { formatPageMetadata } from "./formatters.js";
|
|
8
8
|
import { validateXhtmlAsync, parseXhtml, parseStructure, serializeXhtml, enhanceXhtmlError } from "../utils/xhtml/index.js";
|
|
@@ -46,72 +46,17 @@ function getContentSummary(content) {
|
|
|
46
46
|
result.headingCount = doc.querySelectorAll('h1, h2, h3, h4, h5, h6').length;
|
|
47
47
|
return result;
|
|
48
48
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Resolve content from either direct content string or bufferId.
|
|
51
|
-
* Returns { content, error } - if error is set, return it as the tool result.
|
|
52
|
-
*/
|
|
53
|
-
function resolveContentFromBuffer(contentArg, bufferIdArg) {
|
|
54
|
-
// Exactly one of content or bufferId must be provided
|
|
55
|
-
if (contentArg && bufferIdArg) {
|
|
56
|
-
return {
|
|
57
|
-
error: formatError({
|
|
58
|
-
error: true,
|
|
59
|
-
message: "Provide either 'content' or 'bufferId', not both",
|
|
60
|
-
statusCode: 400,
|
|
61
|
-
}),
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
if (bufferIdArg) {
|
|
65
|
-
const bufferChunk = contentBuffer.getChunk(bufferIdArg);
|
|
66
|
-
if (!bufferChunk) {
|
|
67
|
-
return {
|
|
68
|
-
error: formatError({
|
|
69
|
-
error: true,
|
|
70
|
-
message: `Buffer ${bufferIdArg} not found or expired`,
|
|
71
|
-
statusCode: 404,
|
|
72
|
-
}),
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
// Validate that buffer contains XHTML content for Confluence
|
|
76
|
-
const bufferInfo = contentBuffer.getInfo(bufferIdArg);
|
|
77
|
-
if (bufferInfo?.metadata?.contentType && bufferInfo.metadata.contentType !== "xhtml") {
|
|
78
|
-
return {
|
|
79
|
-
error: formatError({
|
|
80
|
-
error: true,
|
|
81
|
-
message: `Buffer ${bufferIdArg} contains ${bufferInfo.metadata.contentType} content, but Confluence requires XHTML.`,
|
|
82
|
-
statusCode: 400,
|
|
83
|
-
details: {
|
|
84
|
-
hint: "Create Confluence content with buffer_create, then edit with buffer_edit.",
|
|
85
|
-
foundContentType: bufferInfo.metadata.contentType,
|
|
86
|
-
expectedContentType: "xhtml",
|
|
87
|
-
},
|
|
88
|
-
}),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
// Get full content from buffer
|
|
92
|
-
const fullContent = contentBuffer.getChunk(bufferIdArg, 0, bufferChunk.totalSize);
|
|
93
|
-
if (!fullContent) {
|
|
94
|
-
return {
|
|
95
|
-
error: formatError({
|
|
96
|
-
error: true,
|
|
97
|
-
message: "Failed to retrieve full buffer content",
|
|
98
|
-
statusCode: 500,
|
|
99
|
-
}),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
return { content: fullContent.chunk };
|
|
103
|
-
}
|
|
104
|
-
// Direct content provided
|
|
105
|
-
return { content: contentArg };
|
|
106
|
-
}
|
|
107
49
|
/**
|
|
108
50
|
* Validate XHTML content before Confluence write operations.
|
|
109
51
|
* Returns error result if validation fails, null if valid.
|
|
52
|
+
* When bufferId is provided, includes it in error response for recovery.
|
|
110
53
|
*/
|
|
111
|
-
async function validateContentForWrite(content) {
|
|
54
|
+
async function validateContentForWrite(content, bufferId) {
|
|
112
55
|
const validation = await validateXhtmlAsync(content, { validatePlantUml: true });
|
|
113
56
|
if (!validation.valid) {
|
|
114
57
|
const errorMessages = [];
|
|
58
|
+
let errorElementId;
|
|
59
|
+
let errorContext;
|
|
115
60
|
// XHTML structure errors
|
|
116
61
|
if (validation.errors && validation.errors.length > 0) {
|
|
117
62
|
errorMessages.push("XHTML validation errors:");
|
|
@@ -124,6 +69,14 @@ async function validateContentForWrite(content) {
|
|
|
124
69
|
? err.location.context.substring(0, 60) + "..."
|
|
125
70
|
: err.location.context;
|
|
126
71
|
errorMessages.push(` Near: "${contextPreview}"`);
|
|
72
|
+
// Capture first error context for recovery
|
|
73
|
+
if (!errorContext) {
|
|
74
|
+
errorContext = err.location.context;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Capture first error elementId for recovery
|
|
78
|
+
if (!errorElementId && err.location?.elementId) {
|
|
79
|
+
errorElementId = err.location.elementId;
|
|
127
80
|
}
|
|
128
81
|
});
|
|
129
82
|
}
|
|
@@ -151,10 +104,18 @@ async function validateContentForWrite(content) {
|
|
|
151
104
|
errorMessages.push(" </ac:structured-macro>");
|
|
152
105
|
}
|
|
153
106
|
}
|
|
154
|
-
// Add
|
|
107
|
+
// Add recovery instructions
|
|
155
108
|
errorMessages.push("");
|
|
156
|
-
|
|
157
|
-
|
|
109
|
+
if (bufferId) {
|
|
110
|
+
errorMessages.push(`RECOVERY: Use buffer_edit(bufferId="${bufferId}", ...) to fix errors.`);
|
|
111
|
+
if (errorElementId) {
|
|
112
|
+
errorMessages.push(` buffer_edit(bufferId="${bufferId}", replace=${errorElementId}, content="<fixed>...</fixed>")`);
|
|
113
|
+
}
|
|
114
|
+
else if (errorContext) {
|
|
115
|
+
errorMessages.push(` Use buffer_grep(bufferId="${bufferId}", pattern="...") to find the error location.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
errorMessages.push('TIP: Call help(topic="storage") for XHTML syntax (HTML vs XHTML differences).');
|
|
158
119
|
errorMessages.push("");
|
|
159
120
|
errorMessages.push("ACTION REQUIRED: Fix content errors before calling this tool again.");
|
|
160
121
|
errorMessages.push("DO NOT claim success - the draft was NOT created.");
|
|
@@ -164,7 +125,12 @@ async function validateContentForWrite(content) {
|
|
|
164
125
|
statusCode: 400,
|
|
165
126
|
details: {
|
|
166
127
|
validationErrors: errorMessages,
|
|
167
|
-
|
|
128
|
+
...(bufferId && { bufferId }),
|
|
129
|
+
...(errorElementId && { errorElementId }),
|
|
130
|
+
...(errorContext && { errorContext }),
|
|
131
|
+
hint: errorElementId
|
|
132
|
+
? `Use buffer_edit(bufferId="${bufferId}", replace=${errorElementId}, content="...") to fix`
|
|
133
|
+
: `Use buffer_grep to find the error, then buffer_edit to fix`,
|
|
168
134
|
},
|
|
169
135
|
});
|
|
170
136
|
}
|
|
@@ -185,7 +151,9 @@ function storeXhtmlWithStructure(content, metadata) {
|
|
|
185
151
|
export function createConfluenceTools(client) {
|
|
186
152
|
return {
|
|
187
153
|
confluence_search_content: {
|
|
188
|
-
description: `Search Confluence content using CQL. Auto-fetches all results
|
|
154
|
+
description: `Search Confluence content using CQL. Auto-fetches all results.
|
|
155
|
+
|
|
156
|
+
Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.
|
|
189
157
|
|
|
190
158
|
TIP: See help(topic="cql") for CQL syntax guide.
|
|
191
159
|
|
|
@@ -199,8 +167,10 @@ WARNING: Use text~ (not content~ or body~). Use space KEY (not name).`,
|
|
|
199
167
|
handler: async (args) => {
|
|
200
168
|
try {
|
|
201
169
|
const result = await client.searchContentAll(args.cql, args.expand);
|
|
202
|
-
|
|
203
|
-
|
|
170
|
+
return formatSuccessBuffered(result, {
|
|
171
|
+
resourceType: "confluence_search",
|
|
172
|
+
title: `CQL: ${args.cql.substring(0, 100)}${args.cql.length > 100 ? "..." : ""}`,
|
|
173
|
+
});
|
|
204
174
|
}
|
|
205
175
|
catch (error) {
|
|
206
176
|
// Enhanced error handling for common CQL errors
|
|
@@ -561,7 +531,9 @@ WORKFLOW:
|
|
|
561
531
|
},
|
|
562
532
|
},
|
|
563
533
|
confluence_list_spaces: {
|
|
564
|
-
description: `List all accessible Confluence spaces
|
|
534
|
+
description: `List all accessible Confluence spaces.
|
|
535
|
+
|
|
536
|
+
Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
565
537
|
inputSchema: z.object({
|
|
566
538
|
type: z
|
|
567
539
|
.enum(["global", "personal"])
|
|
@@ -571,7 +543,10 @@ WORKFLOW:
|
|
|
571
543
|
handler: async (args) => {
|
|
572
544
|
try {
|
|
573
545
|
const result = await client.listSpaces(args.type);
|
|
574
|
-
return
|
|
546
|
+
return formatSuccessBuffered(result, {
|
|
547
|
+
resourceType: "confluence_spaces",
|
|
548
|
+
title: args.type ? `${args.type} spaces` : "All Spaces",
|
|
549
|
+
});
|
|
575
550
|
}
|
|
576
551
|
catch (error) {
|
|
577
552
|
return formatError(isApiError(error) ? error : new Error(String(error)));
|
|
@@ -579,7 +554,9 @@ WORKFLOW:
|
|
|
579
554
|
},
|
|
580
555
|
},
|
|
581
556
|
confluence_get_space: {
|
|
582
|
-
description:
|
|
557
|
+
description: `Get detailed information about a space.
|
|
558
|
+
|
|
559
|
+
Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
583
560
|
inputSchema: z.object({
|
|
584
561
|
spaceKey: z.string().describe("Space key"),
|
|
585
562
|
expand: z.array(z.string()).optional().describe("Additional data to expand"),
|
|
@@ -587,8 +564,11 @@ WORKFLOW:
|
|
|
587
564
|
handler: async (args) => {
|
|
588
565
|
try {
|
|
589
566
|
const result = await client.getSpace(args.spaceKey, args.expand);
|
|
590
|
-
|
|
591
|
-
|
|
567
|
+
return formatSuccessBuffered(result, {
|
|
568
|
+
resourceType: "confluence_space",
|
|
569
|
+
title: result.name || args.spaceKey,
|
|
570
|
+
spaceKey: args.spaceKey,
|
|
571
|
+
});
|
|
592
572
|
}
|
|
593
573
|
catch (error) {
|
|
594
574
|
return formatError(isApiError(error) ? error : new Error(String(error)));
|
|
@@ -596,7 +576,9 @@ WORKFLOW:
|
|
|
596
576
|
},
|
|
597
577
|
},
|
|
598
578
|
confluence_get_page_children: {
|
|
599
|
-
description: `Get all child pages of a page
|
|
579
|
+
description: `Get all child pages of a page.
|
|
580
|
+
|
|
581
|
+
Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
600
582
|
inputSchema: z.object({
|
|
601
583
|
pageId: z.coerce.string().describe("Parent page ID (accepts string or number)"),
|
|
602
584
|
expand: z.array(z.string()).optional().describe("Additional data to expand"),
|
|
@@ -604,7 +586,11 @@ WORKFLOW:
|
|
|
604
586
|
handler: async (args) => {
|
|
605
587
|
try {
|
|
606
588
|
const result = await client.getPageChildren(args.pageId, args.expand);
|
|
607
|
-
return
|
|
589
|
+
return formatSuccessBuffered(result, {
|
|
590
|
+
resourceType: "confluence_page_children",
|
|
591
|
+
title: `Page ${args.pageId} children`,
|
|
592
|
+
pageId: args.pageId,
|
|
593
|
+
});
|
|
608
594
|
}
|
|
609
595
|
catch (error) {
|
|
610
596
|
return formatError(isApiError(error) ? error : new Error(String(error)));
|
|
@@ -628,14 +614,20 @@ WORKFLOW:
|
|
|
628
614
|
},
|
|
629
615
|
},
|
|
630
616
|
confluence_get_comments: {
|
|
631
|
-
description: `Get all comments on a Confluence page
|
|
617
|
+
description: `Get all comments on a Confluence page.
|
|
618
|
+
|
|
619
|
+
Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
632
620
|
inputSchema: z.object({
|
|
633
621
|
pageId: z.coerce.string().describe("Page ID (accepts string or number)"),
|
|
634
622
|
}),
|
|
635
623
|
handler: async (args) => {
|
|
636
624
|
try {
|
|
637
625
|
const result = await client.getComments(args.pageId);
|
|
638
|
-
return
|
|
626
|
+
return formatSuccessBuffered(result, {
|
|
627
|
+
resourceType: "confluence_comments",
|
|
628
|
+
title: `Page ${args.pageId} comments`,
|
|
629
|
+
pageId: args.pageId,
|
|
630
|
+
});
|
|
639
631
|
}
|
|
640
632
|
catch (error) {
|
|
641
633
|
return formatError(isApiError(error) ? error : new Error(String(error)));
|
|
@@ -660,14 +652,20 @@ WORKFLOW:
|
|
|
660
652
|
},
|
|
661
653
|
},
|
|
662
654
|
confluence_list_attachments: {
|
|
663
|
-
description: `List all attachments on a Confluence page
|
|
655
|
+
description: `List all attachments on a Confluence page.
|
|
656
|
+
|
|
657
|
+
Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
664
658
|
inputSchema: z.object({
|
|
665
659
|
pageId: z.coerce.string().describe("Page ID (accepts string or number)"),
|
|
666
660
|
}),
|
|
667
661
|
handler: async (args) => {
|
|
668
662
|
try {
|
|
669
663
|
const result = await client.listAttachments(args.pageId);
|
|
670
|
-
return
|
|
664
|
+
return formatSuccessBuffered(result, {
|
|
665
|
+
resourceType: "confluence_attachments",
|
|
666
|
+
title: `Page ${args.pageId} attachments`,
|
|
667
|
+
pageId: args.pageId,
|
|
668
|
+
});
|
|
671
669
|
}
|
|
672
670
|
catch (error) {
|
|
673
671
|
return formatError(isApiError(error) ? error : new Error(String(error)));
|
|
@@ -716,37 +714,31 @@ Returns the user's personal space key and details. Use this to verify your perso
|
|
|
716
714
|
confluence_draft_create: {
|
|
717
715
|
description: `Create a Confluence draft for user review. Returns draftId, bufferId, structure (element IDs), and clickable URL.
|
|
718
716
|
|
|
719
|
-
|
|
720
|
-
IMPORTANT: Call help(topic="storage") BEFORE creating XHTML content for proper syntax.
|
|
721
|
-
IMPORTANT: User must validate the draft in Confluence UI before publishing.
|
|
722
|
-
IMPORTANT: Raw @startuml outside macros is NOT supported. Use buffer_edit with plantuml parameter.
|
|
717
|
+
REQUIRES bufferId - content must be in a buffer for validation and error recovery.
|
|
723
718
|
|
|
724
|
-
|
|
725
|
-
1.
|
|
726
|
-
2.
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
- Use confluence_review_publish(draftId) to apply changes to original
|
|
730
|
-
- Use confluence_review_discard(draftId) to cancel without changes
|
|
731
|
-
- Use confluence_review_list() to find all review drafts
|
|
719
|
+
Workflow for NEW page:
|
|
720
|
+
1. buffer_create(content="<h1>Title</h1><p>Content</p>", contentType="xhtml") → bufferId, structure
|
|
721
|
+
2. buffer_validate_xhtml(bufferId) → check for errors, get elementId if invalid
|
|
722
|
+
3. buffer_edit(bufferId, replace=elementId, content="...") → fix errors if any
|
|
723
|
+
4. confluence_draft_create(spaceKey, title, bufferId) → creates draft for review
|
|
732
724
|
|
|
733
|
-
Workflow for
|
|
734
|
-
1. confluence_get_page(pageId) → bufferId, structure
|
|
735
|
-
2. buffer_edit(bufferId,
|
|
736
|
-
3.
|
|
737
|
-
4.
|
|
738
|
-
5.
|
|
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
|
|
739
732
|
|
|
740
|
-
|
|
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.`,
|
|
741
737
|
inputSchema: z.object({
|
|
742
738
|
pageId: z.coerce.string().optional().describe("Existing page ID to create edit draft for. When provided, bufferId must come from that page."),
|
|
743
739
|
spaceKey: z.string().optional().describe("Space key (required for new pages, auto-populated when pageId is provided)"),
|
|
744
740
|
title: z.string().optional().describe("Page title (required for new pages, auto-populated when pageId is provided)"),
|
|
745
|
-
|
|
746
|
-
.string()
|
|
747
|
-
.optional()
|
|
748
|
-
.describe("Page content in Confluence storage format (XHTML-based)"),
|
|
749
|
-
bufferId: z.string().optional().describe("Buffer ID containing content (alternative to content)"),
|
|
741
|
+
bufferId: z.string().describe("Buffer ID containing XHTML content (from buffer_create or confluence_get_page)"),
|
|
750
742
|
parentId: z.string().optional().describe("Parent page ID"),
|
|
751
743
|
labels: z.array(z.string()).optional().describe("Array of labels"),
|
|
752
744
|
}),
|
|
@@ -757,27 +749,41 @@ Provide either 'content' (string) OR 'bufferId' (from buffer_create/buffer_edit)
|
|
|
757
749
|
let parentId = args.parentId;
|
|
758
750
|
let originalPageId;
|
|
759
751
|
let originalPageVersion;
|
|
752
|
+
// Validate buffer exists and get content
|
|
753
|
+
const bufferInfo = contentBuffer.getInfo(args.bufferId);
|
|
754
|
+
if (!bufferInfo) {
|
|
755
|
+
return formatError({
|
|
756
|
+
error: true,
|
|
757
|
+
message: `Buffer not found or expired: ${args.bufferId}`,
|
|
758
|
+
statusCode: 404,
|
|
759
|
+
details: {
|
|
760
|
+
hint: "Create a buffer first: buffer_create(content='<h1>...</h1>', contentType='xhtml')",
|
|
761
|
+
},
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
// Validate buffer contains XHTML content
|
|
765
|
+
if (bufferInfo.metadata?.contentType && bufferInfo.metadata.contentType !== "xhtml") {
|
|
766
|
+
return formatError({
|
|
767
|
+
error: true,
|
|
768
|
+
message: `Buffer '${args.bufferId}' is not XHTML content (found: ${bufferInfo.metadata.contentType})`,
|
|
769
|
+
statusCode: 400,
|
|
770
|
+
details: {
|
|
771
|
+
hint: "Use buffer_create(content='...', contentType='xhtml') to create an XHTML buffer",
|
|
772
|
+
},
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
// Get full content from buffer
|
|
776
|
+
const fullContent = contentBuffer.getChunk(args.bufferId, 0, bufferInfo.totalSize);
|
|
777
|
+
if (!fullContent) {
|
|
778
|
+
return formatError({
|
|
779
|
+
error: true,
|
|
780
|
+
message: "Failed to retrieve buffer content",
|
|
781
|
+
statusCode: 500,
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
const content = fullContent.chunk;
|
|
760
785
|
if (args.pageId) {
|
|
761
786
|
// MODE: Edit existing page - validate bufferId came from this page
|
|
762
|
-
if (!args.bufferId) {
|
|
763
|
-
return formatError({
|
|
764
|
-
error: true,
|
|
765
|
-
message: "When pageId is provided, bufferId is required (must come from confluence_get_page or confluence_edit of that page)",
|
|
766
|
-
statusCode: 400,
|
|
767
|
-
details: {
|
|
768
|
-
hint: "First call confluence_get_page(pageId) or confluence_edit(pageId) to get a bufferId, then modify with buffer_edit",
|
|
769
|
-
},
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
// Validate buffer originated from the specified page
|
|
773
|
-
const bufferInfo = contentBuffer.getInfo(args.bufferId);
|
|
774
|
-
if (!bufferInfo) {
|
|
775
|
-
return formatError({
|
|
776
|
-
error: true,
|
|
777
|
-
message: `Buffer not found or expired: ${args.bufferId}`,
|
|
778
|
-
statusCode: 404,
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
787
|
const bufferSourceId = bufferInfo.metadata?.resourceId;
|
|
782
788
|
if (bufferSourceId !== args.pageId) {
|
|
783
789
|
return formatError({
|
|
@@ -828,19 +834,6 @@ Provide either 'content' (string) OR 'bufferId' (from buffer_create/buffer_edit)
|
|
|
828
834
|
});
|
|
829
835
|
}
|
|
830
836
|
}
|
|
831
|
-
// Resolve content from either content string or bufferId
|
|
832
|
-
const resolved = resolveContentFromBuffer(args.content, args.bufferId);
|
|
833
|
-
if (resolved.error) {
|
|
834
|
-
return resolved.error;
|
|
835
|
-
}
|
|
836
|
-
if (!resolved.content) {
|
|
837
|
-
return formatError({
|
|
838
|
-
error: true,
|
|
839
|
-
message: "Either 'content' or 'bufferId' must be provided",
|
|
840
|
-
statusCode: 400,
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
const content = resolved.content;
|
|
844
837
|
// Check for raw PlantUML that should use buffer_edit with plantuml parameter
|
|
845
838
|
const rawPlantUml = detectRawPlantUml(content);
|
|
846
839
|
if (rawPlantUml) {
|
|
@@ -855,7 +848,7 @@ Provide either 'content' (string) OR 'bufferId' (from buffer_create/buffer_edit)
|
|
|
855
848
|
});
|
|
856
849
|
}
|
|
857
850
|
// Validate XHTML and PlantUML content before writing
|
|
858
|
-
const validationError = await validateContentForWrite(content);
|
|
851
|
+
const validationError = await validateContentForWrite(content, args.bufferId);
|
|
859
852
|
if (validationError) {
|
|
860
853
|
return validationError;
|
|
861
854
|
}
|
|
@@ -1041,14 +1034,15 @@ Use buffer_edit(bufferId, after=ID, content/plantuml/fromBufferId) to modify, th
|
|
|
1041
1034
|
},
|
|
1042
1035
|
},
|
|
1043
1036
|
confluence_draft_list: {
|
|
1044
|
-
description: `List your draft pages. Use confluence_draft_open to load a draft for editing
|
|
1037
|
+
description: `List your draft pages. Use confluence_draft_open to load a draft for editing.
|
|
1038
|
+
|
|
1039
|
+
Returns bufferId. Use buffer_get_chunk to read, buffer_grep to search.`,
|
|
1045
1040
|
inputSchema: z.object({
|
|
1046
1041
|
spaceKey: z.string().optional().describe("Filter by space key"),
|
|
1047
|
-
limit: z.number().optional().describe("Max results (default: 25)"),
|
|
1048
1042
|
}),
|
|
1049
1043
|
handler: async (args) => {
|
|
1050
1044
|
try {
|
|
1051
|
-
const result = await client.listUserDrafts(args.spaceKey
|
|
1045
|
+
const result = await client.listUserDrafts(args.spaceKey);
|
|
1052
1046
|
// Build the base URL for constructing full URLs
|
|
1053
1047
|
const baseUrl = client.getBaseUrl();
|
|
1054
1048
|
const drafts = result.results.map((page) => ({
|
|
@@ -1059,9 +1053,12 @@ Use buffer_edit(bufferId, after=ID, content/plantuml/fromBufferId) to modify, th
|
|
|
1059
1053
|
created: page.version?.when || "",
|
|
1060
1054
|
url: `${baseUrl}/pages/resumedraft.action?draftId=${page.id}`,
|
|
1061
1055
|
}));
|
|
1062
|
-
return
|
|
1056
|
+
return formatSuccessBuffered({
|
|
1063
1057
|
drafts,
|
|
1064
1058
|
total: result.totalSize,
|
|
1059
|
+
}, {
|
|
1060
|
+
resourceType: "confluence_drafts",
|
|
1061
|
+
title: args.spaceKey ? `Drafts in ${args.spaceKey}` : "All Drafts",
|
|
1065
1062
|
});
|
|
1066
1063
|
}
|
|
1067
1064
|
catch (error) {
|
|
@@ -1125,7 +1122,7 @@ Returns new draftId, bufferId, structure (element IDs), and URL. Always use the
|
|
|
1125
1122
|
});
|
|
1126
1123
|
}
|
|
1127
1124
|
// Validate XHTML and PlantUML content before writing
|
|
1128
|
-
const validationError = await validateContentForWrite(savedContent);
|
|
1125
|
+
const validationError = await validateContentForWrite(savedContent, args.bufferId);
|
|
1129
1126
|
if (validationError) {
|
|
1130
1127
|
return validationError;
|
|
1131
1128
|
}
|