
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A TypeScript SDK for building MCP (Model Context Protocol) handlers with first-class Zod integration for type safety and runtime validation.
npm install wasmcp
Note: wasmcp includes Zod v4 as a dependency.
import { createTool, createHandler, z } from 'wasmcp';
// Define a tool using factory function
const helloTool = createTool({
name: 'hello',
description: 'Say hello to someone',
schema: z.object({
name: z.string().describe('Name to greet')
}),
execute: async (args) => {
// TypeScript knows args is { name: string }
return `Hello, ${args.name}!`;
}
});
// Create and export the handler
export const handler = createHandler({
tools: [helloTool]
});
The createTool function is the simplest way to define tools:
const emailTool = createTool({
name: 'send_email',
description: 'Send an email',
schema: z.object({
to: z.string().email('Invalid email address'),
cc: z.array(z.string().email()).optional(),
subject: z.string().max(100, 'Subject too long'),
body: z.string(),
priority: z.enum(['low', 'normal', 'high']).default('normal')
}),
execute: async (args) => {
console.log(`Sending ${args.priority} priority email to ${args.to}`);
return `Email sent to ${args.to} with subject "${args.subject}"`;
}
});
For more complex tools that need internal state or helper methods, use the class-based API:
import { Tool } from 'wasmcp';
class DatabaseQueryTool extends Tool {
readonly name = 'db_query';
readonly description = 'Query the database';
readonly schema = z.object({
query: z.string(),
limit: z.number().int().positive().default(10)
});
// Private helper methods
private sanitizeQuery(query: string): string {
// Complex sanitization logic
return query.replace(/;/g, '');
}
private async connectToDb() {
// Connection logic
}
async execute(args) {
const sanitized = this.sanitizeQuery(args.query);
await this.connectToDb();
// Execute query...
return `Query executed: ${sanitized}`;
}
}
Both approaches work seamlessly with createHandler:
export const handler = createHandler({
tools: [emailTool, DatabaseQueryTool]
});
const calculatorTool = createTool({
name: 'calculator',
description: 'Perform math operations',
schema: z.object({
a: z.number(),
b: z.number(),
operation: z.enum(['add', 'subtract', 'multiply', 'divide'])
}).refine(
(data) => !(data.operation === 'divide' && data.b === 0),
{ message: "Cannot divide by zero" }
),
execute: async (args) => {
switch (args.operation) {
case 'add': return String(args.a + args.b);
case 'subtract': return String(args.a - args.b);
case 'multiply': return String(args.a * args.b);
case 'divide': return String(args.a / args.b);
}
}
});
While tools are the primary feature used today, the SDK also supports resources and prompts:
import { Resource, Prompt, PromptMessage } from 'wasmcp';
// Resources provide read-only data
class ConfigResource extends Resource {
readonly uri = 'config://app';
readonly name = 'Application Config';
readonly description = 'Current configuration';
readonly mimeType = 'application/json';
read() {
return JSON.stringify({ version: '1.0.0' });
}
}
// Prompts generate conversation templates
class GreetingPrompt extends Prompt {
readonly name = 'greeting';
readonly description = 'Generate a greeting';
readonly schema = z.object({
name: z.string(),
formal: z.boolean().optional()
});
resolve(args): PromptMessage[] {
const greeting = args.formal
? `Good day, ${args.name}.`
: `Hey ${args.name}!`;
return [
{ role: 'assistant', content: greeting }
];
}
}
// Include them in your handler
export const handler = createHandler({
tools: [HelloTool, CalculatorTool],
resources: [ConfigResource],
prompts: [GreetingPrompt]
});
Set up your project with the necessary build tools:
npm install -D @bytecodealliance/jco typescript esbuild
Configure your build scripts in package.json:
{
"scripts": {
"build": "tsc && esbuild dist/index.js --bundle --format=esm --platform=node --outfile=dist/bundled.js && jco componentize dist/bundled.js --wit ./wit --world-name mcp-handler --out dist/handler.wasm"
}
}
Build your component:
npm run build
prettifyError provides user-friendly errorsWhen validation fails, users get helpful error messages:
✖ Invalid arguments:
✖ Invalid email address
→ at to
✖ Subject too long: expected string with max length 100
→ at subject
The SDK is designed for performance:
FAQs
TypeScript SDK for building MCP (Model Context Protocol) WebAssembly components
We found that wasmcp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.