Skip to content

JavaScript/TypeScript Skills Execution in NCP

Overview

NCP skills are JavaScript/TypeScript first. Skills contain executable code examples in their SKILL.md documentation that AI can directly use in code mode. This approach provides:

  • No installation required - Works immediately
  • Cross-platform - Runs everywhere (Node.js, Deno, browser)
  • Sandboxed security - Isolated execution environment
  • Rich ecosystem - Access to entire npm registry
  • Type safety - TypeScript support with IntelliSense

How It Works

1. Skills Contain JavaScript Examples

Skills include executable JavaScript/TypeScript code blocks:

markdown
---
name: pdf-processing
description: PDF creation and manipulation with pdf-lib
---

# PDF Processing

## Creating a PDF

\`\`\`javascript
import { PDFDocument, rgb, StandardFonts } from 'pdf-lib';

async function createPDF() {
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage([600, 400]);
  
  const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
  page.drawText('Hello World!', {
    x: 50,
    y: 350,
    size: 30,
    font: font,
    color: rgb(0, 0, 0),
  });
  
  const pdfBytes = await pdfDoc.save();
  return pdfBytes;
}
\`\`\`

2. AI Reads Skill and Learns Patterns

typescript
// AI executes this to learn
const skillContent = await skill['pdf-processing']({ depth: 2 });

// AI now has:
// - Full SKILL.md with all JavaScript examples
// - Available resources (reference/, scripts/)
// - Knowledge of pdf-lib API patterns

3. AI Writes Code Using Patterns

AI adapts the examples for the specific task:

typescript
// AI-generated code based on skill examples
const code = `
import { PDFDocument, rgb } from 'pdf-lib';

