@netpad/mcp-server 2.4.3 → 2.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -21826,6 +21826,21 @@ function formatToolOutput(output) {
21826
21826
  }
21827
21827
 
21828
21828
  // src/index.ts
21829
+ import {
21830
+ UI_RESOURCES
21831
+ } from "@netpad/mcp-apps";
21832
+ function withUIResource(textContent, resourceId, data) {
21833
+ const resource = UI_RESOURCES[resourceId];
21834
+ return {
21835
+ content: [{ type: "text", text: textContent }],
21836
+ _meta: {
21837
+ ui: {
21838
+ resourceUri: resource.uri,
21839
+ data
21840
+ }
21841
+ }
21842
+ };
21843
+ }
21829
21844
  function createNetPadMcpServer(options) {
21830
21845
  const server = new McpServer({
21831
21846
  name: options?.name ?? "@netpad/mcp-server",
@@ -22204,14 +22219,26 @@ This will open NetPad where you can:
22204
22219
  If you prefer to work with code, here's the complete TypeScript implementation:
22205
22220
 
22206
22221
  ${formatToolOutput(output)}`;
22207
- return {
22208
- content: [
22209
- {
22210
- type: "text",
22211
- text: outputWithImport
22212
- }
22213
- ]
22222
+ const formPreviewData = {
22223
+ form: {
22224
+ name: schema.name,
22225
+ description: schema.description,
22226
+ fields: (schema.fieldConfigs || []).map((f) => ({
22227
+ id: f.path,
22228
+ type: f.type,
22229
+ label: f.label,
22230
+ placeholder: f.placeholder,
22231
+ required: f.required,
22232
+ options: f.options
22233
+ })),
22234
+ theme: schema.theme,
22235
+ multiPage: schema.multiPage
22236
+ },
22237
+ theme: "dark",
22238
+ mode: "traditional",
22239
+ readonly: true
22214
22240
  };
22241
+ return withUIResource(outputWithImport, "form-preview", formPreviewData);
22215
22242
  }
22216
22243
  );
22217
22244
  server.tool(
@@ -22650,17 +22677,27 @@ Available topics: ${Object.keys(docs).join(", ")}`
22650
22677
  fieldCount: t.fields.length,
22651
22678
  hasMultiPage: !!t.multiPage?.enabled
22652
22679
  }));
22653
- return {
22654
- content: [{
22655
- type: "text",
22656
- text: JSON.stringify({
22657
- templateType: "form",
22658
- templates: summary,
22659
- total: summary.length,
22660
- categories: [...new Set(templates.map((t) => t.category))]
22661
- }, null, 2)
22662
- }]
22680
+ const textResponse = JSON.stringify({
22681
+ templateType: "form",
22682
+ templates: summary,
22683
+ total: summary.length,
22684
+ categories: [...new Set(templates.map((t) => t.category))]
22685
+ }, null, 2);
22686
+ const galleryItems = templates.map((t) => ({
22687
+ id: t.id,
22688
+ name: t.name,
22689
+ description: t.description,
22690
+ category: t.category,
22691
+ tags: t.tags,
22692
+ icon: t.icon || "\u{1F4DD}"
22693
+ }));
22694
+ const galleryData = {
22695
+ templates: galleryItems,
22696
+ templateType: "form",
22697
+ theme: "dark",
22698
+ showCategories: true
22663
22699
  };
22700
+ return withUIResource(textResponse, "template-gallery", galleryData);
22664
22701
  }
