brioright-mcp 1.3.0 → 1.4.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 +6 -0
- package/index.js +51 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,3 +88,9 @@ And pass the Authorization Header: `Bearer your_secure_bearer_token`.
|
|
|
88
88
|
| `create_project` | Create a new project |
|
|
89
89
|
| `list_members` | List workspace members (for finding assignee IDs) |
|
|
90
90
|
| `get_workspace_summary` | Dashboard stats: task counts by status/priority |
|
|
91
|
+
| `bulk_create_tasks` | Create multiple tasks at once |
|
|
92
|
+
| `add_comment` | Add a comment to a task |
|
|
93
|
+
| `get_task_comments` | Get all comments for a given task |
|
|
94
|
+
| `log_time` | Log time entry for a project/task |
|
|
95
|
+
| `add_task_attachment` | Upload a file attachment to a task using a Base64 encoded string |
|
|
96
|
+
| `get_task_attachments` | List all file attachments for a specific task |
|
package/index.js
CHANGED
|
@@ -41,16 +41,21 @@ 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
43
|
// ── Axios client factory ──────────────────────────────────────────────────────
|
|
44
|
-
async function call(method, path, data, overrideApiKey) {
|
|
44
|
+
async function call(method, path, data, overrideApiKey, customHeaders = {}) {
|
|
45
45
|
const key = overrideApiKey || ENV_API_KEY;
|
|
46
46
|
if (!key) {
|
|
47
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
48
|
}
|
|
49
49
|
|
|
50
|
+
const headers = { 'X-API-Key': key, 'Content-Type': 'application/json', ...customHeaders }
|
|
51
|
+
if (headers['Content-Type'] === 'multipart/form-data' || headers['Content-Type'] === null) {
|
|
52
|
+
delete headers['Content-Type']; // Let axios auto-generate the multipart boundary
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
const api = axios.create({
|
|
51
56
|
baseURL: API_URL,
|
|
52
|
-
headers
|
|
53
|
-
timeout:
|
|
57
|
+
headers,
|
|
58
|
+
timeout: 30000,
|
|
54
59
|
})
|
|
55
60
|
|
|
56
61
|
try {
|
|
@@ -129,6 +134,49 @@ function buildServer() {
|
|
|
129
134
|
}
|
|
130
135
|
)
|
|
131
136
|
|
|
137
|
+
// ── get_task_attachments ──────────────────────────────────────────────────
|
|
138
|
+
server.tool('get_task_attachments', 'List all file attachments for a specific task',
|
|
139
|
+
{
|
|
140
|
+
taskId: z.string(),
|
|
141
|
+
workspaceId: z.string().optional(),
|
|
142
|
+
apiKey: z.string().optional().describe('Brioright API Key')
|
|
143
|
+
},
|
|
144
|
+
async ({ taskId, workspaceId, apiKey }) => {
|
|
145
|
+
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
146
|
+
if (!ws) throw new Error('workspaceId is required')
|
|
147
|
+
const data = await call('GET', `/workspaces/${ws}/tasks/${taskId}/attachments`, null, apiKey)
|
|
148
|
+
const attachments = data.attachments || data
|
|
149
|
+
return { content: [{ type: 'text', text: JSON.stringify(attachments, null, 2) }] }
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
// ── add_task_attachment ───────────────────────────────────────────────────
|
|
154
|
+
server.tool('add_task_attachment', 'Upload a file attachment to a task using a Base64 encoded string',
|
|
155
|
+
{
|
|
156
|
+
taskId: z.string(),
|
|
157
|
+
fileName: z.string().describe('Name of the file to attach (e.g. image.png)'),
|
|
158
|
+
fileContent: z.string().describe('Base64 encoded string of the file content'),
|
|
159
|
+
mimeType: z.string().optional().describe('MIME type of the file (e.g. image/png)'),
|
|
160
|
+
workspaceId: z.string().optional(),
|
|
161
|
+
apiKey: z.string().optional().describe('Brioright API Key')
|
|
162
|
+
},
|
|
163
|
+
async ({ taskId, fileName, fileContent, mimeType, workspaceId, apiKey }) => {
|
|
164
|
+
const ws = workspaceId || DEFAULT_WORKSPACE
|
|
165
|
+
if (!ws) throw new Error('workspaceId is required')
|
|
166
|
+
|
|
167
|
+
// Convert base64 to Blob
|
|
168
|
+
const buffer = Buffer.from(fileContent, 'base64')
|
|
169
|
+
const blob = new Blob([buffer], { type: mimeType || 'application/octet-stream' })
|
|
170
|
+
|
|
171
|
+
const formData = new FormData()
|
|
172
|
+
formData.append('file', blob, fileName)
|
|
173
|
+
|
|
174
|
+
const data = await call('POST', `/workspaces/${ws}/tasks/${taskId}/attachments`, formData, apiKey, { 'Content-Type': 'multipart/form-data' })
|
|
175
|
+
const attachment = data.attachment || data
|
|
176
|
+
return { content: [{ type: 'text', text: `✅ File attached successfully!\n\n${JSON.stringify({ id: attachment.id, name: attachment.name, url: attachment.url }, null, 2)}` }] }
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
|
|
132
180
|
// ── create_task ───────────────────────────────────────────────────────────
|
|
133
181
|
server.tool('create_task', 'Create a new task in a Brioright project',
|
|
134
182
|
{
|