outline-mcp-server 4.12.2 → 5.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 +28 -17
- package/build/index.js +52 -51
- package/build/tools/archiveDocument.js +7 -13
- package/build/tools/askDocuments.js +21 -35
- package/build/tools/createCollection.js +14 -29
- package/build/tools/createComment.js +13 -25
- package/build/tools/createDocument.js +15 -34
- package/build/tools/createTemplateFromDocument.js +7 -13
- package/build/tools/deleteComment.js +7 -13
- package/build/tools/deleteDocument.js +7 -13
- package/build/tools/getCollection.js +7 -13
- package/build/tools/getDocument.js +9 -13
- package/build/tools/listCollections.js +18 -12
- package/build/tools/listDocuments.js +34 -55
- package/build/tools/listUsers.js +31 -46
- package/build/tools/moveDocument.js +15 -21
- package/build/tools/searchDocuments.js +14 -21
- package/build/tools/updateCollection.js +14 -29
- package/build/tools/updateComment.js +9 -21
- package/build/tools/updateDocument.js +11 -29
- package/build/utils/getMcpServer.js +16 -0
- package/build/utils/{importTools.js → loadAllTools.js} +8 -5
- package/build/utils/toolRegistry.js +27 -0
- package/package.json +18 -21
- package/bin/cli.js +0 -57
- package/build/e2e/archiveDocument.spec.js +0 -7
- package/build/e2e/askDocuments.spec.js +0 -7
- package/build/e2e/createCollection.spec.js +0 -7
- package/build/e2e/createComment.spec.js +0 -7
- package/build/e2e/createDocument.spec.js +0 -7
- package/build/e2e/createTemplateFromDocument.spec.js +0 -7
- package/build/e2e/deleteComment.spec.js +0 -7
- package/build/e2e/deleteDocument.spec.js +0 -7
- package/build/e2e/getCollection.spec.js +0 -7
- package/build/e2e/getDocument.spec.js +0 -7
- package/build/e2e/listCollections.spec.js +0 -7
- package/build/e2e/listDocuments.spec.js +0 -7
- package/build/e2e/moveDocument.spec.js +0 -7
- package/build/e2e/searchDocuments.spec.js +0 -7
- package/build/e2e/setup.js +0 -33
- package/build/e2e/updateCollection.spec.js +0 -7
- package/build/e2e/updateComment.spec.js +0 -7
- package/build/e2e/updateDocument.spec.js +0 -7
- package/build/e2e/util/smokeTest.js +0 -88
- package/build/types.js +0 -1
- package/build/utils/listTools.js +0 -10
- /package/build/{client.js → outline/outlineClient.js} +0 -0
@@ -1,24 +1,20 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('get_document', {
|
6
7
|
name: 'get_document',
|
7
8
|
description: 'Get details about a specific document. At least id XOR shareId are required.',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
description: 'Unique identifier for the document. Either the UUID or the urlId is acceptable',
|
13
|
-
},
|
14
|
-
},
|
15
|
-
required: ['id'],
|
16
|
-
type: 'object',
|
10
|
+
id: z
|
11
|
+
.string()
|
12
|
+
.describe('Unique identifier for the document. Either the UUID or the urlId is acceptable'),
|
17
13
|
},
|
18
|
-
|
14
|
+
async callback(args) {
|
19
15
|
try {
|
20
16
|
const response = await outlineClient.post('/documents.info', { id: args.id });
|
21
|
-
return response.data.data;
|
17
|
+
return { content: [{ type: 'text', text: JSON.stringify(response.data.data) }] };
|
22
18
|
}
|
23
19
|
catch (error) {
|
24
20
|
console.error('Error getting document:', error.message);
|
@@ -1,27 +1,33 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('list_collections', {
|
6
7
|
name: 'list_collections',
|
7
8
|
description: 'List all collections in the Outline workspace',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
limit: {
|
11
|
-
type: 'number',
|
12
|
-
description: 'Maximum number of collections to return (optional)',
|
13
|
-
},
|
14
|
-
},
|
15
|
-
type: 'object',
|
10
|
+
limit: z.number().describe('Maximum number of collections to return (optional)').optional(),
|
16
11
|
},
|
17
|
-
|
12
|
+
async callback(args) {
|
18
13
|
try {
|
19
14
|
const payload = {};
|
20
15
|
if (args.limit) {
|
21
16
|
payload.limit = args.limit;
|
22
17
|
}
|
23
18
|
const response = await outlineClient.post('/collections.list', payload);
|
24
|
-
return
|
19
|
+
return {
|
20
|
+
content: [
|
21
|
+
{
|
22
|
+
type: 'text',
|
23
|
+
text: `collections: ${JSON.stringify(response.data.data)}`,
|
24
|
+
},
|
25
|
+
{
|
26
|
+
type: 'text',
|
27
|
+
text: `pagination: ${JSON.stringify(response.data.pagination)}`,
|
28
|
+
},
|
29
|
+
],
|
30
|
+
};
|
25
31
|
}
|
26
32
|
catch (error) {
|
27
33
|
console.error('Error listing collections:', error.message);
|
@@ -1,57 +1,33 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('list_documents', {
|
6
7
|
name: 'list_documents',
|
7
8
|
description: 'List documents in the Outline workspace with optional filters',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
description: 'Field to sort by (e.g. "updatedAt") (optional)',
|
29
|
-
},
|
30
|
-
direction: {
|
31
|
-
type: 'string',
|
32
|
-
description: 'Sort direction, either "ASC" or "DESC" (optional)',
|
33
|
-
enum: ['ASC', 'DESC'],
|
34
|
-
},
|
35
|
-
template: {
|
36
|
-
type: 'boolean',
|
37
|
-
description: 'Optionally filter to only templates (optional)',
|
38
|
-
},
|
39
|
-
userId: {
|
40
|
-
type: 'string',
|
41
|
-
description: 'Optionally filter by user ID (optional)',
|
42
|
-
},
|
43
|
-
parentDocumentId: {
|
44
|
-
type: 'string',
|
45
|
-
description: 'Optionally filter by parent document ID (optional)',
|
46
|
-
},
|
47
|
-
backlinkDocumentId: {
|
48
|
-
type: 'string',
|
49
|
-
description: 'Optionally filter by backlink document ID (optional)',
|
50
|
-
},
|
51
|
-
},
|
52
|
-
type: 'object',
|
10
|
+
collectionId: z.string().describe('Filter by collection ID (optional)').optional(),
|
11
|
+
query: z.string().describe('Search query to filter documents (optional)').optional(),
|
12
|
+
limit: z.number().describe('Maximum number of documents to return (optional)').optional(),
|
13
|
+
offset: z.number().describe('Pagination offset (optional)').optional(),
|
14
|
+
sort: z.string().describe('Field to sort by (e.g. "updatedAt") (optional)').optional(),
|
15
|
+
direction: z
|
16
|
+
.enum(['ASC', 'DESC'])
|
17
|
+
.describe('Sort direction, either "ASC" or "DESC" (optional)')
|
18
|
+
.optional(),
|
19
|
+
template: z.boolean().describe('Optionally filter to only templates (optional)').optional(),
|
20
|
+
userId: z.string().describe('Optionally filter by user ID (optional)').optional(),
|
21
|
+
parentDocumentId: z
|
22
|
+
.string()
|
23
|
+
.describe('Optionally filter by parent document ID (optional)')
|
24
|
+
.optional(),
|
25
|
+
backlinkDocumentId: z
|
26
|
+
.string()
|
27
|
+
.describe('Optionally filter by backlink document ID (optional)')
|
28
|
+
.optional(),
|
53
29
|
},
|
54
|
-
|
30
|
+
async callback(args) {
|
55
31
|
try {
|
56
32
|
// Create the payload object
|
57
33
|
const payload = {
|
@@ -78,13 +54,16 @@ registerTool({
|
|
78
54
|
const documents = response.data.data;
|
79
55
|
// Return the documents with additional metadata
|
80
56
|
return {
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
57
|
+
content: [
|
58
|
+
{
|
59
|
+
type: 'text',
|
60
|
+
text: `documents: ${JSON.stringify(documents)}`,
|
61
|
+
},
|
62
|
+
{
|
63
|
+
type: 'text',
|
64
|
+
text: `pagination: ${JSON.stringify(response.data.pagination)}`,
|
65
|
+
},
|
66
|
+
],
|
88
67
|
};
|
89
68
|
}
|
90
69
|
catch (error) {
|
package/build/tools/listUsers.js
CHANGED
@@ -1,54 +1,34 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('list_users', {
|
6
7
|
name: 'list_users',
|
7
8
|
description: 'List all users in the Outline workspace',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
description: 'Search query to filter users (optional)',
|
30
|
-
},
|
31
|
-
emails: {
|
32
|
-
type: 'array',
|
33
|
-
items: {
|
34
|
-
type: 'string',
|
35
|
-
},
|
36
|
-
description: 'Filter by email addresses (optional)',
|
37
|
-
},
|
38
|
-
filter: {
|
39
|
-
type: 'string',
|
40
|
-
description: 'Filter by user status (optional)',
|
41
|
-
enum: ['all', 'invited', 'active', 'suspended'],
|
42
|
-
},
|
43
|
-
role: {
|
44
|
-
type: 'string',
|
45
|
-
description: 'Filter by user role (optional)',
|
46
|
-
enum: ['admin', 'member', 'viewer', 'guest'],
|
47
|
-
},
|
48
|
-
},
|
49
|
-
type: 'object',
|
10
|
+
offset: z.number().describe('Pagination offset (optional)').optional(),
|
11
|
+
limit: z.number().describe('Maximum number of users to return (optional)').optional(),
|
12
|
+
sort: z
|
13
|
+
.string()
|
14
|
+
.describe('Field to sort by (e.g. "name", "email", "createdAt") (optional)')
|
15
|
+
.optional(),
|
16
|
+
direction: z
|
17
|
+
.enum(['ASC', 'DESC'])
|
18
|
+
.describe('Sort direction, either "ASC" or "DESC" (optional)')
|
19
|
+
.optional(),
|
20
|
+
query: z.string().describe('Search query to filter users (optional)').optional(),
|
21
|
+
emails: z.array(z.string()).describe('Filter by email addresses (optional)').optional(),
|
22
|
+
filter: z
|
23
|
+
.enum(['all', 'invited', 'active', 'suspended'])
|
24
|
+
.describe('Filter by user status (optional)')
|
25
|
+
.optional(),
|
26
|
+
role: z
|
27
|
+
.enum(['admin', 'member', 'viewer', 'guest'])
|
28
|
+
.describe('Filter by user role (optional)')
|
29
|
+
.optional(),
|
50
30
|
},
|
51
|
-
|
31
|
+
async callback(args) {
|
52
32
|
try {
|
53
33
|
const payload = {};
|
54
34
|
if (args.offset !== undefined) {
|
@@ -76,7 +56,12 @@ registerTool({
|
|
76
56
|
payload.role = args.role;
|
77
57
|
}
|
78
58
|
const response = await outlineClient.post('/users.list', payload);
|
79
|
-
return
|
59
|
+
return {
|
60
|
+
content: [
|
61
|
+
{ type: 'text', text: `users: ${JSON.stringify(response.data.data)}` },
|
62
|
+
{ type: 'text', text: `pagination: ${JSON.stringify(response.data.pagination)}` },
|
63
|
+
],
|
64
|
+
};
|
80
65
|
}
|
81
66
|
catch (error) {
|
82
67
|
console.error('Error listing users:', error.message);
|
@@ -1,29 +1,23 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('move_document', {
|
6
7
|
name: 'move_document',
|
7
8
|
description: 'Move a document to a different collection or parent document',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
parentDocumentId: {
|
19
|
-
type: 'string',
|
20
|
-
description: 'ID of the parent document to move under (optional)',
|
21
|
-
},
|
22
|
-
},
|
23
|
-
required: ['id'],
|
24
|
-
type: 'object',
|
10
|
+
id: z.string().describe('ID of the document to move'),
|
11
|
+
collectionId: z
|
12
|
+
.string()
|
13
|
+
.describe('ID of the collection to move the document to (optional)')
|
14
|
+
.optional(),
|
15
|
+
parentDocumentId: z
|
16
|
+
.string()
|
17
|
+
.describe('ID of the parent document to move under (optional)')
|
18
|
+
.optional(),
|
25
19
|
},
|
26
|
-
|
20
|
+
async callback(args) {
|
27
21
|
try {
|
28
22
|
const payload = {
|
29
23
|
id: args.id,
|
@@ -35,7 +29,7 @@ registerTool({
|
|
35
29
|
payload.parentDocumentId = args.parentDocumentId;
|
36
30
|
}
|
37
31
|
const response = await outlineClient.post('/documents.move', payload);
|
38
|
-
return response.data.data;
|
32
|
+
return { content: [{ type: 'text', text: JSON.stringify(response.data.data) }] };
|
39
33
|
}
|
40
34
|
catch (error) {
|
41
35
|
console.error('Error moving document:', error.message);
|
@@ -1,29 +1,17 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('search_documents', {
|
6
7
|
name: 'search_documents',
|
7
8
|
description: 'Search for documents in the Outline workspace',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
description: 'Search query to filter documents',
|
13
|
-
},
|
14
|
-
collectionId: {
|
15
|
-
type: 'string',
|
16
|
-
description: 'Filter by collection ID (optional)',
|
17
|
-
},
|
18
|
-
limit: {
|
19
|
-
type: 'number',
|
20
|
-
description: 'Maximum number of documents to return (optional)',
|
21
|
-
},
|
22
|
-
},
|
23
|
-
required: ['query'],
|
24
|
-
type: 'object',
|
10
|
+
query: z.string().describe('Search query to filter documents'),
|
11
|
+
collectionId: z.string().describe('Filter by collection ID (optional)').optional(),
|
12
|
+
limit: z.number().describe('Maximum number of documents to return (optional)').optional(),
|
25
13
|
},
|
26
|
-
|
14
|
+
async callback(args) {
|
27
15
|
try {
|
28
16
|
const payload = {
|
29
17
|
query: args.query,
|
@@ -35,7 +23,12 @@ registerTool({
|
|
35
23
|
payload.limit = args.limit;
|
36
24
|
}
|
37
25
|
const response = await outlineClient.post('/documents.search', payload);
|
38
|
-
return
|
26
|
+
return {
|
27
|
+
content: [
|
28
|
+
{ type: 'text', text: `documents: ${JSON.stringify(response.data.data)}` },
|
29
|
+
{ type: 'text', text: `pagination: ${JSON.stringify(response.data.pagination)}` },
|
30
|
+
],
|
31
|
+
};
|
39
32
|
}
|
40
33
|
catch (error) {
|
41
34
|
console.error('Error searching documents:', error.message);
|
@@ -1,37 +1,22 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('update_collection', {
|
6
7
|
name: 'update_collection',
|
7
8
|
description: 'Update an existing collection',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
},
|
18
|
-
description: {
|
19
|
-
type: 'string',
|
20
|
-
description: 'New description for the collection (optional)',
|
21
|
-
},
|
22
|
-
permission: {
|
23
|
-
type: 'string',
|
24
|
-
description: 'New permission setting for the collection (optional)',
|
25
|
-
},
|
26
|
-
color: {
|
27
|
-
type: 'string',
|
28
|
-
description: 'New color for the collection (optional)',
|
29
|
-
},
|
30
|
-
},
|
31
|
-
required: ['id'],
|
32
|
-
type: 'object',
|
10
|
+
id: z.string().describe('ID of the collection to update'),
|
11
|
+
name: z.string().describe('New name for the collection (optional)').optional(),
|
12
|
+
description: z.string().describe('New description for the collection (optional)').optional(),
|
13
|
+
permission: z
|
14
|
+
.string()
|
15
|
+
.describe('New permission setting for the collection (optional)')
|
16
|
+
.optional(),
|
17
|
+
color: z.string().describe('New color for the collection (optional)').optional(),
|
33
18
|
},
|
34
|
-
|
19
|
+
async callback(args) {
|
35
20
|
try {
|
36
21
|
const payload = {
|
37
22
|
id: args.id,
|
@@ -49,7 +34,7 @@ registerTool({
|
|
49
34
|
payload.color = args.color;
|
50
35
|
}
|
51
36
|
const response = await outlineClient.post('/collections.update', payload);
|
52
|
-
return response.data.data;
|
37
|
+
return { content: [{ type: 'text', text: JSON.stringify(response.data.data) }] };
|
53
38
|
}
|
54
39
|
catch (error) {
|
55
40
|
console.error('Error updating collection:', error.message);
|
@@ -1,29 +1,17 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('update_comment', {
|
6
7
|
name: 'update_comment',
|
7
8
|
description: 'Update an existing comment',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
description: 'ID of the comment to update',
|
13
|
-
},
|
14
|
-
text: {
|
15
|
-
type: 'string',
|
16
|
-
description: 'New content for the comment in markdown format',
|
17
|
-
},
|
18
|
-
data: {
|
19
|
-
type: 'object',
|
20
|
-
description: 'Additional data for the comment (optional)',
|
21
|
-
},
|
22
|
-
},
|
23
|
-
required: ['id'],
|
24
|
-
type: 'object',
|
10
|
+
id: z.string().describe('ID of the comment to update'),
|
11
|
+
text: z.string().describe('New content for the comment in markdown format').optional(),
|
12
|
+
data: z.object({}).describe('Additional data for the comment (optional)').optional(),
|
25
13
|
},
|
26
|
-
|
14
|
+
async callback(args) {
|
27
15
|
try {
|
28
16
|
const payload = {
|
29
17
|
id: args.id,
|
@@ -35,7 +23,7 @@ registerTool({
|
|
35
23
|
payload.data = args.data;
|
36
24
|
}
|
37
25
|
const response = await outlineClient.post('/comments.update', payload);
|
38
|
-
return response.data.data;
|
26
|
+
return { content: [{ type: 'text', text: JSON.stringify(response.data.data) }] };
|
39
27
|
}
|
40
28
|
catch (error) {
|
41
29
|
console.error('Error updating comment:', error.message);
|
@@ -1,37 +1,19 @@
|
|
1
1
|
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
2
|
-
import { outlineClient } from '../
|
3
|
-
import
|
2
|
+
import { outlineClient } from '../outline/outlineClient.js';
|
3
|
+
import toolRegistry from '../utils/toolRegistry.js';
|
4
|
+
import z from 'zod';
|
4
5
|
// Register this tool
|
5
|
-
|
6
|
+
toolRegistry.register('update_document', {
|
6
7
|
name: 'update_document',
|
7
8
|
description: 'Update an existing document',
|
8
9
|
inputSchema: {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
title: {
|
15
|
-
type: 'string',
|
16
|
-
description: 'New title for the document',
|
17
|
-
},
|
18
|
-
text: {
|
19
|
-
type: 'string',
|
20
|
-
description: 'New content for the document in markdown format',
|
21
|
-
},
|
22
|
-
publish: {
|
23
|
-
type: 'boolean',
|
24
|
-
description: 'Whether to publish the document',
|
25
|
-
},
|
26
|
-
done: {
|
27
|
-
type: 'boolean',
|
28
|
-
description: 'Whether the document is marked as done',
|
29
|
-
},
|
30
|
-
},
|
31
|
-
required: ['documentId'],
|
32
|
-
type: 'object',
|
10
|
+
documentId: z.string().describe('ID of the document to update'),
|
11
|
+
title: z.string().describe('New title for the document').optional(),
|
12
|
+
text: z.string().describe('New content for the document in markdown format').optional(),
|
13
|
+
publish: z.boolean().describe('Whether to publish the document').optional(),
|
14
|
+
done: z.boolean().describe('Whether the document is marked as done').optional(),
|
33
15
|
},
|
34
|
-
|
16
|
+
async callback(args) {
|
35
17
|
try {
|
36
18
|
const payload = {
|
37
19
|
id: args.documentId,
|
@@ -49,7 +31,7 @@ registerTool({
|
|
49
31
|
payload.done = args.done;
|
50
32
|
}
|
51
33
|
const response = await outlineClient.post('/documents.update', payload);
|
52
|
-
return response.data.data;
|
34
|
+
return { content: [{ type: 'text', text: JSON.stringify(response.data.data) }] };
|
53
35
|
}
|
54
36
|
catch (error) {
|
55
37
|
console.error('Error updating document:', error.message);
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
2
|
+
import { loadAllTools } from './loadAllTools.js';
|
3
|
+
// Helper to create a new MCP server instance with all tools registered
|
4
|
+
export async function getMcpServer() {
|
5
|
+
const server = new McpServer({
|
6
|
+
name: 'outline-mcp',
|
7
|
+
version: process.env.npm_package_version || 'unknown',
|
8
|
+
description: 'Outline Model Context Protocol server',
|
9
|
+
});
|
10
|
+
await loadAllTools(tool => server.registerTool(tool.name, {
|
11
|
+
description: tool.description,
|
12
|
+
inputSchema: tool.inputSchema,
|
13
|
+
outputSchema: tool.outputSchema,
|
14
|
+
}, tool.callback));
|
15
|
+
return server;
|
16
|
+
}
|
@@ -1,23 +1,26 @@
|
|
1
1
|
import fs from 'fs';
|
2
2
|
import path from 'path';
|
3
3
|
import { fileURLToPath } from 'url';
|
4
|
-
import
|
4
|
+
import toolRegistry from './toolRegistry.js';
|
5
5
|
/**
|
6
6
|
* Dynamically imports all tool files from the tools directory
|
7
7
|
*/
|
8
|
-
export async function
|
8
|
+
export async function loadAllTools(onToolLoaded) {
|
9
9
|
// Get the directory path
|
10
10
|
const __filename = fileURLToPath(import.meta.url);
|
11
11
|
const __dirname = path.dirname(__filename);
|
12
12
|
const toolsDir = path.join(__dirname, '..', 'tools');
|
13
|
-
//
|
13
|
+
// List tool files
|
14
14
|
const toolFiles = fs
|
15
15
|
.readdirSync(toolsDir)
|
16
16
|
.filter(file => file.endsWith('.ts') || file.endsWith('.js'));
|
17
|
+
// Import all tool files, causing them to be restered via `registerTool`
|
17
18
|
for (const file of toolFiles) {
|
18
19
|
const resolved = path.resolve(toolsDir, file);
|
19
20
|
await import(resolved);
|
20
21
|
}
|
21
|
-
//
|
22
|
-
|
22
|
+
// configure McpServer with all definitions
|
23
|
+
for (const tool of toolRegistry.tools) {
|
24
|
+
await onToolLoaded?.(tool);
|
25
|
+
}
|
23
26
|
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class ToolRegistry {
|
2
|
+
constructor() {
|
3
|
+
this.registry = new Map();
|
4
|
+
this.registry = new Map();
|
5
|
+
}
|
6
|
+
get tools() {
|
7
|
+
return Array.from(this.registry.values());
|
8
|
+
}
|
9
|
+
has(name) {
|
10
|
+
return this.registry.has(name);
|
11
|
+
}
|
12
|
+
get(name) {
|
13
|
+
return this.registry.get(name);
|
14
|
+
}
|
15
|
+
/**
|
16
|
+
* Registers a tool with the global registry
|
17
|
+
*/
|
18
|
+
register(name, definition) {
|
19
|
+
if (this.has(name)) {
|
20
|
+
throw new Error(`Attempted to register duplicate tool: "${name}"`);
|
21
|
+
}
|
22
|
+
this.registry.set(name, definition);
|
23
|
+
}
|
24
|
+
}
|
25
|
+
// We'll collect all tool definitions here, keyed by name
|
26
|
+
const toolRegistry = new ToolRegistry();
|
27
|
+
export default toolRegistry;
|