22665
22702
  case "application": {
22666
22703
  if (action === "categories") {
@@ -22748,7 +22785,33 @@ Available topics: ${Object.keys(docs).join(", ")}`
22748
22785
  edges: template.edges
22749
22786
  }
22750
22787
  };
22751
- return { content: [{ type: "text", text: JSON.stringify(workflowForUI, null, 2) }] };
22788
+ const uiData = {
22789
+ workflow: {
22790
+ nodes: template.nodes.map((n) => ({
22791
+ id: n.id,
22792
+ type: n.type,
22793
+ position: n.position,
22794
+ data: { label: n.label || n.type, ...n.config }
22795
+ })),
22796
+ edges: template.edges.map((e) => ({
22797
+ id: e.id,
22798
+ source: e.source,
22799
+ target: e.target,
22800
+ sourceHandle: e.sourceHandle,
22801
+ targetHandle: e.targetHandle,
22802
+ label: e.condition?.label
22803
+ }))
22804
+ },
22805
+ theme: "dark",
22806
+ fitView: true,
22807
+ showMinimap: true,
22808
+ autoLayout: true
22809
+ };
22810
+ return withUIResource(
22811
+ JSON.stringify(workflowForUI, null, 2),
22812
+ "workflow-viewer",
22813
+ uiData
22814
+ );
22752
22815
  }
22753
22816
  let templates = Object.values(WORKFLOW_TEMPLATES);
22754
22817
  if (category) {
@@ -22759,17 +22822,27 @@ Available topics: ${Object.keys(docs).join(", ")}`
22759
22822
  nodesCount: t.nodes.length,
22760
22823
  edgesCount: t.edges.length
22761
22824
  }));
22762
- return {
22763
- content: [{
22764
- type: "text",
22765
- text: JSON.stringify({
22766
- templateType: "workflow",
22767
- templates: summary,
22768
- total: summary.length,
22769
- categories: [...new Set(Object.values(WORKFLOW_TEMPLATES).map((t) => t.category))]
22770
- }, null, 2)
22771
- }]
22825
+ const textResponse = JSON.stringify({
22826
+ templateType: "workflow",
22827
+ templates: summary,
22828
+ total: summary.length,
22829
+ categories: [...new Set(Object.values(WORKFLOW_TEMPLATES).map((t) => t.category))]
22830
+ }, null, 2);
22831
+ const galleryItems = templates.map((t) => ({
22832
+ id: t.id,
22833
+ name: t.name,
22834
+ description: t.description,
22835
+ category: t.category,
22836
+ tags: t.tags,
22837
+ icon: "\u26A1"
22838
+ }));
22839
+ const galleryData = {
22840
+ templates: galleryItems,
22841
+ templateType: "workflow",
22842
+ theme: "dark",
22843
+ showCategories: true
22772
22844
  };
22845
+ return withUIResource(textResponse, "template-gallery", galleryData);
22773
22846
  }
