@mgsoftwarebv/mcp-server-bridge 3.5.4 → 3.5.5

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/dist/index.js CHANGED
@@ -105991,6 +105991,22 @@ var TOOLS = [
105991
105991
  required: ["ticketId"]
105992
105992
  }
105993
105993
  },
105994
+ {
105995
+ name: "delete-ticket-attachment",
105996
+ description: "Safely remove a ticket or comment attachment by id. Validates provider/team access and that the attachment belongs to the requested ticket. Hard-deletes the DB row and vault file, and logs ticket activity with the filename. Find attachment ids via get-ticket-by-id.",
105997
+ inputSchema: {
105998
+ type: "object",
105999
+ properties: {
106000
+ teamId: teamIdProp,
106001
+ ticketId: ticketIdentifierProp,
106002
+ attachmentId: {
106003
+ type: "string",
106004
+ description: "Attachment ID from get-ticket-by-id (ticket or comment attachment)."
106005
+ }
106006
+ },
106007
+ required: ["ticketId", "attachmentId"]
106008
+ }
106009
+ },
105994
106010
  {
105995
106011
  name: "get-customers",
105996
106012
  description: "Get customers with optional search. Each result includes its ID (UUID), name, email, website, phone, status, archived flag, and created date. Archived customers are hidden by default; pass status 'archived' or 'all' to include them.",
@@ -120639,6 +120655,36 @@ function validateAttachmentBuffer(buffer2, mimeType) {
120639
120655
  return null;
120640
120656
  }
120641
120657
 
120658
+ // src/tools/ticket-attachment-delete-util.ts
120659
+ function validateDeleteAttachmentInput(attachmentId) {
120660
+ if (!attachmentId?.trim()) {
120661
+ return "missing_attachment_id";
120662
+ }
120663
+ return null;
120664
+ }
120665
+ function validateAttachmentBelongsToTicket(attachmentTicketId, requestedTicketId) {
120666
+ return attachmentTicketId === requestedTicketId;
120667
+ }
120668
+ function buildDeleteAttachmentResult(input) {
120669
+ return {
120670
+ deleted: true,
120671
+ attachmentId: input.attachmentId,
120672
+ ticketId: input.ticketId,
120673
+ fileName: input.fileName,
120674
+ source: input.source
120675
+ };
120676
+ }
120677
+ function formatDeleteAttachmentRefusal(reason, context2) {
120678
+ switch (reason) {
120679
+ case "missing_attachment_id":
120680
+ return "attachmentId is required. Use get-ticket-by-id to list attachment ids.";
120681
+ case "attachment_not_found":
120682
+ return `Attachment not found: ${context2.attachmentId}. Use get-ticket-by-id on ${context2.ticketNumber} to list valid attachment ids.`;
120683
+ case "wrong_ticket":
120684
+ return `Attachment ${context2.attachmentId} (${context2.fileName ?? "unknown file"}) belongs to ticket ${context2.actualTicketId}, not ${context2.ticketNumber}. Pass the correct ticketId or choose an attachment id from that ticket.`;
120685
+ }
120686
+ }
120687
+
120642
120688
  // src/tools/ticket-attachments.ts
120643
120689
  function textResponse5(text3) {
120644
120690
  return { content: [{ type: "text", text: text3 }] };
@@ -120785,6 +120831,72 @@ Download URL (valid 1 hour):
120785
120831
  ${url3}` : "")
120786
120832
  );
120787
120833
  }
120834
+ async function handleDeleteTicketAttachment(input) {
120835
+ const ctx = getAuthContext() ?? authContext;
120836
+ if (!ctx) {
120837
+ return textResponse5("Error: Not authenticated.");
120838
+ }
120839
+ const inputError = validateDeleteAttachmentInput(input.attachmentId);
120840
+ if (inputError) {
120841
+ return textResponse5(formatDeleteAttachmentRefusal(inputError, { ticketNumber: input.ticketId }));
120842
+ }
120843
+ const access = await loadAccessibleTicket(input.teamId, input.ticketId);
120844
+ if (!access.ok) return access.response;
120845
+ const ticket = access.ticket;
120846
+ const attachment = await findAttachment(input.attachmentId);
120847
+ if (!attachment) {
120848
+ return textResponse5(
120849
+ formatDeleteAttachmentRefusal("attachment_not_found", {
120850
+ attachmentId: input.attachmentId,
120851
+ ticketNumber: ticket.ticketNumber
120852
+ })
120853
+ );
120854
+ }
120855
+ if (!validateAttachmentBelongsToTicket(attachment.ticketId, ticket.id)) {
120856
+ return textResponse5(
120857
+ formatDeleteAttachmentRefusal("wrong_ticket", {
120858
+ attachmentId: input.attachmentId,
120859
+ ticketNumber: ticket.ticketNumber,
120860
+ fileName: attachment.fileName,
120861
+ actualTicketId: attachment.ticketId
120862
+ })
120863
+ );
120864
+ }
120865
+ const table = attachment.source === "ticket" ? schema_exports.ticketAttachments : schema_exports.ticketCommentAttachments;
120866
+ const [deletedRow] = await db.delete(table).where(eq(table.id, input.attachmentId)).returning({ id: table.id });
120867
+ if (!deletedRow) {
120868
+ return textResponse5(
120869
+ `Failed to delete attachment ${input.attachmentId}. It may have been removed already.`
120870
+ );
120871
+ }
120872
+ try {
120873
+ await storage.remove({
120874
+ bucket: "vault",
120875
+ paths: [attachment.storageKey]
120876
+ });
120877
+ } catch {
120878
+ }
120879
+ await db.insert(schema_exports.ticketActivity).values({
120880
+ ticketId: ticket.id,
120881
+ teamId: ticket.teamId,
120882
+ userId: ctx.userId,
120883
+ activityType: "attachment_removed",
120884
+ metadata: {
120885
+ attachmentId: input.attachmentId,
120886
+ fileName: attachment.fileName,
120887
+ source: attachment.source,
120888
+ removedBy: "mcp"
120889
+ }
120890
+ });
120891
+ await db.update(schema_exports.tickets).set({ updatedAt: sql`NOW()`, updatedBy: ctx.userId }).where(eq(schema_exports.tickets.id, ticket.id));
120892
+ const result = buildDeleteAttachmentResult({
120893
+ attachmentId: input.attachmentId,
120894
+ ticketId: ticket.id,
120895
+ fileName: attachment.fileName,
120896
+ source: attachment.source
120897
+ });
120898
+ return textResponse5(JSON.stringify(result, null, 2));
120899
+ }
120788
120900
 
120789
120901
  // src/tools/tiptap-text.ts
120790
120902
  function renderNode(node) {
@@ -122861,6 +122973,10 @@ function createMcpServer() {
122861
122973
  return await handleUploadTicketAttachment(
122862
122974
  asToolArgs(toolArgs)
122863
122975
  );
122976
+ case "delete-ticket-attachment":
122977
+ return await handleDeleteTicketAttachment(
122978
+ asToolArgs(toolArgs)
122979
+ );
122864
122980
  case "get-customers":
122865
122981
  return await handleGetCustomers(asToolArgs(toolArgs));
122866
122982
  case "create-customer":