@wireweave/mcp-server 1.8.1-beta.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +43 -122
  2. package/dist/index.js +614 -795
  3. package/package.json +39 -14
package/dist/index.js CHANGED
@@ -21,139 +21,137 @@ var tools = [
21
21
  name: "wireweave_parse",
22
22
  description: "Parse Wireweave DSL source code into an AST (Abstract Syntax Tree)",
23
23
  inputSchema: {
24
- "type": "object",
25
- "properties": {
26
- "source": {
27
- "type": "string",
28
- "description": "The Wireweave DSL source code to parse"
24
+ type: "object",
25
+ properties: {
26
+ source: {
27
+ type: "string",
28
+ description: "The Wireweave DSL source code to parse"
29
29
  }
30
30
  },
31
- "required": [
32
- "source"
33
- ]
31
+ required: ["source"]
34
32
  }
35
33
  },
36
34
  {
37
35
  name: "wireweave_validate",
38
36
  description: "Validate Wireweave DSL syntax without generating output. Use strict mode to also check for unknown attributes.",
39
37
  inputSchema: {
40
- "type": "object",
41
- "properties": {
42
- "source": {
43
- "type": "string",
44
- "description": "The Wireweave DSL source code to validate"
38
+ type: "object",
39
+ properties: {
40
+ source: {
41
+ type: "string",
42
+ description: "The Wireweave DSL source code to validate"
45
43
  },
46
- "strict": {
47
- "type": "boolean",
48
- "description": "Enable strict mode to also validate that only known attributes are used. Recommended for catching typos and incorrect attribute names.",
49
- "default": false
44
+ strict: {
45
+ type: "boolean",
46
+ description: "Enable strict mode to also validate that only known attributes are used. Recommended for catching typos and incorrect attribute names.",
47
+ default: false
50
48
  }
51
49
  },
52
- "required": [
53
- "source"
54
- ]
50
+ required: ["source"]
55
51
  }
56
52
  },
57
53
  {
58
54
  name: "wireweave_grammar",
59
55
  description: "Get the Wireweave DSL grammar documentation and syntax reference",
60
56
  inputSchema: {
61
- "type": "object",
62
- "properties": {},
63
- "required": []
57
+ type: "object",
58
+ properties: {},
59
+ required: []
64
60
  }
65
61
  },
66
62
  {
67
63
  name: "wireweave_guide",
68
64
  description: "Get the comprehensive LLM guide for Wireweave DSL. This is the PRIMARY resource for learning the language - includes syntax, components, patterns, and best practices. Call this FIRST before generating wireframes.",
69
65
  inputSchema: {
70
- "type": "object",
71
- "properties": {},
72
- "required": []
66
+ type: "object",
67
+ properties: {},
68
+ required: []
73
69
  }
74
70
  },
75
71
  {
76
72
  name: "wireweave_patterns",
77
73
  description: "Get common layout patterns for wireframes including headers, sidebars, forms, cards, and more. Use these as building blocks.",
78
74
  inputSchema: {
79
- "type": "object",
80
- "properties": {},
81
- "required": []
75
+ type: "object",
76
+ properties: {},
77
+ required: []
82
78
  }
83
79
  },
84
80
  {
85
81
  name: "wireweave_examples",
86
82
  description: "Get Wireweave code examples. Use this to learn patterns and best practices for different UI types.",
87
83
  inputSchema: {
88
- "type": "object",
89
- "properties": {
90
- "category": {
91
- "type": "string",
92
- "enum": [
93
- "all",
94
- "basic",
95
- "layout",
96
- "navigation",
97
- "form",
98
- "dashboard"
99
- ],
100
- "description": 'Filter examples by category. Use "all" to get all examples. Categories cover generic component compositions (basic, layout, navigation, form) and a domain-agnostic dashboard shell.',
101
- "default": "all"
84
+ type: "object",
85
+ properties: {
86
+ category: {
87
+ type: "string",
88
+ enum: ["all", "basic", "layout", "navigation", "form", "dashboard"],
89
+ description: 'Filter examples by category. Use "all" to get all examples. Categories cover generic component compositions (basic, layout, navigation, form) and a domain-agnostic dashboard shell.',
90
+ default: "all"
102
91
  },
103
- "limit": {
104
- "type": "number",
105
- "description": "Maximum number of examples to return",
106
- "default": 5
92
+ limit: {
93
+ type: "number",
94
+ description: "Maximum number of examples to return",
95
+ default: 5
107
96
  }
108
97
  },
109
- "required": []
98
+ required: []
99
+ }
100
+ },
101
+ {
102
+ name: "wireweave_list_components",
103
+ description: "List Wireweave DSL components with their categories, attributes, and examples. Use this to discover available components for wireframe generation. Filter by category (layout, navigation, form, etc.) when narrowing the search.",
104
+ inputSchema: {
105
+ type: "object",
106
+ properties: {
107
+ category: {
108
+ type: "string",
109
+ description: 'Filter components by category (e.g., "layout", "navigation", "form", "content", "interaction"). Omit to return all components.'
110
+ }
111
+ },
112
+ required: []
110
113
  }
111
114
  },
112
115
  {
113
116
  name: "wireweave_render_html_code",
114
117
  description: "Render Wireweave DSL to HTML code. Returns the HTML content directly. This is an alias for wireweave_render_html with explicit naming.",
115
118
  inputSchema: {
116
- "type": "object",
117
- "properties": {
118
- "source": {
119
- "type": "string",
120
- "description": "The Wireweave DSL source code to render"
119
+ type: "object",
120
+ properties: {
121
+ source: {
122
+ type: "string",
123
+ description: "The Wireweave DSL source code to render"
121
124
  },
122
- "theme": {
123
- "type": "string",
124
- "enum": [
125
- "light",
126
- "dark"
127
- ],
128
- "description": "Color theme for rendering",
129
- "default": "light"
125
+ theme: {
126
+ type: "string",
127
+ enum: ["light", "dark"],
128
+ description: "Color theme for rendering",
129
+ default: "light"
130
130
  },
131
- "fullDocument": {
132
- "type": "boolean",
133
- "description": "Return a complete HTML document instead of fragment",
134
- "default": false
131
+ fullDocument: {
132
+ type: "boolean",
133
+ description: "Return a complete HTML document instead of fragment",
134
+ default: false
135
135
  }
136
136
  },
137
- "required": [
138
- "source"
139
- ]
137
+ required: ["source"]
140
138
  }
141
139
  },
142
140
  {
143
141
  name: "wireweave_validate_ux",
144
142
  description: "Validate Wireweave DSL for UX best practices. Returns issues with severity levels and actionable recommendations.",
145
143
  inputSchema: {
146
- "type": "object",
147
- "properties": {
148
- "source": {
149
- "type": "string",
150
- "description": "The Wireweave DSL source code to validate"
144
+ type: "object",
145
+ properties: {
146
+ source: {
147
+ type: "string",
148
+ description: "The Wireweave DSL source code to validate"
151
149
  },
152
- "categories": {
153
- "type": "array",
154
- "items": {
155
- "type": "string",
156
- "enum": [
150
+ categories: {
151
+ type: "array",
152
+ items: {
153
+ type: "string",
154
+ enum: [
157
155
  "accessibility",
158
156
  "usability",
159
157
  "form",
@@ -166,516 +164,510 @@ var tools = [
166
164
  "interaction"
167
165
  ]
168
166
  },
169
- "description": "UX rule categories to check. If not specified, all categories are checked."
167
+ description: "UX rule categories to check. If not specified, all categories are checked."
170
168
  },
171
- "minSeverity": {
172
- "type": "string",
173
- "enum": [
174
- "error",
175
- "warning",
176
- "info"
177
- ],
178
- "description": "Minimum severity level to report",
179
- "default": "info"
169
+ minSeverity: {
170
+ type: "string",
171
+ enum: ["error", "warning", "info"],
172
+ description: "Minimum severity level to report",
173
+ default: "info"
180
174
  },
181
- "maxIssues": {
182
- "type": "number",
183
- "description": "Maximum number of issues to return"
175
+ maxIssues: {
176
+ type: "number",
177
+ description: "Maximum number of issues to return"
184
178
  },
185
- "disabledRules": {
186
- "type": "array",
187
- "items": {
188
- "type": "string"
179
+ disabledRules: {
180
+ type: "array",
181
+ items: {
182
+ type: "string"
189
183
  },
190
- "description": 'List of rule IDs to disable (e.g., ["a11y-input-label", "form-submit-button"])'
184
+ description: 'List of rule IDs to disable (e.g., ["a11y-input-label", "form-submit-button"])'
191
185
  }
192
186
  },
193
- "required": [
194
- "source"
195
- ]
187
+ required: ["source"]
196
188
  }
197
189
  },
198
190
  {
199
191
  name: "wireweave_ux_rules",
200
192
  description: "Get available UX rule categories and their descriptions",
201
193
  inputSchema: {
202
- "type": "object",
203
- "properties": {},
204
- "required": []
194
+ type: "object",
195
+ properties: {},
196
+ required: []
205
197
  }
206
198
  },
207
199
  {
208
200
  name: "wireweave_diff",
209
201
  description: "Compare two Wireweave DSL sources and return the differences between them",
210
202
  inputSchema: {
211
- "type": "object",
212
- "properties": {
213
- "oldSource": {
214
- "type": "string",
215
- "description": "The original Wireweave DSL source code"
203
+ type: "object",
204
+ properties: {
205
+ oldSource: {
206
+ type: "string",
207
+ description: "The original Wireweave DSL source code"
208
+ },
209
+ newSource: {
210
+ type: "string",
211
+ description: "The modified Wireweave DSL source code"
216
212
  },
217
- "newSource": {
218
- "type": "string",
219
- "description": "The modified Wireweave DSL source code"
213
+ ignoreAttributes: {
214
+ type: "boolean",
215
+ description: "Ignore attribute changes, only compare structure",
216
+ default: false
217
+ },
218
+ ignoreOrder: {
219
+ type: "boolean",
220
+ description: "Ignore the order of children when comparing",
221
+ default: false
222
+ }
223
+ },
224
+ required: ["oldSource", "newSource"]
225
+ }
226
+ },
227
+ {
228
+ name: "wireweave_export_json",
229
+ description: "Export Wireweave DSL to JSON format",
230
+ inputSchema: {
231
+ type: "object",
232
+ properties: {
233
+ source: {
234
+ type: "string",
235
+ description: "The Wireweave DSL source code to export"
220
236
  },
221
- "ignoreAttributes": {
222
- "type": "boolean",
223
- "description": "Ignore attribute changes, only compare structure",
224
- "default": false
237
+ includeLocations: {
238
+ type: "boolean",
239
+ description: "Include source location information in output",
240
+ default: false
225
241
  },
226
- "ignoreOrder": {
227
- "type": "boolean",
228
- "description": "Ignore the order of children when comparing",
229
- "default": false
242
+ prettyPrint: {
243
+ type: "boolean",
244
+ description: "Format JSON with indentation",
245
+ default: true
246
+ }
247
+ },
248
+ required: ["source"]
249
+ }
250
+ },
251
+ {
252
+ name: "wireweave_export_figma",
253
+ description: "Export Wireweave DSL to Figma-compatible format",
254
+ inputSchema: {
255
+ type: "object",
256
+ properties: {
257
+ source: {
258
+ type: "string",
259
+ description: "The Wireweave DSL source code to export"
230
260
  }
231
261
  },
232
- "required": [
233
- "oldSource",
234
- "newSource"
235
- ]
262
+ required: ["source"]
236
263
  }
237
264
  },
238
265
  {
239
266
  name: "wireweave_analyze",
240
267
  description: "Analyze Wireweave DSL for statistics and metrics including component usage, tree structure, accessibility score, and complexity",
241
268
  inputSchema: {
242
- "type": "object",
243
- "properties": {
244
- "source": {
245
- "type": "string",
246
- "description": "The Wireweave DSL source code to analyze"
269
+ type: "object",
270
+ properties: {
271
+ source: {
272
+ type: "string",
273
+ description: "The Wireweave DSL source code to analyze"
247
274
  },
248
- "includeComponentBreakdown": {
249
- "type": "boolean",
250
- "description": "Include detailed component usage breakdown",
251
- "default": true
275
+ includeComponentBreakdown: {
276
+ type: "boolean",
277
+ description: "Include detailed component usage breakdown",
278
+ default: true
252
279
  },
253
- "includeAccessibility": {
254
- "type": "boolean",
255
- "description": "Include accessibility analysis",
256
- "default": true
280
+ includeAccessibility: {
281
+ type: "boolean",
282
+ description: "Include accessibility analysis",
283
+ default: true
257
284
  },
258
- "includeComplexity": {
259
- "type": "boolean",
260
- "description": "Include complexity metrics",
261
- "default": true
285
+ includeComplexity: {
286
+ type: "boolean",
287
+ description: "Include complexity metrics",
288
+ default: true
262
289
  },
263
- "includeLayout": {
264
- "type": "boolean",
265
- "description": "Include layout pattern analysis",
266
- "default": true
290
+ includeLayout: {
291
+ type: "boolean",
292
+ description: "Include layout pattern analysis",
293
+ default: true
267
294
  },
268
- "includeContent": {
269
- "type": "boolean",
270
- "description": "Include content analysis",
271
- "default": true
295
+ includeContent: {
296
+ type: "boolean",
297
+ description: "Include content analysis",
298
+ default: true
272
299
  }
273
300
  },
274
- "required": [
275
- "source"
276
- ]
301
+ required: ["source"]
277
302
  }
278
303
  },
279
304
  {
280
305
  name: "wireweave_cloud_list_projects",
281
306
  description: "List all your Wireweave projects. Projects help organize your wireframes. WORKFLOW: Call this first before saving wireframes. If the list is empty, ask the user whether to create a new project (call wireweave_cloud_create_project) or use the default project.",
282
307
  inputSchema: {
283
- "type": "object",
284
- "properties": {
285
- "includeArchived": {
286
- "type": "boolean",
287
- "description": "Include archived projects",
288
- "default": false
308
+ type: "object",
309
+ properties: {
310
+ includeArchived: {
311
+ type: "boolean",
312
+ description: "Include archived projects",
313
+ default: false
289
314
  }
290
315
  },
291
- "required": []
316
+ required: []
292
317
  }
293
318
  },
294
319
  {
295
320
  name: "wireweave_cloud_create_project",
296
321
  description: "Create a new project to organize wireframes. Use this when the user wants to organize their wireframes into a specific project. The project can have a custom name, description, and color.",
297
322
  inputSchema: {
298
- "type": "object",
299
- "properties": {
300
- "name": {
301
- "type": "string",
302
- "description": "Project name"
323
+ type: "object",
324
+ properties: {
325
+ name: {
326
+ type: "string",
327
+ description: "Project name"
303
328
  },
304
- "description": {
305
- "type": "string",
306
- "description": "Project description"
329
+ description: {
330
+ type: "string",
331
+ description: "Project description"
307
332
  },
308
- "color": {
309
- "type": "string",
310
- "description": "Project color (hex code, e.g., #6366f1)"
333
+ color: {
334
+ type: "string",
335
+ description: "Project color (hex code, e.g., #6366f1)"
311
336
  }
312
337
  },
313
- "required": [
314
- "name"
315
- ]
338
+ required: ["name"]
316
339
  }
317
340
  },
318
341
  {
319
342
  name: "wireweave_cloud_update_project",
320
343
  description: "Update an existing project",
321
344
  inputSchema: {
322
- "type": "object",
323
- "properties": {
324
- "id": {
325
- "type": "string",
326
- "description": "Project ID to update"
345
+ type: "object",
346
+ properties: {
347
+ id: {
348
+ type: "string",
349
+ description: "Project ID to update"
327
350
  },
328
- "name": {
329
- "type": "string",
330
- "description": "New project name"
351
+ name: {
352
+ type: "string",
353
+ description: "New project name"
331
354
  },
332
- "description": {
333
- "type": "string",
334
- "description": "New project description"
355
+ description: {
356
+ type: "string",
357
+ description: "New project description"
335
358
  },
336
- "color": {
337
- "type": "string",
338
- "description": "New project color (hex code)"
359
+ color: {
360
+ type: "string",
361
+ description: "New project color (hex code)"
339
362
  },
340
- "isArchived": {
341
- "type": "boolean",
342
- "description": "Archive or unarchive the project"
363
+ isArchived: {
364
+ type: "boolean",
365
+ description: "Archive or unarchive the project"
343
366
  }
344
367
  },
345
- "required": [
346
- "id"
347
- ]
368
+ required: ["id"]
348
369
  }
349
370
  },
350
371
  {
351
372
  name: "wireweave_cloud_list_wireframes",
352
373
  description: "List your saved wireframes. Optionally filter by project or tags.",
353
374
  inputSchema: {
354
- "type": "object",
355
- "properties": {
356
- "projectId": {
357
- "type": "string",
358
- "description": "Filter by project ID"
375
+ type: "object",
376
+ properties: {
377
+ projectId: {
378
+ type: "string",
379
+ description: "Filter by project ID"
359
380
  },
360
- "tags": {
361
- "type": "array",
362
- "items": {
363
- "type": "string"
381
+ tags: {
382
+ type: "array",
383
+ items: {
384
+ type: "string"
364
385
  },
365
- "description": "Filter by tags"
386
+ description: "Filter by tags"
366
387
  },
367
- "limit": {
368
- "type": "number",
369
- "description": "Maximum number of wireframes to return",
370
- "default": 20
388
+ limit: {
389
+ type: "number",
390
+ description: "Maximum number of wireframes to return",
391
+ default: 20
371
392
  },
372
- "offset": {
373
- "type": "number",
374
- "description": "Offset for pagination",
375
- "default": 0
393
+ offset: {
394
+ type: "number",
395
+ description: "Offset for pagination",
396
+ default: 0
376
397
  }
377
398
  },
378
- "required": []
399
+ required: []
379
400
  }
380
401
  },
381
402
  {
382
403
  name: "wireweave_cloud_get_wireframe",
383
404
  description: "Get a specific wireframe by ID, including its code and metadata",
384
405
  inputSchema: {
385
- "type": "object",
386
- "properties": {
387
- "id": {
388
- "type": "string",
389
- "description": "Wireframe ID"
406
+ type: "object",
407
+ properties: {
408
+ id: {
409
+ type: "string",
410
+ description: "Wireframe ID"
390
411
  }
391
412
  },
392
- "required": [
393
- "id"
394
- ]
413
+ required: ["id"]
395
414
  }
396
415
  },
397
416
  {
398
417
  name: "wireweave_cloud_save_wireframe",
399
418
  description: "Save a new wireframe to the cloud. Free (v2.0+).\n\nRECOMMENDED WORKFLOW:\n1. Call wireweave_cloud_list_projects to get available projects\n2. If projects exist: Ask user which project to save to\n3. If no projects: Ask user to (a) create a new project, or (b) save to default project\n4. Call this tool with the chosen projectId (or omit for default project)\n\nNote: If projectId is not provided, the wireframe will be saved to the user's default project.",
400
419
  inputSchema: {
401
- "type": "object",
402
- "properties": {
403
- "name": {
404
- "type": "string",
405
- "description": "Wireframe name"
420
+ type: "object",
421
+ properties: {
422
+ name: {
423
+ type: "string",
424
+ description: "Wireframe name"
406
425
  },
407
- "code": {
408
- "type": "string",
409
- "description": "Wireweave DSL code"
426
+ code: {
427
+ type: "string",
428
+ description: "Wireweave DSL code"
410
429
  },
411
- "description": {
412
- "type": "string",
413
- "description": "Wireframe description"
430
+ description: {
431
+ type: "string",
432
+ description: "Wireframe description"
414
433
  },
415
- "projectId": {
416
- "type": "string",
417
- "description": "Project ID to save to. Get available projects using wireweave_cloud_list_projects first."
434
+ projectId: {
435
+ type: "string",
436
+ description: "Project ID to save to. Get available projects using wireweave_cloud_list_projects first."
418
437
  },
419
- "tags": {
420
- "type": "array",
421
- "items": {
422
- "type": "string"
438
+ tags: {
439
+ type: "array",
440
+ items: {
441
+ type: "string"
423
442
  },
424
- "description": "Tags for categorization"
443
+ description: "Tags for categorization"
425
444
  },
426
- "isPublic": {
427
- "type": "boolean",
428
- "description": "Make wireframe publicly visible",
429
- "default": false
445
+ isPublic: {
446
+ type: "boolean",
447
+ description: "Make wireframe publicly visible",
448
+ default: false
430
449
  }
431
450
  },
432
- "required": [
433
- "name",
434
- "code"
435
- ]
451
+ required: ["name", "code"]
436
452
  }
437
453
  },
438
454
  {
439
455
  name: "wireweave_cloud_update_wireframe",
440
456
  description: "Update an existing wireframe. Creates a new version automatically. Free (v2.0+).",
441
457
  inputSchema: {
442
- "type": "object",
443
- "properties": {
444
- "id": {
445
- "type": "string",
446
- "description": "Wireframe ID to update"
458
+ type: "object",
459
+ properties: {
460
+ id: {
461
+ type: "string",
462
+ description: "Wireframe ID to update"
447
463
  },
448
- "name": {
449
- "type": "string",
450
- "description": "New name (optional)"
464
+ name: {
465
+ type: "string",
466
+ description: "New name (optional)"
451
467
  },
452
- "code": {
453
- "type": "string",
454
- "description": "New Wireweave DSL code (optional)"
468
+ code: {
469
+ type: "string",
470
+ description: "New Wireweave DSL code (optional)"
455
471
  },
456
- "description": {
457
- "type": "string",
458
- "description": "New description (optional)"
472
+ description: {
473
+ type: "string",
474
+ description: "New description (optional)"
459
475
  },
460
- "tags": {
461
- "type": "array",
462
- "items": {
463
- "type": "string"
476
+ tags: {
477
+ type: "array",
478
+ items: {
479
+ type: "string"
464
480
  },
465
- "description": "New tags (optional)"
481
+ description: "New tags (optional)"
466
482
  },
467
- "isPublic": {
468
- "type": "boolean",
469
- "description": "Update public visibility (optional)"
483
+ isPublic: {
484
+ type: "boolean",
485
+ description: "Update public visibility (optional)"
470
486
  }
471
487
  },
472
- "required": [
473
- "id"
474
- ]
488
+ required: ["id"]
475
489
  }
476
490
  },
477
491
  {
478
492
  name: "wireweave_cloud_delete_wireframe",
479
493
  description: "Delete a wireframe permanently",
480
494
  inputSchema: {
481
- "type": "object",
482
- "properties": {
483
- "id": {
484
- "type": "string",
485
- "description": "Wireframe ID to delete"
495
+ type: "object",
496
+ properties: {
497
+ id: {
498
+ type: "string",
499
+ description: "Wireframe ID to delete"
486
500
  }
487
501
  },
488
- "required": [
489
- "id"
490
- ]
502
+ required: ["id"]
491
503
  }
492
504
  },
493
505
  {
494
506
  name: "wireweave_cloud_get_versions",
495
507
  description: "Get version history of a wireframe",
496
508
  inputSchema: {
497
- "type": "object",
498
- "properties": {
499
- "wireframeId": {
500
- "type": "string",
501
- "description": "Wireframe ID"
509
+ type: "object",
510
+ properties: {
511
+ wireframeId: {
512
+ type: "string",
513
+ description: "Wireframe ID"
502
514
  }
503
515
  },
504
- "required": [
505
- "wireframeId"
506
- ]
516
+ required: ["wireframeId"]
507
517
  }
508
518
  },
509
519
  {
510
520
  name: "wireweave_cloud_restore_version",
511
521
  description: "Restore a wireframe to a previous version. Free (v2.0+).",
512
522
  inputSchema: {
513
- "type": "object",
514
- "properties": {
515
- "wireframeId": {
516
- "type": "string",
517
- "description": "Wireframe ID"
523
+ type: "object",
524
+ properties: {
525
+ wireframeId: {
526
+ type: "string",
527
+ description: "Wireframe ID"
518
528
  },
519
- "version": {
520
- "type": "number",
521
- "description": "Version number to restore"
529
+ version: {
530
+ type: "number",
531
+ description: "Version number to restore"
522
532
  }
523
533
  },
524
- "required": [
525
- "wireframeId",
526
- "version"
527
- ]
534
+ required: ["wireframeId", "version"]
528
535
  }
529
536
  },
530
537
  {
531
538
  name: "wireweave_cloud_create_share_link",
532
539
  description: "Create a shareable link for a wireframe. Free (v2.0+).",
533
540
  inputSchema: {
534
- "type": "object",
535
- "properties": {
536
- "wireframeId": {
537
- "type": "string",
538
- "description": "Wireframe ID to share"
541
+ type: "object",
542
+ properties: {
543
+ wireframeId: {
544
+ type: "string",
545
+ description: "Wireframe ID to share"
539
546
  },
540
- "title": {
541
- "type": "string",
542
- "description": "Custom title for the shared view"
547
+ title: {
548
+ type: "string",
549
+ description: "Custom title for the shared view"
543
550
  },
544
- "allowCopy": {
545
- "type": "boolean",
546
- "description": "Allow viewers to copy the code",
547
- "default": false
551
+ allowCopy: {
552
+ type: "boolean",
553
+ description: "Allow viewers to copy the code",
554
+ default: false
548
555
  },
549
- "password": {
550
- "type": "string",
551
- "description": "Password protection (optional)"
556
+ password: {
557
+ type: "string",
558
+ description: "Password protection (optional)"
552
559
  },
553
- "expiresInDays": {
554
- "type": "number",
555
- "description": "Link expiration in days (optional, null = never)"
560
+ expiresInDays: {
561
+ type: "number",
562
+ description: "Link expiration in days (optional, null = never)"
556
563
  }
557
564
  },
558
- "required": [
559
- "wireframeId"
560
- ]
565
+ required: ["wireframeId"]
561
566
  }
562
567
  },
563
568
  {
564
569
  name: "wireweave_cloud_list_shares",
565
570
  description: "List share links for a wireframe",
566
571
  inputSchema: {
567
- "type": "object",
568
- "properties": {
569
- "wireframeId": {
570
- "type": "string",
571
- "description": "Wireframe ID"
572
+ type: "object",
573
+ properties: {
574
+ wireframeId: {
575
+ type: "string",
576
+ description: "Wireframe ID"
572
577
  }
573
578
  },
574
- "required": [
575
- "wireframeId"
576
- ]
579
+ required: ["wireframeId"]
577
580
  }
578
581
  },
579
582
  {
580
583
  name: "wireweave_cloud_diff_versions",
581
584
  description: "Compare two versions of a wireframe and return the differences. Useful for reviewing changes without loading full code.",
582
585
  inputSchema: {
583
- "type": "object",
584
- "properties": {
585
- "wireframeId": {
586
- "type": "string",
587
- "description": "Wireframe ID"
586
+ type: "object",
587
+ properties: {
588
+ wireframeId: {
589
+ type: "string",
590
+ description: "Wireframe ID"
588
591
  },
589
- "versionA": {
590
- "type": "number",
591
- "description": "First version number to compare"
592
+ versionA: {
593
+ type: "number",
594
+ description: "First version number to compare"
592
595
  },
593
- "versionB": {
594
- "type": "number",
595
- "description": "Second version number to compare"
596
+ versionB: {
597
+ type: "number",
598
+ description: "Second version number to compare"
596
599
  }
597
600
  },
598
- "required": [
599
- "wireframeId",
600
- "versionA",
601
- "versionB"
602
- ]
601
+ required: ["wireframeId", "versionA", "versionB"]
603
602
  }
604
603
  },
605
604
  {
606
605
  name: "wireweave_account_balance",
607
606
  description: "Check your current credit balance and subscription status",
608
607
  inputSchema: {
609
- "type": "object",
610
- "properties": {},
611
- "required": []
608
+ type: "object",
609
+ properties: {},
610
+ required: []
612
611
  }
613
612
  },
614
613
  {
615
614
  name: "wireweave_account_subscription",
616
615
  description: "Get detailed subscription information including plan features",
617
616
  inputSchema: {
618
- "type": "object",
619
- "properties": {},
620
- "required": []
617
+ type: "object",
618
+ properties: {},
619
+ required: []
621
620
  }
622
621
  },
623
622
  {
624
623
  name: "wireweave_account_transactions",
625
624
  description: "View your credit transaction history",
626
625
  inputSchema: {
627
- "type": "object",
628
- "properties": {
629
- "limit": {
630
- "type": "number",
631
- "description": "Number of transactions to return",
632
- "default": 20
626
+ type: "object",
627
+ properties: {
628
+ limit: {
629
+ type: "number",
630
+ description: "Number of transactions to return",
631
+ default: 20
633
632
  },
634
- "type": {
635
- "type": "string",
636
- "enum": [
637
- "purchase",
638
- "subscription",
639
- "usage",
640
- "refund",
641
- "bonus",
642
- "admin"
643
- ],
644
- "description": "Filter by transaction type"
633
+ type: {
634
+ type: "string",
635
+ enum: ["purchase", "subscription", "usage", "refund", "bonus", "admin"],
636
+ description: "Filter by transaction type"
645
637
  }
646
638
  },
647
- "required": []
639
+ required: []
648
640
  }
649
641
  },
650
642
  {
651
643
  name: "wireweave_pricing",
652
644
  description: "Get current pricing information for plans, credit packs, and feature costs",
653
645
  inputSchema: {
654
- "type": "object",
655
- "properties": {},
656
- "required": []
646
+ type: "object",
647
+ properties: {},
648
+ required: []
657
649
  }
658
650
  },
659
651
  {
660
652
  name: "wireweave_gallery",
661
653
  description: "Browse public wireframe gallery for inspiration",
662
654
  inputSchema: {
663
- "type": "object",
664
- "properties": {
665
- "tags": {
666
- "type": "array",
667
- "items": {
668
- "type": "string"
655
+ type: "object",
656
+ properties: {
657
+ tags: {
658
+ type: "array",
659
+ items: {
660
+ type: "string"
669
661
  },
670
- "description": "Filter by tags"
662
+ description: "Filter by tags"
671
663
  },
672
- "limit": {
673
- "type": "number",
674
- "description": "Number of wireframes to return",
675
- "default": 20
664
+ limit: {
665
+ type: "number",
666
+ description: "Number of wireframes to return",
667
+ default: 20
676
668
  }
677
669
  },
678
- "required": []
670
+ required: []
679
671
  }
680
672
  }
681
673
  ];
@@ -686,44 +678,83 @@ var toolEndpoints = {
686
678
  wireweave_guide: { method: "GET", path: "/tools/guide" },
687
679
  wireweave_patterns: { method: "GET", path: "/tools/patterns" },
688
680
  wireweave_examples: { method: "GET", path: "/tools/examples" },
681
+ wireweave_list_components: { method: "GET", path: "/tools/list-components" },
689
682
  wireweave_render_html_code: { method: "POST", path: "/tools/render/html" },
690
683
  wireweave_validate_ux: { method: "POST", path: "/tools/validate/ux" },
691
684
  wireweave_ux_rules: { method: "GET", path: "/tools/ux-rules" },
692
685
  wireweave_diff: { method: "POST", path: "/tools/diff" },
686
+ wireweave_export_json: { method: "POST", path: "/tools/export/json" },
687
+ wireweave_export_figma: { method: "POST", path: "/tools/export/figma" },
693
688
  wireweave_analyze: { method: "POST", path: "/tools/analyze" },
694
689
  wireweave_cloud_list_projects: { method: "GET", path: "/cloud/projects" },
695
690
  wireweave_cloud_create_project: { method: "POST", path: "/cloud/projects" },
696
- wireweave_cloud_update_project: { method: "PATCH", path: "/cloud/projects/:id", pathParams: ["id"] },
691
+ wireweave_cloud_update_project: {
692
+ method: "PATCH",
693
+ path: "/cloud/projects/:id",
694
+ pathParams: ["id"]
695
+ },
697
696
  wireweave_cloud_list_wireframes: { method: "GET", path: "/cloud/wireframes" },
698
- wireweave_cloud_get_wireframe: { method: "GET", path: "/cloud/wireframes/:id", pathParams: ["id"] },
697
+ wireweave_cloud_get_wireframe: {
698
+ method: "GET",
699
+ path: "/cloud/wireframes/:id",
700
+ pathParams: ["id"]
701
+ },
699
702
  wireweave_cloud_save_wireframe: { method: "POST", path: "/cloud/wireframes" },
700
- wireweave_cloud_update_wireframe: { method: "PATCH", path: "/cloud/wireframes/:id", pathParams: ["id"] },
701
- wireweave_cloud_delete_wireframe: { method: "DELETE", path: "/cloud/wireframes/:id", pathParams: ["id"] },
702
- wireweave_cloud_get_versions: { method: "GET", path: "/cloud/wireframes/:wireframeId/versions", pathParams: ["wireframeId"] },
703
- wireweave_cloud_restore_version: { method: "POST", path: "/cloud/wireframes/:wireframeId/versions/:version/restore", pathParams: ["wireframeId", "version"] },
704
- wireweave_cloud_create_share_link: { method: "POST", path: "/cloud/wireframes/:wireframeId/shares", pathParams: ["wireframeId"] },
705
- wireweave_cloud_list_shares: { method: "GET", path: "/cloud/wireframes/:wireframeId/shares", pathParams: ["wireframeId"] },
706
- wireweave_cloud_diff_versions: { method: "GET", path: "/cloud/wireframes/:wireframeId/diff", pathParams: ["wireframeId"] },
703
+ wireweave_cloud_update_wireframe: {
704
+ method: "PATCH",
705
+ path: "/cloud/wireframes/:id",
706
+ pathParams: ["id"]
707
+ },
708
+ wireweave_cloud_delete_wireframe: {
709
+ method: "DELETE",
710
+ path: "/cloud/wireframes/:id",
711
+ pathParams: ["id"]
712
+ },
713
+ wireweave_cloud_get_versions: {
714
+ method: "GET",
715
+ path: "/cloud/wireframes/:wireframeId/versions",
716
+ pathParams: ["wireframeId"]
717
+ },
718
+ wireweave_cloud_restore_version: {
719
+ method: "POST",
720
+ path: "/cloud/wireframes/:wireframeId/versions/:version/restore",
721
+ pathParams: ["wireframeId", "version"]
722
+ },
723
+ wireweave_cloud_create_share_link: {
724
+ method: "POST",
725
+ path: "/cloud/wireframes/:wireframeId/shares",
726
+ pathParams: ["wireframeId"]
727
+ },
728
+ wireweave_cloud_list_shares: {
729
+ method: "GET",
730
+ path: "/cloud/wireframes/:wireframeId/shares",
731
+ pathParams: ["wireframeId"]
732
+ },
733
+ wireweave_cloud_diff_versions: {
734
+ method: "GET",
735
+ path: "/cloud/wireframes/:wireframeId/diff",
736
+ pathParams: ["wireframeId"]
737
+ },
707
738
  wireweave_account_balance: { method: "GET", path: "/billing/balance" },
708
739
  wireweave_account_subscription: { method: "GET", path: "/billing/subscription" },
709
740
  wireweave_account_transactions: { method: "GET", path: "/billing/transactions" },
710
741
  wireweave_pricing: { method: "GET", path: "/billing/pricing" },
711
742
  wireweave_gallery: { method: "GET", path: "/cloud/gallery" }
712
743
  };
744
+ var localToolNames = /* @__PURE__ */ new Set([
745
+ "wireweave_parse",
746
+ "wireweave_validate",
747
+ "wireweave_list_components",
748
+ "wireweave_render_html_code",
749
+ "wireweave_validate_ux",
750
+ "wireweave_diff",
751
+ "wireweave_export_json",
752
+ "wireweave_export_figma",
753
+ "wireweave_analyze"
754
+ ]);
713
755
 
714
756
  // src/prompts.ts
715
757
  var prompts = [
716
- {
717
- name: "create_wireframe",
718
- description: "Create a new wireframe from a natural language description. Generates Wireweave DSL code.",
719
- arguments: [
720
- {
721
- name: "description",
722
- description: 'Description of the wireframe to create (e.g., "dashboard with sidebar nav and a stats card row")',
723
- required: true
724
- }
725
- ]
726
- },
727
758
  {
728
759
  name: "improve_ux",
729
760
  description: "Analyze existing wireframe code and suggest UX improvements based on best practices.",
@@ -750,27 +781,38 @@ var prompts = [
750
781
  required: false
751
782
  }
752
783
  ]
784
+ },
785
+ {
786
+ name: "create_wireframe",
787
+ description: "Create a new wireframe from a natural language description. Generates Wireweave DSL code.",
788
+ arguments: [
789
+ {
790
+ name: "description",
791
+ description: 'Description of the wireframe to create (e.g., "dashboard with sidebar nav and a stats card row")',
792
+ required: true
793
+ }
794
+ ]
753
795
  }
754
796
  ];
755
797
  var promptTemplates = {
756
- "create_wireframe": `Create a Wireweave DSL wireframe for: {{description}}
757
-
758
- Please use the wireweave_guide tool first to understand the DSL syntax, then generate valid Wireweave code.
759
- After generating, use wireweave_validate to check the syntax and wireweave_validate_ux to check UX best practices.`,
760
- "improve_ux": `Analyze and improve the UX of this Wireweave wireframe:
798
+ improve_ux: `Analyze and improve the UX of this Wireweave wireframe:
761
799
 
762
800
  \`\`\`wireframe
763
801
  {{code}}
764
802
  \`\`\`
765
803
 
766
804
  Please use wireweave_validate_ux to get specific recommendations, then suggest improvements.`,
767
- "convert_to_wireframe": `Convert this UI description to Wireweave DSL code:
805
+ convert_to_wireframe: `Convert this UI description to Wireweave DSL code:
768
806
 
769
807
  {{ui_description}}
770
808
 
771
809
  Style preference: {{style}}
772
810
 
773
- Use wireweave_guide for syntax reference and wireweave_patterns for common layouts.`
811
+ Use wireweave_guide for syntax reference and wireweave_patterns for common layouts.`,
812
+ create_wireframe: `Create a Wireweave DSL wireframe for: {{description}}
813
+
814
+ Please use the wireweave_guide tool first to understand the DSL syntax, then generate valid Wireweave code.
815
+ After generating, use wireweave_validate to check the syntax and wireweave_validate_ux to check UX best practices.`
774
816
  };
775
817
 
776
818
  // src/resources.ts
@@ -814,231 +856,80 @@ var resourceToTool = {
814
856
  "wireweave://ux-rules": "wireweave_ux_rules"
815
857
  };
816
858
 
817
- // src/api.ts
818
- function buildRequest(config, endpoint, args) {
819
- let path2 = endpoint.path;
820
- const body = { ...args };
821
- if (endpoint.pathParams && args) {
822
- for (const param of endpoint.pathParams) {
823
- const value = args[param];
824
- if (value !== void 0) {
825
- path2 = path2.replace(`:${param}`, String(value));
826
- delete body[param];
827
- }
828
- }
829
- }
830
- let url = `${config.apiUrl}${path2}`;
831
- const options = {
832
- method: endpoint.method,
833
- headers: {
834
- "Content-Type": "application/json",
835
- "x-api-key": config.apiKey
836
- }
859
+ // src/handlers.ts
860
+ import { dispatch } from "@wireweave/sdk";
861
+ function dispatchOptions(ctx) {
862
+ return {
863
+ apiConfig: ctx.apiConfig,
864
+ endpoints: ctx.endpoints,
865
+ fetchFn: ctx.fetchFn
837
866
  };
838
- if (["POST", "PATCH", "PUT"].includes(endpoint.method) && Object.keys(body).length > 0) {
839
- options.body = JSON.stringify(body);
840
- } else if (endpoint.method === "GET" && Object.keys(body).length > 0) {
841
- const params = new URLSearchParams();
842
- for (const [key, value] of Object.entries(body)) {
843
- if (value !== void 0 && value !== null) {
844
- if (Array.isArray(value)) {
845
- params.append(key, value.join(","));
846
- } else {
847
- params.append(key, String(value));
848
- }
849
- }
850
- }
851
- url = `${url}?${params.toString()}`;
852
- }
853
- return { url, options, bodyForGet: body };
854
867
  }
855
- function parseErrorMessage(status, error) {
856
- if (status === 401) return "Invalid API key. Get one at https://wireweave.org";
857
- if (status === 402) return `Insufficient credits. ${error.message || "Please add more credits."}`;
858
- if (status === 403) return "Access denied. Upgrade your plan for this feature.";
859
- if (status === 404 && error.error?.includes("project")) {
860
- return "Project not found. Call wireweave_cloud_list_projects to see available projects.";
861
- }
862
- if (status === 400 && error.error?.includes("name")) {
863
- return "Invalid wireframe name. Provide a non-empty name for the wireframe.";
864
- }
865
- if (status === 429) return "Rate limit exceeded. Please wait and try again.";
866
- if (status >= 500) return "Service temporarily unavailable";
867
- return error.error || error.message || "Request failed";
868
+ function handleListTools() {
869
+ return { tools };
868
870
  }
869
- function extractCreditInfo(headers) {
870
- return {
871
- balance: headers.get("X-Credits-Balance") ? parseInt(headers.get("X-Credits-Balance"), 10) : void 0,
872
- monthlyRemaining: headers.get("X-Credits-Monthly-Remaining") ? parseInt(headers.get("X-Credits-Monthly-Remaining"), 10) : void 0,
873
- totalAvailable: headers.get("X-Credits-Total-Available") ? parseInt(headers.get("X-Credits-Total-Available"), 10) : void 0
874
- };
871
+ async function handleCallTool(name, args, ctx) {
872
+ return dispatch(name, args ?? {}, dispatchOptions(ctx));
875
873
  }
876
- async function callApi(config, endpoint, args, fetchFn = fetch) {
877
- if (!config.apiKey) {
878
- throw new Error("WIREWEAVE_API_KEY environment variable is required");
879
- }
880
- const { url, options } = buildRequest(config, endpoint, args);
881
- const response = await fetchFn(url, options);
882
- const creditInfo = extractCreditInfo(response.headers);
883
- if (!response.ok) {
884
- const error = await response.json().catch(() => ({ error: "Request failed" }));
885
- const userMessage = parseErrorMessage(response.status, error);
886
- throw new Error(userMessage);
874
+ function handleListPrompts() {
875
+ return { prompts };
876
+ }
877
+ function handleGetPrompt(name, args) {
878
+ const prompt = prompts.find((p) => p.name === name);
879
+ if (!prompt) {
880
+ throw new Error(`Prompt not found: ${name}`);
887
881
  }
888
- const result = await response.json();
889
- if (creditInfo.balance !== void 0 || creditInfo.totalAvailable !== void 0) {
890
- return {
891
- ...result,
892
- _credits: creditInfo
893
- };
882
+ const template = promptTemplates[name];
883
+ if (!template) {
884
+ throw new Error(`Prompt template not found: ${name}`);
894
885
  }
895
- return result;
896
- }
897
-
898
- // src/local-tools.ts
899
- import * as fs from "fs";
900
- import * as path from "path";
901
- import * as os from "os";
902
- var localTools = [
903
- {
904
- name: "wireweave_render_html_file",
905
- description: "Render Wireweave DSL to HTML and save to a local file. Returns the file path. Use this when you need a persistent HTML file for preview or browser viewing. Credits are charged via internal API call.",
906
- inputSchema: {
907
- type: "object",
908
- properties: {
909
- source: {
910
- type: "string",
911
- description: "The Wireweave DSL source code to render"
912
- },
913
- theme: {
914
- type: "string",
915
- enum: ["light", "dark"],
916
- description: "Color theme for rendering",
917
- default: "light"
918
- },
919
- outputDir: {
920
- type: "string",
921
- description: "Output directory for the HTML file. Defaults to system temp directory."
922
- },
923
- filename: {
924
- type: "string",
925
- description: "Custom filename without extension. Defaults to wireframe-{timestamp}."
926
- }
927
- },
928
- required: ["source"]
886
+ let messageText = template;
887
+ if (args) {
888
+ for (const [key, value] of Object.entries(args)) {
889
+ messageText = messageText.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), String(value));
929
890
  }
930
891
  }
931
- ];
932
- var LOCAL_TOOL_NAMES = new Set(localTools.map((t) => t.name));
933
- async function handleLocalTool(name, args, apiConfig2) {
934
- switch (name) {
935
- case "wireweave_render_html_file":
936
- return handleRenderHtmlFile(args, apiConfig2);
937
- default:
938
- return {
939
- content: [
940
- {
941
- type: "text",
942
- text: JSON.stringify({ error: `Unknown local tool: ${name}` }, null, 2)
943
- }
944
- ],
945
- isError: true
946
- };
947
- }
948
- }
949
- async function handleRenderHtmlFile(args, apiConfig2) {
950
- const { source, theme = "light", outputDir, filename } = args;
951
- if (!source || typeof source !== "string") {
952
- return {
953
- content: [
954
- {
892
+ messageText = messageText.replace(/\{\{[^}]+\}\}/g, "");
893
+ return {
894
+ description: prompt.description,
895
+ messages: [
896
+ {
897
+ role: "user",
898
+ content: {
955
899
  type: "text",
956
- text: JSON.stringify({ error: "source is required" }, null, 2)
900
+ text: messageText
957
901
  }
958
- ],
959
- isError: true
960
- };
902
+ }
903
+ ]
904
+ };
905
+ }
906
+ function handleListResources() {
907
+ return { resources };
908
+ }
909
+ async function handleReadResource(uri, ctx) {
910
+ const resource = resources.find((r) => r.uri === uri);
911
+ if (!resource) {
912
+ throw new Error(`Resource not found: ${uri}`);
961
913
  }
962
- try {
963
- const endpoint = toolEndpoints["wireweave_render_html_code"];
964
- if (!endpoint) {
965
- return {
966
- content: [
967
- {
968
- type: "text",
969
- text: JSON.stringify(
970
- { error: "wireweave_render_html_code endpoint not found" },
971
- null,
972
- 2
973
- )
974
- }
975
- ],
976
- isError: true
977
- };
978
- }
979
- const result = await callApi(apiConfig2, endpoint, {
980
- source,
981
- theme,
982
- fullDocument: true
983
- // Always request full document for file output
984
- });
985
- if (!result.success || !result.html) {
986
- return {
987
- content: [
988
- {
989
- type: "text",
990
- text: JSON.stringify(
991
- { error: result.error || "No HTML content returned from API" },
992
- null,
993
- 2
994
- )
995
- }
996
- ],
997
- isError: true
998
- };
999
- }
1000
- const dir = typeof outputDir === "string" ? outputDir : os.tmpdir();
1001
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1002
- const fname = typeof filename === "string" ? filename : `wireframe-${timestamp}`;
1003
- const filePath = path.join(dir, `${fname}.html`);
1004
- let htmlContent = result.html;
1005
- if (result.css && !htmlContent.includes("<style>")) {
1006
- htmlContent = htmlContent.replace("</head>", `<style>${result.css}</style></head>`);
1007
- }
1008
- fs.writeFileSync(filePath, htmlContent, "utf-8");
1009
- return {
1010
- content: [
1011
- {
1012
- type: "text",
1013
- text: JSON.stringify(
1014
- {
1015
- success: true,
1016
- filePath,
1017
- message: `HTML file saved to: ${filePath}`
1018
- },
1019
- null,
1020
- 2
1021
- )
1022
- }
1023
- ]
1024
- };
1025
- } catch (error) {
1026
- return {
1027
- content: [
1028
- {
1029
- type: "text",
1030
- text: JSON.stringify(
1031
- {
1032
- error: error instanceof Error ? error.message : "Failed to render HTML file"
1033
- },
1034
- null,
1035
- 2
1036
- )
1037
- }
1038
- ],
1039
- isError: true
1040
- };
914
+ const toolName = resourceToTool[uri];
915
+ if (!toolName) {
916
+ throw new Error(`No tool mapping for resource: ${uri}`);
917
+ }
918
+ const result = await dispatch(toolName, {}, dispatchOptions(ctx));
919
+ if (result.isError) {
920
+ const message = result.content[0]?.text ?? "Unknown error";
921
+ throw new Error(`Failed to fetch resource: ${message}`);
1041
922
  }
923
+ const text = result.content[0]?.text ?? "";
924
+ return {
925
+ contents: [
926
+ {
927
+ uri,
928
+ mimeType: resource.mimeType,
929
+ text
930
+ }
931
+ ]
932
+ };
1042
933
  }
1043
934
 
1044
935
  // src/index.ts
@@ -1048,13 +939,22 @@ var apiConfig = {
1048
939
  apiUrl: API_URL,
1049
940
  apiKey: API_KEY
1050
941
  };
942
+ var handlerContext = {
943
+ apiConfig,
944
+ endpoints: toolEndpoints
945
+ };
1051
946
  var isHttpMode = process.argv.includes("--http") || process.env.WIREWEAVE_TRANSPORT === "http";
1052
947
  var HTTP_PORT = parseInt(process.env.WIREWEAVE_MCP_PORT || "3305", 10);
1053
948
  var HTTP_HOST = process.env.WIREWEAVE_MCP_HOST || "127.0.0.1";
1054
949
  function log(message, level = "info") {
1055
950
  const prefix = level === "error" ? "\u274C" : level === "warn" ? "\u26A0\uFE0F" : "\u2713";
1056
- const output = isHttpMode ? console.log : console.error;
1057
- output(`[Wireweave] ${prefix} ${message}`);
951
+ const line = `[Wireweave] ${prefix} ${message}
952
+ `;
953
+ if (isHttpMode) {
954
+ process.stdout.write(line);
955
+ } else {
956
+ process.stderr.write(line);
957
+ }
1058
958
  }
1059
959
  function createMcpServer() {
1060
960
  const server = new Server(
@@ -1070,119 +970,20 @@ function createMcpServer() {
1070
970
  }
1071
971
  }
1072
972
  );
1073
- server.setRequestHandler(ListToolsRequestSchema, async () => {
1074
- return { tools: [...tools, ...localTools] };
1075
- });
973
+ server.setRequestHandler(ListToolsRequestSchema, () => handleListTools());
1076
974
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
1077
975
  const { name, arguments: args } = request.params;
1078
- if (LOCAL_TOOL_NAMES.has(name)) {
1079
- return handleLocalTool(name, args, apiConfig);
1080
- }
1081
- const endpoint = toolEndpoints[name];
1082
- if (!endpoint) {
1083
- const allTools = [...tools, ...localTools];
1084
- return {
1085
- content: [
1086
- {
1087
- type: "text",
1088
- text: JSON.stringify({
1089
- error: `Unknown tool: ${name}`,
1090
- availableTools: allTools.map((t) => t.name)
1091
- }, null, 2)
1092
- }
1093
- ],
1094
- isError: true
1095
- };
1096
- }
1097
- try {
1098
- const result = await callApi(apiConfig, endpoint, args);
1099
- return {
1100
- content: [
1101
- {
1102
- type: "text",
1103
- text: JSON.stringify(result, null, 2)
1104
- }
1105
- ]
1106
- };
1107
- } catch (error) {
1108
- return {
1109
- content: [
1110
- {
1111
- type: "text",
1112
- text: JSON.stringify({
1113
- error: error instanceof Error ? error.message : "Unknown error"
1114
- }, null, 2)
1115
- }
1116
- ],
1117
- isError: true
1118
- };
1119
- }
976
+ return handleCallTool(name, args, handlerContext);
1120
977
  });
1121
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
1122
- return { prompts };
1123
- });
1124
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
978
+ server.setRequestHandler(ListPromptsRequestSchema, () => handleListPrompts());
979
+ server.setRequestHandler(GetPromptRequestSchema, (request) => {
1125
980
  const { name, arguments: args } = request.params;
1126
- const prompt = prompts.find((p) => p.name === name);
1127
- if (!prompt) {
1128
- throw new Error(`Prompt not found: ${name}`);
1129
- }
1130
- const template = promptTemplates[name];
1131
- if (!template) {
1132
- throw new Error(`Prompt template not found: ${name}`);
1133
- }
1134
- let messageText = template;
1135
- if (args) {
1136
- for (const [key, value] of Object.entries(args)) {
1137
- messageText = messageText.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), String(value));
1138
- }
1139
- }
1140
- messageText = messageText.replace(/\{\{[^}]+\}\}/g, "");
1141
- return {
1142
- description: prompt.description,
1143
- messages: [
1144
- {
1145
- role: "user",
1146
- content: {
1147
- type: "text",
1148
- text: messageText
1149
- }
1150
- }
1151
- ]
1152
- };
1153
- });
1154
- server.setRequestHandler(ListResourcesRequestSchema, async () => {
1155
- return { resources };
981
+ return handleGetPrompt(name, args);
1156
982
  });
983
+ server.setRequestHandler(ListResourcesRequestSchema, () => handleListResources());
1157
984
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1158
985
  const { uri } = request.params;
1159
- const resource = resources.find((r) => r.uri === uri);
1160
- if (!resource) {
1161
- throw new Error(`Resource not found: ${uri}`);
1162
- }
1163
- const toolName = resourceToTool[uri];
1164
- if (!toolName) {
1165
- throw new Error(`No tool mapping for resource: ${uri}`);
1166
- }
1167
- const endpoint = toolEndpoints[toolName];
1168
- if (!endpoint) {
1169
- throw new Error(`Tool endpoint not found: ${toolName}`);
1170
- }
1171
- try {
1172
- const result = await callApi(apiConfig, endpoint, {});
1173
- const content = typeof result === "string" ? result : JSON.stringify(result, null, 2);
1174
- return {
1175
- contents: [
1176
- {
1177
- uri,
1178
- mimeType: resource.mimeType,
1179
- text: content
1180
- }
1181
- ]
1182
- };
1183
- } catch (error) {
1184
- throw new Error(`Failed to fetch resource: ${error instanceof Error ? error.message : "Unknown error"}`);
1185
- }
986
+ return handleReadResource(uri, handlerContext);
1186
987
  });
1187
988
  server.onerror = () => {
1188
989
  log("An error occurred", "error");
@@ -1193,91 +994,109 @@ async function startStdio() {
1193
994
  const server = createMcpServer();
1194
995
  const transport = new StdioServerTransport();
1195
996
  await server.connect(transport);
1196
- process.on("SIGINT", async () => {
1197
- await server.close();
1198
- process.exit(0);
997
+ process.on("SIGINT", () => {
998
+ void (async () => {
999
+ await server.close();
1000
+ process.exit(0);
1001
+ })();
1199
1002
  });
1200
- log(`MCP server started (stdio) with ${tools.length + localTools.length} tools (${localTools.length} local), ${prompts.length} prompts, ${resources.length} resources`);
1003
+ log(
1004
+ `MCP server started (stdio) with ${tools.length} tools (${localToolNames.size} local + ${tools.length - localToolNames.size} server), ${prompts.length} prompts, ${resources.length} resources`
1005
+ );
1201
1006
  if (!API_KEY) {
1202
1007
  log("API key not configured. Get one at https://wireweave.org", "warn");
1203
1008
  }
1204
1009
  }
1205
- async function startHttp() {
1010
+ function startHttp() {
1206
1011
  const transports = /* @__PURE__ */ new Map();
1207
- const httpServer = createServer(async (req, res) => {
1208
- const url = new URL(req.url || "/", `http://${req.headers.host}`);
1209
- if (url.pathname !== "/mcp") {
1210
- if (url.pathname === "/health") {
1211
- res.writeHead(200, { "Content-Type": "application/json" });
1212
- res.end(JSON.stringify({
1213
- status: "ok",
1214
- transport: "streamable-http",
1215
- activeSessions: transports.size,
1216
- tools: tools.length + localTools.length
1217
- }));
1012
+ const httpServer = createServer((req, res) => {
1013
+ void (async () => {
1014
+ const url = new URL(req.url || "/", `http://${req.headers.host}`);
1015
+ if (url.pathname !== "/mcp") {
1016
+ if (url.pathname === "/health") {
1017
+ res.writeHead(200, { "Content-Type": "application/json" });
1018
+ res.end(
1019
+ JSON.stringify({
1020
+ status: "ok",
1021
+ transport: "streamable-http",
1022
+ activeSessions: transports.size,
1023
+ tools: tools.length
1024
+ })
1025
+ );
1026
+ return;
1027
+ }
1028
+ res.writeHead(404, { "Content-Type": "application/json" });
1029
+ res.end(JSON.stringify({ error: "Not found. Use /mcp for MCP protocol." }));
1218
1030
  return;
1219
1031
  }
1220
- res.writeHead(404, { "Content-Type": "application/json" });
1221
- res.end(JSON.stringify({ error: "Not found. Use /mcp for MCP protocol." }));
1222
- return;
1223
- }
1224
- const sessionId = req.headers["mcp-session-id"];
1225
- if (sessionId && transports.has(sessionId)) {
1226
- const existing = transports.get(sessionId);
1227
- await existing.transport.handleRequest(req, res);
1228
- return;
1229
- }
1230
- if (req.method === "DELETE") {
1231
- res.writeHead(404);
1232
- res.end();
1233
- return;
1234
- }
1235
- if (req.method !== "POST") {
1236
- res.writeHead(400, { "Content-Type": "application/json" });
1237
- res.end(JSON.stringify({ error: "Session required. Send an initialization POST first." }));
1238
- return;
1239
- }
1240
- const MAX_SESSIONS = parseInt(process.env.WIREWEAVE_MCP_MAX_SESSIONS || "10", 10);
1241
- if (transports.size >= MAX_SESSIONS) {
1242
- res.writeHead(503, { "Content-Type": "application/json" });
1243
- res.end(JSON.stringify({ error: "Too many active sessions" }));
1244
- return;
1245
- }
1246
- const server = createMcpServer();
1247
- const transport = new StreamableHTTPServerTransport({
1248
- sessionIdGenerator: () => randomUUID(),
1249
- onsessioninitialized: (sessionId2) => {
1250
- transports.set(sessionId2, { server, transport });
1251
- log(`New session: ${sessionId2}`);
1032
+ const sessionId = req.headers["mcp-session-id"];
1033
+ if (sessionId && transports.has(sessionId)) {
1034
+ const existing = transports.get(sessionId);
1035
+ await existing.transport.handleRequest(req, res);
1036
+ return;
1252
1037
  }
1253
- });
1254
- transport.onclose = () => {
1255
- if (transport.sessionId) {
1256
- transports.delete(transport.sessionId);
1257
- log(`Session closed: ${transport.sessionId}`);
1038
+ if (req.method === "DELETE") {
1039
+ res.writeHead(404);
1040
+ res.end();
1041
+ return;
1042
+ }
1043
+ if (req.method !== "POST") {
1044
+ res.writeHead(400, { "Content-Type": "application/json" });
1045
+ res.end(JSON.stringify({ error: "Session required. Send an initialization POST first." }));
1046
+ return;
1047
+ }
1048
+ const MAX_SESSIONS = parseInt(process.env.WIREWEAVE_MCP_MAX_SESSIONS || "10", 10);
1049
+ if (transports.size >= MAX_SESSIONS) {
1050
+ res.writeHead(503, { "Content-Type": "application/json" });
1051
+ res.end(JSON.stringify({ error: "Too many active sessions" }));
1052
+ return;
1258
1053
  }
1259
- };
1260
- await server.connect(transport);
1261
- await transport.handleRequest(req, res);
1054
+ const server = createMcpServer();
1055
+ const transport = new StreamableHTTPServerTransport({
1056
+ sessionIdGenerator: () => randomUUID(),
1057
+ onsessioninitialized: (sessionId2) => {
1058
+ transports.set(sessionId2, { server, transport });
1059
+ log(`New session: ${sessionId2}`);
1060
+ }
1061
+ });
1062
+ transport.onclose = () => {
1063
+ if (transport.sessionId) {
1064
+ transports.delete(transport.sessionId);
1065
+ log(`Session closed: ${transport.sessionId}`);
1066
+ }
1067
+ };
1068
+ await server.connect(transport);
1069
+ await transport.handleRequest(req, res);
1070
+ })();
1262
1071
  });
1263
1072
  httpServer.listen(HTTP_PORT, HTTP_HOST, () => {
1264
1073
  log(`MCP server started (streamable-http) at http://${HTTP_HOST}:${HTTP_PORT}/mcp`);
1265
1074
  log(`Health check: http://${HTTP_HOST}:${HTTP_PORT}/health`);
1266
- log(`${tools.length + localTools.length} tools (${localTools.length} local), ${prompts.length} prompts, ${resources.length} resources`);
1075
+ log(
1076
+ `${tools.length} tools (${localToolNames.size} local + ${tools.length - localToolNames.size} server), ${prompts.length} prompts, ${resources.length} resources`
1077
+ );
1267
1078
  if (!API_KEY) {
1268
1079
  log("API key not configured. Get one at https://wireweave.org", "warn");
1269
1080
  }
1270
1081
  });
1271
- process.on("SIGINT", async () => {
1272
- log("Shutting down...");
1273
- for (const [, { server }] of transports) {
1274
- await server.close();
1275
- }
1276
- httpServer.close();
1277
- process.exit(0);
1082
+ process.on("SIGINT", () => {
1083
+ void (async () => {
1084
+ log("Shutting down...");
1085
+ for (const [, { server }] of transports) {
1086
+ await server.close();
1087
+ }
1088
+ httpServer.close();
1089
+ process.exit(0);
1090
+ })();
1278
1091
  });
1279
1092
  }
1280
- var main = isHttpMode ? startHttp : startStdio;
1093
+ async function main() {
1094
+ if (isHttpMode) {
1095
+ startHttp();
1096
+ } else {
1097
+ await startStdio();
1098
+ }
1099
+ }
1281
1100
  main().catch(() => {
1282
1101
  log("Failed to start server", "error");
1283
1102
  process.exit(1);