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.
Files changed (3) hide show
  1. package/README.md +6 -0
  2. package/index.js +51 -3
  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: { 'X-API-Key': key, 'Content-Type': 'application/json' },
53
- timeout: 10000,
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
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brioright-mcp",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
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",