async function createInvoice(data) {
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage([595, 842]); // A4 size
  
  const font = await pdfDoc.embedFont('Helvetica');
  
  // Add invoice header
  page.drawText('INVOICE', {
    x: 50,
    y: 792,
    size: 24,
    font,
    color: rgb(0, 0, 0)
  });
  
  // Add invoice details from data
  page.drawText(\`Invoice #: \${data.invoiceNumber}\`, {
    x: 50,
    y: 750,
    size: 12,
    font
  });
  
  return await pdfDoc.save();
}

// Execute with provided data
const pdfBytes = await createInvoice({
  invoiceNumber: "INV-001",
  date: "2024-12-23"
});

return pdfBytes;
`;

await code.run({ code });

4. Code Executes in Sandboxed Environment

NCP's code executor:

  • ✅ Validates code with TypeScript AST analysis
  • ✅ Injects MCP tool namespaces
  • ✅ Provides memory limits (128MB default)
  • ✅ Enforces execution timeout (30s default)
  • ✅ Runs in isolated V8 context or Worker Thread

Document Processing

PDF - pdf-lib

javascript
import { PDFDocument, rgb } from 'pdf-lib';

// Create, edit, merge PDFs
const pdfDoc = await PDFDocument.create();
const page = pdfDoc.addPage();
page.drawText('Hello!', { x: 50, y: 50 });
const bytes = await pdfDoc.save();

DOCX - docx

javascript
import { Document, Paragraph, TextRun, Packer } from 'docx';

const doc = new Document({
  sections: [{
    children: [
      new Paragraph({
        children: [new TextRun("Hello World")]
      })
    ]
  }]
});

const buffer = await Packer.toBuffer(doc);

PPTX - pptxgenjs

javascript
import pptxgen from 'pptxgenjs';

let pres = new pptxgen();
let slide = pres.addSlide();
slide.addText('Hello', { x: 1, y: 1, fontSize: 24 });
const buffer = await pres.write({ outputType: 'arraybuffer' });

XLSX - xlsx (SheetJS)

javascript
import * as XLSX from 'xlsx';

const ws = XLSX.utils.aoa_to_sheet([
  ['Name', 'Age'],
  ['John', 30],
  ['Jane', 25]
]);

const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
XLSX.writeFile(wb, 'output.xlsx');

Data Processing

javascript
// CSV parsing
import Papa from 'papaparse';

const csv = Papa.parse(csvString, { header: true });

// JSON manipulation
import { JSONPath } from 'jsonpath-plus';

const result = JSONPath({ path: '$.users[*].name', json: data });

// Data transformation
import _ from 'lodash';

const grouped = _.groupBy(items, 'category');

Web Scraping & HTTP

javascript
// HTTP requests
import axios from 'axios';

const response = await axios.get('https://api.example.com/data');

// HTML parsing
import * as cheerio from 'cheerio';

const $ = cheerio.load(html);
const titles = $('h1').map((i, el) => $(el).text()).get();

Creating JavaScript Skills

Skill Structure

my-skill/
├── SKILL.md                 # Main documentation with JS examples
├── reference/
│   ├── advanced.md          # Advanced patterns
│   └── api-reference.md     # Complete API documentation
├── scripts/
│   ├── helper.js            # Utility scripts
│   └── examples.js          # Working examples
└── package.json             # Optional: npm dependencies

SKILL.md Template

markdown
---
name: my-skill
description: Brief description of what this skill does
---

# My Skill

## Overview

Description of the skill and when to use it.

## Quick Start

\`\`\`javascript
// Simple example that works immediately
import { SomeLibrary } from 'some-package';

async function example() {
  const result = await SomeLibrary.doSomething();
  return result;
}
\`\`\`

## Common Patterns

### Pattern 1: Basic Usage

\`\`\`javascript
// Code example showing basic usage
\`\`\`

### Pattern 2: Advanced Usage

\`\`\`javascript
// Code example showing advanced features
\`\`\`

## Error Handling

\`\`\`javascript
try {
  const result = await operation();
} catch (error) {
  // Handle specific error types
  if (error.code === 'ENOENT') {
    // File not found
  }
}
\`\`\`

## Best Practices

- Use async/await for asynchronous operations
- Handle errors gracefully
- Validate inputs before processing
- Return structured data

## Reference

For more details, see [reference/advanced.md](./reference/advanced.md)

Package Management

Installing Dependencies

Dependencies are automatically installed when imported in code mode:

javascript
// These imports trigger automatic installation if needed
import pdfLib from 'pdf-lib';
import docx from 'docx';
import pptxgen from 'pptxgenjs';

Manual Installation

If automatic installation doesn't work, use npm MCP:

typescript
// Install package via npm MCP
await npm.install({ package: 'pdf-lib' });

// Then use in code
import { PDFDocument } from 'pdf-lib';

Examples

Example 1: PDF Invoice Generator

Skill: Create professional invoices

javascript
import { PDFDocument, rgb, StandardFonts } from 'pdf-lib';

async function generateInvoice(invoiceData) {
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage([595, 842]); // A4
  const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
  const boldFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
  
  // Header
  page.drawText('INVOICE', {
    x: 50,
    y: 792,
    size: 24,
    font: boldFont,
    color: rgb(0, 0, 0.5)
  });
  
  // Invoice details
  let y = 750;
  page.drawText(`Invoice #: ${invoiceData.number}`, { x: 50, y, size: 12, font });
  y -= 20;
  page.drawText(`Date: ${invoiceData.date}`, { x: 50, y, size: 12, font });
  y -= 40;
  
  // Items table
  page.drawText('Description', { x: 50, y, size: 12, font: boldFont });
  page.drawText('Amount', { x: 450, y, size: 12, font: boldFont });
  y -= 20;
  
  invoiceData.items.forEach(item => {
    page.drawText(item.description, { x: 50, y, size: 10, font });
    page.drawText(`$${item.amount.toFixed(2)}`, { x: 450, y, size: 10, font });
    y -= 20;
  });
  
  // Total
  y -= 20;
  const total = invoiceData.items.reduce((sum, item) => sum + item.amount, 0);
  page.drawText('Total:', { x: 400, y, size: 12, font: boldFont });
  page.drawText(`$${total.toFixed(2)}`, { x: 450, y, size: 12, font: boldFont });
  
  return await pdfDoc.save();
}

// Usage
const invoice = await generateInvoice({
  number: 'INV-001',
  date: '2024-12-23',
  items: [
    { description: 'Web Development', amount: 5000 },
    { description: 'Consulting', amount: 2000 }
  ]
});

Example 2: Excel Report Generator

Skill: Create formatted spreadsheets

javascript
import * as XLSX from 'xlsx';

function generateReport(data) {
  // Create worksheet from array of arrays
  const ws = XLSX.utils.aoa_to_sheet([
    ['Report Generated:', new Date().toISOString()],
    [],
    ['Name', 'Sales', 'Region', 'Performance'],
    ...data.map(row => [
      row.name,
      row.sales,
      row.region,
      row.sales > 10000 ? 'Excellent' : 'Good'
    ])
  ]);
  
  // Set column widths
  ws['!cols'] = [
    { wch: 20 }, // Name
    { wch: 10 }, // Sales
    { wch: 15 }, // Region
    { wch: 15 }  // Performance
  ];
  
  // Create workbook and add worksheet
  const wb = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb, ws, 'Sales Report');
  
  // Generate buffer
  return XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' });
}

