@mgsoftwarebv/mcp-server-bridge 1.0.0 → 2.1.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 CHANGED
@@ -10,12 +10,33 @@ npm install -g @mgsoftwarebv/mcp-server-bridge
10
10
 
11
11
  ## 🔧 Cursor Configuratie
12
12
 
13
+ ### Voor MG Software SaaS Klanten (Aanbevolen)
14
+
13
15
  Voeg het volgende toe aan je `~/.cursor/mcp.json`:
14
16
 
15
17
  ```json
16
18
  {
17
19
  "mcpServers": {
18
- "mg-tickets-v2": {
20
+ "mg-tickets": {
21
+ "command": "npx",
22
+ "args": [
23
+ "-y",
24
+ "@mgsoftwarebv/mcp-server-bridge@latest",
25
+ "--api-key=mid_your_api_key_here"
26
+ ]
27
+ }
28
+ }
29
+ }
30
+ ```
31
+
32
+ **Dat is alles!** Geen database credentials, geen Supabase URL - alleen je API key.
33
+
34
+ ### Voor Eigen Database (Advanced)
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "mg-tickets-custom": {
19
40
  "command": "npx",
20
41
  "args": [
21
42
  "-y",
@@ -23,7 +44,8 @@ Voeg het volgende toe aan je `~/.cursor/mcp.json`:
23
44
  "--api-key=mid_your_api_key_here"
24
45
  ],
25
46
  "env": {
26
- "MG_TICKETS_BASE_URL": "https://cvjdbczxyczjnatuolsk.supabase.co/functions/v1/mcp-server"
47
+ "SUPABASE_URL": "https://your-project.supabase.co",
48
+ "SUPABASE_SERVICE_ROLE_KEY": "your_service_role_key"
27
49
  }
28
50
  }
29
51
  }
package/dist/index.js CHANGED
@@ -1,21 +1,45 @@
1
1
  #!/usr/bin/env node
