aiquila-mcp 0.3.28 → 0.3.30
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/dist/auth/provider.js +5 -2
- package/dist/server.js +2 -0
- package/dist/tool-registry.js +22 -5
- package/dist/tools/apps/absence.js +21 -0
- package/dist/tools/apps/activity.js +14 -0
- package/dist/tools/apps/aiquila.js +21 -0
- package/dist/tools/apps/announcements.js +21 -0
- package/dist/tools/apps/assistant.js +28 -0
- package/dist/tools/apps/bookmarks.js +91 -0
- package/dist/tools/apps/calendar.js +42 -0
- package/dist/tools/apps/circles.js +56 -0
- package/dist/tools/apps/contacts.js +42 -0
- package/dist/tools/apps/cookbook.js +42 -0
- package/dist/tools/apps/cowork.js +67 -6
- package/dist/tools/apps/deck.js +84 -0
- package/dist/tools/apps/forms.js +175 -0
- package/dist/tools/apps/groups.js +28 -0
- package/dist/tools/apps/mail.js +70 -0
- package/dist/tools/apps/maps.js +175 -0
- package/dist/tools/apps/news.js +119 -0
- package/dist/tools/apps/notes.js +35 -0
- package/dist/tools/apps/notifications.js +28 -0
- package/dist/tools/apps/passman.js +21 -0
- package/dist/tools/apps/photos.js +77 -0
- package/dist/tools/apps/polls.js +147 -0
- package/dist/tools/apps/projects.js +49 -0
- package/dist/tools/apps/recommendations.js +7 -0
- package/dist/tools/apps/registration.js +21 -0
- package/dist/tools/apps/shares.js +70 -0
- package/dist/tools/apps/social-sharing.js +7 -0
- package/dist/tools/apps/talk.js +70 -0
- package/dist/tools/apps/tasks.js +42 -0
- package/dist/tools/apps/terms-of-service.js +35 -0
- package/dist/tools/apps/text.js +35 -0
- package/dist/tools/apps/translate.js +7 -0
- package/dist/tools/apps/trash.js +21 -0
- package/dist/tools/apps/user-status.js +35 -0
- package/dist/tools/apps/users.js +28 -0
- package/dist/tools/apps/versions.js +14 -0
- package/dist/tools/system/apps.js +42 -0
- package/dist/tools/system/files.js +105 -0
- package/dist/tools/system/occ.js +7 -0
- package/dist/tools/system/search.js +14 -0
- package/dist/tools/system/security.js +14 -0
- package/dist/tools/system/status.js +21 -0
- package/dist/tools/system/tags.js +42 -0
- package/dist/tools/types.js +0 -3
- package/dist/transports/http.js +51 -3
- package/dist/transports/lazy-auth.js +63 -0
- package/package.json +1 -1
package/dist/auth/provider.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
3
3
|
import { SignJWT, jwtVerify } from 'jose';
|
|
4
|
-
import { InvalidGrantError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
|
|
4
|
+
import { InvalidGrantError, InvalidTokenError, } from '@modelcontextprotocol/sdk/server/auth/errors.js';
|
|
5
5
|
import { ClientsStore, CodeStore, RefreshStore } from './store.js';
|
|
6
6
|
import { logger } from '../logger.js';
|
|
7
7
|
// --- JWT helpers (HMAC-SHA256 via jose) ---
|
|
@@ -196,7 +196,10 @@ export class NextcloudOAuthProvider {
|
|
|
196
196
|
const claims = await verifyJwt(token, this.getSecret(), issuer ? { issuer, audience: new URL('/mcp', issuer).toString() } : undefined);
|
|
197
197
|
if (!claims) {
|
|
198
198
|
logger.warn('[auth] Access token verification failed: invalid or expired token');
|
|
199
|
-
|
|
199
|
+
// InvalidTokenError (not a bare Error) so the SDK answers 401 with a
|
|
200
|
+
// WWW-Authenticate challenge. A bare Error becomes a 500, and clients
|
|
201
|
+
// treat that as a server fault rather than a cue to re-authenticate.
|
|
202
|
+
throw new InvalidTokenError('Invalid or expired access token');
|
|
200
203
|
}
|
|
201
204
|
return {
|
|
202
205
|
token,
|
package/dist/server.js
CHANGED
|
@@ -25,7 +25,9 @@ export async function createServer() {
|
|
|
25
25
|
for (const tool of toolSet) {
|
|
26
26
|
const name = tool.name;
|
|
27
27
|
server.registerTool(name, {
|
|
28
|
+
title: tool.title,
|
|
28
29
|
description: tool.description,
|
|
30
|
+
annotations: tool.annotations,
|
|
29
31
|
inputSchema: tool.inputSchema,
|
|
30
32
|
}, async (...args) => {
|
|
31
33
|
const start = Date.now();
|
package/dist/tool-registry.js
CHANGED
|
@@ -156,7 +156,10 @@ async function detectEnabledApps() {
|
|
|
156
156
|
return apps;
|
|
157
157
|
}
|
|
158
158
|
catch (err) {
|
|
159
|
-
logger.warn({ err: err instanceof Error ? err.message : String(err) }, '[startup] Could not detect enabled apps — registering
|
|
159
|
+
logger.warn({ err: err instanceof Error ? err.message : String(err) }, '[startup] Could not detect enabled apps — registering ALL tools as a fallback. ' +
|
|
160
|
+
'/ocs/v2.php/cloud/apps requires admin credentials; a non-admin NEXTCLOUD_USER always ' +
|
|
161
|
+
'lands here. Set MCP_TOOLS to an explicit category/tool whitelist, or use an admin app ' +
|
|
162
|
+
'password, to register only the tools you need.');
|
|
160
163
|
return null;
|
|
161
164
|
}
|
|
162
165
|
}
|
|
@@ -186,6 +189,15 @@ function filterByEnabledApps(enabledApps) {
|
|
|
186
189
|
}
|
|
187
190
|
// Cached result — cleared only on process restart
|
|
188
191
|
let cachedToolSets = null;
|
|
192
|
+
/**
|
|
193
|
+
* Tool count above which we warn. Not a protocol limit — no MCP client documents one —
|
|
194
|
+
* but very large tool lists are worth flagging, and reaching this number usually means
|
|
195
|
+
* app-detection fell back to registering everything.
|
|
196
|
+
*/
|
|
197
|
+
export const HIGH_TOOL_COUNT = 100;
|
|
198
|
+
function countTools(toolSets) {
|
|
199
|
+
return toolSets.reduce((sum, ts) => sum + ts.length, 0);
|
|
200
|
+
}
|
|
189
201
|
/**
|
|
190
202
|
* Returns filtered tool arrays based on MCP_TOOLS env var or auto-detection.
|
|
191
203
|
* Result is cached after first call.
|
|
@@ -194,16 +206,21 @@ export async function getFilteredToolSets() {
|
|
|
194
206
|
if (cachedToolSets)
|
|
195
207
|
return cachedToolSets;
|
|
196
208
|
const mcpToolsFilter = parseMcpTools();
|
|
209
|
+
let source;
|
|
197
210
|
if (mcpToolsFilter) {
|
|
198
211
|
cachedToolSets = filterByExplicitList(mcpToolsFilter);
|
|
199
|
-
|
|
200
|
-
logger.info({ tools: toolCount, source: 'MCP_TOOLS' }, '[startup] Tool filtering applied');
|
|
212
|
+
source = 'MCP_TOOLS';
|
|
201
213
|
}
|
|
202
214
|
else {
|
|
203
215
|
const enabledApps = await detectEnabledApps();
|
|
204
216
|
cachedToolSets = filterByEnabledApps(enabledApps);
|
|
205
|
-
|
|
206
|
-
|
|
217
|
+
source = enabledApps ? 'app-detection' : 'all (fallback)';
|
|
218
|
+
}
|
|
219
|
+
const toolCount = countTools(cachedToolSets);
|
|
220
|
+
logger.info({ tools: toolCount, source }, '[startup] Tool filtering applied');
|
|
221
|
+
if (toolCount > HIGH_TOOL_COUNT) {
|
|
222
|
+
logger.warn({ tools: toolCount, threshold: HIGH_TOOL_COUNT, source }, `[startup] Registering ${toolCount} tools. Set MCP_TOOLS to a category/tool whitelist to ` +
|
|
223
|
+
'narrow this down — some clients degrade on very large tool lists.');
|
|
207
224
|
}
|
|
208
225
|
return cachedToolSets;
|
|
209
226
|
}
|
|
@@ -11,6 +11,13 @@ import { getNextcloudConfig } from '../types.js';
|
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
12
|
export const getOutOfOfficeTool = {
|
|
13
13
|
name: 'get_out_of_office',
|
|
14
|
+
title: 'Get Out-of-Office Status',
|
|
15
|
+
annotations: {
|
|
16
|
+
readOnlyHint: true,
|
|
17
|
+
destructiveHint: false,
|
|
18
|
+
idempotentHint: true,
|
|
19
|
+
openWorldHint: false,
|
|
20
|
+
},
|
|
14
21
|
description: "Get a user's current out-of-office / absence status (NC 28+)",
|
|
15
22
|
inputSchema: z.object({
|
|
16
23
|
userId: z
|
|
@@ -49,6 +56,13 @@ export const getOutOfOfficeTool = {
|
|
|
49
56
|
// ---------------------------------------------------------------------------
|
|
50
57
|
export const setOutOfOfficeTool = {
|
|
51
58
|
name: 'set_out_of_office',
|
|
59
|
+
title: 'Set Out-of-Office Status',
|
|
60
|
+
annotations: {
|
|
61
|
+
readOnlyHint: false,
|
|
62
|
+
destructiveHint: true,
|
|
63
|
+
idempotentHint: true,
|
|
64
|
+
openWorldHint: false,
|
|
65
|
+
},
|
|
52
66
|
description: 'Set an out-of-office / absence period with status message (NC 28+)',
|
|
53
67
|
inputSchema: z.object({
|
|
54
68
|
firstDay: z.string().describe('First day of absence (YYYY-MM-DD)'),
|
|
@@ -107,6 +121,13 @@ export const setOutOfOfficeTool = {
|
|
|
107
121
|
// ---------------------------------------------------------------------------
|
|
108
122
|
export const clearOutOfOfficeTool = {
|
|
109
123
|
name: 'clear_out_of_office',
|
|
124
|
+
title: 'Clear Out-of-Office Status',
|
|
125
|
+
annotations: {
|
|
126
|
+
readOnlyHint: false,
|
|
127
|
+
destructiveHint: true,
|
|
128
|
+
idempotentHint: true,
|
|
129
|
+
openWorldHint: false,
|
|
130
|
+
},
|
|
110
131
|
description: "Clear a user's out-of-office / absence status (NC 28+)",
|
|
111
132
|
inputSchema: z.object({
|
|
112
133
|
userId: z
|
|
@@ -15,6 +15,13 @@ function formatActivities(activities) {
|
|
|
15
15
|
// ---------------------------------------------------------------------------
|
|
16
16
|
export const listActivityTool = {
|
|
17
17
|
name: 'list_activity',
|
|
18
|
+
title: 'List Activity',
|
|
19
|
+
annotations: {
|
|
20
|
+
readOnlyHint: true,
|
|
21
|
+
destructiveHint: false,
|
|
22
|
+
idempotentHint: true,
|
|
23
|
+
openWorldHint: false,
|
|
24
|
+
},
|
|
18
25
|
description: 'List recent entries from the Nextcloud activity feed (file changes, shares, ' +
|
|
19
26
|
'comments, calendar/contact edits, etc.) for the current user.',
|
|
20
27
|
inputSchema: z.object({
|
|
@@ -77,6 +84,13 @@ export const listActivityTool = {
|
|
|
77
84
|
// ---------------------------------------------------------------------------
|
|
78
85
|
export const getObjectActivityTool = {
|
|
79
86
|
name: 'get_object_activity',
|
|
87
|
+
title: 'Get Object Activity',
|
|
88
|
+
annotations: {
|
|
89
|
+
readOnlyHint: true,
|
|
90
|
+
destructiveHint: false,
|
|
91
|
+
idempotentHint: true,
|
|
92
|
+
openWorldHint: false,
|
|
93
|
+
},
|
|
80
94
|
description: 'List the activity history for a single object, e.g. one file. Use object_type ' +
|
|
81
95
|
"'files' with a file ID to see what happened to that file.",
|
|
82
96
|
inputSchema: z.object({
|
|
@@ -21,6 +21,13 @@ async function runOCC(command, args = []) {
|
|
|
21
21
|
*/
|
|
22
22
|
export const showConfigTool = {
|
|
23
23
|
name: 'aiquila_show_config',
|
|
24
|
+
title: 'Show AIquila Configuration',
|
|
25
|
+
annotations: {
|
|
26
|
+
readOnlyHint: true,
|
|
27
|
+
destructiveHint: false,
|
|
28
|
+
idempotentHint: true,
|
|
29
|
+
openWorldHint: false,
|
|
30
|
+
},
|
|
24
31
|
description: 'Show current AIquila configuration',
|
|
25
32
|
inputSchema: z.object({}),
|
|
26
33
|
handler: async () => {
|
|
@@ -52,6 +59,13 @@ export const showConfigTool = {
|
|
|
52
59
|
*/
|
|
53
60
|
export const configureTool = {
|
|
54
61
|
name: 'aiquila_configure',
|
|
62
|
+
title: 'Configure AIquila',
|
|
63
|
+
annotations: {
|
|
64
|
+
readOnlyHint: false,
|
|
65
|
+
destructiveHint: true,
|
|
66
|
+
idempotentHint: true,
|
|
67
|
+
openWorldHint: false,
|
|
68
|
+
},
|
|
55
69
|
description: 'Configure AIquila settings (API key, model, tokens, timeout)',
|
|
56
70
|
inputSchema: z.object({
|
|
57
71
|
apiKey: z.string().optional().describe('Anthropic API key'),
|
|
@@ -104,6 +118,13 @@ export const configureTool = {
|
|
|
104
118
|
*/
|
|
105
119
|
export const testTool = {
|
|
106
120
|
name: 'aiquila_test',
|
|
121
|
+
title: 'Test AIquila Claude Integration',
|
|
122
|
+
annotations: {
|
|
123
|
+
readOnlyHint: true,
|
|
124
|
+
destructiveHint: false,
|
|
125
|
+
idempotentHint: true,
|
|
126
|
+
openWorldHint: true,
|
|
127
|
+
},
|
|
107
128
|
description: 'Test AIquila Claude API integration with a simple prompt',
|
|
108
129
|
inputSchema: z.object({
|
|
109
130
|
prompt: z.string().default('Hello, Claude!').describe('Test prompt to send to Claude API'),
|
|
@@ -21,6 +21,13 @@ function formatAnnouncements(items) {
|
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
22
|
export const listAnnouncementsTool = {
|
|
23
23
|
name: 'list_announcements',
|
|
24
|
+
title: 'List Announcements',
|
|
25
|
+
annotations: {
|
|
26
|
+
readOnlyHint: true,
|
|
27
|
+
destructiveHint: false,
|
|
28
|
+
idempotentHint: true,
|
|
29
|
+
openWorldHint: false,
|
|
30
|
+
},
|
|
24
31
|
description: 'List announcements from the Nextcloud Announcement Center (org-wide notices such as ' +
|
|
25
32
|
'maintenance windows, events, or news). Returns newest first.',
|
|
26
33
|
inputSchema: z.object({
|
|
@@ -70,6 +77,13 @@ export const listAnnouncementsTool = {
|
|
|
70
77
|
// ---------------------------------------------------------------------------
|
|
71
78
|
export const createAnnouncementTool = {
|
|
72
79
|
name: 'create_announcement',
|
|
80
|
+
title: 'Create Announcement',
|
|
81
|
+
annotations: {
|
|
82
|
+
readOnlyHint: false,
|
|
83
|
+
destructiveHint: false,
|
|
84
|
+
idempotentHint: false,
|
|
85
|
+
openWorldHint: false,
|
|
86
|
+
},
|
|
73
87
|
description: 'Create a new announcement in the Announcement Center. This is visible to all or ' +
|
|
74
88
|
'selected groups and can trigger notifications/emails — use deliberately. Requires the ' +
|
|
75
89
|
'configured Nextcloud user to be an admin.',
|
|
@@ -142,6 +156,13 @@ export const createAnnouncementTool = {
|
|
|
142
156
|
// ---------------------------------------------------------------------------
|
|
143
157
|
export const deleteAnnouncementTool = {
|
|
144
158
|
name: 'delete_announcement',
|
|
159
|
+
title: 'Delete Announcement',
|
|
160
|
+
annotations: {
|
|
161
|
+
readOnlyHint: false,
|
|
162
|
+
destructiveHint: true,
|
|
163
|
+
idempotentHint: true,
|
|
164
|
+
openWorldHint: false,
|
|
165
|
+
},
|
|
145
166
|
description: 'Delete an announcement by its ID. Requires the configured Nextcloud user to be an admin.',
|
|
146
167
|
inputSchema: z.object({
|
|
147
168
|
id: z.number().describe('The announcement ID to delete'),
|
|
@@ -14,6 +14,13 @@ const STATUS_LABELS = {
|
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
export const listTextTasksTool = {
|
|
16
16
|
name: 'list_text_tasks',
|
|
17
|
+
title: 'List Text Tasks',
|
|
18
|
+
annotations: {
|
|
19
|
+
readOnlyHint: true,
|
|
20
|
+
destructiveHint: false,
|
|
21
|
+
idempotentHint: true,
|
|
22
|
+
openWorldHint: false,
|
|
23
|
+
},
|
|
17
24
|
description: "List AI task types available in Nextcloud's TaskProcessing framework (summarize, headline, image-to-text, text-to-image, …). Shows which task types have at least one provider configured.",
|
|
18
25
|
inputSchema: z.object({}),
|
|
19
26
|
handler: async () => {
|
|
@@ -54,6 +61,13 @@ export const listTextTasksTool = {
|
|
|
54
61
|
// ---------------------------------------------------------------------------
|
|
55
62
|
export const processTextTool = {
|
|
56
63
|
name: 'process_text',
|
|
64
|
+
title: 'Process Text with AI',
|
|
65
|
+
annotations: {
|
|
66
|
+
readOnlyHint: false,
|
|
67
|
+
destructiveHint: false,
|
|
68
|
+
idempotentHint: false,
|
|
69
|
+
openWorldHint: true,
|
|
70
|
+
},
|
|
57
71
|
description: "Submit a text-processing task to Nextcloud's AI framework and return the task ID. Use get_task_result to poll until it completes. Common task types: 'core:text2text' (free prompt), 'core:summarize' (summary), 'core:headline' (headline), 'core:extract_topics' (topics).",
|
|
58
72
|
inputSchema: z.object({
|
|
59
73
|
taskType: z
|
|
@@ -107,6 +121,13 @@ export const processTextTool = {
|
|
|
107
121
|
// ---------------------------------------------------------------------------
|
|
108
122
|
export const getTaskResultTool = {
|
|
109
123
|
name: 'get_task_result',
|
|
124
|
+
title: 'Get AI Task Result',
|
|
125
|
+
annotations: {
|
|
126
|
+
readOnlyHint: true,
|
|
127
|
+
destructiveHint: false,
|
|
128
|
+
idempotentHint: true,
|
|
129
|
+
openWorldHint: false,
|
|
130
|
+
},
|
|
110
131
|
description: 'Get the status and result of a Nextcloud AI task previously created by process_text or generate_image. Status: 1=scheduled, 2=running, 3=successful, 4=failed.',
|
|
111
132
|
inputSchema: z.object({
|
|
112
133
|
taskId: z.number().describe('The task ID returned by process_text or generate_image'),
|
|
@@ -168,6 +189,13 @@ export const getTaskResultTool = {
|
|
|
168
189
|
// ---------------------------------------------------------------------------
|
|
169
190
|
export const generateImageTool = {
|
|
170
191
|
name: 'generate_image',
|
|
192
|
+
title: 'Generate Image',
|
|
193
|
+
annotations: {
|
|
194
|
+
readOnlyHint: false,
|
|
195
|
+
destructiveHint: false,
|
|
196
|
+
idempotentHint: false,
|
|
197
|
+
openWorldHint: true,
|
|
198
|
+
},
|
|
171
199
|
description: "Generate an image from a text prompt using Nextcloud's text-to-image AI provider (e.g. Stable Diffusion via LocalAI). Returns the task ID; use get_task_result to check completion.",
|
|
172
200
|
inputSchema: z.object({
|
|
173
201
|
prompt: z.string().describe('Text description of the image to generate'),
|
|
@@ -48,6 +48,13 @@ function formatFolderTree(folder, indent = 0) {
|
|
|
48
48
|
// ── Bookmark Tools ──────────────────────────────────────────────────────────
|
|
49
49
|
export const listBookmarksTool = {
|
|
50
50
|
name: 'list_bookmarks',
|
|
51
|
+
title: 'List Bookmarks',
|
|
52
|
+
annotations: {
|
|
53
|
+
readOnlyHint: true,
|
|
54
|
+
destructiveHint: false,
|
|
55
|
+
idempotentHint: true,
|
|
56
|
+
openWorldHint: false,
|
|
57
|
+
},
|
|
51
58
|
description: 'List bookmarks from Nextcloud Bookmarks app. Supports search, tag filtering, folder filtering, sorting, and pagination.',
|
|
52
59
|
inputSchema: z.object({
|
|
53
60
|
search: z
|
|
@@ -122,6 +129,13 @@ export const listBookmarksTool = {
|
|
|
122
129
|
};
|
|
123
130
|
export const getBookmarkTool = {
|
|
124
131
|
name: 'get_bookmark',
|
|
132
|
+
title: 'Get Bookmark',
|
|
133
|
+
annotations: {
|
|
134
|
+
readOnlyHint: true,
|
|
135
|
+
destructiveHint: false,
|
|
136
|
+
idempotentHint: true,
|
|
137
|
+
openWorldHint: false,
|
|
138
|
+
},
|
|
125
139
|
description: 'Get full details of a single bookmark by its ID.',
|
|
126
140
|
inputSchema: z.object({
|
|
127
141
|
id: z.number().describe('The bookmark ID'),
|
|
@@ -153,6 +167,13 @@ export const getBookmarkTool = {
|
|
|
153
167
|
};
|
|
154
168
|
export const createBookmarkTool = {
|
|
155
169
|
name: 'create_bookmark',
|
|
170
|
+
title: 'Create Bookmark',
|
|
171
|
+
annotations: {
|
|
172
|
+
readOnlyHint: false,
|
|
173
|
+
destructiveHint: false,
|
|
174
|
+
idempotentHint: false,
|
|
175
|
+
openWorldHint: false,
|
|
176
|
+
},
|
|
156
177
|
description: 'Create a new bookmark in Nextcloud Bookmarks. URL is required; title, description, tags, and folders are optional.',
|
|
157
178
|
inputSchema: z.object({
|
|
158
179
|
url: z.string().describe('The URL to bookmark'),
|
|
@@ -200,6 +221,13 @@ export const createBookmarkTool = {
|
|
|
200
221
|
};
|
|
201
222
|
export const updateBookmarkTool = {
|
|
202
223
|
name: 'update_bookmark',
|
|
224
|
+
title: 'Update Bookmark',
|
|
225
|
+
annotations: {
|
|
226
|
+
readOnlyHint: false,
|
|
227
|
+
destructiveHint: true,
|
|
228
|
+
idempotentHint: true,
|
|
229
|
+
openWorldHint: false,
|
|
230
|
+
},
|
|
203
231
|
description: 'Update an existing bookmark. Only provided fields are changed.',
|
|
204
232
|
inputSchema: z.object({
|
|
205
233
|
id: z.number().describe('The bookmark ID to update'),
|
|
@@ -250,6 +278,13 @@ export const updateBookmarkTool = {
|
|
|
250
278
|
};
|
|
251
279
|
export const deleteBookmarkTool = {
|
|
252
280
|
name: 'delete_bookmark',
|
|
281
|
+
title: 'Delete Bookmark',
|
|
282
|
+
annotations: {
|
|
283
|
+
readOnlyHint: false,
|
|
284
|
+
destructiveHint: true,
|
|
285
|
+
idempotentHint: true,
|
|
286
|
+
openWorldHint: false,
|
|
287
|
+
},
|
|
253
288
|
description: 'Delete a bookmark by its ID. This action is irreversible.',
|
|
254
289
|
inputSchema: z.object({
|
|
255
290
|
id: z.number().describe('The bookmark ID to delete'),
|
|
@@ -282,6 +317,13 @@ export const deleteBookmarkTool = {
|
|
|
282
317
|
// ── Folder Tools ────────────────────────────────────────────────────────────
|
|
283
318
|
export const listBookmarkFoldersTool = {
|
|
284
319
|
name: 'list_bookmark_folders',
|
|
320
|
+
title: 'List Bookmark Folders',
|
|
321
|
+
annotations: {
|
|
322
|
+
readOnlyHint: true,
|
|
323
|
+
destructiveHint: false,
|
|
324
|
+
idempotentHint: true,
|
|
325
|
+
openWorldHint: false,
|
|
326
|
+
},
|
|
285
327
|
description: 'List the bookmark folder hierarchy. Returns a tree structure of all folders.',
|
|
286
328
|
inputSchema: z.object({
|
|
287
329
|
root: z
|
|
@@ -328,6 +370,13 @@ export const listBookmarkFoldersTool = {
|
|
|
328
370
|
};
|
|
329
371
|
export const getBookmarkFolderContentsTool = {
|
|
330
372
|
name: 'get_bookmark_folder_contents',
|
|
373
|
+
title: 'Get Bookmark Folder Contents',
|
|
374
|
+
annotations: {
|
|
375
|
+
readOnlyHint: true,
|
|
376
|
+
destructiveHint: false,
|
|
377
|
+
idempotentHint: true,
|
|
378
|
+
openWorldHint: false,
|
|
379
|
+
},
|
|
331
380
|
description: 'Get the contents of a bookmark folder (bookmarks and subfolders).',
|
|
332
381
|
inputSchema: z.object({
|
|
333
382
|
id: z.number().describe('The folder ID (-1 for root)'),
|
|
@@ -382,6 +431,13 @@ export const getBookmarkFolderContentsTool = {
|
|
|
382
431
|
};
|
|
383
432
|
export const createBookmarkFolderTool = {
|
|
384
433
|
name: 'create_bookmark_folder',
|
|
434
|
+
title: 'Create Bookmark Folder',
|
|
435
|
+
annotations: {
|
|
436
|
+
readOnlyHint: false,
|
|
437
|
+
destructiveHint: false,
|
|
438
|
+
idempotentHint: false,
|
|
439
|
+
openWorldHint: false,
|
|
440
|
+
},
|
|
385
441
|
description: 'Create a new bookmark folder.',
|
|
386
442
|
inputSchema: z.object({
|
|
387
443
|
title: z.string().describe('Folder name'),
|
|
@@ -420,6 +476,13 @@ export const createBookmarkFolderTool = {
|
|
|
420
476
|
};
|
|
421
477
|
export const updateBookmarkFolderTool = {
|
|
422
478
|
name: 'update_bookmark_folder',
|
|
479
|
+
title: 'Update Bookmark Folder',
|
|
480
|
+
annotations: {
|
|
481
|
+
readOnlyHint: false,
|
|
482
|
+
destructiveHint: true,
|
|
483
|
+
idempotentHint: true,
|
|
484
|
+
openWorldHint: false,
|
|
485
|
+
},
|
|
423
486
|
description: 'Update a bookmark folder (rename or move to a different parent).',
|
|
424
487
|
inputSchema: z.object({
|
|
425
488
|
id: z.number().describe('The folder ID to update'),
|
|
@@ -458,6 +521,13 @@ export const updateBookmarkFolderTool = {
|
|
|
458
521
|
};
|
|
459
522
|
export const deleteBookmarkFolderTool = {
|
|
460
523
|
name: 'delete_bookmark_folder',
|
|
524
|
+
title: 'Delete Bookmark Folder',
|
|
525
|
+
annotations: {
|
|
526
|
+
readOnlyHint: false,
|
|
527
|
+
destructiveHint: true,
|
|
528
|
+
idempotentHint: true,
|
|
529
|
+
openWorldHint: false,
|
|
530
|
+
},
|
|
461
531
|
description: 'Delete a bookmark folder and all its contents. This action is irreversible.',
|
|
462
532
|
inputSchema: z.object({
|
|
463
533
|
id: z.number().describe('The folder ID to delete'),
|
|
@@ -490,6 +560,13 @@ export const deleteBookmarkFolderTool = {
|
|
|
490
560
|
// ── Tag Tools ───────────────────────────────────────────────────────────────
|
|
491
561
|
export const listBookmarkTagsTool = {
|
|
492
562
|
name: 'list_bookmark_tags',
|
|
563
|
+
title: 'List Bookmark Tags',
|
|
564
|
+
annotations: {
|
|
565
|
+
readOnlyHint: true,
|
|
566
|
+
destructiveHint: false,
|
|
567
|
+
idempotentHint: true,
|
|
568
|
+
openWorldHint: false,
|
|
569
|
+
},
|
|
493
570
|
description: 'List all tags used across bookmarks.',
|
|
494
571
|
inputSchema: z.object({}),
|
|
495
572
|
handler: async () => {
|
|
@@ -528,6 +605,13 @@ export const listBookmarkTagsTool = {
|
|
|
528
605
|
};
|
|
529
606
|
export const renameBookmarkTagTool = {
|
|
530
607
|
name: 'rename_bookmark_tag',
|
|
608
|
+
title: 'Rename Bookmark Tag',
|
|
609
|
+
annotations: {
|
|
610
|
+
readOnlyHint: false,
|
|
611
|
+
destructiveHint: true,
|
|
612
|
+
idempotentHint: true,
|
|
613
|
+
openWorldHint: false,
|
|
614
|
+
},
|
|
531
615
|
description: 'Rename a bookmark tag. All bookmarks with the old tag will be updated.',
|
|
532
616
|
inputSchema: z.object({
|
|
533
617
|
old_name: z.string().describe('Current tag name'),
|
|
@@ -563,6 +647,13 @@ export const renameBookmarkTagTool = {
|
|
|
563
647
|
};
|
|
564
648
|
export const deleteBookmarkTagTool = {
|
|
565
649
|
name: 'delete_bookmark_tag',
|
|
650
|
+
title: 'Delete Bookmark Tag',
|
|
651
|
+
annotations: {
|
|
652
|
+
readOnlyHint: false,
|
|
653
|
+
destructiveHint: true,
|
|
654
|
+
idempotentHint: true,
|
|
655
|
+
openWorldHint: false,
|
|
656
|
+
},
|
|
566
657
|
description: 'Delete a bookmark tag. The tag will be removed from all bookmarks.',
|
|
567
658
|
inputSchema: z.object({
|
|
568
659
|
name: z.string().describe('Tag name to delete'),
|
|
@@ -628,6 +628,13 @@ async function resolveEventByUid(calendarName, uid) {
|
|
|
628
628
|
*/
|
|
629
629
|
export const listCalendarsTool = {
|
|
630
630
|
name: 'list_calendars',
|
|
631
|
+
title: 'List Calendars',
|
|
632
|
+
annotations: {
|
|
633
|
+
readOnlyHint: true,
|
|
634
|
+
destructiveHint: false,
|
|
635
|
+
idempotentHint: true,
|
|
636
|
+
openWorldHint: false,
|
|
637
|
+
},
|
|
631
638
|
description: 'List all calendars available to the current user, including their supported component types (events, tasks, journals) and metadata.',
|
|
632
639
|
inputSchema: z.object({}),
|
|
633
640
|
handler: async () => {
|
|
@@ -691,6 +698,13 @@ export const listCalendarsTool = {
|
|
|
691
698
|
*/
|
|
692
699
|
export const listEventsTool = {
|
|
693
700
|
name: 'list_events',
|
|
701
|
+
title: 'List Calendar Events',
|
|
702
|
+
annotations: {
|
|
703
|
+
readOnlyHint: true,
|
|
704
|
+
destructiveHint: false,
|
|
705
|
+
idempotentHint: true,
|
|
706
|
+
openWorldHint: false,
|
|
707
|
+
},
|
|
694
708
|
description: 'List events from a Nextcloud calendar within an optional time range. Returns event details including time, location, attendees, recurrence, and UIDs.',
|
|
695
709
|
inputSchema: z.object({
|
|
696
710
|
calendarName: z
|
|
@@ -805,6 +819,13 @@ export const listEventsTool = {
|
|
|
805
819
|
*/
|
|
806
820
|
export const getEventTool = {
|
|
807
821
|
name: 'get_event',
|
|
822
|
+
title: 'Get Calendar Event',
|
|
823
|
+
annotations: {
|
|
824
|
+
readOnlyHint: true,
|
|
825
|
+
destructiveHint: false,
|
|
826
|
+
idempotentHint: true,
|
|
827
|
+
openWorldHint: false,
|
|
828
|
+
},
|
|
808
829
|
description: 'Get detailed information about a single calendar event by its UID, including full description, attendees, and recurrence rules.',
|
|
809
830
|
inputSchema: z.object({
|
|
810
831
|
uid: z.string().describe('The UID of the event'),
|
|
@@ -854,6 +875,13 @@ export const getEventTool = {
|
|
|
854
875
|
*/
|
|
855
876
|
export const createEventTool = {
|
|
856
877
|
name: 'create_event',
|
|
878
|
+
title: 'Create Calendar Event',
|
|
879
|
+
annotations: {
|
|
880
|
+
readOnlyHint: false,
|
|
881
|
+
destructiveHint: false,
|
|
882
|
+
idempotentHint: false,
|
|
883
|
+
openWorldHint: false,
|
|
884
|
+
},
|
|
857
885
|
description: 'Create a new calendar event in Nextcloud with date/time, location, description, attendees, and optional recurrence.',
|
|
858
886
|
inputSchema: z.object({
|
|
859
887
|
summary: z.string().describe('The event title'),
|
|
@@ -1075,6 +1103,13 @@ export const createEventTool = {
|
|
|
1075
1103
|
*/
|
|
1076
1104
|
export const updateEventTool = {
|
|
1077
1105
|
name: 'update_event',
|
|
1106
|
+
title: 'Update Calendar Event',
|
|
1107
|
+
annotations: {
|
|
1108
|
+
readOnlyHint: false,
|
|
1109
|
+
destructiveHint: true,
|
|
1110
|
+
idempotentHint: true,
|
|
1111
|
+
openWorldHint: false,
|
|
1112
|
+
},
|
|
1078
1113
|
description: "Update an existing calendar event's fields by UID. Uses CalDAV ETag-based optimistic concurrency.",
|
|
1079
1114
|
inputSchema: z.object({
|
|
1080
1115
|
uid: z.string().describe('The UID of the event to update'),
|
|
@@ -1248,6 +1283,13 @@ export const updateEventTool = {
|
|
|
1248
1283
|
*/
|
|
1249
1284
|
export const deleteEventTool = {
|
|
1250
1285
|
name: 'delete_event',
|
|
1286
|
+
title: 'Delete Calendar Event',
|
|
1287
|
+
annotations: {
|
|
1288
|
+
readOnlyHint: false,
|
|
1289
|
+
destructiveHint: true,
|
|
1290
|
+
idempotentHint: true,
|
|
1291
|
+
openWorldHint: false,
|
|
1292
|
+
},
|
|
1251
1293
|
description: 'Delete a calendar event from Nextcloud by UID. This action is irreversible.',
|
|
1252
1294
|
inputSchema: z.object({
|
|
1253
1295
|
uid: z.string().describe('The UID of the event to delete'),
|
|
@@ -67,6 +67,13 @@ function formatMember(m) {
|
|
|
67
67
|
// ---------------------------------------------------------------------------
|
|
68
68
|
export const circlesListTool = {
|
|
69
69
|
name: 'circles_list',
|
|
70
|
+
title: 'List Circles',
|
|
71
|
+
annotations: {
|
|
72
|
+
readOnlyHint: true,
|
|
73
|
+
destructiveHint: false,
|
|
74
|
+
idempotentHint: true,
|
|
75
|
+
openWorldHint: false,
|
|
76
|
+
},
|
|
70
77
|
description: 'List all circles/teams accessible to the current user. Returns circle IDs, names, owners, and configuration.',
|
|
71
78
|
inputSchema: z.object({
|
|
72
79
|
limit: z.number().optional().describe('Maximum number of circles to return'),
|
|
@@ -95,6 +102,13 @@ export const circlesListTool = {
|
|
|
95
102
|
// ---------------------------------------------------------------------------
|
|
96
103
|
export const circlesGetTool = {
|
|
97
104
|
name: 'circles_get',
|
|
105
|
+
title: 'Get Circle',
|
|
106
|
+
annotations: {
|
|
107
|
+
readOnlyHint: true,
|
|
108
|
+
destructiveHint: false,
|
|
109
|
+
idempotentHint: true,
|
|
110
|
+
openWorldHint: false,
|
|
111
|
+
},
|
|
98
112
|
description: 'Get detailed information about a specific circle/team, including its description, owner, and configuration flags.',
|
|
99
113
|
inputSchema: z.object({
|
|
100
114
|
circleId: z.string().describe('The circle ID to retrieve'),
|
|
@@ -128,6 +142,13 @@ export const circlesGetTool = {
|
|
|
128
142
|
// ---------------------------------------------------------------------------
|
|
129
143
|
export const circlesCreateTool = {
|
|
130
144
|
name: 'circles_create',
|
|
145
|
+
title: 'Create Circle',
|
|
146
|
+
annotations: {
|
|
147
|
+
readOnlyHint: false,
|
|
148
|
+
destructiveHint: false,
|
|
149
|
+
idempotentHint: false,
|
|
150
|
+
openWorldHint: false,
|
|
151
|
+
},
|
|
131
152
|
description: 'Create a new circle/team. The current user becomes the owner. Set personal=true for a private circle only visible to the owner.',
|
|
132
153
|
inputSchema: z.object({
|
|
133
154
|
name: z.string().describe('Name for the new circle'),
|
|
@@ -161,6 +182,13 @@ export const circlesCreateTool = {
|
|
|
161
182
|
// ---------------------------------------------------------------------------
|
|
162
183
|
export const circlesDeleteTool = {
|
|
163
184
|
name: 'circles_delete',
|
|
185
|
+
title: 'Delete Circle',
|
|
186
|
+
annotations: {
|
|
187
|
+
readOnlyHint: false,
|
|
188
|
+
destructiveHint: true,
|
|
189
|
+
idempotentHint: true,
|
|
190
|
+
openWorldHint: false,
|
|
191
|
+
},
|
|
164
192
|
description: 'Delete a circle/team. Requires owner privileges.',
|
|
165
193
|
inputSchema: z.object({
|
|
166
194
|
circleId: z.string().describe('The circle ID to delete'),
|
|
@@ -182,6 +210,13 @@ export const circlesDeleteTool = {
|
|
|
182
210
|
// ---------------------------------------------------------------------------
|
|
183
211
|
export const circlesListMembersTool = {
|
|
184
212
|
name: 'circles_list_members',
|
|
213
|
+
title: 'List Circle Members',
|
|
214
|
+
annotations: {
|
|
215
|
+
readOnlyHint: true,
|
|
216
|
+
destructiveHint: false,
|
|
217
|
+
idempotentHint: true,
|
|
218
|
+
openWorldHint: false,
|
|
219
|
+
},
|
|
185
220
|
description: 'List all members of a circle/team. Returns member IDs (needed for removal), user IDs, types, and permission levels.',
|
|
186
221
|
inputSchema: z.object({
|
|
187
222
|
circleId: z.string().describe('The circle ID to list members for'),
|
|
@@ -204,6 +239,13 @@ export const circlesListMembersTool = {
|
|
|
204
239
|
// ---------------------------------------------------------------------------
|
|
205
240
|
export const circlesAddMemberTool = {
|
|
206
241
|
name: 'circles_add_member',
|
|
242
|
+
title: 'Add Circle Member',
|
|
243
|
+
annotations: {
|
|
244
|
+
readOnlyHint: false,
|
|
245
|
+
destructiveHint: false,
|
|
246
|
+
idempotentHint: true,
|
|
247
|
+
openWorldHint: false,
|
|
248
|
+
},
|
|
207
249
|
description: 'Add a member to a circle/team. Requires moderator privileges or higher. Member type: 1=user (default), 2=group, 4=mail, 16=circle.',
|
|
208
250
|
inputSchema: z.object({
|
|
209
251
|
circleId: z.string().describe('The circle ID to add the member to'),
|
|
@@ -232,6 +274,13 @@ export const circlesAddMemberTool = {
|
|
|
232
274
|
// ---------------------------------------------------------------------------
|
|
233
275
|
export const circlesRemoveMemberTool = {
|
|
234
276
|
name: 'circles_remove_member',
|
|
277
|
+
title: 'Remove Circle Member',
|
|
278
|
+
annotations: {
|
|
279
|
+
readOnlyHint: false,
|
|
280
|
+
destructiveHint: true,
|
|
281
|
+
idempotentHint: true,
|
|
282
|
+
openWorldHint: false,
|
|
283
|
+
},
|
|
235
284
|
description: 'Remove a member from a circle/team. Use circles_list_members to get the memberId. Requires moderator privileges or higher.',
|
|
236
285
|
inputSchema: z.object({
|
|
237
286
|
circleId: z.string().describe('The circle ID to remove the member from'),
|
|
@@ -252,6 +301,13 @@ export const circlesRemoveMemberTool = {
|
|
|
252
301
|
// ---------------------------------------------------------------------------
|
|
253
302
|
export const circlesSearchTool = {
|
|
254
303
|
name: 'circles_search',
|
|
304
|
+
title: 'Search Circles',
|
|
305
|
+
annotations: {
|
|
306
|
+
readOnlyHint: true,
|
|
307
|
+
destructiveHint: false,
|
|
308
|
+
idempotentHint: true,
|
|
309
|
+
openWorldHint: false,
|
|
310
|
+
},
|
|
255
311
|
description: 'Search for circles/teams by name.',
|
|
256
312
|
inputSchema: z.object({
|
|
257
313
|
term: z.string().describe('Search term to match against circle names'),
|