overture-mcp 0.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/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ startHttpServer,
4
+ wsManager
5
+ } from "./chunk-LFRCKLZZ.js";
6
+
7
+ // src/cli.ts
8
+ import chalk from "chalk";
9
+ import open from "open";
10
+ var HTTP_PORT = parseInt(process.env.OVERTURE_HTTP_PORT || "3031", 10);
11
+ var WS_PORT = parseInt(process.env.OVERTURE_WS_PORT || "3030", 10);
12
+ function printBanner() {
13
+ console.log(
14
+ chalk.cyan(`
15
+ ____ __
16
+ / __ \\__ _____ _____/ /___ __________
17
+ / / / / / / / _ \\/ ___/ __/ / / / ___/ _ \\
18
+ / /_/ / /_/ / __/ / / /_/ /_/ / / / __/
19
+ \\____/\\__,_/\\___/_/ \\__/\\__,_/_/ \\___/
20
+
21
+ `)
22
+ );
23
+ console.log(chalk.gray("Agent Plan Visualizer by Sixth"));
24
+ console.log(chalk.gray("\u2500".repeat(45)));
25
+ console.log();
26
+ }
27
+ async function main() {
28
+ printBanner();
29
+ console.log(chalk.blue("Starting servers..."));
30
+ startHttpServer(HTTP_PORT);
31
+ wsManager.start(WS_PORT);
32
+ console.log();
33
+ console.log(chalk.green("\u2713"), "Overture is running!");
34
+ console.log();
35
+ console.log(chalk.gray(" UI: "), chalk.cyan(`http://localhost:${HTTP_PORT}`));
36
+ console.log(chalk.gray(" WebSocket: "), chalk.cyan(`ws://localhost:${WS_PORT}`));
37
+ console.log();
38
+ console.log(chalk.gray("Press Ctrl+C to stop"));
39
+ setTimeout(() => {
40
+ open(`http://localhost:${HTTP_PORT}`);
41
+ }, 500);
42
+ process.on("SIGINT", () => {
43
+ console.log();
44
+ console.log(chalk.yellow("Shutting down..."));
45
+ wsManager.stop();
46
+ process.exit(0);
47
+ });
48
+ process.on("SIGTERM", () => {
49
+ wsManager.stop();
50
+ process.exit(0);
51
+ });
52
+ }
53
+ main().catch((error) => {
54
+ console.error(chalk.red("Fatal error:"), error);
55
+ process.exit(1);
56
+ });
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,608 @@
1
+ import {
2
+ handleCheckPause,
3
+ handleCheckRerun,
4
+ handleCreateNewPlan,
5
+ handleGetApproval,
6
+ handleGetResumeInfo,
7
+ handleGetUsageInstructions,
8
+ handlePlanCompleted,
9
+ handlePlanFailed,
10
+ handleRequestPlanUpdate,
11
+ handleStreamPlanChunk,
12
+ handleSubmitPlan,
13
+ handleUpdateNodeStatus,
14
+ historyStorage,
15
+ startHttpServer,
16
+ wsManager
17
+ } from "./chunk-LFRCKLZZ.js";
18
+
19
+ // src/index.ts
20
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
21
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
22
+ import {
23
+ CallToolRequestSchema,
24
+ ListToolsRequestSchema
25
+ } from "@modelcontextprotocol/sdk/types.js";
26
+ import { z } from "zod";
27
+ import open from "open";
28
+ var HTTP_PORT = parseInt(process.env.OVERTURE_HTTP_PORT || "3031", 10);
29
+ var WS_PORT = parseInt(process.env.OVERTURE_WS_PORT || "3030", 10);
30
+ var AUTO_OPEN_BROWSER = process.env.OVERTURE_AUTO_OPEN !== "false";
31
+ var StreamPlanChunkSchema = z.object({
32
+ xml_chunk: z.string().describe("A chunk of the plan XML to process"),
33
+ workspace_path: z.string().optional().describe("Absolute path to the workspace/project directory"),
34
+ agent_type: z.string().optional().describe("The type of agent (claude-code, cline, cursor, sixth)")
35
+ });
36
+ var SubmitPlanSchema = z.object({
37
+ plan_xml: z.string().describe("The complete plan XML"),
38
+ workspace_path: z.string().optional().describe("Absolute path to the workspace/project directory"),
39
+ agent_type: z.string().optional().describe("The type of agent (claude-code, cline, cursor, sixth)")
40
+ });
41
+ var GetApprovalSchema = z.object({
42
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
43
+ });
44
+ var UpdateNodeStatusSchema = z.object({
45
+ node_id: z.string().describe("The ID of the node to update"),
46
+ status: z.enum(["pending", "active", "completed", "failed", "skipped"]).describe("The new status of the node"),
47
+ output: z.string().optional().describe("Optional output/result from the node execution"),
48
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
49
+ });
50
+ var PlanCompletedSchema = z.object({
51
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
52
+ });
53
+ var PlanFailedSchema = z.object({
54
+ error: z.string().describe("The error message"),
55
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
56
+ });
57
+ var CheckRerunSchema = z.object({
58
+ timeout_ms: z.number().optional().describe("How long to wait for a rerun request (default 5000ms)"),
59
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
60
+ });
61
+ var CheckPauseSchema = z.object({
62
+ wait: z.boolean().optional().describe("If true, block until execution is resumed. If false, return immediately."),
63
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
64
+ });
65
+ var GetResumeInfoSchema = z.object({
66
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
67
+ });
68
+ var NodeDataSchema = z.object({
69
+ id: z.string().describe("Unique ID for the node"),
70
+ type: z.enum(["task", "decision"]).describe("Node type"),
71
+ title: z.string().describe("Node title"),
72
+ description: z.string().describe("Node description"),
73
+ complexity: z.enum(["low", "medium", "high"]).optional().describe("Task complexity"),
74
+ expectedOutput: z.string().optional().describe("Expected output description"),
75
+ risks: z.string().optional().describe("Potential risks")
76
+ });
77
+ var PlanOperationSchema = z.discriminatedUnion("op", [
78
+ z.object({
79
+ op: z.literal("insert_after"),
80
+ reference_node_id: z.string().describe("Node ID to insert after"),
81
+ node: NodeDataSchema
82
+ }),
83
+ z.object({
84
+ op: z.literal("insert_before"),
85
+ reference_node_id: z.string().describe("Node ID to insert before"),
86
+ node: NodeDataSchema
87
+ }),
88
+ z.object({
89
+ op: z.literal("delete"),
90
+ node_id: z.string().describe("Node ID to delete")
91
+ }),
92
+ z.object({
93
+ op: z.literal("replace"),
94
+ node_id: z.string().describe("Node ID to replace"),
95
+ node: z.object({
96
+ id: z.string().optional().describe("New ID (optional)"),
97
+ type: z.enum(["task", "decision"]).optional(),
98
+ title: z.string().describe("New title"),
99
+ description: z.string().describe("New description"),
100
+ complexity: z.enum(["low", "medium", "high"]).optional(),
101
+ expectedOutput: z.string().optional(),
102
+ risks: z.string().optional()
103
+ })
104
+ })
105
+ ]);
106
+ var RequestPlanUpdateSchema = z.object({
107
+ operations: z.array(PlanOperationSchema).describe("Array of operations to apply to the plan (insert_after, insert_before, delete, replace)"),
108
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
109
+ });
110
+ var CreateNewPlanSchema = z.object({
111
+ project_id: z.string().optional().describe("Project ID (optional, uses current project if not specified)")
112
+ });
113
+ var GetUsageInstructionsSchema = z.object({
114
+ agent_type: z.string().describe("The type of agent requesting instructions (claude-code, cline, cursor, sixth)")
115
+ });
116
+ var TOOLS = [
117
+ {
118
+ name: "stream_plan_chunk",
119
+ description: "Stream a chunk of the plan XML to Overture. IMPORTANT: Call get_usage_instructions first to learn the correct XML format and workflow. Use this to send the plan incrementally as it is generated. Each chunk will be parsed and nodes/edges will appear in real-time on the canvas.",
120
+ inputSchema: {
121
+ type: "object",
122
+ properties: {
123
+ xml_chunk: {
124
+ type: "string",
125
+ description: "A chunk of the plan XML to process"
126
+ },
127
+ workspace_path: {
128
+ type: "string",
129
+ description: "Absolute path to the workspace/project directory. Used to identify the project for multi-project support."
130
+ },
131
+ agent_type: {
132
+ type: "string",
133
+ description: "The type of agent (claude-code, cline, cursor, sixth)"
134
+ }
135
+ },
136
+ required: ["xml_chunk"]
137
+ }
138
+ },
139
+ {
140
+ name: "submit_plan",
141
+ description: "Submit a complete plan XML to Overture. IMPORTANT: Call get_usage_instructions first to learn the correct XML format and workflow. Use this if you have the entire plan ready at once. The plan will be parsed and displayed on the canvas.",
142
+ inputSchema: {
143
+ type: "object",
144
+ properties: {
145
+ plan_xml: {
146
+ type: "string",
147
+ description: "The complete plan XML"
148
+ },
149
+ workspace_path: {
150
+ type: "string",
151
+ description: "Absolute path to the workspace/project directory. Used to identify the project for multi-project support."
152
+ },
153
+ agent_type: {
154
+ type: "string",
155
+ description: "The type of agent (claude-code, cline, cursor, sixth)"
156
+ }
157
+ },
158
+ required: ["plan_xml"]
159
+ }
160
+ },
161
+ {
162
+ name: "get_approval",
163
+ description: 'Wait for user approval of the plan in the Overture UI. Returns status: "approved" (with field values and selected branches), "cancelled" (user rejected), or "pending" (still waiting). If status is "pending", call this tool again to continue waiting - the user may need up to 15-30 minutes to review and customize the plan.',
164
+ inputSchema: {
165
+ type: "object",
166
+ properties: {
167
+ project_id: {
168
+ type: "string",
169
+ description: "Project ID (optional, uses current project if not specified)"
170
+ }
171
+ },
172
+ required: []
173
+ }
174
+ },
175
+ {
176
+ name: "update_node_status",
177
+ description: "Update the status of a node during execution. Use this to show progress as you work through the plan. The node will visually update on the canvas.",
178
+ inputSchema: {
179
+ type: "object",
180
+ properties: {
181
+ node_id: {
182
+ type: "string",
183
+ description: "The ID of the node to update"
184
+ },
185
+ status: {
186
+ type: "string",
187
+ enum: ["pending", "active", "completed", "failed", "skipped"],
188
+ description: "The new status of the node"
189
+ },
190
+ output: {
191
+ type: "string",
192
+ description: "Optional output/result from the node execution"
193
+ },
194
+ project_id: {
195
+ type: "string",
196
+ description: "Project ID (optional, uses current project if not specified)"
197
+ }
198
+ },
199
+ required: ["node_id", "status"]
200
+ }
201
+ },
202
+ {
203
+ name: "plan_completed",
204
+ description: "Mark the plan as successfully completed. Call this after all nodes have been executed.",
205
+ inputSchema: {
206
+ type: "object",
207
+ properties: {
208
+ project_id: {
209
+ type: "string",
210
+ description: "Project ID (optional, uses current project if not specified)"
211
+ }
212
+ },
213
+ required: []
214
+ }
215
+ },
216
+ {
217
+ name: "plan_failed",
218
+ description: "Mark the plan as failed. Call this if an unrecoverable error occurs during execution.",
219
+ inputSchema: {
220
+ type: "object",
221
+ properties: {
222
+ error: {
223
+ type: "string",
224
+ description: "The error message"
225
+ },
226
+ project_id: {
227
+ type: "string",
228
+ description: "Project ID (optional, uses current project if not specified)"
229
+ }
230
+ },
231
+ required: ["error"]
232
+ }
233
+ },
234
+ {
235
+ name: "check_rerun",
236
+ description: "Check if the user has requested to re-run any nodes. Call this after plan_completed to allow users to re-run specific nodes or re-run from a node to the end. Returns immediately if there's a pending request, otherwise waits briefly.",
237
+ inputSchema: {
238
+ type: "object",
239
+ properties: {
240
+ timeout_ms: {
241
+ type: "number",
242
+ description: "How long to wait for a rerun request (default 5000ms)"
243
+ },
244
+ project_id: {
245
+ type: "string",
246
+ description: "Project ID (optional, uses current project if not specified)"
247
+ }
248
+ },
249
+ required: []
250
+ }
251
+ },
252
+ {
253
+ name: "check_pause",
254
+ description: "Check if the user has paused execution. Call this before starting each node to respect user pause requests. If wait=true, blocks until the user resumes.",
255
+ inputSchema: {
256
+ type: "object",
257
+ properties: {
258
+ wait: {
259
+ type: "boolean",
260
+ description: "If true, block until execution is resumed. If false, return immediately with current state."
261
+ },
262
+ project_id: {
263
+ type: "string",
264
+ description: "Project ID (optional, uses current project if not specified)"
265
+ }
266
+ },
267
+ required: []
268
+ }
269
+ },
270
+ {
271
+ name: "get_resume_info",
272
+ description: "Get detailed information about a paused or failed plan to help resume execution. Returns the current node where execution stopped, list of completed/pending/failed nodes, user-configured field values, selected branches, and other metadata. Use this when resuming a plan that was paused, failed, or loaded from history.",
273
+ inputSchema: {
274
+ type: "object",
275
+ properties: {
276
+ project_id: {
277
+ type: "string",
278
+ description: "Project ID (optional, uses current project if not specified)"
279
+ }
280
+ },
281
+ required: []
282
+ }
283
+ },
284
+ {
285
+ name: "request_plan_update",
286
+ description: "Update an existing plan with incremental operations. Pass an array of operations to insert, delete, or replace nodes. Operations are applied in order with smooth animations. After calling this, call get_approval to confirm changes with the user.",
287
+ inputSchema: {
288
+ type: "object",
289
+ properties: {
290
+ operations: {
291
+ type: "array",
292
+ description: "Array of operations to apply to the plan",
293
+ items: {
294
+ type: "object",
295
+ oneOf: [
296
+ {
297
+ type: "object",
298
+ properties: {
299
+ op: { type: "string", enum: ["insert_after"], description: "Insert a node after the reference node" },
300
+ reference_node_id: { type: "string", description: "Node ID to insert after" },
301
+ node: {
302
+ type: "object",
303
+ properties: {
304
+ id: { type: "string" },
305
+ type: { type: "string", enum: ["task", "decision"] },
306
+ title: { type: "string" },
307
+ description: { type: "string" },
308
+ complexity: { type: "string", enum: ["low", "medium", "high"] },
309
+ expectedOutput: { type: "string" },
310
+ risks: { type: "string" }
311
+ },
312
+ required: ["id", "type", "title", "description"]
313
+ }
314
+ },
315
+ required: ["op", "reference_node_id", "node"]
316
+ },
317
+ {
318
+ type: "object",
319
+ properties: {
320
+ op: { type: "string", enum: ["insert_before"], description: "Insert a node before the reference node" },
321
+ reference_node_id: { type: "string", description: "Node ID to insert before" },
322
+ node: {
323
+ type: "object",
324
+ properties: {
325
+ id: { type: "string" },
326
+ type: { type: "string", enum: ["task", "decision"] },
327
+ title: { type: "string" },
328
+ description: { type: "string" },
329
+ complexity: { type: "string", enum: ["low", "medium", "high"] },
330
+ expectedOutput: { type: "string" },
331
+ risks: { type: "string" }
332
+ },
333
+ required: ["id", "type", "title", "description"]
334
+ }
335
+ },
336
+ required: ["op", "reference_node_id", "node"]
337
+ },
338
+ {
339
+ type: "object",
340
+ properties: {
341
+ op: { type: "string", enum: ["delete"], description: "Delete a node (edges auto-reconnect)" },
342
+ node_id: { type: "string", description: "Node ID to delete" }
343
+ },
344
+ required: ["op", "node_id"]
345
+ },
346
+ {
347
+ type: "object",
348
+ properties: {
349
+ op: { type: "string", enum: ["replace"], description: "Replace a node's content in-place" },
350
+ node_id: { type: "string", description: "Node ID to replace" },
351
+ node: {
352
+ type: "object",
353
+ properties: {
354
+ id: { type: "string" },
355
+ type: { type: "string", enum: ["task", "decision"] },
356
+ title: { type: "string" },
357
+ description: { type: "string" },
358
+ complexity: { type: "string", enum: ["low", "medium", "high"] },
359
+ expectedOutput: { type: "string" },
360
+ risks: { type: "string" }
361
+ },
362
+ required: ["title", "description"]
363
+ }
364
+ },
365
+ required: ["op", "node_id", "node"]
366
+ }
367
+ ]
368
+ }
369
+ },
370
+ project_id: {
371
+ type: "string",
372
+ description: "Project ID (optional, uses current project if not specified)"
373
+ }
374
+ },
375
+ required: ["operations"]
376
+ }
377
+ },
378
+ {
379
+ name: "create_new_plan",
380
+ description: `Signal that you are creating a completely new, unrelated plan. IMPORTANT: Call get_usage_instructions first if you haven't already. Call this BEFORE submitting a new plan when the user asks for something unrelated to the current plan (e.g., "let's work on something else", "forget that, build X instead"). The new plan will be added alongside existing plans (Figma-style artboards). After calling this, submit the new plan using submit_plan or stream_plan_chunk, then call get_approval.`,
381
+ inputSchema: {
382
+ type: "object",
383
+ properties: {
384
+ project_id: {
385
+ type: "string",
386
+ description: "Project ID (optional, uses current project if not specified)"
387
+ }
388
+ },
389
+ required: []
390
+ }
391
+ },
392
+ {
393
+ name: "get_usage_instructions",
394
+ description: "Get detailed usage instructions for Overture MCP. CALL THIS FIRST before using any other Overture tools. Returns comprehensive documentation on how to structure plans, use XML format, handle approvals, and execute nodes. Pass your agent type to get agent-specific instructions.",
395
+ inputSchema: {
396
+ type: "object",
397
+ properties: {
398
+ agent_type: {
399
+ type: "string",
400
+ description: 'The type of agent requesting instructions. Supported: "claude-code", "cline", "cursor", "sixth"'
401
+ }
402
+ },
403
+ required: ["agent_type"]
404
+ }
405
+ }
406
+ ];
407
+ async function main() {
408
+ await historyStorage.initialize();
409
+ startHttpServer(HTTP_PORT);
410
+ wsManager.start(WS_PORT);
411
+ if (AUTO_OPEN_BROWSER) {
412
+ setTimeout(() => {
413
+ open(`http://localhost:${HTTP_PORT}`);
414
+ }, 500);
415
+ }
416
+ const server = new Server(
417
+ {
418
+ name: "overture",
419
+ version: "0.1.0"
420
+ },
421
+ {
422
+ capabilities: {
423
+ tools: {}
424
+ }
425
+ }
426
+ );
427
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
428
+ return { tools: TOOLS };
429
+ });
430
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
431
+ const { name, arguments: args } = request.params;
432
+ try {
433
+ switch (name) {
434
+ case "stream_plan_chunk": {
435
+ const parsed = StreamPlanChunkSchema.parse(args);
436
+ const result = handleStreamPlanChunk(parsed.xml_chunk, parsed.workspace_path, parsed.agent_type);
437
+ return {
438
+ content: [
439
+ {
440
+ type: "text",
441
+ text: JSON.stringify(result)
442
+ }
443
+ ]
444
+ };
445
+ }
446
+ case "submit_plan": {
447
+ const parsed = SubmitPlanSchema.parse(args);
448
+ const result = handleSubmitPlan(parsed.plan_xml, parsed.workspace_path, parsed.agent_type);
449
+ return {
450
+ content: [
451
+ {
452
+ type: "text",
453
+ text: JSON.stringify(result)
454
+ }
455
+ ]
456
+ };
457
+ }
458
+ case "get_approval": {
459
+ const parsed = GetApprovalSchema.parse(args);
460
+ const result = await handleGetApproval(parsed.project_id);
461
+ return {
462
+ content: [
463
+ {
464
+ type: "text",
465
+ text: JSON.stringify(result)
466
+ }
467
+ ]
468
+ };
469
+ }
470
+ case "update_node_status": {
471
+ const parsed = UpdateNodeStatusSchema.parse(args);
472
+ const result = handleUpdateNodeStatus(
473
+ parsed.node_id,
474
+ parsed.status,
475
+ parsed.output,
476
+ parsed.project_id
477
+ );
478
+ return {
479
+ content: [
480
+ {
481
+ type: "text",
482
+ text: JSON.stringify(result)
483
+ }
484
+ ]
485
+ };
486
+ }
487
+ case "plan_completed": {
488
+ const parsed = PlanCompletedSchema.parse(args);
489
+ const result = handlePlanCompleted(parsed.project_id);
490
+ return {
491
+ content: [
492
+ {
493
+ type: "text",
494
+ text: JSON.stringify(result)
495
+ }
496
+ ]
497
+ };
498
+ }
499
+ case "plan_failed": {
500
+ const parsed = PlanFailedSchema.parse(args);
501
+ const result = handlePlanFailed(parsed.error, parsed.project_id);
502
+ return {
503
+ content: [
504
+ {
505
+ type: "text",
506
+ text: JSON.stringify(result)
507
+ }
508
+ ]
509
+ };
510
+ }
511
+ case "check_rerun": {
512
+ const parsed = CheckRerunSchema.parse(args);
513
+ const result = await handleCheckRerun(parsed.timeout_ms || 5e3, parsed.project_id);
514
+ return {
515
+ content: [
516
+ {
517
+ type: "text",
518
+ text: JSON.stringify(result)
519
+ }
520
+ ]
521
+ };
522
+ }
523
+ case "check_pause": {
524
+ const parsed = CheckPauseSchema.parse(args);
525
+ const result = await handleCheckPause(parsed.wait || false, parsed.project_id);
526
+ return {
527
+ content: [
528
+ {
529
+ type: "text",
530
+ text: JSON.stringify(result)
531
+ }
532
+ ]
533
+ };
534
+ }
535
+ case "get_resume_info": {
536
+ const parsed = GetResumeInfoSchema.parse(args);
537
+ const result = handleGetResumeInfo(parsed.project_id);
538
+ return {
539
+ content: [
540
+ {
541
+ type: "text",
542
+ text: JSON.stringify(result)
543
+ }
544
+ ]
545
+ };
546
+ }
547
+ case "request_plan_update": {
548
+ const parsed = RequestPlanUpdateSchema.parse(args);
549
+ const result = handleRequestPlanUpdate(parsed.operations, parsed.project_id);
550
+ return {
551
+ content: [
552
+ {
553
+ type: "text",
554
+ text: JSON.stringify(result)
555
+ }
556
+ ]
557
+ };
558
+ }
559
+ case "create_new_plan": {
560
+ const parsed = CreateNewPlanSchema.parse(args);
561
+ const result = handleCreateNewPlan(parsed.project_id);
562
+ return {
563
+ content: [
564
+ {
565
+ type: "text",
566
+ text: JSON.stringify(result)
567
+ }
568
+ ]
569
+ };
570
+ }
571
+ case "get_usage_instructions": {
572
+ const parsed = GetUsageInstructionsSchema.parse(args);
573
+ const result = await handleGetUsageInstructions(parsed.agent_type);
574
+ return {
575
+ content: [
576
+ {
577
+ type: "text",
578
+ text: JSON.stringify(result)
579
+ }
580
+ ]
581
+ };
582
+ }
583
+ default:
584
+ throw new Error(`Unknown tool: ${name}`);
585
+ }
586
+ } catch (error) {
587
+ const message = error instanceof Error ? error.message : "Unknown error";
588
+ return {
589
+ content: [
590
+ {
591
+ type: "text",
592
+ text: JSON.stringify({ success: false, error: message })
593
+ }
594
+ ],
595
+ isError: true
596
+ };
597
+ }
598
+ });
599
+ const transport = new StdioServerTransport();
600
+ await server.connect(transport);
601
+ console.error("[Overture] MCP server started");
602
+ console.error(`[Overture] UI: http://localhost:${HTTP_PORT}`);
603
+ console.error(`[Overture] WebSocket: ws://localhost:${WS_PORT}`);
604
+ }
605
+ main().catch((error) => {
606
+ console.error("[Overture] Fatal error:", error);
607
+ process.exit(1);
608
+ });