@delega-dev/mcp 1.0.1

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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -0
  3. package/dist/index.js +373 -0
  4. package/package.json +52 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Delega Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # delega-mcp
2
+
3
+ MCP server for [Delega](https://delega.dev) — task infrastructure for AI agents.
4
+
5
+ Connect any MCP-compatible client (Claude Desktop, Cursor, Windsurf, etc.) to your Delega instance and manage tasks, projects, and agents through natural language.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g delega-mcp
11
+ ```
12
+
13
+ ## Configure
14
+
15
+ Add to your MCP client config (e.g. Claude Desktop `claude_desktop_config.json`):
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "delega": {
21
+ "command": "delega-mcp",
22
+ "env": {
23
+ "DELEGA_API_URL": "http://127.0.0.1:18890",
24
+ "DELEGA_AGENT_KEY": "dlg_your_agent_key_here"
25
+ }
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ ### Environment Variables
32
+
33
+ | Variable | Default | Description |
34
+ |----------|---------|-------------|
35
+ | `DELEGA_API_URL` | `http://127.0.0.1:18890` | Delega API endpoint |
36
+ | `DELEGA_AGENT_KEY` | (none) | Agent API key for authenticated requests |
37
+
38
+ For the hosted tier, use `https://api.delega.dev` as the URL.
39
+
40
+ ## Tools
41
+
42
+ | Tool | Description |
43
+ |------|-------------|
44
+ | `list_tasks` | List tasks, filter by project, label, due date, completion |
45
+ | `get_task` | Get full task details including subtasks |
46
+ | `create_task` | Create a new task |
47
+ | `update_task` | Update task fields |
48
+ | `complete_task` | Mark a task as completed |
49
+ | `delete_task` | Delete a task permanently |
50
+ | `add_comment` | Add a comment to a task |
51
+ | `list_projects` | List all projects |
52
+ | `get_stats` | Get task statistics |
53
+ | `list_agents` | List registered agents |
54
+ | `register_agent` | Register a new agent (returns API key) |
55
+
56
+ ## Self-Hosted vs Hosted
57
+
58
+ **Self-hosted (free):** Run your own Delega instance, point `DELEGA_API_URL` at it.
59
+
60
+ **Hosted:** Use `https://api.delega.dev` — free up to 1,000 tasks/month.
61
+
62
+ ## Links
63
+
64
+ - [Delega](https://delega.dev) — Main site
65
+ - [GitHub](https://github.com/delega-dev/delega-mcp) — Source code
66
+ - [API Docs](https://delega.dev/docs) — REST API reference
67
+
68
+ ## License
69
+
70
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,373 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { z } from "zod";
7
+
8
+ // src/delega-client.ts
9
+ var DEFAULT_BASE_URL = "http://127.0.0.1:18890";
10
+ var DelegaClient = class {
11
+ baseUrl;
12
+ agentKey;
13
+ constructor(baseUrl, agentKey) {
14
+ this.baseUrl = (baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
15
+ this.agentKey = agentKey;
16
+ }
17
+ async request(method, path, body, query) {
18
+ const url = new URL(path, this.baseUrl);
19
+ if (query) {
20
+ for (const [key, value] of Object.entries(query)) {
21
+ if (value !== void 0 && value !== "") {
22
+ url.searchParams.set(key, value);
23
+ }
24
+ }
25
+ }
26
+ const headers = {
27
+ "Content-Type": "application/json"
28
+ };
29
+ if (this.agentKey) {
30
+ headers["X-Agent-Key"] = this.agentKey;
31
+ }
32
+ const res = await fetch(url.toString(), {
33
+ method,
34
+ headers,
35
+ body: body ? JSON.stringify(body) : void 0
36
+ });
37
+ if (!res.ok) {
38
+ const text = await res.text().catch(() => "");
39
+ throw new Error(
40
+ `Delega API error: ${res.status} ${res.statusText}${text ? ` \u2014 ${text}` : ""}`
41
+ );
42
+ }
43
+ if (res.status === 204) {
44
+ return void 0;
45
+ }
46
+ return res.json();
47
+ }
48
+ // ── Tasks ──
49
+ async listTasks(params) {
50
+ const query = {};
51
+ if (params.project_id !== void 0) query.project_id = String(params.project_id);
52
+ if (params.label !== void 0) query.label = params.label;
53
+ if (params.due !== void 0) query.due = params.due;
54
+ if (params.completed !== void 0) query.completed = String(params.completed);
55
+ return this.request("GET", "/api/tasks", void 0, query);
56
+ }
57
+ async getTask(taskId) {
58
+ return this.request("GET", `/api/tasks/${taskId}`);
59
+ }
60
+ async createTask(data) {
61
+ return this.request("POST", "/api/tasks", data);
62
+ }
63
+ async updateTask(taskId, data) {
64
+ return this.request("PUT", `/api/tasks/${taskId}`, data);
65
+ }
66
+ async completeTask(taskId) {
67
+ return this.request("POST", `/api/tasks/${taskId}/complete`);
68
+ }
69
+ async deleteTask(taskId) {
70
+ return this.request("DELETE", `/api/tasks/${taskId}`);
71
+ }
72
+ // ── Comments ──
73
+ async addComment(taskId, data) {
74
+ return this.request(
75
+ "POST",
76
+ `/api/tasks/${taskId}/comments`,
77
+ data
78
+ );
79
+ }
80
+ // ── Projects ──
81
+ async listProjects() {
82
+ return this.request("GET", "/api/projects");
83
+ }
84
+ // ── Stats ──
85
+ async getStats() {
86
+ return this.request("GET", "/api/stats");
87
+ }
88
+ // ── Agents ──
89
+ async listAgents() {
90
+ return this.request("GET", "/api/agents");
91
+ }
92
+ async registerAgent(data) {
93
+ return this.request("POST", "/api/agents", data);
94
+ }
95
+ };
96
+
97
+ // src/index.ts
98
+ var client = new DelegaClient(
99
+ process.env.DELEGA_API_URL,
100
+ process.env.DELEGA_AGENT_KEY
101
+ );
102
+ function formatTask(t) {
103
+ const lines = [];
104
+ lines.push(`[#${t.id}] ${t.content}`);
105
+ if (t.description) lines.push(` Description: ${t.description}`);
106
+ if (t.project?.name ?? t.project_name)
107
+ lines.push(` Project: ${t.project?.name ?? t.project_name}`);
108
+ if (t.labels?.length) lines.push(` Labels: ${t.labels.join(", ")}`);
109
+ if (t.priority) lines.push(` Priority: ${t.priority}`);
110
+ if (t.due_date) lines.push(` Due: ${t.due_date}`);
111
+ lines.push(` Completed: ${t.completed ? "yes" : "no"}`);
112
+ if (t.subtasks?.length) {
113
+ lines.push(` Subtasks:`);
114
+ for (const s of t.subtasks) {
115
+ lines.push(` [#${s.id}] ${s.content} (${s.completed ? "done" : "pending"})`);
116
+ }
117
+ }
118
+ return lines.join("\n");
119
+ }
120
+ function formatProject(p) {
121
+ return `[#${p.id}] ${p.name}`;
122
+ }
123
+ function formatAgent(a) {
124
+ const lines = [];
125
+ lines.push(`[#${a.id}] ${a.name}${a.display_name ? ` (${a.display_name})` : ""}`);
126
+ if (a.description) lines.push(` Description: ${a.description}`);
127
+ if (a.api_key) lines.push(` API Key: ${a.api_key}`);
128
+ if (a.permissions?.length) lines.push(` Permissions: ${a.permissions.join(", ")}`);
129
+ if (a.active !== void 0) lines.push(` Active: ${a.active ? "yes" : "no"}`);
130
+ return lines.join("\n");
131
+ }
132
+ var server = new McpServer({
133
+ name: "delega-mcp",
134
+ version: "1.0.0"
135
+ });
136
+ server.tool(
137
+ "list_tasks",
138
+ "List tasks from Delega, optionally filtered by project, label, due date, or completion status",
139
+ {
140
+ project_id: z.number().int().optional().describe("Filter by project ID"),
141
+ label: z.string().optional().describe("Filter by label name"),
142
+ due: z.enum(["today", "upcoming", "overdue"]).optional().describe("Filter by due date category"),
143
+ completed: z.boolean().optional().describe("Filter by completion status")
144
+ },
145
+ async ({ project_id, label, due, completed }) => {
146
+ try {
147
+ const tasks = await client.listTasks({ project_id, label, due, completed });
148
+ if (!tasks.length) {
149
+ return { content: [{ type: "text", text: "No tasks found." }] };
150
+ }
151
+ const text = tasks.map(formatTask).join("\n\n");
152
+ return { content: [{ type: "text", text }] };
153
+ } catch (e) {
154
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
155
+ }
156
+ }
157
+ );
158
+ server.tool(
159
+ "get_task",
160
+ "Get full details of a specific task including subtasks",
161
+ {
162
+ task_id: z.number().int().describe("The task ID")
163
+ },
164
+ async ({ task_id }) => {
165
+ try {
166
+ const task = await client.getTask(task_id);
167
+ return { content: [{ type: "text", text: formatTask(task) }] };
168
+ } catch (e) {
169
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
170
+ }
171
+ }
172
+ );
173
+ server.tool(
174
+ "create_task",
175
+ "Create a new task in Delega",
176
+ {
177
+ content: z.string().describe("Task title / content"),
178
+ description: z.string().optional().describe("Detailed description"),
179
+ project_id: z.number().int().optional().describe("Project ID to assign to"),
180
+ labels: z.array(z.string()).optional().describe("Labels to apply"),
181
+ priority: z.number().int().min(1).max(4).optional().describe("Priority: 1=normal, 2=medium, 3=high, 4=urgent"),
182
+ due_date: z.string().optional().describe("Due date in YYYY-MM-DD format")
183
+ },
184
+ async (params) => {
185
+ try {
186
+ const task = await client.createTask(params);
187
+ return {
188
+ content: [{ type: "text", text: `Task created:
189
+
190
+ ${formatTask(task)}` }]
191
+ };
192
+ } catch (e) {
193
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
194
+ }
195
+ }
196
+ );
197
+ server.tool(
198
+ "update_task",
199
+ "Update an existing task's fields",
200
+ {
201
+ task_id: z.number().int().describe("The task ID to update"),
202
+ content: z.string().optional().describe("New task title / content"),
203
+ description: z.string().optional().describe("New description"),
204
+ labels: z.array(z.string()).optional().describe("New labels"),
205
+ priority: z.number().int().optional().describe("New priority (1-4)"),
206
+ due_date: z.string().optional().describe("New due date (YYYY-MM-DD)"),
207
+ project_id: z.number().int().optional().describe("Move to project ID")
208
+ },
209
+ async ({ task_id, ...updates }) => {
210
+ try {
211
+ const task = await client.updateTask(task_id, updates);
212
+ return {
213
+ content: [{ type: "text", text: `Task updated:
214
+
215
+ ${formatTask(task)}` }]
216
+ };
217
+ } catch (e) {
218
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
219
+ }
220
+ }
221
+ );
222
+ server.tool(
223
+ "complete_task",
224
+ "Mark a task as completed",
225
+ {
226
+ task_id: z.number().int().describe("The task ID to complete")
227
+ },
228
+ async ({ task_id }) => {
229
+ try {
230
+ const task = await client.completeTask(task_id);
231
+ let text = `Task #${task_id} completed.`;
232
+ if (task?.next_occurrence) {
233
+ text += `
234
+ Next occurrence: ${task.next_occurrence}`;
235
+ }
236
+ return { content: [{ type: "text", text }] };
237
+ } catch (e) {
238
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
239
+ }
240
+ }
241
+ );
242
+ server.tool(
243
+ "delete_task",
244
+ "Delete a task permanently",
245
+ {
246
+ task_id: z.number().int().describe("The task ID to delete")
247
+ },
248
+ async ({ task_id }) => {
249
+ try {
250
+ await client.deleteTask(task_id);
251
+ return {
252
+ content: [{ type: "text", text: `Task #${task_id} deleted.` }]
253
+ };
254
+ } catch (e) {
255
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
256
+ }
257
+ }
258
+ );
259
+ server.tool(
260
+ "add_comment",
261
+ "Add a comment to a task",
262
+ {
263
+ task_id: z.number().int().describe("The task ID to comment on"),
264
+ content: z.string().describe("Comment text"),
265
+ author: z.string().optional().describe("Comment author name")
266
+ },
267
+ async ({ task_id, content, author }) => {
268
+ try {
269
+ const comment = await client.addComment(task_id, { content, author });
270
+ return {
271
+ content: [
272
+ {
273
+ type: "text",
274
+ text: `Comment added to task #${task_id}:
275
+ "${comment.content ?? content}"${comment.author ? ` \u2014 ${comment.author}` : ""}`
276
+ }
277
+ ]
278
+ };
279
+ } catch (e) {
280
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
281
+ }
282
+ }
283
+ );
284
+ server.tool(
285
+ "list_projects",
286
+ "List all projects in Delega",
287
+ {},
288
+ async () => {
289
+ try {
290
+ const projects = await client.listProjects();
291
+ if (!projects.length) {
292
+ return { content: [{ type: "text", text: "No projects found." }] };
293
+ }
294
+ const text = projects.map(formatProject).join("\n");
295
+ return { content: [{ type: "text", text }] };
296
+ } catch (e) {
297
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
298
+ }
299
+ }
300
+ );
301
+ server.tool(
302
+ "get_stats",
303
+ "Get task statistics from Delega (totals, completed today, due today, overdue, by project)",
304
+ {},
305
+ async () => {
306
+ try {
307
+ const stats = await client.getStats();
308
+ const lines = ["Task Statistics:"];
309
+ if (stats.total !== void 0) lines.push(` Total tasks: ${stats.total}`);
310
+ if (stats.completed_today !== void 0) lines.push(` Completed today: ${stats.completed_today}`);
311
+ if (stats.due_today !== void 0) lines.push(` Due today: ${stats.due_today}`);
312
+ if (stats.overdue !== void 0) lines.push(` Overdue: ${stats.overdue}`);
313
+ if (stats.by_project) {
314
+ lines.push(" By project:");
315
+ for (const [name, count] of Object.entries(stats.by_project)) {
316
+ lines.push(` ${name}: ${count}`);
317
+ }
318
+ }
319
+ return { content: [{ type: "text", text: lines.join("\n") }] };
320
+ } catch (e) {
321
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
322
+ }
323
+ }
324
+ );
325
+ server.tool(
326
+ "list_agents",
327
+ "List all registered agents in Delega",
328
+ {},
329
+ async () => {
330
+ try {
331
+ const agents = await client.listAgents();
332
+ if (!agents.length) {
333
+ return { content: [{ type: "text", text: "No agents registered." }] };
334
+ }
335
+ const text = agents.map(formatAgent).join("\n\n");
336
+ return { content: [{ type: "text", text }] };
337
+ } catch (e) {
338
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
339
+ }
340
+ }
341
+ );
342
+ server.tool(
343
+ "register_agent",
344
+ "Register a new agent in Delega. Returns the API key (shown only at creation \u2014 save it!)",
345
+ {
346
+ name: z.string().describe("Unique agent name (e.g. 'coordinator', 'researcher')"),
347
+ display_name: z.string().optional().describe("Human-readable name (e.g. 'Research Bot')"),
348
+ description: z.string().optional().describe("What this agent does"),
349
+ permissions: z.array(z.string()).optional().describe("Permission scopes (e.g. ['tasks:read', 'tasks:write'])")
350
+ },
351
+ async (params) => {
352
+ try {
353
+ const agent = await client.registerAgent(params);
354
+ return {
355
+ content: [{ type: "text", text: `Agent registered:
356
+
357
+ ${formatAgent(agent)}
358
+
359
+ \u26A0\uFE0F Save the API key \u2014 it won't be shown again.` }]
360
+ };
361
+ } catch (e) {
362
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
363
+ }
364
+ }
365
+ );
366
+ async function main() {
367
+ const transport = new StdioServerTransport();
368
+ await server.connect(transport);
369
+ }
370
+ main().catch((err) => {
371
+ console.error("Fatal:", err);
372
+ process.exit(1);
373
+ });
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@delega-dev/mcp",
3
+ "version": "1.0.1",
4
+ "description": "MCP server for Delega \u2014 task infrastructure for AI agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "delega-mcp": "dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "tsx src/index.ts",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "delega",
23
+ "tasks",
24
+ "ai-agents",
25
+ "delegation",
26
+ "model-context-protocol",
27
+ "task-management",
28
+ "agent-infrastructure"
29
+ ],
30
+ "author": "Delega Contributors",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/delega-dev/delega-mcp"
35
+ },
36
+ "homepage": "https://delega.dev",
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "dependencies": {
41
+ "@modelcontextprotocol/sdk": "^1.12.1",
42
+ "zod": "^3.24.2"
43
+ },
44
+ "devDependencies": {
45
+ "tsup": "^8.4.0",
46
+ "tsx": "^4.19.3",
47
+ "typescript": "^5.7.3"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ }
52
+ }