2
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
- import { MGTicketsMCPClient } from '@mgsoftwarebv/mcp-client';
4
+ import { ListToolsRequestSchema, ListResourcesRequestSchema, CallToolRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
+ import { createClient } from '@supabase/supabase-js';
6
+ import { createHash } from 'crypto';
6
7
 
7
8
  var args = process.argv.slice(2);
8
9
  var apiKey = args.find((arg) => arg.startsWith("--api-key="))?.split("=")[1] || process.env.MG_TICKETS_API_KEY;
9
- var baseUrl = args.find((arg) => arg.startsWith("--base-url="))?.split("=")[1] || process.env.MG_TICKETS_BASE_URL || "https://cvjdbczxyczjnatuolsk.supabase.co/functions/v1/mcp-server";
10
+ var supabaseUrl = args.find((arg) => arg.startsWith("--supabase-url="))?.split("=")[1] || process.env.SUPABASE_URL || "https://cvjdbczxyczjnatuolsk.supabase.co";
11
+ var supabaseKey = args.find((arg) => arg.startsWith("--supabase-key="))?.split("=")[1] || process.env.SUPABASE_SERVICE_ROLE_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImN2amRiY3p4eWN6am5hdHVvbHNrIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc1NjE0NzcyNCwiZXhwIjoyMDcxNzIzNzI0fQ.LljuNdCZXDcSIVTeIVOSNsvGNBfWsIM1QIswBJmGXKE";
10
12
  if (!apiKey) {
11
13
  console.error("\u274C API key is required. Use --api-key=your_key or set MG_TICKETS_API_KEY environment variable");
12
14
  process.exit(1);
13
15
  }
14
- var client = new MGTicketsMCPClient({
15
- baseUrl,
16
- apiKey,
17
- timeout: 3e4
18
- });
16
+ var supabase = createClient(supabaseUrl, supabaseKey);
17
+ async function validateApiKey(key) {
18
+ if (!key.startsWith("mid_") || key.length !== 68) {
19
+ console.error("\u{1F511} Invalid API key format");
20
+ return null;
21
+ }
22
+ try {
23
+ const keyHash = createHash("sha256").update(key).digest("hex");
24
+ console.error(`\u{1F50D} Validating API key hash: ${keyHash.substring(0, 16)}...`);
25
+ const { data: apiKeyData, error } = await supabase.from("api_keys").select("id, user_id, team_id, scopes, last_used_at").eq("key_hash", keyHash).single();
26
+ if (error || !apiKeyData) {
27
+ console.error("\u274C API key not found or invalid:", error?.message);
28
+ return null;
29
+ }
30
+ await supabase.from("api_keys").update({ last_used_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", apiKeyData.id);
31
+ console.error(`\u2705 API key validated for user ${apiKeyData.user_id} in team ${apiKeyData.team_id}`);
32
+ return {
33
+ userId: apiKeyData.user_id,
34
+ teamId: apiKeyData.team_id,
35
+ scopes: apiKeyData.scopes || []
36
+ };
37
+ } catch (error) {
38
+ console.error("\u{1F4A5} API key validation error:", error);
39
+ return null;
40
+ }
41
+ }
42
+ var authContext = null;
19
43
  var server = new Server(
20
44
  {
21
45
  name: "mg-tickets-mcp-bridge",
@@ -28,124 +52,437 @@ var server = new Server(
28
52
  }
29
53
  }
30
54
  );
31
- server.setRequestHandler(ListToolsRequestSchema, async () => {
32
- try {
33
- const result = await client.listTools();
34
- if (!result.success || !result.data) {
35
- throw new Error(result.error || "Failed to list tools");
55
+ var TOOLS = [
56
+ {
57
+ name: "get-tickets",
58
+ description: "Get tickets with optional filtering by status, priority, project, customer, or search query",
59
+ inputSchema: {
60
+ type: "object",
61
+ properties: {
62
+ status: { type: "string", enum: ["open", "in_progress", "review", "resolved", "closed", "backlog"] },
63
+ priority: { type: "string", enum: ["low", "medium", "high", "critical"] },
64
+ projectId: { type: "string" },
65
+ customerId: { type: "string" },
66
+ q: { type: "string", description: "Search query for title or description" },
67
+ pageSize: { type: "number", default: 20, maximum: 100 }
68
+ },
69
+ required: []
36
70
  }
37
- return {
38
- tools: result.data.tools.map((tool) => ({
39
- name: tool.name,
40
- description: tool.description,
41
- inputSchema: tool.inputSchema
42
- }))
43
- };
44
- } catch (error) {
45
- console.error("Error listing tools:", error);
46
- return { tools: [] };
71
+ },
72
+ {
73
+ name: "get-ticket-by-id",
74
+ description: "Get a specific ticket by its ID",
75
+ inputSchema: {
76
+ type: "object",
77
+ properties: {
78
+ id: { type: "string", description: "Ticket ID" }
79
+ },
80
+ required: ["id"]
81
+ }
82
+ },
83
+ {
84
+ name: "create-ticket",
85
+ description: "Create a new ticket",
86
+ inputSchema: {
87
+ type: "object",
88
+ properties: {
89
+ title: { type: "string", description: "Ticket title" },
90
+ description: { type: "string" },
91
+ status: { type: "string", enum: ["open", "in_progress", "review", "resolved", "closed", "backlog"], default: "open" },
92
+ priority: { type: "string", enum: ["low", "medium", "high", "critical"], default: "medium" },
93
+ type: { type: "string", enum: ["task", "bug", "feature", "support", "question", "improvement"], default: "task" },
94
+ projectId: { type: "string" },
95
+ customerId: { type: "string" }
96
+ },
97
+ required: ["title"]
98
+ }
99
+ },
100
+ {
101
+ name: "get-customers",
102
+ description: "Get customers with optional search",
103
+ inputSchema: {
104
+ type: "object",
105
+ properties: {
106
+ q: { type: "string", description: "Search query for customer name or email" },
107
+ pageSize: { type: "number", default: 20, maximum: 100 }
108
+ },
109
+ required: []
110
+ }
111
+ },
112
+ {
113
+ name: "create-customer",
114
+ description: "Create a new customer",
115
+ inputSchema: {
116
+ type: "object",
117
+ properties: {
118
+ name: { type: "string", description: "Customer name" },
119
+ email: { type: "string" },
120
+ website: { type: "string" }
121
+ },
122
+ required: ["name"]
123
+ }
124
+ },
125
+ {
126
+ name: "get-projects",
127
+ description: "Get projects with optional filtering",
128
+ inputSchema: {
129
+ type: "object",
130
+ properties: {
131
+ customerId: { type: "string", description: "Filter by customer ID" },
132
+ q: { type: "string", description: "Search query for project name" },
133
+ pageSize: { type: "number", default: 20, maximum: 100 }
134
+ },
135
+ required: []
136
+ }
137
+ },
138
+ {
139
+ name: "create-project",
140
+ description: "Create a new project",
141
+ inputSchema: {
142
+ type: "object",
143
+ properties: {
144
+ name: { type: "string", description: "Project name" },
145
+ description: { type: "string" },
146
+ customerId: { type: "string" },
147
+ status: { type: "string", enum: ["active", "on_hold", "completed", "cancelled"], default: "active" }
148
+ },
149
+ required: ["name"]
150
+ }
151
+ }
152
+ ];
153
+ var RESOURCES = [
154
+ {
155
+ uri: "tickets://recent",
156
+ name: "Recent Tickets",
157
+ description: "Most recently created tickets",
158
+ mimeType: "application/json"
159
+ },
160
+ {
161
+ uri: "customers://all",
162
+ name: "All Customers",
163
+ description: "Complete customer directory",
164
+ mimeType: "application/json"
165
+ },
166
+ {
167
+ uri: "projects://active",
168
+ name: "Active Projects",
169
+ description: "Currently active projects",
170
+ mimeType: "application/json"
47
171
  }
172
+ ];
173
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
174
+ return { tools: TOOLS };
175
+ });
176
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
177
+ return { resources: RESOURCES };
48
178
  });
49
179
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
50
- try {
51
- const { name, arguments: args2 } = request.params;
52
- console.error(`\u{1F6E0}\uFE0F Executing tool: ${name}`);
53
- console.error(`\u{1F4DD} Arguments:`, JSON.stringify(args2, null, 2));
54
- const result = await client.executeTool(name, args2);
55
- if (!result.success) {
56
- throw new Error(result.error || "Tool execution failed");
57
- }
58
- console.error(`\u2705 Tool executed successfully`);
180
+ if (!authContext) {
59
181
  return {
60
- content: [
61
- {
62
- type: "text",
63
- text: JSON.stringify(result.data || result, null, 2)
64
- }
65
- ]
182
+ content: [{ type: "text", text: "Error: Not authenticated. API key validation failed." }]
66
183
  };
184
+ }
185
+ const { name, arguments: args2 } = request.params;
186
+ console.error(`\u{1F6E0}\uFE0F Executing tool: ${name} for team ${authContext.teamId}`);
187
+ try {
188
+ switch (name) {
189
+ case "get-tickets": {
190
+ const { status, priority, projectId, customerId, q, pageSize = 20 } = args2;
191
+ let query = supabase.from("tickets").select(`
192
+ id,
193
+ ticket_number,
194
+ title,
195
+ description,
196
+ status,
197
+ priority,
198
+ type,
199
+ created_at,
200
+ project_id,
201
+ customer_id,
202
+ projects:project_id(id, name),
203
+ customers:customer_id(id, name)
204
+ `).eq("team_id", authContext.teamId).limit(Math.min(pageSize, 100));
205
+ if (status) query = query.eq("status", status);
206
+ if (priority) query = query.eq("priority", priority);
207
+ if (projectId) query = query.eq("project_id", projectId);
208
+ if (customerId) query = query.eq("customer_id", customerId);
209
+ if (q) query = query.or(`title.ilike.%${q}%,description.ilike.%${q}%`);
210
+ const { data, error } = await query.order("created_at", { ascending: false });
211
+ if (error) throw error;
212
+ return {
213
+ content: [{
214
+ type: "text",
215
+ text: `Found ${data?.length || 0} tickets:
216
+
217
+ ${data?.map(
218
+ (ticket) => `**${ticket.ticket_number}**: ${ticket.title}
219
+ Status: ${ticket.status} | Priority: ${ticket.priority}
220
+ ${ticket.projects?.name ? `Project: ${ticket.projects.name}
221
+ ` : ""}${ticket.customers?.name ? `Customer: ${ticket.customers.name}
222
+ ` : ""}Created: ${new Date(ticket.created_at).toLocaleDateString()}
223
+ `
224
+ ).join("\n") || "No tickets found."}`
225
+ }]
226
+ };
227
+ }
228
+ case "get-ticket-by-id": {
229
+ const { id } = args2;
230
+ const { data, error } = await supabase.from("tickets").select(`
231
+ *,
232
+ projects:project_id(id, name),
233
+ customers:customer_id(id, name),
234
+ assignee:assignee_id(id, full_name, email),
235
+ requester:requester_id(id, full_name, email)
236
+ `).eq("id", id).eq("team_id", authContext.teamId).single();
237
+ if (error) throw error;
238
+ return {
239
+ content: [{
240
+ type: "text",
241
+ text: `**Ticket Details:**
242
+
243
+ **${data.ticket_number}**: ${data.title}
244
+ Status: ${data.status}
245
+ Priority: ${data.priority}
246
+ Type: ${data.type}
247
+ ${data.description ? `Description: ${data.description}
248
+ ` : ""}${data.projects?.name ? `Project: ${data.projects.name}
249
+ ` : ""}${data.customers?.name ? `Customer: ${data.customers.name}
250
+ ` : ""}${data.assignee?.full_name ? `Assignee: ${data.assignee.full_name}
251
+ ` : ""}Requester: ${data.requester?.full_name || "Unknown"}
252
+ Created: ${new Date(data.created_at).toLocaleDateString()}
253
+ `
254
+ }]
255
+ };
256
+ }
257
+ case "create-ticket": {
258
+ const { title, description, status = "open", priority = "medium", type = "task", projectId, customerId } = args2;
259
+ const year = (/* @__PURE__ */ new Date()).getFullYear();
260
+ const { count } = await supabase.from("tickets").select("*", { count: "exact", head: true }).eq("team_id", authContext.teamId);
261
+ const ticketNumber = `${year}-${String((count || 0) + 1).padStart(3, "0")}`;
262
+ const { data, error } = await supabase.from("tickets").insert({
263
+ team_id: authContext.teamId,
264
+ ticket_number: ticketNumber,
265
+ title,
266
+ description,
267
+ status,
268
+ priority,
269
+ type,
270
+ project_id: projectId || null,
271
+ customer_id: customerId || null,
272
+ requester_id: authContext.userId
273
+ }).select().single();
274
+ if (error) throw error;
275
+ return {
276
+ content: [{
277
+ type: "text",
278
+ text: `\u2705 **Ticket Created Successfully!**
279
+
280
+ Ticket Number: **${ticketNumber}**
281
+ Title: ${title}
282
+ Status: ${status}
283
+ Priority: ${priority}
284
+ Type: ${type}
285
+ `
286
+ }]
287
+ };
288
+ }
289
+ case "get-customers": {
290
+ const { q, pageSize = 20 } = args2;
291
+ let query = supabase.from("customers").select("id, name, email, website, created_at").eq("team_id", authContext.teamId).limit(Math.min(pageSize, 100));
292
+ if (q) query = query.or(`name.ilike.%${q}%,email.ilike.%${q}%`);
293
+ const { data, error } = await query.order("name");
294
+ if (error) throw error;
295
+ return {
296
+ content: [{
297
+ type: "text",
298
+ text: `Found ${data?.length || 0} customers:
299
+
300
+ ${data?.map(
301
+ (customer) => `**${customer.name}**
302
+ ${customer.email ? `Email: ${customer.email}
303
+ ` : ""}${customer.website ? `Website: ${customer.website}
304
+ ` : ""}Created: ${new Date(customer.created_at).toLocaleDateString()}
305
+ `
306
+ ).join("\n") || "No customers found."}`
307
+ }]
308
+ };
309
+ }
310
+ case "create-customer": {
311
+ const { name: name2, email, website } = args2;
312
+ const { data, error } = await supabase.from("customers").insert({
313
+ team_id: authContext.teamId,
314
+ name: name2,
315
+ email: email || null,
316
+ website: website || null,
317
+ user_id: authContext.userId
318
+ }).select().single();
319
+ if (error) throw error;
320
+ return {
321
+ content: [{
322
+ type: "text",
323
+ text: `\u2705 **Customer Created Successfully!**
324
+
325
+ Name: ${name2}
326
+ ${email ? `Email: ${email}
327
+ ` : ""}${website ? `Website: ${website}
328
+ ` : ""}`
329
+ }]
330
+ };
331
+ }
332
+ case "get-projects": {
333
+ const { customerId, q, pageSize = 20 } = args2;
334
+ let query = supabase.from("projects").select(`
335
+ id,
336
+ name,
337
+ description,
338
+ customer_id,
339
+ status,
340
+ created_at,
341
+ customers:customer_id(id, name)
342
+ `).eq("team_id", authContext.teamId).limit(Math.min(pageSize, 100));
343
+ if (customerId) query = query.eq("customer_id", customerId);
344
+ if (q) query = query.ilike("name", `%${q}%`);
345
+ const { data, error } = await query.order("name");
346
+ if (error) throw error;
347
+ return {
348
+ content: [{
349
+ type: "text",
350
+ text: `Found ${data?.length || 0} projects:
351
+
352
+ ${data?.map(
353
+ (project) => `**${project.name}**
354
+ Status: ${project.status}
355
+ ${project.description ? `Description: ${project.description}
356
+ ` : ""}${project.customers?.name ? `Customer: ${project.customers.name}
357
+ ` : ""}Created: ${new Date(project.created_at).toLocaleDateString()}
358
+ `
359
+ ).join("\n") || "No projects found."}`
360
+ }]
361
+ };
362
+ }
363
+ case "create-project": {
364
+ const { name: name2, description, customerId, status = "active" } = args2;
365
+ const { data, error } = await supabase.from("projects").insert({
366
+ team_id: authContext.teamId,
367
+ name: name2,
368
+ description: description || null,
369
+ customer_id: customerId || null,
370
+ status,
371
+ user_id: authContext.userId
372
+ }).select().single();
373
+ if (error) throw error;
374
+ return {
375
+ content: [{
376
+ type: "text",
377
+ text: `\u2705 **Project Created Successfully!**
378
+
379
+ Name: ${name2}
380
+ Status: ${status}
381
+ ${description ? `Description: ${description}
382
+ ` : ""}`
383
+ }]
384
+ };
385
+ }
386
+ default:
387
+ throw new Error(`Unknown tool: ${name}`);
388
+ }
67
389
  } catch (error) {
68
390
  console.error(`\u274C Tool execution error:`, error);
69
391
  return {
70
- content: [
71
- {
72
- type: "text",
73
- text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`
74
- }
75
- ]
392
+ content: [{
393
+ type: "text",
394
+ text: `Error executing ${name}: ${error instanceof Error ? error.message : "Unknown error"}`
395
+ }]
76
396
  };
77
397
  }
78
398
  });
79
- server.setRequestHandler(ListResourcesRequestSchema, async () => {
80
- try {
81
- const result = await client.listResources();
82
- if (!result.success || !result.data) {
83
- throw new Error(result.error || "Failed to list resources");
84
- }
399
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
400
+ if (!authContext) {
85
401
  return {
86
- resources: result.data.resources.map((resource) => ({
87
- uri: resource.uri,
88
- name: resource.name,
89
- description: resource.description,
90
- mimeType: resource.mimeType
91
- }))
402
+ contents: [{
403
+ uri: request.params.uri,
404
+ mimeType: "text/plain",
405
+ text: "Error: Not authenticated. API key validation failed."
406
+ }]
92
407
  };
93
- } catch (error) {
94
- console.error("Error listing resources:", error);
95
- return { resources: [] };
96
408
  }
97
- });
98
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
409
+ const { uri } = request.params;
410
+ console.error(`\u{1F4DA} Reading resource: ${uri}`);
99
411
  try {
100
- const { uri } = request.params;
101
- console.error(`\u{1F4DA} Reading resource: ${uri}`);
102
- const result = await client.getResource(uri);
103
- if (!result.success) {
104
- throw new Error(result.error || "Resource read failed");
412
+ switch (uri) {
413
+ case "tickets://recent": {
414
+ const { data, error } = await supabase.from("tickets").select(`
415
+ id,
416
+ ticket_number,
417
+ title,
418
+ status,
419
+ priority,
420
+ created_at
421
+ `).eq("team_id", authContext.teamId).order("created_at", { ascending: false }).limit(20);
422
+ if (error) throw error;
423
+ return {
424
+ contents: [{
425
+ uri,
426
+ mimeType: "application/json",
427
+ text: JSON.stringify(data, null, 2)
428
+ }]
429
+ };
430
+ }
431
+ case "customers://all": {
432
+ const { data, error } = await supabase.from("customers").select("id, name, email, website, created_at").eq("team_id", authContext.teamId).order("name").limit(50);
433
+ if (error) throw error;
434
+ return {
435
+ contents: [{
436
+ uri,
437
+ mimeType: "application/json",
438
+ text: JSON.stringify(data, null, 2)
439
+ }]
440
+ };
441
+ }
442
+ case "projects://active": {
443
+ const { data, error } = await supabase.from("projects").select(`
444
+ id,
445
+ name,
446
+ description,
447
+ status,
448
+ created_at,
449
+ customers:customer_id(id, name)
450
+ `).eq("team_id", authContext.teamId).eq("status", "active").order("name").limit(50);
451
+ if (error) throw error;
452
+ return {
453
+ contents: [{
454
+ uri,
455
+ mimeType: "application/json",
456
+ text: JSON.stringify(data, null, 2)
457
+ }]
458
+ };
459
+ }
460
+ default:
461
+ throw new Error(`Unknown resource: ${uri}`);
105
462
  }
106
- console.error(`\u2705 Resource read successfully`);
107
- return {
108
- contents: [
109
- {
110
- uri,
111
- mimeType: "application/json",
112
- text: JSON.stringify(result.data, null, 2)
113
- }
114
- ]
115
- };
116
463
  } catch (error) {
117
464
  console.error(`\u274C Resource read error:`, error);
118
465
  return {
119
- contents: [
120
- {
121
- uri: request.params.uri,
122
- mimeType: "text/plain",
123
- text: `Error: ${error instanceof Error ? error.message : "Unknown error"}`
124
- }
125
- ]
466
+ contents: [{
467
+ uri,
468
+ mimeType: "text/plain",
469
+ text: `Error reading ${uri}: ${error instanceof Error ? error.message : "Unknown error"}`
470
+ }]
126
471
  };
127
472
  }
128
473
  });
129
474
  async function main() {
130
475
  console.error("\u{1F680} Starting MG Tickets MCP Bridge Server...");
131
- console.error(`\u{1F517} Base URL: ${baseUrl}`);
132
476
  console.error(`\u{1F511} API Key: ${apiKey?.substring(0, 10)}...`);
133
- try {
134
- const serverInfo = await client.getServerInfo();
135
- if (serverInfo.success && serverInfo.data) {
136
- console.error(`\u2705 Connected to MCP server: ${serverInfo.data.name} v${serverInfo.data.version}`);
137
- if (serverInfo.data.authenticated) {
138
- console.error(`\u{1F464} Authenticated as user: ${serverInfo.data.user?.userId}`);
139
- console.error(`\u{1F3E2} Team: ${serverInfo.data.user?.teamId}`);
140
- }
141
- } else {
142
- console.error(`\u26A0\uFE0F Server connection warning: ${serverInfo.error}`);
143
- }
144
- } catch (error) {
145
- console.error(`\u274C Failed to connect to HTTP server: ${error}`);
477
+ authContext = await validateApiKey(apiKey);
478
+ if (!authContext) {
479
+ console.error("\u274C API key validation failed. Please check your key and try again.");
480
+ process.exit(1);
146
481
  }
147
- const transport = new StdioServerTransport();
482
+ console.error(`\u2705 Authenticated as user ${authContext.userId} in team ${authContext.teamId}`);
483
+ console.error(`\u{1F4CB} Available scopes: ${authContext.scopes.join(", ")}`);
148
484
  console.error("\u{1F4E1} MCP Bridge Server ready for connections");
485
+ const transport = new StdioServerTransport();
149
486
  await server.connect(transport);
150
487
  }
151
488
  process.on("SIGINT", async () => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["args"],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';\r\nimport { MGTicketsMCPClient } from '@mgsoftwarebv/mcp-client';\r\n\r\n// Parse command line arguments\r\nconst args = process.argv.slice(2);\r\nconst apiKey = args.find(arg => arg.startsWith('--api-key='))?.split('=')[1] || process.env.MG_TICKETS_API_KEY;\r\nconst baseUrl = args.find(arg => arg.startsWith('--base-url='))?.split('=')[1] || process.env.MG_TICKETS_BASE_URL || 'https://cvjdbczxyczjnatuolsk.supabase.co/functions/v1/mcp-server';\r\n\r\nif (!apiKey) {\r\n console.error('❌ API key is required. Use --api-key=your_key or set MG_TICKETS_API_KEY environment variable');\r\n process.exit(1);\r\n}\r\n\r\n// Initialize the MG Tickets client\r\nconst client = new MGTicketsMCPClient({\r\n baseUrl,\r\n apiKey,\r\n timeout: 30000,\r\n});\r\n\r\n// Create MCP server\r\nconst server = new Server(\r\n {\r\n name: 'mg-tickets-mcp-bridge',\r\n version: '1.0.0',\r\n },\r\n {\r\n capabilities: {\r\n tools: {},\r\n resources: {},\r\n },\r\n }\r\n);\r\n\r\n// List tools handler - proxy to HTTP server\r\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\r\n try {\r\n const result = await client.listTools();\r\n if (!result.success || !result.data) {\r\n throw new Error(result.error || 'Failed to list tools');\r\n }\r\n \r\n return {\r\n tools: result.data.tools.map(tool => ({\r\n name: tool.name,\r\n description: tool.description,\r\n inputSchema: tool.inputSchema,\r\n })),\r\n };\r\n } catch (error) {\r\n console.error('Error listing tools:', error);\r\n return { tools: [] };\r\n }\r\n});\r\n\r\n// Call tool handler - proxy to HTTP server\r\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\r\n try {\r\n const { name, arguments: args } = request.params;\r\n \r\n console.error(`🛠️ Executing tool: ${name}`);\r\n console.error(`📝 Arguments:`, JSON.stringify(args, null, 2));\r\n \r\n const result = await client.executeTool(name, args);\r\n \r\n if (!result.success) {\r\n throw new Error(result.error || 'Tool execution failed');\r\n }\r\n \r\n console.error(`✅ Tool executed successfully`);\r\n \r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: JSON.stringify(result.data || result, null, 2),\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n console.error(`❌ Tool execution error:`, error);\r\n return {\r\n content: [\r\n {\r\n type: 'text',\r\n text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,\r\n },\r\n ],\r\n };\r\n }\r\n});\r\n\r\n// List resources handler - proxy to HTTP server\r\nserver.setRequestHandler(ListResourcesRequestSchema, async () => {\r\n try {\r\n const result = await client.listResources();\r\n if (!result.success || !result.data) {\r\n throw new Error(result.error || 'Failed to list resources');\r\n }\r\n \r\n return {\r\n resources: result.data.resources.map(resource => ({\r\n uri: resource.uri,\r\n name: resource.name,\r\n description: resource.description,\r\n mimeType: resource.mimeType,\r\n })),\r\n };\r\n } catch (error) {\r\n console.error('Error listing resources:', error);\r\n return { resources: [] };\r\n }\r\n});\r\n\r\n// Read resource handler - proxy to HTTP server\r\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\r\n try {\r\n const { uri } = request.params;\r\n \r\n console.error(`📚 Reading resource: ${uri}`);\r\n \r\n const result = await client.getResource(uri);\r\n \r\n if (!result.success) {\r\n throw new Error(result.error || 'Resource read failed');\r\n }\r\n \r\n console.error(`✅ Resource read successfully`);\r\n \r\n return {\r\n contents: [\r\n {\r\n uri,\r\n mimeType: 'application/json',\r\n text: JSON.stringify(result.data, null, 2),\r\n },\r\n ],\r\n };\r\n } catch (error) {\r\n console.error(`❌ Resource read error:`, error);\r\n return {\r\n contents: [\r\n {\r\n uri: request.params.uri,\r\n mimeType: 'text/plain',\r\n text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,\r\n },\r\n ],\r\n };\r\n }\r\n});\r\n\r\n// Start the server\r\nasync function main() {\r\n console.error('🚀 Starting MG Tickets MCP Bridge Server...');\r\n console.error(`🔗 Base URL: ${baseUrl}`);\r\n console.error(`🔑 API Key: ${apiKey?.substring(0, 10)}...`);\r\n \r\n // Test connection to HTTP server\r\n try {\r\n const serverInfo = await client.getServerInfo();\r\n if (serverInfo.success && serverInfo.data) {\r\n console.error(`✅ Connected to MCP server: ${serverInfo.data.name} v${serverInfo.data.version}`);\r\n if ((serverInfo.data as any).authenticated) {\r\n console.error(`👤 Authenticated as user: ${(serverInfo.data as any).user?.userId}`);\r\n console.error(`🏢 Team: ${(serverInfo.data as any).user?.teamId}`);\r\n }\r\n } else {\r\n console.error(`⚠️ Server connection warning: ${serverInfo.error}`);\r\n }\r\n } catch (error) {\r\n console.error(`❌ Failed to connect to HTTP server: ${error}`);\r\n }\r\n \r\n const transport = new StdioServerTransport();\r\n console.error('📡 MCP Bridge Server ready for connections');\r\n \r\n await server.connect(transport);\r\n}\r\n\r\n// Handle graceful shutdown\r\nprocess.on('SIGINT', async () => {\r\n console.error('👋 Shutting down MCP Bridge Server...');\r\n process.exit(0);\r\n});\r\n\r\nprocess.on('SIGTERM', async () => {\r\n console.error('👋 Shutting down MCP Bridge Server...');\r\n process.exit(0);\r\n});\r\n\r\n// Start the server\r\nmain().catch((error) => {\r\n console.error('💥 Fatal error:', error);\r\n process.exit(1);\r\n});\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["args","name"],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { createClient } from '@supabase/supabase-js';\nimport { createHash } from 'crypto';\n\n// Parse command line arguments and environment\nconst args = process.argv.slice(2);\nconst apiKey = args.find(arg => arg.startsWith('--api-key='))?.split('=')[1] || process.env.MG_TICKETS_API_KEY;\n// Default to MG Software's Supabase for SaaS customers\nconst supabaseUrl = args.find(arg => arg.startsWith('--supabase-url='))?.split('=')[1] || \n process.env.SUPABASE_URL || \n 'https://cvjdbczxyczjnatuolsk.supabase.co';\n\nconst supabaseKey = args.find(arg => arg.startsWith('--supabase-key='))?.split('=')[1] || \n process.env.SUPABASE_SERVICE_ROLE_KEY || \n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImN2amRiY3p4eWN6am5hdHVvbHNrIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc1NjE0NzcyNCwiZXhwIjoyMDcxNzIzNzI0fQ.LljuNdCZXDcSIVTeIVOSNsvGNBfWsIM1QIswBJmGXKE';\n\nif (!apiKey) {\n console.error('❌ API key is required. Use --api-key=your_key or set MG_TICKETS_API_KEY environment variable');\n process.exit(1);\n}\n\n// Supabase credentials validation (optional with defaults)\nif (!supabaseUrl || !supabaseKey) {\n console.error('❌ Supabase credentials missing. Using defaults for MG Software SaaS.');\n}\n\n// Initialize Supabase client with service role\nconst supabase = createClient(supabaseUrl, supabaseKey);\n\ninterface AuthContext {\n userId: string;\n teamId: string;\n scopes: string[];\n}\n\n// API Key validation - direct database access\nasync function validateApiKey(key: string): Promise<AuthContext | null> {\n if (!key.startsWith('mid_') || key.length !== 68) {\n console.error('🔑 Invalid API key format');\n return null;\n }\n\n try {\n // Hash the API key\n const keyHash = createHash('sha256').update(key).digest('hex');\n console.error(`🔍 Validating API key hash: ${keyHash.substring(0, 16)}...`);\n \n // Query database for API key\n const { data: apiKeyData, error } = await supabase\n .from('api_keys')\n .select('id, user_id, team_id, scopes, last_used_at')\n .eq('key_hash', keyHash)\n .single();\n\n if (error || !apiKeyData) {\n console.error('❌ API key not found or invalid:', error?.message);\n return null;\n }\n\n // Update last used timestamp\n await supabase\n .from('api_keys')\n .update({ last_used_at: new Date().toISOString() })\n .eq('id', apiKeyData.id);\n\n console.error(`✅ API key validated for user ${apiKeyData.user_id} in team ${apiKeyData.team_id}`);\n \n return {\n userId: apiKeyData.user_id,\n teamId: apiKeyData.team_id,\n scopes: apiKeyData.scopes || []\n };\n } catch (error) {\n console.error('💥 API key validation error:', error);\n return null;\n }\n}\n\n// Validate auth context once at startup\nlet authContext: AuthContext | null = null;\n\n// MCP Server setup\nconst server = new Server(\n {\n name: 'mg-tickets-mcp-bridge',\n version: '1.0.0',\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n },\n }\n);\n\n// Available tools definition\nconst TOOLS = [\n {\n name: 'get-tickets',\n description: 'Get tickets with optional filtering by status, priority, project, customer, or search query',\n inputSchema: {\n type: 'object',\n properties: {\n status: { type: 'string', enum: ['open', 'in_progress', 'review', 'resolved', 'closed', 'backlog'] },\n priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] },\n projectId: { type: 'string' },\n customerId: { type: 'string' },\n q: { type: 'string', description: 'Search query for title or description' },\n pageSize: { type: 'number', default: 20, maximum: 100 }\n },\n required: []\n }\n },\n {\n name: 'get-ticket-by-id',\n description: 'Get a specific ticket by its ID',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Ticket ID' }\n },\n required: ['id']\n }\n },\n {\n name: 'create-ticket',\n description: 'Create a new ticket',\n inputSchema: {\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Ticket title' },\n description: { type: 'string' },\n status: { type: 'string', enum: ['open', 'in_progress', 'review', 'resolved', 'closed', 'backlog'], default: 'open' },\n priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], default: 'medium' },\n type: { type: 'string', enum: ['task', 'bug', 'feature', 'support', 'question', 'improvement'], default: 'task' },\n projectId: { type: 'string' },\n customerId: { type: 'string' }\n },\n required: ['title']\n }\n },\n {\n name: 'get-customers',\n description: 'Get customers with optional search',\n inputSchema: {\n type: 'object',\n properties: {\n q: { type: 'string', description: 'Search query for customer name or email' },\n pageSize: { type: 'number', default: 20, maximum: 100 }\n },\n required: []\n }\n },\n {\n name: 'create-customer',\n description: 'Create a new customer',\n inputSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Customer name' },\n email: { type: 'string' },\n website: { type: 'string' }\n },\n required: ['name']\n }\n },\n {\n name: 'get-projects',\n description: 'Get projects with optional filtering',\n inputSchema: {\n type: 'object',\n properties: {\n customerId: { type: 'string', description: 'Filter by customer ID' },\n q: { type: 'string', description: 'Search query for project name' },\n pageSize: { type: 'number', default: 20, maximum: 100 }\n },\n required: []\n }\n },\n {\n name: 'create-project',\n description: 'Create a new project',\n inputSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Project name' },\n description: { type: 'string' },\n customerId: { type: 'string' },\n status: { type: 'string', enum: ['active', 'on_hold', 'completed', 'cancelled'], default: 'active' }\n },\n required: ['name']\n }\n }\n];\n\n// Available resources\nconst RESOURCES = [\n {\n uri: 'tickets://recent',\n name: 'Recent Tickets',\n description: 'Most recently created tickets',\n mimeType: 'application/json'\n },\n {\n uri: 'customers://all',\n name: 'All Customers', \n description: 'Complete customer directory',\n mimeType: 'application/json'\n },\n {\n uri: 'projects://active',\n name: 'Active Projects',\n description: 'Currently active projects',\n mimeType: 'application/json'\n }\n];\n\n// List tools handler\nserver.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools: TOOLS };\n});\n\n// List resources handler\nserver.setRequestHandler(ListResourcesRequestSchema, async () => {\n return { resources: RESOURCES };\n});\n\n// Tool execution handler\nserver.setRequestHandler(CallToolRequestSchema, async (request) => {\n if (!authContext) {\n return {\n content: [{ type: 'text', text: 'Error: Not authenticated. API key validation failed.' }],\n };\n }\n\n const { name, arguments: args } = request.params;\n console.error(`🛠️ Executing tool: ${name} for team ${authContext.teamId}`);\n \n try {\n switch (name) {\n case 'get-tickets': {\n const { status, priority, projectId, customerId, q, pageSize = 20 } = args as any;\n \n let query = supabase\n .from('tickets')\n .select(`\n id,\n ticket_number,\n title,\n description,\n status,\n priority,\n type,\n created_at,\n project_id,\n customer_id,\n projects:project_id(id, name),\n customers:customer_id(id, name)\n `)\n .eq('team_id', authContext.teamId)\n .limit(Math.min(pageSize, 100));\n \n if (status) query = query.eq('status', status);\n if (priority) query = query.eq('priority', priority);\n if (projectId) query = query.eq('project_id', projectId);\n if (customerId) query = query.eq('customer_id', customerId);\n if (q) query = query.or(`title.ilike.%${q}%,description.ilike.%${q}%`);\n \n const { data, error } = await query.order('created_at', { ascending: false });\n \n if (error) throw error;\n \n return {\n content: [{\n type: 'text',\n text: `Found ${data?.length || 0} tickets:\\n\\n${data?.map(ticket => \n `**${ticket.ticket_number}**: ${ticket.title}\\n` +\n `Status: ${ticket.status} | Priority: ${ticket.priority}\\n` +\n `${(ticket.projects as any)?.name ? `Project: ${(ticket.projects as any).name}\\n` : ''}` +\n `${(ticket.customers as any)?.name ? `Customer: ${(ticket.customers as any).name}\\n` : ''}` +\n `Created: ${new Date(ticket.created_at).toLocaleDateString()}\\n`\n ).join('\\n') || 'No tickets found.'}`\n }]\n };\n }\n \n case 'get-ticket-by-id': {\n const { id } = args as any;\n \n const { data, error } = await supabase\n .from('tickets')\n .select(`\n *,\n projects:project_id(id, name),\n customers:customer_id(id, name),\n assignee:assignee_id(id, full_name, email),\n requester:requester_id(id, full_name, email)\n `)\n .eq('id', id)\n .eq('team_id', authContext.teamId)\n .single();\n \n if (error) throw error;\n \n return {\n content: [{\n type: 'text',\n text: `**Ticket Details:**\\n\\n` +\n `**${data.ticket_number}**: ${data.title}\\n` +\n `Status: ${data.status}\\n` +\n `Priority: ${data.priority}\\n` +\n `Type: ${data.type}\\n` +\n `${data.description ? `Description: ${data.description}\\n` : ''}` +\n `${(data.projects as any)?.name ? `Project: ${(data.projects as any).name}\\n` : ''}` +\n `${(data.customers as any)?.name ? `Customer: ${(data.customers as any).name}\\n` : ''}` +\n `${data.assignee?.full_name ? `Assignee: ${data.assignee.full_name}\\n` : ''}` +\n `Requester: ${data.requester?.full_name || 'Unknown'}\\n` +\n `Created: ${new Date(data.created_at).toLocaleDateString()}\\n`\n }]\n };\n }\n \n case 'create-ticket': {\n const { title, description, status = 'open', priority = 'medium', type = 'task', projectId, customerId } = args as any;\n \n // Generate ticket number\n const year = new Date().getFullYear();\n const { count } = await supabase\n .from('tickets')\n .select('*', { count: 'exact', head: true })\n .eq('team_id', authContext.teamId);\n \n const ticketNumber = `${year}-${String((count || 0) + 1).padStart(3, '0')}`;\n \n const { data, error } = await supabase\n .from('tickets')\n .insert({\n team_id: authContext.teamId,\n ticket_number: ticketNumber,\n title,\n description,\n status,\n priority,\n type,\n project_id: projectId || null,\n customer_id: customerId || null,\n requester_id: authContext.userId\n })\n .select()\n .single();\n \n if (error) throw error;\n \n return {\n content: [{\n type: 'text',\n text: `✅ **Ticket Created Successfully!**\\n\\n` +\n `Ticket Number: **${ticketNumber}**\\n` +\n `Title: ${title}\\n` +\n `Status: ${status}\\n` +\n `Priority: ${priority}\\n` +\n `Type: ${type}\\n`\n }]\n };\n }\n \n case 'get-customers': {\n const { q, pageSize = 20 } = args as any;\n \n let query = supabase\n .from('customers')\n .select('id, name, email, website, created_at')\n .eq('team_id', authContext.teamId)\n .limit(Math.min(pageSize, 100));\n \n if (q) query = query.or(`name.ilike.%${q}%,email.ilike.%${q}%`);\n \n const { data, error } = await query.order('name');\n \n if (error) throw error;\n \n return {\n content: [{\n type: 'text',\n text: `Found ${data?.length || 0} customers:\\n\\n${data?.map(customer => \n `**${customer.name}**\\n` +\n `${customer.email ? `Email: ${customer.email}\\n` : ''}` +\n `${customer.website ? `Website: ${customer.website}\\n` : ''}` +\n `Created: ${new Date(customer.created_at).toLocaleDateString()}\\n`\n ).join('\\n') || 'No customers found.'}`\n }]\n };\n }\n \n case 'create-customer': {\n const { name, email, website } = args as any;\n \n const { data, error } = await supabase\n .from('customers')\n .insert({\n team_id: authContext.teamId,\n name,\n email: email || null,\n website: website || null,\n user_id: authContext.userId\n })\n .select()\n .single();\n \n if (error) throw error;\n \n return {\n content: [{\n type: 'text',\n text: `✅ **Customer Created Successfully!**\\n\\n` +\n `Name: ${name}\\n` +\n `${email ? `Email: ${email}\\n` : ''}` +\n `${website ? `Website: ${website}\\n` : ''}`\n }]\n };\n }\n \n case 'get-projects': {\n const { customerId, q, pageSize = 20 } = args as any;\n \n let query = supabase\n .from('projects')\n .select(`\n id,\n name,\n description,\n customer_id,\n status,\n created_at,\n customers:customer_id(id, name)\n `)\n .eq('team_id', authContext.teamId)\n .limit(Math.min(pageSize, 100));\n \n if (customerId) query = query.eq('customer_id', customerId);\n if (q) query = query.ilike('name', `%${q}%`);\n \n const { data, error } = await query.order('name');\n \n if (error) throw error;\n \n return {\n content: [{\n type: 'text',\n text: `Found ${data?.length || 0} projects:\\n\\n${data?.map(project => \n `**${project.name}**\\n` +\n `Status: ${project.status}\\n` +\n `${project.description ? `Description: ${project.description}\\n` : ''}` +\n `${(project.customers as any)?.name ? `Customer: ${(project.customers as any).name}\\n` : ''}` +\n `Created: ${new Date(project.created_at).toLocaleDateString()}\\n`\n ).join('\\n') || 'No projects found.'}`\n }]\n };\n }\n \n case 'create-project': {\n const { name, description, customerId, status = 'active' } = args as any;\n \n const { data, error } = await supabase\n .from('projects')\n .insert({\n team_id: authContext.teamId,\n name,\n description: description || null,\n customer_id: customerId || null,\n status,\n user_id: authContext.userId\n })\n .select()\n .single();\n \n if (error) throw error;\n \n return {\n content: [{\n type: 'text',\n text: `✅ **Project Created Successfully!**\\n\\n` +\n `Name: ${name}\\n` +\n `Status: ${status}\\n` +\n `${description ? `Description: ${description}\\n` : ''}`\n }]\n };\n }\n \n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n \n } catch (error) {\n console.error(`❌ Tool execution error:`, error);\n return {\n content: [{\n type: 'text',\n text: `Error executing ${name}: ${error instanceof Error ? error.message : 'Unknown error'}`\n }]\n };\n }\n});\n\n// Resource read handler\nserver.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n if (!authContext) {\n return {\n contents: [{\n uri: request.params.uri,\n mimeType: 'text/plain',\n text: 'Error: Not authenticated. API key validation failed.'\n }]\n };\n }\n\n const { uri } = request.params;\n console.error(`📚 Reading resource: ${uri}`);\n \n try {\n switch (uri) {\n case 'tickets://recent': {\n const { data, error } = await supabase\n .from('tickets')\n .select(`\n id,\n ticket_number,\n title,\n status,\n priority,\n created_at\n `)\n .eq('team_id', authContext.teamId)\n .order('created_at', { ascending: false })\n .limit(20);\n \n if (error) throw error;\n \n return {\n contents: [{\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2)\n }]\n };\n }\n \n case 'customers://all': {\n const { data, error } = await supabase\n .from('customers')\n .select('id, name, email, website, created_at')\n .eq('team_id', authContext.teamId)\n .order('name')\n .limit(50);\n \n if (error) throw error;\n \n return {\n contents: [{\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2)\n }]\n };\n }\n \n case 'projects://active': {\n const { data, error } = await supabase\n .from('projects')\n .select(`\n id,\n name,\n description,\n status,\n created_at,\n customers:customer_id(id, name)\n `)\n .eq('team_id', authContext.teamId)\n .eq('status', 'active')\n .order('name')\n .limit(50);\n \n if (error) throw error;\n \n return {\n contents: [{\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(data, null, 2)\n }]\n };\n }\n \n default:\n throw new Error(`Unknown resource: ${uri}`);\n }\n \n } catch (error) {\n console.error(`❌ Resource read error:`, error);\n return {\n contents: [{\n uri,\n mimeType: 'text/plain',\n text: `Error reading ${uri}: ${error instanceof Error ? error.message : 'Unknown error'}`\n }]\n };\n }\n});\n\n// Main function\nasync function main() {\n console.error('🚀 Starting MG Tickets MCP Bridge Server...');\n console.error(`🔑 API Key: ${apiKey?.substring(0, 10)}...`);\n \n // Validate API key\n authContext = await validateApiKey(apiKey!);\n if (!authContext) {\n console.error('❌ API key validation failed. Please check your key and try again.');\n process.exit(1);\n }\n \n console.error(`✅ Authenticated as user ${authContext.userId} in team ${authContext.teamId}`);\n console.error(`📋 Available scopes: ${authContext.scopes.join(', ')}`);\n console.error('📡 MCP Bridge Server ready for connections');\n \n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\n// Handle graceful shutdown\nprocess.on('SIGINT', async () => {\n console.error('👋 Shutting down MCP Bridge Server...');\n process.exit(0);\n});\n\nprocess.on('SIGTERM', async () => {\n console.error('👋 Shutting down MCP Bridge Server...');\n process.exit(0);\n});\n\n// Start the server\nmain().catch((error) => {\n console.error('💥 Fatal error:', error);\n process.exit(1);\n});"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mgsoftwarebv/mcp-server-bridge",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "MCP Server bridge for MG Tickets - connects Cursor to HTTP MCP server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -23,8 +23,9 @@
23
23
  "author": "MG Software B.V.",
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
- "@mgsoftwarebv/mcp-client": "^1.0.0",
27
- "@modelcontextprotocol/sdk": "^1.0.4"
26
+ "@modelcontextprotocol/sdk": "^1.0.4",
27
+ "@supabase/supabase-js": "^2.50.0",
28
+ "crypto": "^1.0.1"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@types/node": "^20.0.0",