@fruition/fcp-mcp-server 1.22.0 → 1.23.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 (2) hide show
  1. package/dist/index.js +82 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -165,6 +165,7 @@ const TOOL_PERMISSIONS = {
165
165
  unroo_list_tasks: 'viewer',
166
166
  unroo_get_task: 'viewer',
167
167
  unroo_list_comments: 'viewer',
168
+ unroo_list_attachments: 'viewer',
168
169
  unroo_get_my_tasks: 'viewer',
169
170
  unroo_get_parking_lot: 'viewer',
170
171
  unroo_get_backlog: 'viewer',
@@ -842,6 +843,18 @@ class UnrooClient {
842
843
  return this.fetch(`/api/external/fcp/tasks/${encodeURIComponent(taskId)}/comments`);
843
844
  }
844
845
  // ============================================================================
846
+ // Attachment APIs
847
+ // ============================================================================
848
+ async listAttachments(taskId, opts = {}) {
849
+ const params = new URLSearchParams();
850
+ if (opts.includeContent)
851
+ params.set('include_content', 'true');
852
+ const query = params.toString();
853
+ // Inline image fetches can be slow if the bucket has cold objects; give it
854
+ // a longer timeout than the default 15s.
855
+ return this.fetch(`/api/external/fcp/tasks/${encodeURIComponent(taskId)}/attachments${query ? `?${query}` : ''}`, {}, 60_000);
856
+ }
857
+ // ============================================================================
845
858
  // Parking Lot / Backlog APIs
846
859
  // ============================================================================
847
860
  async logFutureWork(input) {
@@ -1825,6 +1838,24 @@ const TOOLS = [
1825
1838
  required: ['task_id'],
1826
1839
  },
1827
1840
  },
1841
+ {
1842
+ name: 'unroo_list_attachments',
1843
+ description: 'List file attachments on an Unroo task. Use this to see screenshots, logs, or other files attached to a bug report or ticket. By default, image and text attachments are embedded inline so you can view them directly; pass include_content=false to get metadata only (faster for large attachments).',
1844
+ inputSchema: {
1845
+ type: 'object',
1846
+ properties: {
1847
+ task_id: {
1848
+ type: 'string',
1849
+ description: 'Task ID or Jira key (e.g., task_abc123 or FLYFRU-189)',
1850
+ },
1851
+ include_content: {
1852
+ type: 'boolean',
1853
+ description: 'When true (default), embed image and text content inline. Set to false to return metadata only.',
1854
+ },
1855
+ },
1856
+ required: ['task_id'],
1857
+ },
1858
+ },
1828
1859
  {
1829
1860
  name: 'unroo_get_my_tasks',
1830
1861
  description: 'Get tasks assigned to the current user (based on API key). Useful for finding your work items.',
@@ -3643,6 +3674,57 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3643
3674
  ],
3644
3675
  };
3645
3676
  }
3677
+ case 'unroo_list_attachments': {
3678
+ const { task_id, include_content } = args;
3679
+ const includeContent = include_content !== false; // default true
3680
+ const result = await unrooClient.listAttachments(task_id, { includeContent });
3681
+ // Summary block: metadata only, no base64 bodies (those go into image/text blocks below).
3682
+ const summary = {
3683
+ total: result.total,
3684
+ attachments: result.attachments.map((a) => ({
3685
+ id: a.id,
3686
+ file_name: a.file_name,
3687
+ file_size: a.file_size,
3688
+ mime_type: a.mime_type,
3689
+ uploaded_by: a.uploaded_by,
3690
+ created_at: a.created_at,
3691
+ file_url: a.file_url,
3692
+ jira_attachment_id: a.jira_attachment_id,
3693
+ inlined: !!a.content_base64,
3694
+ content_omitted_reason: a.content_omitted_reason,
3695
+ })),
3696
+ };
3697
+ const content = [
3698
+ { type: 'text', text: JSON.stringify(summary, null, 2) },
3699
+ ];
3700
+ if (includeContent) {
3701
+ for (const a of result.attachments) {
3702
+ if (!a.content_base64)
3703
+ continue;
3704
+ if (a.content_kind === 'image') {
3705
+ content.push({
3706
+ type: 'image',
3707
+ data: a.content_base64,
3708
+ mimeType: a.mime_type || 'application/octet-stream',
3709
+ });
3710
+ }
3711
+ else if (a.content_kind === 'text') {
3712
+ let decoded;
3713
+ try {
3714
+ decoded = Buffer.from(a.content_base64, 'base64').toString('utf8');
3715
+ }
3716
+ catch {
3717
+ decoded = '[failed to decode text content]';
3718
+ }
3719
+ content.push({
3720
+ type: 'text',
3721
+ text: `--- ${a.file_name} (${a.mime_type || 'text'}) ---\n${decoded}`,
3722
+ });
3723
+ }
3724
+ }
3725
+ }
3726
+ return { content };
3727
+ }
3646
3728
  case 'unroo_get_my_tasks': {
3647
3729
  const { status, limit } = args;
3648
3730
  // Note: The API key determines the user, tasks are filtered server-side
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fruition/fcp-mcp-server",
3
- "version": "1.22.0",
3
+ "version": "1.23.0",
4
4
  "description": "MCP Server for FCP Launch Coordination System - enables Claude Code to interact with FCP launches and track development time",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",