// Usage
const reportData = [
  { name: 'John Doe', sales: 15000, region: 'North' },
  { name: 'Jane Smith', sales: 8000, region: 'South' }
];

const excelBuffer = generateReport(reportData);

Best Practices

1. Use Async/Await Consistently

javascript
// ✅ Good
async function processDocument() {
  const doc = await loadDocument();
  const result = await processContent(doc);
  return result;
}

// ❌ Bad - mixing callbacks and promises
function processDocument(callback) {
  loadDocument().then(doc => {
    processContent(doc, callback);
  });
}

2. Handle Errors Gracefully

javascript
async function safeOperation() {
  try {
    return await riskyOperation();
  } catch (error) {
    // Log error for debugging
    console.error('Operation failed:', error.message);
    
    // Return safe fallback
    return { success: false, error: error.message };
  }
}

3. Validate Inputs

javascript
function processUser(user) {
  // Validate required fields
  if (!user || !user.name || !user.email) {
    throw new Error('Invalid user: name and email required');
  }
  
  // Validate format
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(user.email)) {
    throw new Error('Invalid email format');
  }
  
  // Process valid data
  return transformUser(user);
}

4. Return Structured Data

javascript
// ✅ Good - structured response
async function createDocument() {
  try {
    const doc = await generateDoc();
    return {
      success: true,
      document: doc,
      metadata: {
        size: doc.length,
        created: new Date()
      }
    };
  } catch (error) {
    return {
      success: false,
      error: error.message
    };
  }
}

// ❌ Bad - unclear return values
async function createDocument() {
  const doc = await generateDoc();
  return doc; // What if it fails? No context.
}

Troubleshooting

Package Not Found

If import fails, install explicitly:

typescript
// If this fails:
import pdfLib from 'pdf-lib';

// Try manual install:
await npm.install({ package: 'pdf-lib' });

Memory Limit Exceeded

Increase memory limit for large operations:

typescript
await code.run({
  code: largeOperation,
  memory: 256 * 1024 * 1024 // 256MB
});

Timeout Issues

Increase timeout for long-running operations:

typescript
await code.run({
  code: slowOperation,
  timeout: 60000 // 60 seconds
});

Migration from Python Skills

If you have Python-based skills, here are JavaScript equivalents:

PythonJavaScriptnpm Package
pypdfPDFDocumentpdf-lib
python-docxDocumentdocx
python-pptxPresentationpptxgenjs
pandasDataFrame operationsdanfojs, lodash
requestsHTTP clientaxios, fetch
beautifulsoup4HTML parsercheerio
Pillow (PIL)Image processingsharp, jimp
numpyNumeric arraysndarray, numjs

Summary

JavaScript/TypeScript skills in NCP:

  • ✅ Work immediately without installation
  • ✅ Execute in secure sandboxed environment
  • ✅ Access to entire npm ecosystem
  • ✅ Type-safe with TypeScript support
  • ✅ Cross-platform compatibility
  • ✅ AI can read, learn, and execute patterns
  • ✅ Full integration with code mode

Skills are executable documentation that teach AI how to solve problems using JavaScript!

Released under the Elastic License 2.0.