ticksy-mcp 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Artem Semkin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # ticksy-mcp
2
+
3
+ MCP server for the [Ticksy](https://ticksy.com) support ticket API. Gives AI agents full read and write access to your support tickets.
4
+
5
+ ## Tools
6
+
7
+ ### Read
8
+
9
+ - `list_open_tickets` — open tickets with embedded comments; optionally filter to those awaiting a reply
10
+ - `list_closed_tickets` — most recently closed tickets
11
+ - `get_ticket` — single ticket with full comment thread
12
+ - `get_ticket_comments` — comments for a ticket without full ticket data
13
+ - `list_my_tickets` — open tickets assigned to the authenticated agent
14
+ - `count_responses_needed` — number of tickets awaiting a support response
15
+ - `count_my_responses` — same, scoped to the authenticated agent
16
+
17
+ ### Write
18
+
19
+ - `reply_to_ticket` — post a public reply (or staff-only with `private: true`)
20
+ - `add_ticket_note` — post an internal note visible only to staff
21
+ - `close_ticket` / `reopen_ticket` — change ticket status
22
+ - `mark_ticket_read` / `mark_ticket_unread` — toggle read state
23
+ - `star_ticket` / `unstar_ticket` — toggle star
24
+ - `create_customer` — create a new customer account
25
+
26
+ ## Setup
27
+
28
+ You need two environment variables:
29
+
30
+ - **`TICKSY_DOMAIN`** — your subdomain (e.g. `acme` for `acme.ticksy.com`)
31
+ - **`TICKSY_API_KEY`** — from your [Ticksy profile page](https://ticksy.com)
32
+
33
+ <details>
34
+ <summary>Claude Desktop</summary>
35
+
36
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "ticksy": {
42
+ "command": "npx",
43
+ "args": ["-y", "ticksy-mcp"],
44
+ "env": {
45
+ "TICKSY_DOMAIN": "your-domain",
46
+ "TICKSY_API_KEY": "your-api-key"
47
+ }
48
+ }
49
+ }
50
+ }
51
+ ```
52
+ </details>
53
+
54
+ <details>
55
+ <summary>Claude Code</summary>
56
+
57
+ ```bash
58
+ claude mcp add ticksy \
59
+ -e TICKSY_DOMAIN=your-domain \
60
+ -e TICKSY_API_KEY=your-api-key \
61
+ -- npx -y ticksy-mcp
62
+ ```
63
+ </details>
64
+
65
+ <details>
66
+ <summary>VS Code / Cursor</summary>
67
+
68
+ Add to `.vscode/mcp.json` (VS Code) or `.cursor/mcp.json` (Cursor) in your project:
69
+
70
+ ```json
71
+ {
72
+ "servers": {
73
+ "ticksy": {
74
+ "command": "npx",
75
+ "args": ["-y", "ticksy-mcp"],
76
+ "env": {
77
+ "TICKSY_DOMAIN": "your-domain",
78
+ "TICKSY_API_KEY": "your-api-key"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+ </details>
85
+
86
+ ## Build from source
87
+
88
+ ```bash
89
+ git clone https://github.com/artkrsk/ticksy-mcp.git
90
+ cd ticksy-mcp
91
+ pnpm install
92
+ pnpm build
93
+ ```
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { z } from 'zod';
5
+ import { listOpenTickets, listClosedTickets, getTicket, getTicketComments, listMyTickets, countResponsesNeeded, countMyResponsesNeeded, closeTicket, openTicket, markAsRead, markAsUnread, starTicket, unstarTicket, createCustomer, replyToTicket, addTicketNote, } from './ticksy.js';
6
+ // ── Validate env ───────────────────────────────────────────────
7
+ if (!process.env.TICKSY_DOMAIN || !process.env.TICKSY_API_KEY) {
8
+ console.error('Missing required env vars: TICKSY_DOMAIN, TICKSY_API_KEY');
9
+ process.exit(1);
10
+ }
11
+ // ── Server ─────────────────────────────────────────────────────
12
+ const server = new McpServer({ name: 'ticksy', version: '1.0.0' }, { capabilities: { logging: {} } });
13
+ // ── Helpers ────────────────────────────────────────────────────
14
+ async function run(fn, format = v => JSON.stringify(v, null, 2)) {
15
+ try {
16
+ const result = await fn();
17
+ return { content: [{ type: 'text', text: format(result) }] };
18
+ }
19
+ catch (err) {
20
+ return { isError: true, content: [{ type: 'text', text: String(err) }] };
21
+ }
22
+ }
23
+ const TICKET_ID_SCHEMA = {
24
+ ticket_id: z.string().describe('The Ticksy ticket ID'),
25
+ };
26
+ // ── Read tools ──────────────────────────────────────────────────
27
+ server.registerTool('list_open_tickets', {
28
+ description: 'List open support tickets, each with embedded comments.',
29
+ inputSchema: {
30
+ needs_response_only: z
31
+ .boolean()
32
+ .optional()
33
+ .default(false)
34
+ .describe('If true, return only tickets where the customer is waiting for a reply'),
35
+ },
36
+ }, async ({ needs_response_only }) => run(() => listOpenTickets(needs_response_only)));
37
+ server.registerTool('list_closed_tickets', { description: 'List the most recently closed support tickets.' }, async () => run(() => listClosedTickets()));
38
+ server.registerTool('get_ticket', {
39
+ description: 'Get a single ticket with its full comment thread.',
40
+ inputSchema: TICKET_ID_SCHEMA,
41
+ }, async ({ ticket_id }) => run(() => getTicket(ticket_id)));
42
+ server.registerTool('get_ticket_comments', {
43
+ description: 'Get comments for a ticket without full ticket data.',
44
+ inputSchema: TICKET_ID_SCHEMA,
45
+ }, async ({ ticket_id }) => run(() => getTicketComments(ticket_id)));
46
+ server.registerTool('list_my_tickets', { description: 'List open tickets assigned to the authenticated agent.' }, async () => run(() => listMyTickets()));
47
+ server.registerTool('count_responses_needed', { description: 'Count open tickets awaiting a support response.' }, async () => run(() => countResponsesNeeded(), String));
48
+ server.registerTool('count_my_responses', { description: 'Count tickets assigned to you that await a response.' }, async () => run(() => countMyResponsesNeeded(), String));
49
+ // ── Write tools ─────────────────────────────────────────────────
50
+ server.registerTool('reply_to_ticket', {
51
+ description: 'Post a public reply visible to the customer.',
52
+ annotations: { readOnlyHint: false },
53
+ inputSchema: {
54
+ ticket_id: z.string().describe('The Ticksy ticket ID'),
55
+ comment: z.string().describe('Reply body (HTML is accepted)'),
56
+ private: z.boolean().optional().default(false).describe('If true, the reply is visible only to staff'),
57
+ },
58
+ }, async ({ ticket_id, comment, private: isPrivate }) => run(() => replyToTicket(ticket_id, comment, isPrivate)));
59
+ server.registerTool('add_ticket_note', {
60
+ description: 'Post an internal note visible only to staff.',
61
+ annotations: { readOnlyHint: false },
62
+ inputSchema: {
63
+ ticket_id: z.string().describe('The Ticksy ticket ID'),
64
+ comment: z.string().describe('Note body (HTML is accepted)'),
65
+ },
66
+ }, async ({ ticket_id, comment }) => run(() => addTicketNote(ticket_id, comment)));
67
+ const SIMPLE_WRITE_TOOLS = [
68
+ ['close_ticket', 'Close an open ticket.', closeTicket],
69
+ ['reopen_ticket', 'Reopen a closed ticket.', openTicket],
70
+ ['mark_ticket_read', 'Mark a ticket as read.', markAsRead],
71
+ ['mark_ticket_unread', 'Mark a ticket as unread.', markAsUnread],
72
+ ['star_ticket', 'Star a ticket for follow-up.', starTicket],
73
+ ['unstar_ticket', 'Remove star from a ticket.', unstarTicket],
74
+ ];
75
+ for (const [name, description, fn] of SIMPLE_WRITE_TOOLS) {
76
+ server.registerTool(name, { description, annotations: { readOnlyHint: false }, inputSchema: TICKET_ID_SCHEMA }, async ({ ticket_id }) => run(() => fn(ticket_id)));
77
+ }
78
+ server.registerTool('create_customer', {
79
+ description: 'Create a new customer account.',
80
+ annotations: { readOnlyHint: false },
81
+ inputSchema: {
82
+ first_name: z.string().describe('Customer first name'),
83
+ email: z.string().describe('Customer email address'),
84
+ password: z.string().describe('Account password'),
85
+ },
86
+ }, async ({ first_name, email, password }) => run(() => createCustomer(first_name, email, password)));
87
+ // ── Start ──────────────────────────────────────────────────────
88
+ const transport = new StdioServerTransport();
89
+ await server.connect(transport);
90
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,WAAW,EACX,UAAU,EACV,UAAU,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,aAAa,GACd,MAAM,aAAa,CAAA;AAEpB,kEAAkE;AAElE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;IAC9D,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAA;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC;AAED,kEAAkE;AAElE,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EACpC,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAClC,CAAA;AAED,kEAAkE;AAElE,KAAK,UAAU,GAAG,CAAI,EAAoB,EAAE,SAA2B,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IACpG,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAA;QACzB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAA;IACvE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,OAAO,EAAE,IAAa,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAA;IAC5F,CAAC;AACH,CAAC;AAED,MAAM,gBAAgB,GAAG;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;CACvD,CAAA;AAED,mEAAmE;AAEnE,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;IACE,WAAW,EAAE,yDAAyD;IACtE,WAAW,EAAE;QACX,mBAAmB,EAAE,CAAC;aACnB,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CAAC,wEAAwE,CAAC;KACtF;CACF,EACD,KAAK,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CACnF,CAAA;AAED,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB,EAAE,WAAW,EAAE,gDAAgD,EAAE,EACjE,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAC3C,CAAA;AAED,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;IACE,WAAW,EAAE,mDAAmD;IAChE,WAAW,EAAE,gBAAgB;CAC9B,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CACzD,CAAA;AAED,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;IACE,WAAW,EAAE,qDAAqD;IAClE,WAAW,EAAE,gBAAgB;CAC9B,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CACjE,CAAA;AAED,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB,EAAE,WAAW,EAAE,wDAAwD,EAAE,EACzE,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,CACvC,CAAA;AAED,MAAM,CAAC,YAAY,CACjB,wBAAwB,EACxB,EAAE,WAAW,EAAE,iDAAiD,EAAE,EAClE,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,oBAAoB,EAAE,EAAE,MAAM,CAAC,CACtD,CAAA;AAED,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB,EAAE,WAAW,EAAE,sDAAsD,EAAE,EACvE,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,sBAAsB,EAAE,EAAE,MAAM,CAAC,CACxD,CAAA;AAED,mEAAmE;AAEnE,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;IACE,WAAW,EAAE,8CAA8C;IAC3D,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE;IACpC,WAAW,EAAE;QACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACtD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QAC7D,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,6CAA6C,CAAC;KACvG;CACF,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAC9G,CAAA;AAED,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;IACE,WAAW,EAAE,8CAA8C;IAC3D,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE;IACpC,WAAW,EAAE;QACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACtD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;KAC7D;CACF,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAC/E,CAAA;AAED,MAAM,kBAAkB,GAA8D;IACpF,CAAC,cAAc,EAAE,uBAAuB,EAAE,WAAW,CAAC;IACtD,CAAC,eAAe,EAAE,yBAAyB,EAAE,UAAU,CAAC;IACxD,CAAC,kBAAkB,EAAE,wBAAwB,EAAE,UAAU,CAAC;IAC1D,CAAC,oBAAoB,EAAE,0BAA0B,EAAE,YAAY,CAAC;IAChE,CAAC,aAAa,EAAE,8BAA8B,EAAE,UAAU,CAAC;IAC3D,CAAC,eAAe,EAAE,4BAA4B,EAAE,YAAY,CAAC;CAC9D,CAAA;AAED,KAAK,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC,IAAI,kBAAkB,EAAE,CAAC;IACzD,MAAM,CAAC,YAAY,CACjB,IAAI,EACJ,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,EACpF,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAClD,CAAA;AACH,CAAC;AAED,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;IACE,WAAW,EAAE,gCAAgC;IAC7C,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE;IACpC,WAAW,EAAE;QACX,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACtD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QACpD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;KAClD;CACF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAClG,CAAA;AAED,kEAAkE;AAElE,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAA;AAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA"}
@@ -0,0 +1,70 @@
1
+ export interface TicketComment {
2
+ comment_id: string;
3
+ ticket_id: string;
4
+ user_id: string;
5
+ commenter_name: string;
6
+ commenter_email: string;
7
+ user_type: 'user' | 'employee';
8
+ comment: string;
9
+ body?: string;
10
+ private: '0' | '1';
11
+ type: 'comment' | 'note';
12
+ time_stamp: string;
13
+ quoted_text: string | null;
14
+ attachments: Array<{
15
+ id: string;
16
+ file_url: string;
17
+ file_name: string;
18
+ }>;
19
+ post_date?: string;
20
+ user_avatar?: string;
21
+ user_likes?: string;
22
+ my_reply?: '0' | '1';
23
+ username?: string;
24
+ status_string?: string;
25
+ }
26
+ export interface Ticket {
27
+ ticket_title: string;
28
+ status: 'open' | 'closed';
29
+ time_stamp: string;
30
+ needs_response: '0' | '1';
31
+ starred: '0' | '1';
32
+ ticket_type: string;
33
+ user_id: string;
34
+ assigned_to: string;
35
+ assigned_to_email: string;
36
+ category_id: string;
37
+ related_url: string;
38
+ ticket_id?: string;
39
+ elapsed_time?: string;
40
+ user_name?: string;
41
+ user_email?: string;
42
+ user_avatar?: string;
43
+ assigned_to_name?: string;
44
+ response_time?: string;
45
+ envato_purchase_code?: string;
46
+ envato_verified_string?: string;
47
+ ticket_comments?: TicketComment[];
48
+ opened_by_me?: '0' | '1';
49
+ unsubscribed?: '0' | '1';
50
+ }
51
+ export declare function listOpenTickets(needsResponseOnly?: boolean): Promise<Ticket[]>;
52
+ export declare function listClosedTickets(): Promise<Ticket[]>;
53
+ export declare function getTicket(ticketId: string): Promise<{
54
+ data: Ticket;
55
+ comments: TicketComment[];
56
+ }>;
57
+ export declare function getTicketComments(ticketId: string): Promise<TicketComment[]>;
58
+ export declare function listMyTickets(): Promise<Ticket[]>;
59
+ export declare function countResponsesNeeded(): Promise<number>;
60
+ export declare function countMyResponsesNeeded(): Promise<number>;
61
+ export declare function closeTicket(ticketId: string): Promise<unknown>;
62
+ export declare function openTicket(ticketId: string): Promise<unknown>;
63
+ export declare function markAsRead(ticketId: string): Promise<unknown>;
64
+ export declare function markAsUnread(ticketId: string): Promise<unknown>;
65
+ export declare function starTicket(ticketId: string): Promise<unknown>;
66
+ export declare function unstarTicket(ticketId: string): Promise<unknown>;
67
+ export declare function createCustomer(firstName: string, email: string, password: string): Promise<unknown>;
68
+ export declare function replyToTicket(ticketId: string, comment: string, isPrivate?: boolean): Promise<unknown>;
69
+ export declare function addTicketNote(ticketId: string, comment: string): Promise<unknown>;
70
+ //# sourceMappingURL=ticksy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticksy.d.ts","sourceRoot":"","sources":["../src/ticksy.ts"],"names":[],"mappings":"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"}
package/dist/ticksy.js ADDED
@@ -0,0 +1,98 @@
1
+ import { html as htmlDecode } from './utils.js';
2
+ const BASE_URL = `https://api.ticksy.com/v1/${process.env.TICKSY_DOMAIN}/${process.env.TICKSY_API_KEY}`;
3
+ // ── Helpers ────────────────────────────────────────────────────
4
+ function decodeComment(comment) {
5
+ return { ...comment, body: htmlDecode(comment.comment) };
6
+ }
7
+ function decodeTicket(ticket) {
8
+ return {
9
+ ...ticket,
10
+ ticket_comments: (ticket.ticket_comments ?? []).map(decodeComment),
11
+ };
12
+ }
13
+ async function get(path) {
14
+ const res = await fetch(`${BASE_URL}/${path}`, { signal: AbortSignal.timeout(15_000) });
15
+ if (!res.ok) {
16
+ throw new Error(`Ticksy API ${path}: ${res.status} ${res.statusText}`);
17
+ }
18
+ return res.json();
19
+ }
20
+ async function post(action, params = {}) {
21
+ const body = new URLSearchParams({ action, ...params });
22
+ const res = await fetch(BASE_URL, {
23
+ method: 'POST',
24
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
25
+ body,
26
+ signal: AbortSignal.timeout(15_000),
27
+ });
28
+ if (!res.ok) {
29
+ throw new Error(`Ticksy API ${action}: ${res.status} ${res.statusText}`);
30
+ }
31
+ return res.json();
32
+ }
33
+ // ── API calls ──────────────────────────────────────────────────
34
+ export async function listOpenTickets(needsResponseOnly = false) {
35
+ const data = await get('open-tickets.json');
36
+ const tickets = (data['open-tickets'] ?? []).map(decodeTicket);
37
+ return needsResponseOnly ? tickets.filter(t => t.needs_response === '1') : tickets;
38
+ }
39
+ export async function listClosedTickets() {
40
+ const data = await get('closed-tickets.json');
41
+ return (data['closed-tickets'] ?? []).map(decodeTicket);
42
+ }
43
+ export async function getTicket(ticketId) {
44
+ const raw = await get(`ticket.json/${ticketId}`);
45
+ return {
46
+ data: decodeTicket(raw['ticket-data']),
47
+ comments: (raw['ticket-comments'] ?? []).map(decodeComment),
48
+ };
49
+ }
50
+ export async function getTicketComments(ticketId) {
51
+ const data = await get(`ticket-comments.json/${ticketId}`);
52
+ return (data.ticket_comments ?? []).map(decodeComment);
53
+ }
54
+ export async function listMyTickets() {
55
+ const data = await get('my-tickets.json');
56
+ return (data['my-tickets'] ?? []).map(decodeTicket);
57
+ }
58
+ export async function countResponsesNeeded() {
59
+ const data = await get('responses-needed.json');
60
+ return parseInt(data['responses-needed'] ?? '0', 10);
61
+ }
62
+ export async function countMyResponsesNeeded() {
63
+ const data = await get('my-responses-needed.json');
64
+ return parseInt(data['responses-needed'] ?? '0', 10);
65
+ }
66
+ // ── Write operations ────────────────────────────────────────────
67
+ export async function closeTicket(ticketId) {
68
+ return post('close_ticket', { ticket_id: ticketId });
69
+ }
70
+ export async function openTicket(ticketId) {
71
+ return post('open_ticket', { ticket_id: ticketId });
72
+ }
73
+ export async function markAsRead(ticketId) {
74
+ return post('mark_as_read', { ticket_id: ticketId });
75
+ }
76
+ export async function markAsUnread(ticketId) {
77
+ return post('mark_as_unread', { ticket_id: ticketId });
78
+ }
79
+ export async function starTicket(ticketId) {
80
+ return post('star_ticket', { ticket_id: ticketId });
81
+ }
82
+ export async function unstarTicket(ticketId) {
83
+ return post('unstar_ticket', { ticket_id: ticketId });
84
+ }
85
+ export async function createCustomer(firstName, email, password) {
86
+ return post('new_customer', { first_name: firstName, email_address: email, password });
87
+ }
88
+ export async function replyToTicket(ticketId, comment, isPrivate = false) {
89
+ const params = { ticket_id: ticketId, comment };
90
+ if (isPrivate) {
91
+ params.private = 'true';
92
+ }
93
+ return post('new_ticket_comment', params);
94
+ }
95
+ export async function addTicketNote(ticketId, comment) {
96
+ return post('new_ticket_note', { ticket_id: ticketId, comment });
97
+ }
98
+ //# sourceMappingURL=ticksy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticksy.js","sourceRoot":"","sources":["../src/ticksy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Decode HTML entities in a string.
3
+ * Ticksy returns comment bodies as HTML-encoded strings.
4
+ */
5
+ export declare function html(encoded: string): string;
6
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAc5C"}
package/dist/utils.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Decode HTML entities in a string.
3
+ * Ticksy returns comment bodies as HTML-encoded strings.
4
+ */
5
+ export function html(encoded) {
6
+ return encoded
7
+ .replace(/&lt;/g, '<')
8
+ .replace(/&gt;/g, '>')
9
+ .replace(/&amp;/g, '&')
10
+ .replace(/&quot;/g, '"')
11
+ .replace(/&#039;/g, "'")
12
+ .replace(/&nbsp;/g, ' ')
13
+ // Strip HTML tags — return plain text
14
+ .replace(/<br\s*\/?>/gi, '\n')
15
+ .replace(/<\/p>/gi, '\n')
16
+ .replace(/<[^>]+>/g, '')
17
+ .replace(/\n{3,}/g, '\n\n')
18
+ .trim();
19
+ }
20
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,OAAO;SACX,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;QACxB,sCAAsC;SACrC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC;SAC7B,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC;SACxB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,IAAI,EAAE,CAAA;AACX,CAAC"}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "ticksy-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Ticksy support ticket API",
5
+ "author": "Artem Semkin",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "bin": {
10
+ "ticksy-mcp": "dist/index.js"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "tsc --watch",
18
+ "start": "node dist/index.js"
19
+ },
20
+ "dependencies": {
21
+ "@modelcontextprotocol/sdk": "^1.27.1",
22
+ "zod": "^3.24.2"
23
+ },
24
+ "devDependencies": {
25
+ "typescript": "^5.9.3",
26
+ "@types/node": "^22.13.14"
27
+ }
28
+ }