brioright-mcp 1.1.0 → 1.2.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.
- package/index.js +51 -39
- package/package.json +2 -2
- package/test-axios.mjs +20 -0
- package/test-axios2.mjs +20 -0
package/index.js
CHANGED
|
@@ -34,27 +34,31 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
34
34
|
config({ path: join(__dirname, '.env') })
|
|
35
35
|
|
|
36
36
|
const API_URL = process.env.BRIORIGHT_API_URL || 'http://localhost:3001/api'
|
|
37
|
-
const
|
|
37
|
+
const ENV_API_KEY = process.env.BRIORIGHT_API_KEY
|
|
38
38
|
const DEFAULT_WORKSPACE = process.env.BRIORIGHT_WORKSPACE_ID
|
|
39
39
|
const MCP_PORT = parseInt(process.env.MCP_PORT || '4040')
|
|
40
40
|
const MCP_SECRET = process.env.MCP_SECRET // Optional bearer token for HTTP mode
|
|
41
41
|
const USE_HTTP = process.env.MCP_TRANSPORT === 'http'
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
// ── Axios client factory ──────────────────────────────────────────────────────
|
|
44
|
+
async function call(method, path, data, overrideApiKey) {
|
|
45
|
+
const key = overrideApiKey || ENV_API_KEY;
|
|
46
|
+
if (!key) {
|
|
47
|
+
throw new Error('Brioright API error: No API Key provided. Either set BRIORIGHT_API_KEY environment variable or provide apiKey in the tool arguments.');
|
|
48
|
+
}
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
50
|
+
const api = axios.create({
|
|
51
|
+
baseURL: API_URL,
|
|
52
|
+
headers: { 'X-API-Key': key, 'Content-Type': 'application/json' },
|
|
53
|
+
timeout: 10000,
|
|
54
|
+
})
|
|
54
55
|
|
|
55
|
-
async function call(method, path, data) {
|
|
56
56
|
try {
|
|
57
|
-
const
|
|
57
|
+
const reqConfig = { method, url: path };
|
|
58
|
+
if (data !== null && data !== undefined) {
|
|
59
|
+
reqConfig.data = data;
|
|
60
|
+
}
|
|
61
|
+
const res = await api(reqConfig);
|
|
58
62
|
return res.data.data
|
|
59
63
|
} catch (err) {
|
|
60
64
|
const msg = err.response?.data?.message || err.message || 'Unknown error'
|
|
@@ -67,9 +71,10 @@ function buildServer() {
|
|
|
67
71
|
const server = new McpServer({ name: 'brioright', version: '1.0.0' })
|
|
68
72
|
|
|
69
73
|
// ── list_workspaces ───────────────────────────────────────────────────────
|
|
70
|
-
server.tool('list_workspaces', 'List all Brioright workspaces the API key has access to',
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
server.tool('list_workspaces', 'List all Brioright workspaces the API key has access to',
|
|
75
|
+
{ apiKey: z.string().optional().describe('Brioright API Key') },
|
|
76
|
+
async ({ apiKey }) => {
|
|
77
|
+
const data = await call('GET', '/workspaces', null, apiKey)
|
|
73
78
|
const workspaces = data.workspaces || data
|
|
74
79
|
return { content: [{ type: 'text', text: JSON.stringify(workspaces.map(w => ({ id: w.id, slug: w.slug, name: w.name })), null, 2) }] }
|
|
75
80
|
}
|
|
@@ -77,11 +82,14 @@ function buildServer() {
|
|
|
77
82
|
|
|
78
83
|
// ── list_projects ─────────────────────────────────────────────────────────
|
|
79
84
|
server.tool('list_projects', 'List all projects in a workspace',
|
|
80
|
-
{
|
|
81
|
-
|
|
85
|
+
{
|
|
86
|
+
workspaceId: z.string().optional().describe('Workspace slug. Defaults to BRIORIGHT_WORKSPACE_ID.'),
|
|
87
|
+
apiKey: z.string().optional().describe('Brioright API Key')
|
|
88
|
+
},
|
|
89
|
+
async ({ workspaceId, apiKey }) => {
|
|
82
90
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
83
91
|
if (!ws) throw new Error('workspaceId is required')
|
|
84
|
-
const data = await call('GET', `/workspaces/${ws}/projects
|
|
92
|
+
const data = await call('GET', `/workspaces/${ws}/projects`, null, apiKey)
|
|
85
93
|
const projects = data.projects || data
|
|
86
94
|
return { content: [{ type: 'text', text: JSON.stringify(projects.map(p => ({ id: p.id, name: p.name, status: p.status })), null, 2) }] }
|
|
87
95
|
}
|
|
@@ -95,15 +103,16 @@ function buildServer() {
|
|
|
95
103
|
status: z.enum(['todo', 'in_progress', 'in_review', 'done', 'cancelled']).optional(),
|
|
96
104
|
priority: z.enum(['low', 'medium', 'high', 'urgent']).optional(),
|
|
97
105
|
limit: z.number().optional().default(20),
|
|
106
|
+
apiKey: z.string().optional().describe('Brioright API Key')
|
|
98
107
|
},
|
|
99
|
-
async ({ projectId, workspaceId, status, priority, limit }) => {
|
|
108
|
+
async ({ projectId, workspaceId, status, priority, limit, apiKey }) => {
|
|
100
109
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
101
110
|
if (!ws) throw new Error('workspaceId is required')
|
|
102
111
|
const params = new URLSearchParams()
|
|
103
112
|
if (status) params.set('status', status)
|
|
104
113
|
if (priority) params.set('priority', priority)
|
|
105
114
|
params.set('limit', String(limit || 20))
|
|
106
|
-
const data = await call('GET', `/workspaces/${ws}/projects/${projectId}/tasks?${params}
|
|
115
|
+
const data = await call('GET', `/workspaces/${ws}/projects/${projectId}/tasks?${params}`, null, apiKey)
|
|
107
116
|
const tasks = data.tasks || data
|
|
108
117
|
return { content: [{ type: 'text', text: JSON.stringify(tasks.map(t => ({ id: t.id, title: t.title, status: t.status, priority: t.priority, dueDate: t.dueDate, assignee: t.assignee?.name })), null, 2) }] }
|
|
109
118
|
}
|
|
@@ -111,11 +120,11 @@ function buildServer() {
|
|
|
111
120
|
|
|
112
121
|
// ── get_task ──────────────────────────────────────────────────────────────
|
|
113
122
|
server.tool('get_task', 'Get full details of a single task',
|
|
114
|
-
{ taskId: z.string(), workspaceId: z.string().optional() },
|
|
115
|
-
async ({ taskId, workspaceId }) => {
|
|
123
|
+
{ taskId: z.string(), workspaceId: z.string().optional(), apiKey: z.string().optional().describe('Brioright API Key') },
|
|
124
|
+
async ({ taskId, workspaceId, apiKey }) => {
|
|
116
125
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
117
126
|
if (!ws) throw new Error('workspaceId is required')
|
|
118
|
-
const data = await call('GET', `/workspaces/${ws}/tasks/${taskId}
|
|
127
|
+
const data = await call('GET', `/workspaces/${ws}/tasks/${taskId}`, null, apiKey)
|
|
119
128
|
return { content: [{ type: 'text', text: JSON.stringify(data.task || data, null, 2) }] }
|
|
120
129
|
}
|
|
121
130
|
)
|
|
@@ -131,15 +140,16 @@ function buildServer() {
|
|
|
131
140
|
dueDate: z.string().optional().describe('ISO date string e.g. 2026-03-15'),
|
|
132
141
|
assigneeId: z.string().optional(),
|
|
133
142
|
workspaceId: z.string().optional(),
|
|
143
|
+
apiKey: z.string().optional().describe('Brioright API Key')
|
|
134
144
|
},
|
|
135
|
-
async ({ projectId, title, description, status, priority, dueDate, assigneeId, workspaceId }) => {
|
|
145
|
+
async ({ projectId, title, description, status, priority, dueDate, assigneeId, workspaceId, apiKey }) => {
|
|
136
146
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
137
147
|
if (!ws) throw new Error('workspaceId is required')
|
|
138
148
|
const data = await call('POST', `/workspaces/${ws}/projects/${projectId}/tasks`, {
|
|
139
149
|
title, description, status, priority,
|
|
140
150
|
dueDate: dueDate ? new Date(dueDate).toISOString() : undefined,
|
|
141
151
|
assigneeId,
|
|
142
|
-
})
|
|
152
|
+
}, apiKey)
|
|
143
153
|
const task = data.task || data
|
|
144
154
|
return { content: [{ type: 'text', text: `✅ Task created!\n\n${JSON.stringify({ id: task.id, title: task.title, status: task.status, priority: task.priority, dueDate: task.dueDate }, null, 2)}` }] }
|
|
145
155
|
}
|
|
@@ -156,13 +166,14 @@ function buildServer() {
|
|
|
156
166
|
dueDate: z.string().optional(),
|
|
157
167
|
assigneeId: z.string().optional(),
|
|
158
168
|
workspaceId: z.string().optional(),
|
|
169
|
+
apiKey: z.string().optional().describe('Brioright API Key')
|
|
159
170
|
},
|
|
160
|
-
async ({ taskId, workspaceId, ...fields }) => {
|
|
171
|
+
async ({ taskId, workspaceId, apiKey, ...fields }) => {
|
|
161
172
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
162
173
|
if (!ws) throw new Error('workspaceId is required')
|
|
163
174
|
const updates = Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== undefined))
|
|
164
175
|
if (updates.dueDate) updates.dueDate = new Date(updates.dueDate).toISOString()
|
|
165
|
-
const data = await call('PATCH', `/workspaces/${ws}/tasks/${taskId}`, updates)
|
|
176
|
+
const data = await call('PATCH', `/workspaces/${ws}/tasks/${taskId}`, updates, apiKey)
|
|
166
177
|
const task = data.task || data
|
|
167
178
|
return { content: [{ type: 'text', text: `✅ Task updated!\n\n${JSON.stringify({ id: task.id, title: task.title, status: task.status, priority: task.priority }, null, 2)}` }] }
|
|
168
179
|
}
|
|
@@ -170,11 +181,11 @@ function buildServer() {
|
|
|
170
181
|
|
|
171
182
|
// ── complete_task ─────────────────────────────────────────────────────────
|
|
172
183
|
server.tool('complete_task', 'Mark a task as completed',
|
|
173
|
-
{ taskId: z.string(), workspaceId: z.string().optional() },
|
|
174
|
-
async ({ taskId, workspaceId }) => {
|
|
184
|
+
{ taskId: z.string(), workspaceId: z.string().optional(), apiKey: z.string().optional().describe('Brioright API Key') },
|
|
185
|
+
async ({ taskId, workspaceId, apiKey }) => {
|
|
175
186
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
176
187
|
if (!ws) throw new Error('workspaceId is required')
|
|
177
|
-
await call('PATCH', `/workspaces/${ws}/tasks/${taskId}`, { status: 'done' })
|
|
188
|
+
await call('PATCH', `/workspaces/${ws}/tasks/${taskId}`, { status: 'done' }, apiKey)
|
|
178
189
|
return { content: [{ type: 'text', text: `✅ Task ${taskId} marked as done.` }] }
|
|
179
190
|
}
|
|
180
191
|
)
|
|
@@ -186,11 +197,12 @@ function buildServer() {
|
|
|
186
197
|
description: z.string().optional(),
|
|
187
198
|
color: z.string().optional().default('#6366f1'),
|
|
188
199
|
workspaceId: z.string().optional(),
|
|
200
|
+
apiKey: z.string().optional().describe('Brioright API Key')
|
|
189
201
|
},
|
|
190
|
-
async ({ name, description, color, workspaceId }) => {
|
|
202
|
+
async ({ name, description, color, workspaceId, apiKey }) => {
|
|
191
203
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
192
204
|
if (!ws) throw new Error('workspaceId is required')
|
|
193
|
-
const data = await call('POST', `/workspaces/${ws}/projects`, { name, description, color })
|
|
205
|
+
const data = await call('POST', `/workspaces/${ws}/projects`, { name, description, color }, apiKey)
|
|
194
206
|
const project = data.project || data
|
|
195
207
|
return { content: [{ type: 'text', text: `✅ Project created!\n\n${JSON.stringify({ id: project.id, name: project.name }, null, 2)}` }] }
|
|
196
208
|
}
|
|
@@ -198,11 +210,11 @@ function buildServer() {
|
|
|
198
210
|
|
|
199
211
|
// ── list_members ──────────────────────────────────────────────────────────
|
|
200
212
|
server.tool('list_members', 'List workspace members (useful for finding assignee IDs)',
|
|
201
|
-
{ workspaceId: z.string().optional() },
|
|
202
|
-
async ({ workspaceId }) => {
|
|
213
|
+
{ workspaceId: z.string().optional(), apiKey: z.string().optional().describe('Brioright API Key') },
|
|
214
|
+
async ({ workspaceId, apiKey }) => {
|
|
203
215
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
204
216
|
if (!ws) throw new Error('workspaceId is required')
|
|
205
|
-
const data = await call('GET', `/workspaces/${ws}/members
|
|
217
|
+
const data = await call('GET', `/workspaces/${ws}/members`, null, apiKey)
|
|
206
218
|
const members = data.members || data
|
|
207
219
|
return { content: [{ type: 'text', text: JSON.stringify(members.map(m => ({ id: m.user?.id || m.id, name: m.user?.name || m.name, email: m.user?.email || m.email, role: m.role })), null, 2) }] }
|
|
208
220
|
}
|
|
@@ -210,11 +222,11 @@ function buildServer() {
|
|
|
210
222
|
|
|
211
223
|
// ── get_workspace_summary ─────────────────────────────────────────────────
|
|
212
224
|
server.tool('get_workspace_summary', 'Dashboard stats: task counts by status and priority',
|
|
213
|
-
{ workspaceId: z.string().optional() },
|
|
214
|
-
async ({ workspaceId }) => {
|
|
225
|
+
{ workspaceId: z.string().optional(), apiKey: z.string().optional().describe('Brioright API Key') },
|
|
226
|
+
async ({ workspaceId, apiKey }) => {
|
|
215
227
|
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
216
228
|
if (!ws) throw new Error('workspaceId is required')
|
|
217
|
-
const data = await call('GET', `/workspaces/${ws}/dashboard/stats
|
|
229
|
+
const data = await call('GET', `/workspaces/${ws}/dashboard/stats`, null, apiKey)
|
|
218
230
|
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] }
|
|
219
231
|
}
|
|
220
232
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brioright-mcp",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "MCP server for Brioright — lets AI assistants create and manage tasks via natural language",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -22,4 +22,4 @@
|
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=18.0.0"
|
|
24
24
|
}
|
|
25
|
-
}
|
|
25
|
+
}
|
package/test-axios.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
async function test() {
|
|
4
|
+
const api = axios.create({
|
|
5
|
+
baseURL: 'https://brioright.online/api',
|
|
6
|
+
headers: { 'X-API-Key': 'brio_9847f9c385632d4d1c888afc42c8c3906ffad22bf7713c062a2d1c6db90adadf', 'Content-Type': 'application/json' },
|
|
7
|
+
timeout: 10000,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const res = await api({ method: 'GET', url: '/workspaces', data: null });
|
|
12
|
+
console.log("SUCCESS:");
|
|
13
|
+
console.log(res.data);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.log("ERROR:");
|
|
16
|
+
console.log(err.response?.data || err.message);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
test();
|
package/test-axios2.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
async function test() {
|
|
4
|
+
const api = axios.create({
|
|
5
|
+
baseURL: 'https://brioright.online/api',
|
|
6
|
+
headers: { 'X-API-Key': 'brio_9847f9c385632d4d1c888afc42c8c3906ffad22bf7713c062a2d1c6db90adadf', 'Content-Type': 'application/json' },
|
|
7
|
+
timeout: 10000,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const res = await api({ method: 'GET', url: '/workspaces' }); // data: undefined
|
|
12
|
+
console.log("SUCCESS:");
|
|
13
|
+
console.log(res.data);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.log("ERROR:");
|
|
16
|
+
console.log(err.response?.data || err.message);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
test();
|