dueey-mcp 1.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/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/index.js +231 -0
- package/package.json +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gregory Murphy
|
|
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,97 @@
|
|
|
1
|
+
# Dueey MCP Server
|
|
2
|
+
|
|
3
|
+
MCP server for the [Dueey](https://dueey.com) PM Assistant public API.
|
|
4
|
+
Exposes boards, lists, cards, and exports as MCP tools for Claude and other AI clients.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
### Option A: Install from npm
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g dueey-mcp
|
|
12
|
+
# or use with npx: npx dueey-mcp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Option B: Install from source
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install
|
|
19
|
+
npm run build
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Get your API key
|
|
23
|
+
|
|
24
|
+
In Dueey: **Settings → API Access** → generate a token (starts with `pm_...`).
|
|
25
|
+
|
|
26
|
+
### 3. Add to your AI client
|
|
27
|
+
|
|
28
|
+
#### Claude Desktop
|
|
29
|
+
|
|
30
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or
|
|
31
|
+
`%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"dueey": {
|
|
37
|
+
"command": "node",
|
|
38
|
+
"args": ["/path/to/dueey-mcp/dist/index.js"],
|
|
39
|
+
"env": {
|
|
40
|
+
"DUEEY_API_KEY": "pm_your_token_here"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Restart Claude Desktop.
|
|
48
|
+
|
|
49
|
+
#### Cursor
|
|
50
|
+
|
|
51
|
+
Add the server in **Cursor Settings → Features → MCP** (or your project’s `.cursor/mcp.json`). Example:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"dueey": {
|
|
57
|
+
"command": "node",
|
|
58
|
+
"args": ["/path/to/dueey-mcp/dist/index.js"],
|
|
59
|
+
"env": {
|
|
60
|
+
"DUEEY_API_KEY": "pm_your_token_here"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If you installed globally (`npm install -g dueey-mcp`), use the path from `npm root -g` (e.g. `"args": ["/usr/local/lib/node_modules/dueey-mcp/dist/index.js"]`) or use `npx`: `"command": "npx", "args": ["dueey-mcp"]` and keep `env` as above.
|
|
68
|
+
|
|
69
|
+
#### Other clients
|
|
70
|
+
|
|
71
|
+
Any client that supports MCP over stdio (e.g. Windsurf, Continue, custom setups) can use this server: run `node /path/to/dist/index.js` with `DUEEY_API_KEY` set in the environment and point the client at that process.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Available Tools
|
|
76
|
+
|
|
77
|
+
| Tool | Description |
|
|
78
|
+
|------|-------------|
|
|
79
|
+
| `get_me` | Current authenticated user |
|
|
80
|
+
| `list_boards` | All boards (optional `workspaceId` filter) |
|
|
81
|
+
| `get_board` | Single board by ID or slug |
|
|
82
|
+
| `list_lists` | Lists/columns for a board |
|
|
83
|
+
| `list_cards` | Cards filtered by board or list |
|
|
84
|
+
| `get_card` | Single card by UUID or cardKey (e.g. `SWAT-42`) |
|
|
85
|
+
| `create_card` | Create a card with title, description, priority, labels, dates, checklist |
|
|
86
|
+
| `update_card` | Update any card field; use `listId` to move a card |
|
|
87
|
+
| `get_data` | Full export — all workspaces, boards, lists, cards |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Example prompts
|
|
92
|
+
|
|
93
|
+
- *"Show me all my Dueey boards"*
|
|
94
|
+
- *"List the cards in my Roadmap board"*
|
|
95
|
+
- *"Create a high-priority card called 'Fix login bug' in my Backlog list"*
|
|
96
|
+
- *"Move card SWAT-12 to the Done column"*
|
|
97
|
+
- *"Export all my data from Dueey"*
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
const BASE_URL = "https://dueey.com/api/v1";
|
|
6
|
+
const API_KEY = process.env.DUEEY_API_KEY ?? "";
|
|
7
|
+
if (!API_KEY) {
|
|
8
|
+
console.error("Error: DUEEY_API_KEY environment variable is required.");
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
async function dueeyFetch(path, options = {}) {
|
|
12
|
+
const { params, ...fetchOptions } = options;
|
|
13
|
+
const url = new URL(`${BASE_URL}${path}`);
|
|
14
|
+
if (params) {
|
|
15
|
+
for (const [k, v] of Object.entries(params)) {
|
|
16
|
+
if (v !== undefined)
|
|
17
|
+
url.searchParams.set(k, String(v));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const res = await fetch(url.toString(), {
|
|
21
|
+
...fetchOptions,
|
|
22
|
+
headers: {
|
|
23
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
...(fetchOptions.headers ?? {}),
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
const text = await res.text().catch(() => "");
|
|
30
|
+
throw new McpError(ErrorCode.InternalError, `Dueey API error ${res.status}: ${text || res.statusText}`);
|
|
31
|
+
}
|
|
32
|
+
return res.json();
|
|
33
|
+
}
|
|
34
|
+
const server = new Server({ name: "dueey-mcp", version: "1.0.0" }, { capabilities: { tools: {} } });
|
|
35
|
+
// ─── Tool Definitions ────────────────────────────────────────────────────────
|
|
36
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
37
|
+
tools: [
|
|
38
|
+
// User
|
|
39
|
+
{
|
|
40
|
+
name: "get_me",
|
|
41
|
+
description: "Get the currently authenticated Dueey user (id, email, name).",
|
|
42
|
+
inputSchema: { type: "object", properties: {}, required: [] },
|
|
43
|
+
},
|
|
44
|
+
// Boards
|
|
45
|
+
{
|
|
46
|
+
name: "list_boards",
|
|
47
|
+
description: "List all boards the user has access to, optionally filtered by workspace.",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
workspaceId: { type: "string", description: "Filter by workspace ID" },
|
|
52
|
+
fields: { type: "string", description: "Comma-separated fields to return" },
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "get_board",
|
|
58
|
+
description: "Get full details for a single board by its ID or slug.",
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: "object",
|
|
61
|
+
required: ["id"],
|
|
62
|
+
properties: {
|
|
63
|
+
id: { type: "string", description: "Board ID or slug" },
|
|
64
|
+
fields: { type: "string" },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
// Lists
|
|
69
|
+
{
|
|
70
|
+
name: "list_lists",
|
|
71
|
+
description: "Get all lists (columns) for a specific board.",
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: "object",
|
|
74
|
+
required: ["boardId"],
|
|
75
|
+
properties: {
|
|
76
|
+
boardId: { type: "string", description: "Board ID" },
|
|
77
|
+
fields: { type: "string" },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
// Cards
|
|
82
|
+
{
|
|
83
|
+
name: "list_cards",
|
|
84
|
+
description: "List cards, optionally filtered by board or list. Returns up to `limit` cards (default 50).",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: {
|
|
88
|
+
boardId: { type: "string" },
|
|
89
|
+
listId: { type: "string" },
|
|
90
|
+
limit: { type: "number", description: "Max results (default 50)" },
|
|
91
|
+
fields: { type: "string" },
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "get_card",
|
|
97
|
+
description: "Get a single card by its UUID or cardKey (e.g. SWAT-42).",
|
|
98
|
+
inputSchema: {
|
|
99
|
+
type: "object",
|
|
100
|
+
required: ["id"],
|
|
101
|
+
properties: {
|
|
102
|
+
id: { type: "string", description: "Card UUID or cardKey" },
|
|
103
|
+
fields: { type: "string" },
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "create_card",
|
|
109
|
+
description: "Create a new card in a list.",
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: "object",
|
|
112
|
+
required: ["listId", "title"],
|
|
113
|
+
properties: {
|
|
114
|
+
listId: { type: "string" },
|
|
115
|
+
title: { type: "string" },
|
|
116
|
+
description: { type: "string" },
|
|
117
|
+
priority: {
|
|
118
|
+
type: "string",
|
|
119
|
+
enum: ["critical", "high", "medium", "low", "none"],
|
|
120
|
+
},
|
|
121
|
+
labels: { type: "array", items: { type: "string" } },
|
|
122
|
+
dueDate: { type: "string", description: "ISO date e.g. 2025-12-31" },
|
|
123
|
+
startDate: { type: "string" },
|
|
124
|
+
checklist: {
|
|
125
|
+
type: "array",
|
|
126
|
+
items: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
text: { type: "string" },
|
|
130
|
+
completed: { type: "boolean" },
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "update_card",
|
|
139
|
+
description: "Update an existing card. Pass only the fields you want to change. Use `listId` to move a card to another list.",
|
|
140
|
+
inputSchema: {
|
|
141
|
+
type: "object",
|
|
142
|
+
required: ["id"],
|
|
143
|
+
properties: {
|
|
144
|
+
id: { type: "string", description: "Card UUID or cardKey" },
|
|
145
|
+
title: { type: "string" },
|
|
146
|
+
description: { type: "string" },
|
|
147
|
+
priority: {
|
|
148
|
+
type: "string",
|
|
149
|
+
enum: ["critical", "high", "medium", "low", "none"],
|
|
150
|
+
},
|
|
151
|
+
labels: { type: "array", items: { type: "string" } },
|
|
152
|
+
dueDate: { type: "string", nullable: true },
|
|
153
|
+
startDate: { type: "string", nullable: true },
|
|
154
|
+
checklist: { type: "array" },
|
|
155
|
+
listId: { type: "string", description: "Move card to this list" },
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
// Export
|
|
160
|
+
{
|
|
161
|
+
name: "get_data",
|
|
162
|
+
description: "Full export of all workspaces, boards, lists, and cards keyed by ID. Use `compact=true` to omit nulls and heavy fields.",
|
|
163
|
+
inputSchema: {
|
|
164
|
+
type: "object",
|
|
165
|
+
properties: {
|
|
166
|
+
compact: { type: "boolean" },
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
}));
|
|
172
|
+
// ─── Tool Handlers ───────────────────────────────────────────────────────────
|
|
173
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
174
|
+
const { name, arguments: args = {} } = request.params;
|
|
175
|
+
const ok = (data) => ({
|
|
176
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
177
|
+
});
|
|
178
|
+
switch (name) {
|
|
179
|
+
case "get_me":
|
|
180
|
+
return ok(await dueeyFetch("/me"));
|
|
181
|
+
case "list_boards":
|
|
182
|
+
return ok(await dueeyFetch("/boards", {
|
|
183
|
+
params: { workspaceId: args.workspaceId, fields: args.fields },
|
|
184
|
+
}));
|
|
185
|
+
case "get_board":
|
|
186
|
+
return ok(await dueeyFetch(`/boards/${args.id}`, {
|
|
187
|
+
params: { fields: args.fields },
|
|
188
|
+
}));
|
|
189
|
+
case "list_lists":
|
|
190
|
+
return ok(await dueeyFetch("/lists", {
|
|
191
|
+
params: { boardId: args.boardId, fields: args.fields },
|
|
192
|
+
}));
|
|
193
|
+
case "list_cards":
|
|
194
|
+
return ok(await dueeyFetch("/cards", {
|
|
195
|
+
params: {
|
|
196
|
+
boardId: args.boardId,
|
|
197
|
+
listId: args.listId,
|
|
198
|
+
limit: args.limit,
|
|
199
|
+
fields: args.fields,
|
|
200
|
+
},
|
|
201
|
+
}));
|
|
202
|
+
case "get_card":
|
|
203
|
+
return ok(await dueeyFetch(`/cards/${args.id}`, {
|
|
204
|
+
params: { fields: args.fields },
|
|
205
|
+
}));
|
|
206
|
+
case "create_card": {
|
|
207
|
+
const { ...body } = args;
|
|
208
|
+
return ok(await dueeyFetch("/cards", {
|
|
209
|
+
method: "POST",
|
|
210
|
+
body: JSON.stringify(body),
|
|
211
|
+
}));
|
|
212
|
+
}
|
|
213
|
+
case "update_card": {
|
|
214
|
+
const { id, ...body } = args;
|
|
215
|
+
return ok(await dueeyFetch(`/cards/${id}`, {
|
|
216
|
+
method: "PATCH",
|
|
217
|
+
body: JSON.stringify(body),
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
case "get_data":
|
|
221
|
+
return ok(await dueeyFetch("/data", {
|
|
222
|
+
params: { compact: args.compact ? "1" : undefined },
|
|
223
|
+
}));
|
|
224
|
+
default:
|
|
225
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
// ─── Start ───────────────────────────────────────────────────────────────────
|
|
229
|
+
const transport = new StdioServerTransport();
|
|
230
|
+
server.connect(transport);
|
|
231
|
+
console.error("Dueey MCP server running.");
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dueey-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for the Dueey PM Assistant public API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": { "dueey-mcp": "dist/index.js" },
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"start": "node dist/index.js",
|
|
11
|
+
"dev": "ts-node --esm src/index.ts",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"files": ["dist", "README.md"],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/gmurph91/dueeymcp.git"
|
|
18
|
+
},
|
|
19
|
+
"keywords": ["mcp", "dueey", "model-context-protocol", "claude", "pm", "project-management"],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^20.0.0",
|
|
26
|
+
"typescript": "^5.0.0"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18"
|
|
30
|
+
}
|
|
31
|
+
}
|