22774
22847
  case "conversational": {
22775
22848
  if (action === "categories") {
@@ -26290,6 +26363,249 @@ You can use any valid hex color.`
26290
26363
  };
26291
26364
  }
26292
26365
  );
26366
+ server.tool(
26367
+ "import_google_form",
26368
+ `Import a Google Form into NetPad. This tool generates the API call and mapping preview for importing a Google Form.
26369
+
26370
+ IMPORTANT: Before using this tool, the user must have:
26371
+ 1. Connected their Google account via the NetPad UI (Settings > Integrations > Google Forms)
26372
+ 2. Obtained a credentialId for their Google Forms connection
26373
+
26374
+ The tool returns:
26375
+ - Instructions for completing the import via the NetPad API
26376
+ - A preview of how the Google Form fields will be mapped to NetPad field types
26377
+ - Any warnings about fields that may need manual adjustment`,
26378
+ {
26379
+ formId: external_exports.string().describe("The Google Form ID to import. Can be found in the form URL: https://docs.google.com/forms/d/{FORM_ID}/edit"),
26380
+ organizationId: external_exports.string().describe("The NetPad organization ID"),
26381
+ projectId: external_exports.string().describe("The NetPad project ID where the form will be created"),
26382
+ credentialId: external_exports.string().optional().describe("The credential ID for the Google Forms connection. If not provided, the user must set it up via the UI first."),
26383
+ preview: external_exports.boolean().optional().describe("If true, only return the mapping preview without creating the form (default: true)")
26384
+ },
26385
+ async ({ formId, organizationId, projectId, credentialId, preview = true }) => {
26386
+ const baseUrl = "https://netpad.io";
26387
+ const fieldTypeMapping = `
26388
+ ## Google Forms to NetPad Field Type Mapping
26389
+
26390
+ | Google Forms Type | NetPad Type | Confidence |
26391
+ |-------------------|-------------|------------|
26392
+ | SHORT_ANSWER | short_text | Exact |
26393
+ | PARAGRAPH_TEXT | long_text | Exact |
26394
+ | MULTIPLE_CHOICE | radio | Exact |
26395
+ | CHECKBOXES | checkbox_group | Exact |
26396
+ | DROPDOWN | dropdown | Exact |
26397
+ | LINEAR_SCALE | rating | Exact |
26398
+ | MULTIPLE_CHOICE_GRID | matrix | Approximate |
26399
+ | CHECKBOX_GRID | matrix | Approximate |
26400
+ | DATE | date | Exact |
26401
+ | TIME | time | Exact |
26402
+ | FILE_UPLOAD | file | Exact |
26403
+ `;
26404
+ if (!credentialId) {
26405
+ return {
26406
+ content: [{
26407
+ type: "text",
26408
+ text: `# Google Forms Import
26409
+
26410
+ ## Setup Required
26411
+
26412
+ Before importing Google Forms, you need to connect your Google account:
26413
+
26414
+ 1. Go to **Settings > Integrations** in NetPad
26415
+ 2. Click **Connect Google Account** under Google Forms
26416
+ 3. Authorize NetPad to read your forms
26417
+ 4. Copy the credential ID from the connection details
26418
+
26419
+ Or use this URL to start the OAuth flow:
26420
+ \`\`\`
26421
+ ${baseUrl}/api/auth/google?provider=google_forms&orgId=${organizationId}
26422
+ \`\`\`
26423
+
26424
+ ## Once Connected
26425
+
26426
+ Call this tool again with the \`credentialId\` parameter to preview or import the form.
26427
+
26428
+ ${fieldTypeMapping}`
26429
+ }]
26430
+ };
26431
+ }
26432
+ const previewApiCall = `
26433
+ ## Preview Import
26434
+
26435
+ To see how the Google Form will be mapped to NetPad fields:
26436
+
26437
+ \`\`\`bash
26438
+ curl "${baseUrl}/api/integrations/google-forms/preview?\\
26439
+ orgId=${organizationId}&\\
26440
+ credentialId=${credentialId}&\\
26441
+ formId=${formId}"
26442
+ \`\`\`
26443
+
26444
+ Or using fetch:
26445
+
26446
+ \`\`\`typescript
26447
+ const response = await fetch(
26448
+ '${baseUrl}/api/integrations/google-forms/preview?' + new URLSearchParams({
26449
+ orgId: '${organizationId}',
26450
+ credentialId: '${credentialId}',
26451
+ formId: '${formId}',
26452
+ })
26453
+ );
26454
+ const preview = await response.json();
26455
+ console.log('Fields:', preview.previewConfig.fieldConfigs);
26456
+ console.log('Warnings:', preview.mappingResult.warnings);
26457
+ \`\`\`
26458
+ `;
26459
+ const importApiCall = `
26460
+ ## Execute Import
26461
+
26462
+ To create the NetPad form from the Google Form:
26463
+
26464
+ \`\`\`bash
26465
+ curl -X POST "${baseUrl}/api/integrations/google-forms/import" \\
26466
+ -H "Content-Type: application/json" \\
26467
+ -d '{
26468
+ "orgId": "${organizationId}",
26469
+ "credentialId": "${credentialId}",
26470
+ "formId": "${formId}",
26471
+ "projectId": "${projectId}"
26472
+ }'
26473
+ \`\`\`
26474
+
26475
+ Or using fetch:
26476
+
26477
+ \`\`\`typescript
26478
+ const response = await fetch('${baseUrl}/api/integrations/google-forms/import', {
26479
+ method: 'POST',
26480
+ headers: { 'Content-Type': 'application/json' },
26481
+ body: JSON.stringify({
26482
+ orgId: '${organizationId}',
26483
+ credentialId: '${credentialId}',
26484
+ formId: '${formId}',
26485
+ projectId: '${projectId}',
26486
+ // Optional customizations:
26487
+ customizations: {
26488
+ name: 'Custom Form Name', // Override the form name
26489
+ fieldOverrides: { // Modify specific field mappings
26490
+ 'field_path': { type: 'dropdown' }
26491
+ },
26492
+ excludeFields: ['unwanted_field'] // Skip certain fields
26493
+ }
26494
+ })
26495
+ });
26496
+
26497
+ const result = await response.json();
26498
+ if (result.success) {
26499
+ console.log('Form created:', result.form.id);
26500
+ console.log('Edit URL:', result.importReport.viewUrl);
26501
+ }
26502
+ \`\`\`
26503
+ `;
26504
+ return {
26505
+ content: [{
26506
+ type: "text",
26507
+ text: `# Google Forms Import
26508
+
26509
+ **Form ID:** ${formId}
26510
+ **Organization:** ${organizationId}
26511
+ **Project:** ${projectId}
26512
+ **Credential:** ${credentialId}
26513
+
26514
+ ${previewApiCall}
26515
+
26516
+ ${preview ? "" : importApiCall}
26517
+
26518
+ ${fieldTypeMapping}
26519
+
26520
+ ## Using the Import Wizard UI
26521
+
26522
+ Alternatively, users can import Google Forms through the NetPad UI:
26523
+
26524
+ 1. Go to **Forms** in your project
26525
+ 2. Click **Import** > **Import from Google Forms**
26526
+ 3. Select the Google account and form
26527
+ 4. Review the field mappings
26528
+ 5. Click **Import**
26529
+
26530
+ ## Notes
26531
+
26532
+ - Only form structure is imported, not responses/submissions
26533
+ - Some field types may be approximated (see mapping table)
26534
+ - Validation rules are preserved where possible
26535
+ - Section/page breaks become multi-page form pages
26536
+ - Images and videos in the form are not imported`
26537
+ }]
26538
+ };
26539
+ }
26540
+ );
26541
+ server.tool(
26542
+ "list_google_forms",
26543
+ "List Google Forms available for import. Requires a connected Google account.",
26544
+ {
26545
+ organizationId: external_exports.string().describe("The NetPad organization ID"),
26546
+ credentialId: external_exports.string().describe("The credential ID for the Google Forms connection"),
26547
+ searchQuery: external_exports.string().optional().describe("Search query to filter forms by name")
26548
+ },
26549
+ async ({ organizationId, credentialId, searchQuery }) => {
26550
+ const baseUrl = "https://netpad.io";
26551
+ const params = new URLSearchParams({
26552
+ orgId: organizationId,
26553
+ credentialId
26554
+ });
26555
+ if (searchQuery) {
26556
+ params.set("q", searchQuery);
26557
+ }
26558
+ return {
26559
+ content: [{
26560
+ type: "text",
26561
+ text: `# List Google Forms
26562
+
26563
+ To list forms available for import, make this API call:
26564
+
26565
+ \`\`\`bash
26566
+ curl "${baseUrl}/api/integrations/google-forms?${params.toString()}"
26567
+ \`\`\`
26568
+
26569
+ Or using fetch:
26570
+
26571
+ \`\`\`typescript
26572
+ const response = await fetch(
26573
+ '${baseUrl}/api/integrations/google-forms?${params.toString()}'
26574
+ );
26575
+ const data = await response.json();
26576
+
26577
+ // data.forms contains:
26578
+ // - id: Form ID for importing
26579
+ // - name: Form title
26580
+ // - modifiedTime: Last modified date
26581
+ // - webViewLink: Link to edit form in Google
26582
+
26583
+ for (const form of data.forms) {
26584
+ console.log(\`\${form.name} (ID: \${form.id})\`);
26585
+ }
26586
+ \`\`\`
26587
+
26588
+ ## Response Format
26589
+
26590
+ \`\`\`json
26591
+ {
26592
+ "forms": [
26593
+ {
26594
+ "id": "1BxiMVs0XRA5nFMdkkxYYfYpHm5PZ-abc123",
26595
+ "name": "Customer Feedback Survey",
26596
+ "modifiedTime": "2024-01-15T10:30:00Z",
26597
+ "webViewLink": "https://docs.google.com/forms/d/.../edit"
26598
+ }
26599
+ ],
26600
+ "nextPageToken": "..." // For pagination
26601
+ }
26602
+ \`\`\`
26603
+
26604
+ Use the \`import_google_form\` tool with the form ID to import a specific form.`
26605
+ }]
26606
+ };
26607
+ }
26608
+ );
26293
26609
  server.resource(
26294
26610
  "netpad-extension-reference",
26295
26611
  "netpad://reference/extensions",