@vinhnguyen/confluence-mcp 1.0.0 → 1.1.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 +114 -5
- package/index.js +342 -0
- package/package.json +45 -15
package/README.md
CHANGED
|
@@ -5,23 +5,39 @@ A Model Context Protocol (MCP) server that provides tools for interacting with C
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Page Operations**: Get, create, update, delete pages
|
|
8
|
+
- **Page Hierarchy**: Move pages, list child pages, get page with children
|
|
8
9
|
- **Space Operations**: List spaces, get space details, browse space content
|
|
9
10
|
- **Search**: Full CQL support, search by text or title
|
|
10
|
-
- **Labels**: Get, add, remove page labels
|
|
11
|
+
- **Labels**: Get, add, remove, and batch manage page labels
|
|
11
12
|
- **Comments**: Read and add page comments
|
|
12
13
|
- **Attachments**: List page attachments
|
|
13
14
|
- **Special**: Extract DONE sections from daily reports
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
18
|
+
### Using npx (recommended, no install required)
|
|
19
|
+
|
|
20
|
+
No installation needed! Just configure Claude Desktop or Claude Code as shown below.
|
|
21
|
+
|
|
22
|
+
### Global Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g @vinhnguyen/confluence-mcp
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### From Source
|
|
29
|
+
|
|
17
30
|
```bash
|
|
31
|
+
git clone https://github.com/vinhnguyen/confluence-mcp.git
|
|
18
32
|
cd confluence-mcp
|
|
19
33
|
npm install
|
|
20
34
|
```
|
|
21
35
|
|
|
22
36
|
## Configuration
|
|
23
37
|
|
|
24
|
-
|
|
38
|
+
### Prerequisites
|
|
39
|
+
|
|
40
|
+
The MCP server requires Atlassian credentials:
|
|
25
41
|
|
|
26
42
|
| Variable | Description | Example |
|
|
27
43
|
|----------|-------------|---------|
|
|
@@ -35,9 +51,49 @@ The MCP server requires three environment variables:
|
|
|
35
51
|
2. Click "Create API token"
|
|
36
52
|
3. Give it a label and copy the token
|
|
37
53
|
|
|
38
|
-
|
|
54
|
+
### Claude Desktop
|
|
55
|
+
|
|
56
|
+
Add the server to your Claude Desktop configuration file:
|
|
57
|
+
|
|
58
|
+
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
59
|
+
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
60
|
+
|
|
61
|
+
Using npx (recommended, no install required):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"confluence": {
|
|
67
|
+
"command": "npx",
|
|
68
|
+
"args": ["-y", "@vinhnguyen/confluence-mcp"],
|
|
69
|
+
"env": {
|
|
70
|
+
"ATLASSIAN_EMAIL": "your.email@company.com",
|
|
71
|
+
"ATLASSIAN_API_TOKEN": "your_api_token",
|
|
72
|
+
"ATLASSIAN_DOMAIN": "your-domain.atlassian.net"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
39
78
|
|
|
40
|
-
|
|
79
|
+
Or if installed globally via npm:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"mcpServers": {
|
|
84
|
+
"confluence": {
|
|
85
|
+
"command": "confluence-mcp",
|
|
86
|
+
"env": {
|
|
87
|
+
"ATLASSIAN_EMAIL": "your.email@company.com",
|
|
88
|
+
"ATLASSIAN_API_TOKEN": "your_api_token",
|
|
89
|
+
"ATLASSIAN_DOMAIN": "your-domain.atlassian.net"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Or from source:
|
|
41
97
|
|
|
42
98
|
```json
|
|
43
99
|
{
|
|
@@ -55,6 +111,55 @@ Add to your Claude Code MCP settings (`~/.claude/claude_desktop_config.json` or
|
|
|
55
111
|
}
|
|
56
112
|
```
|
|
57
113
|
|
|
114
|
+
### Claude Code
|
|
115
|
+
|
|
116
|
+
Add to your `~/.claude.json` (project) or `~/.claude/settings.json` (global):
|
|
117
|
+
|
|
118
|
+
Using npx (recommended):
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"mcpServers": {
|
|
123
|
+
"confluence": {
|
|
124
|
+
"command": "npx",
|
|
125
|
+
"args": ["-y", "@vinhnguyen/confluence-mcp"],
|
|
126
|
+
"env": {
|
|
127
|
+
"ATLASSIAN_EMAIL": "your.email@company.com",
|
|
128
|
+
"ATLASSIAN_API_TOKEN": "your_api_token",
|
|
129
|
+
"ATLASSIAN_DOMAIN": "your-domain.atlassian.net"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Or if installed globally:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"mcpServers": {
|
|
141
|
+
"confluence": {
|
|
142
|
+
"command": "confluence-mcp",
|
|
143
|
+
"env": {
|
|
144
|
+
"ATLASSIAN_EMAIL": "your.email@company.com",
|
|
145
|
+
"ATLASSIAN_API_TOKEN": "your_api_token",
|
|
146
|
+
"ATLASSIAN_DOMAIN": "your-domain.atlassian.net"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Restart Claude Desktop or Claude Code after updating the config.**
|
|
154
|
+
|
|
155
|
+
## Environment Variables
|
|
156
|
+
|
|
157
|
+
| Variable | Description | Required |
|
|
158
|
+
|----------|-------------|----------|
|
|
159
|
+
| `ATLASSIAN_EMAIL` | Your Atlassian account email | Yes |
|
|
160
|
+
| `ATLASSIAN_API_TOKEN` | API token from Atlassian | Yes |
|
|
161
|
+
| `ATLASSIAN_DOMAIN` | Your Confluence domain (e.g., `company.atlassian.net`) | Yes |
|
|
162
|
+
|
|
58
163
|
## Available Tools
|
|
59
164
|
|
|
60
165
|
### Page Operations
|
|
@@ -64,8 +169,12 @@ Add to your Claude Code MCP settings (`~/.claude/claude_desktop_config.json` or
|
|
|
64
169
|
| `confluence_get_page` | Get page details including content, version, metadata |
|
|
65
170
|
| `confluence_get_page_content` | Get page content as text or HTML |
|
|
66
171
|
| `confluence_get_child_pages` | Get all child pages of a parent (with pagination) |
|
|
172
|
+
| `confluence_get_page_with_children` | Get a page along with all its immediate child pages |
|
|
173
|
+
| `confluence_list_child_pages` | List immediate child pages (folder contents view) |
|
|
67
174
|
| `confluence_create_page` | Create a new page in a space |
|
|
68
|
-
| `confluence_update_page` | Update an existing page |
|
|
175
|
+
| `confluence_update_page` | Update an existing page (requires version number) |
|
|
176
|
+
| `confluence_update_page_auto` | Update a page with automatic version handling |
|
|
177
|
+
| `confluence_move_page` | Move a page to a new parent (restructure hierarchy) |
|
|
69
178
|
| `confluence_delete_page` | Delete a page (moves to trash) |
|
|
70
179
|
|
|
71
180
|
### Space Operations
|
package/index.js
CHANGED
|
@@ -204,6 +204,22 @@ class ConfluenceClient {
|
|
|
204
204
|
};
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
// Auto-versioning update: fetches current version automatically
|
|
208
|
+
async updatePageAuto(pageId, newTitle = null, newBody = null) {
|
|
209
|
+
// Fetch current page to get version and existing data
|
|
210
|
+
const currentPage = await this.getPage(pageId);
|
|
211
|
+
|
|
212
|
+
if (!currentPage) {
|
|
213
|
+
throw new Error(`Page with ID ${pageId} not found`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const title = newTitle || currentPage.title;
|
|
217
|
+
const content = newBody || currentPage.content;
|
|
218
|
+
const currentVersion = currentPage.version;
|
|
219
|
+
|
|
220
|
+
return this.updatePage(pageId, title, content, currentVersion);
|
|
221
|
+
}
|
|
222
|
+
|
|
207
223
|
async deletePage(pageId) {
|
|
208
224
|
await this.request(`/wiki/rest/api/content/${pageId}`, {
|
|
209
225
|
method: "DELETE",
|
|
@@ -211,6 +227,126 @@ class ConfluenceClient {
|
|
|
211
227
|
return { success: true, deletedPageId: pageId };
|
|
212
228
|
}
|
|
213
229
|
|
|
230
|
+
// List immediate child pages (using API v2 for better pagination)
|
|
231
|
+
async listChildPages(pageId, limit = 50) {
|
|
232
|
+
const allChildren = [];
|
|
233
|
+
let nextUrl = `/wiki/api/v2/pages/${pageId}/children?limit=${limit}`;
|
|
234
|
+
|
|
235
|
+
while (nextUrl) {
|
|
236
|
+
const url = nextUrl.startsWith("http")
|
|
237
|
+
? nextUrl
|
|
238
|
+
: `${this.baseUrl}${nextUrl}`;
|
|
239
|
+
const data = await this.request(url);
|
|
240
|
+
|
|
241
|
+
if (data.results) {
|
|
242
|
+
allChildren.push(
|
|
243
|
+
...data.results.map((page) => ({
|
|
244
|
+
id: page.id,
|
|
245
|
+
title: page.title,
|
|
246
|
+
status: page.status,
|
|
247
|
+
parentId: page.parentId,
|
|
248
|
+
spaceId: page.spaceId,
|
|
249
|
+
}))
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
nextUrl = data._links?.next || null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
parentPageId: pageId,
|
|
258
|
+
childCount: allChildren.length,
|
|
259
|
+
children: allChildren,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Move a page to a new parent (restructure hierarchy)
|
|
264
|
+
async movePage(pageId, newParentId) {
|
|
265
|
+
// First, get current page details
|
|
266
|
+
const currentPage = await this.request(
|
|
267
|
+
`/wiki/rest/api/content/${pageId}?expand=version,space,ancestors`
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
if (!currentPage) {
|
|
271
|
+
throw new Error(`Page with ID ${pageId} not found`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Update page with new parent (ancestors)
|
|
275
|
+
const body = {
|
|
276
|
+
type: "page",
|
|
277
|
+
title: currentPage.title,
|
|
278
|
+
ancestors: [{ id: newParentId }],
|
|
279
|
+
version: {
|
|
280
|
+
number: currentPage.version.number + 1,
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const data = await this.request(`/wiki/rest/api/content/${pageId}`, {
|
|
285
|
+
method: "PUT",
|
|
286
|
+
body: JSON.stringify(body),
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
id: data.id,
|
|
291
|
+
title: data.title,
|
|
292
|
+
newParentId: newParentId,
|
|
293
|
+
version: data.version?.number,
|
|
294
|
+
webUrl: data._links?.webui
|
|
295
|
+
? `${this.baseUrl}/wiki${data._links.webui}`
|
|
296
|
+
: null,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Manage labels: add or remove multiple labels at once
|
|
301
|
+
async manageLabels(pageId, action, labels) {
|
|
302
|
+
if (!Array.isArray(labels) || labels.length === 0) {
|
|
303
|
+
throw new Error("Labels must be a non-empty array");
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const results = {
|
|
307
|
+
pageId,
|
|
308
|
+
action,
|
|
309
|
+
processed: [],
|
|
310
|
+
errors: [],
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
if (action === "add") {
|
|
314
|
+
// Add all labels at once
|
|
315
|
+
const labelData = labels.map((name) => ({ name, prefix: "global" }));
|
|
316
|
+
try {
|
|
317
|
+
const data = await this.request(
|
|
318
|
+
`/wiki/rest/api/content/${pageId}/label`,
|
|
319
|
+
{
|
|
320
|
+
method: "POST",
|
|
321
|
+
body: JSON.stringify(labelData),
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
results.processed = data.results.map((label) => label.name);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
results.errors.push({ labels, error: error.message });
|
|
327
|
+
}
|
|
328
|
+
} else if (action === "remove") {
|
|
329
|
+
// Remove labels one by one (API limitation)
|
|
330
|
+
for (const labelName of labels) {
|
|
331
|
+
try {
|
|
332
|
+
await this.request(
|
|
333
|
+
`/wiki/rest/api/content/${pageId}/label/${labelName}`,
|
|
334
|
+
{
|
|
335
|
+
method: "DELETE",
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
results.processed.push(labelName);
|
|
339
|
+
} catch (error) {
|
|
340
|
+
results.errors.push({ label: labelName, error: error.message });
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
throw new Error(`Invalid action: ${action}. Use 'add' or 'remove'.`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return results;
|
|
348
|
+
}
|
|
349
|
+
|
|
214
350
|
// -------------------------------------------------------------------------
|
|
215
351
|
// Space Operations
|
|
216
352
|
// -------------------------------------------------------------------------
|
|
@@ -402,6 +538,77 @@ class ConfluenceClient {
|
|
|
402
538
|
fullContent: content,
|
|
403
539
|
};
|
|
404
540
|
}
|
|
541
|
+
|
|
542
|
+
// -------------------------------------------------------------------------
|
|
543
|
+
// Get page with children
|
|
544
|
+
// -------------------------------------------------------------------------
|
|
545
|
+
|
|
546
|
+
async getPageWithChildren(pageId, includeFullContent = false) {
|
|
547
|
+
// Fetch the parent page
|
|
548
|
+
const parentPage = await this.getPage(pageId);
|
|
549
|
+
|
|
550
|
+
// Fetch child pages (using existing getChildPages method which handles pagination)
|
|
551
|
+
let childPages = [];
|
|
552
|
+
try {
|
|
553
|
+
childPages = await this.getChildPages(pageId);
|
|
554
|
+
} catch (error) {
|
|
555
|
+
// If fetching children fails (e.g., no children or permission issues), continue with empty array
|
|
556
|
+
childPages = [];
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// If includeFullContent is true, fetch full content for each child page
|
|
560
|
+
let childPagesWithContent = [];
|
|
561
|
+
if (includeFullContent && childPages.length > 0) {
|
|
562
|
+
childPagesWithContent = await Promise.all(
|
|
563
|
+
childPages.map(async (child) => {
|
|
564
|
+
try {
|
|
565
|
+
const fullChild = await this.getPage(child.id);
|
|
566
|
+
return {
|
|
567
|
+
id: fullChild.id,
|
|
568
|
+
title: fullChild.title,
|
|
569
|
+
spaceKey: fullChild.spaceKey,
|
|
570
|
+
version: fullChild.version,
|
|
571
|
+
content: fullChild.content,
|
|
572
|
+
contentAsText: fullChild.contentAsText,
|
|
573
|
+
webUrl: fullChild.webUrl,
|
|
574
|
+
};
|
|
575
|
+
} catch (error) {
|
|
576
|
+
// If fetching a child fails, return basic info with error
|
|
577
|
+
return {
|
|
578
|
+
id: child.id,
|
|
579
|
+
title: child.title,
|
|
580
|
+
status: child.status,
|
|
581
|
+
error: `Failed to fetch content: ${error.message}`,
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
})
|
|
585
|
+
);
|
|
586
|
+
} else {
|
|
587
|
+
// Just return basic info (id, title, status)
|
|
588
|
+
childPagesWithContent = childPages.map((child) => ({
|
|
589
|
+
id: child.id,
|
|
590
|
+
title: child.title,
|
|
591
|
+
status: child.status,
|
|
592
|
+
}));
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return {
|
|
596
|
+
parent: {
|
|
597
|
+
id: parentPage.id,
|
|
598
|
+
title: parentPage.title,
|
|
599
|
+
spaceKey: parentPage.spaceKey,
|
|
600
|
+
version: parentPage.version,
|
|
601
|
+
content: parentPage.content,
|
|
602
|
+
contentAsText: parentPage.contentAsText,
|
|
603
|
+
webUrl: parentPage.webUrl,
|
|
604
|
+
},
|
|
605
|
+
childPages: {
|
|
606
|
+
count: childPagesWithContent.length,
|
|
607
|
+
includeFullContent,
|
|
608
|
+
pages: childPagesWithContent,
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
}
|
|
405
612
|
}
|
|
406
613
|
|
|
407
614
|
// ============================================================================
|
|
@@ -550,6 +757,94 @@ const TOOLS = [
|
|
|
550
757
|
required: ["pageId"],
|
|
551
758
|
},
|
|
552
759
|
},
|
|
760
|
+
{
|
|
761
|
+
name: "confluence_update_page_auto",
|
|
762
|
+
description:
|
|
763
|
+
"Update an existing Confluence page with automatic version handling. Fetches the current version automatically so you don't need to provide it. You can update title, body, or both.",
|
|
764
|
+
inputSchema: {
|
|
765
|
+
type: "object",
|
|
766
|
+
properties: {
|
|
767
|
+
pageId: {
|
|
768
|
+
type: "string",
|
|
769
|
+
description: "The ID of the page to update",
|
|
770
|
+
},
|
|
771
|
+
newTitle: {
|
|
772
|
+
type: "string",
|
|
773
|
+
description: "The new title for the page (optional - keeps existing title if not provided)",
|
|
774
|
+
},
|
|
775
|
+
newBody: {
|
|
776
|
+
type: "string",
|
|
777
|
+
description: "The new content in Confluence storage format (XHTML). Optional - keeps existing content if not provided.",
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
required: ["pageId"],
|
|
781
|
+
},
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
name: "confluence_list_child_pages",
|
|
785
|
+
description:
|
|
786
|
+
"List all immediate child pages of a parent page (folder contents view). Returns page IDs, titles, and status for each child.",
|
|
787
|
+
inputSchema: {
|
|
788
|
+
type: "object",
|
|
789
|
+
properties: {
|
|
790
|
+
pageId: {
|
|
791
|
+
type: "string",
|
|
792
|
+
description: "The ID of the parent page to list children from",
|
|
793
|
+
},
|
|
794
|
+
limit: {
|
|
795
|
+
type: "number",
|
|
796
|
+
description: "Maximum number of children per API request (default: 50). Pagination is handled automatically.",
|
|
797
|
+
},
|
|
798
|
+
},
|
|
799
|
+
required: ["pageId"],
|
|
800
|
+
},
|
|
801
|
+
},
|
|
802
|
+
{
|
|
803
|
+
name: "confluence_move_page",
|
|
804
|
+
description:
|
|
805
|
+
"Move a page to a new parent, restructuring the page hierarchy. The page will become a child of the specified new parent page.",
|
|
806
|
+
inputSchema: {
|
|
807
|
+
type: "object",
|
|
808
|
+
properties: {
|
|
809
|
+
pageId: {
|
|
810
|
+
type: "string",
|
|
811
|
+
description: "The ID of the page to move",
|
|
812
|
+
},
|
|
813
|
+
newParentId: {
|
|
814
|
+
type: "string",
|
|
815
|
+
description: "The ID of the new parent page",
|
|
816
|
+
},
|
|
817
|
+
},
|
|
818
|
+
required: ["pageId", "newParentId"],
|
|
819
|
+
},
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
name: "confluence_manage_labels",
|
|
823
|
+
description:
|
|
824
|
+
"Add or remove multiple labels from a page in a single operation. Use action 'add' to add labels or 'remove' to remove them.",
|
|
825
|
+
inputSchema: {
|
|
826
|
+
type: "object",
|
|
827
|
+
properties: {
|
|
828
|
+
pageId: {
|
|
829
|
+
type: "string",
|
|
830
|
+
description: "The ID of the page to manage labels on",
|
|
831
|
+
},
|
|
832
|
+
action: {
|
|
833
|
+
type: "string",
|
|
834
|
+
enum: ["add", "remove"],
|
|
835
|
+
description: "The action to perform: 'add' to add labels, 'remove' to remove labels",
|
|
836
|
+
},
|
|
837
|
+
labels: {
|
|
838
|
+
type: "array",
|
|
839
|
+
items: {
|
|
840
|
+
type: "string",
|
|
841
|
+
},
|
|
842
|
+
description: "Array of label names to add or remove",
|
|
843
|
+
},
|
|
844
|
+
},
|
|
845
|
+
required: ["pageId", "action", "labels"],
|
|
846
|
+
},
|
|
847
|
+
},
|
|
553
848
|
|
|
554
849
|
// Space Operations
|
|
555
850
|
{
|
|
@@ -795,6 +1090,26 @@ const TOOLS = [
|
|
|
795
1090
|
required: ["pageId"],
|
|
796
1091
|
},
|
|
797
1092
|
},
|
|
1093
|
+
{
|
|
1094
|
+
name: "confluence_get_page_with_children",
|
|
1095
|
+
description:
|
|
1096
|
+
"Get a Confluence page along with all its immediate child pages in a single request. Returns the parent page content followed by a list of child pages. Optionally fetches full content for each child page.",
|
|
1097
|
+
inputSchema: {
|
|
1098
|
+
type: "object",
|
|
1099
|
+
properties: {
|
|
1100
|
+
pageId: {
|
|
1101
|
+
type: "string",
|
|
1102
|
+
description: "The ID of the parent page to retrieve",
|
|
1103
|
+
},
|
|
1104
|
+
includeFullContent: {
|
|
1105
|
+
type: "boolean",
|
|
1106
|
+
description:
|
|
1107
|
+
"If true, fetch full content for each child page. If false (default), only return child page IDs and titles.",
|
|
1108
|
+
},
|
|
1109
|
+
},
|
|
1110
|
+
required: ["pageId"],
|
|
1111
|
+
},
|
|
1112
|
+
},
|
|
798
1113
|
];
|
|
799
1114
|
|
|
800
1115
|
// ============================================================================
|
|
@@ -847,6 +1162,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
847
1162
|
result = await client.deletePage(args.pageId);
|
|
848
1163
|
break;
|
|
849
1164
|
|
|
1165
|
+
case "confluence_update_page_auto":
|
|
1166
|
+
result = await client.updatePageAuto(
|
|
1167
|
+
args.pageId,
|
|
1168
|
+
args.newTitle,
|
|
1169
|
+
args.newBody
|
|
1170
|
+
);
|
|
1171
|
+
break;
|
|
1172
|
+
|
|
1173
|
+
case "confluence_list_child_pages":
|
|
1174
|
+
result = await client.listChildPages(args.pageId, args.limit);
|
|
1175
|
+
break;
|
|
1176
|
+
|
|
1177
|
+
case "confluence_move_page":
|
|
1178
|
+
result = await client.movePage(args.pageId, args.newParentId);
|
|
1179
|
+
break;
|
|
1180
|
+
|
|
1181
|
+
case "confluence_manage_labels":
|
|
1182
|
+
result = await client.manageLabels(args.pageId, args.action, args.labels);
|
|
1183
|
+
break;
|
|
1184
|
+
|
|
850
1185
|
// Space Operations
|
|
851
1186
|
case "confluence_list_spaces":
|
|
852
1187
|
result = await client.listSpaces(args.limit);
|
|
@@ -913,6 +1248,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
913
1248
|
result = await client.extractDoneSections(args.pageId);
|
|
914
1249
|
break;
|
|
915
1250
|
|
|
1251
|
+
case "confluence_get_page_with_children":
|
|
1252
|
+
result = await client.getPageWithChildren(
|
|
1253
|
+
args.pageId,
|
|
1254
|
+
args.includeFullContent || false
|
|
1255
|
+
);
|
|
1256
|
+
break;
|
|
1257
|
+
|
|
916
1258
|
default:
|
|
917
1259
|
throw new Error(`Unknown tool: ${name}`);
|
|
918
1260
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vinhnguyen/confluence-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "MCP server for Confluence - read, create, update, delete pages and manage spaces",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"confluence-mcp": "./index.js"
|
|
9
9
|
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/glorynguyen/confluence-mcp.git"
|
|
13
|
+
},
|
|
10
14
|
"scripts": {
|
|
11
|
-
"start": "node index.js"
|
|
15
|
+
"start": "node index.js",
|
|
16
|
+
"semantic-release": "semantic-release"
|
|
12
17
|
},
|
|
13
18
|
"keywords": [
|
|
14
19
|
"mcp",
|
|
@@ -19,25 +24,50 @@
|
|
|
19
24
|
"ai",
|
|
20
25
|
"llm"
|
|
21
26
|
],
|
|
22
|
-
"author": "
|
|
27
|
+
"author": "Vinh Nguyen",
|
|
23
28
|
"license": "MIT",
|
|
24
|
-
"
|
|
25
|
-
"type": "git",
|
|
26
|
-
"url": "https://github.com/vinhnguyen/confluence-mcp"
|
|
27
|
-
},
|
|
28
|
-
"homepage": "https://github.com/vinhnguyen/confluence-mcp#readme",
|
|
29
|
+
"homepage": "https://github.com/glorynguyen/confluence-mcp#readme",
|
|
29
30
|
"bugs": {
|
|
30
|
-
"url": "https://github.com/
|
|
31
|
+
"url": "https://github.com/glorynguyen/confluence-mcp/issues"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
35
|
+
"html-to-text": "^9.0.5"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
39
|
+
"@semantic-release/git": "^10.0.1",
|
|
40
|
+
"@semantic-release/github": "^12.0.3",
|
|
41
|
+
"semantic-release": "^25.0.3"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
31
45
|
},
|
|
32
46
|
"files": [
|
|
33
47
|
"index.js",
|
|
34
48
|
"README.md"
|
|
35
49
|
],
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
50
|
+
"release": {
|
|
51
|
+
"branches": [
|
|
52
|
+
"main"
|
|
53
|
+
],
|
|
54
|
+
"plugins": [
|
|
55
|
+
"@semantic-release/commit-analyzer",
|
|
56
|
+
"@semantic-release/release-notes-generator",
|
|
57
|
+
"@semantic-release/changelog",
|
|
58
|
+
"@semantic-release/npm",
|
|
59
|
+
[
|
|
60
|
+
"@semantic-release/git",
|
|
61
|
+
{
|
|
62
|
+
"assets": [
|
|
63
|
+
"package.json",
|
|
64
|
+
"package-lock.json",
|
|
65
|
+
"CHANGELOG.md"
|
|
66
|
+
],
|
|
67
|
+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"@semantic-release/github"
|
|
71
|
+
]
|
|
42
72
|
}
|
|
43
73
|
}
|