Calculator Server
A complete calculator with multiple operations.calculator.ts
import { z } from 'zod';
import { tool, createSdkMcpServer, query } from '@qwen-code/sdk';
// Define calculator tools
const addTool = tool(
'add',
'Add two numbers together',
{
a: z.number().describe('First number'),
b: z.number().describe('Second number'),
},
async (args) => ({
content: [{
type: 'text',
text: `${args.a} + ${args.b} = ${args.a + args.b}`,
}],
})
);
const subtractTool = tool(
'subtract',
'Subtract second number from first',
{
a: z.number().describe('First number'),
b: z.number().describe('Second number'),
},
async (args) => ({
content: [{
type: 'text',
text: `${args.a} - ${args.b} = ${args.a - args.b}`,
}],
})
);
const multiplyTool = tool(
'multiply',
'Multiply two numbers',
{
a: z.number().describe('First number'),
b: z.number().describe('Second number'),
},
async (args) => ({
content: [{
type: 'text',
text: `${args.a} × ${args.b} = ${args.a * args.b}`,
}],
})
);
const divideTool = tool(
'divide',
'Divide first number by second',
{
a: z.number().describe('Numerator'),
b: z.number().describe('Denominator (non-zero)'),
},
async (args) => {
if (args.b === 0) {
return {
content: [{ type: 'text', text: 'Error: Division by zero' }],
isError: true,
};
}
return {
content: [{
type: 'text',
text: `${args.a} ÷ ${args.b} = ${args.a / args.b}`,
}],
};
}
);
// Create calculator server
const calculatorServer = createSdkMcpServer({
name: 'calculator',
version: '1.0.0',
tools: [addTool, subtractTool, multiplyTool, divideTool],
});
// Use the calculator
async function main() {
const result = query({
prompt: 'Calculate (15 + 7) × 3 - 10',
options: {
permissionMode: 'yolo',
mcpServers: {
calculator: calculatorServer,
},
},
});
for await (const message of result) {
if (message.type === 'assistant') {
console.log('\nAssistant:', message.message.content);
} else if (message.type === 'result') {
console.log('\nFinal result:', message.result);
}
}
}
main().catch(console.error);
Weather API Server
Fetch real weather data using an external API.weather.ts
import { z } from 'zod';
import { tool, createSdkMcpServer, query } from '@qwen-code/sdk';
const weatherTool = tool(
'get_weather',
'Get current weather for a city using OpenWeatherMap API',
{
city: z.string().describe('City name (e.g., "San Francisco")'),
units: z.enum(['metric', 'imperial'])
.default('metric')
.describe('Temperature units'),
},
async (args) => {
try {
const apiKey = process.env.OPENWEATHER_API_KEY;
if (!apiKey) {
return {
content: [{
type: 'text',
text: 'Error: OPENWEATHER_API_KEY not configured',
}],
isError: true,
};
}
const url = `https://api.openweathermap.org/data/2.5/weather?` +
`q=${encodeURIComponent(args.city)}` +
`&units=${args.units}` +
`&appid=${apiKey}`;
const response = await fetch(url);
if (!response.ok) {
const error = await response.json();
return {
content: [{
type: 'text',
text: `Weather API error: ${error.message}`,
}],
isError: true,
};
}
const data = await response.json();
const temp = data.main.temp;
const feelsLike = data.main.feels_like;
const humidity = data.main.humidity;
const description = data.weather[0].description;
const unit = args.units === 'metric' ? '°C' : '°F';
return {
content: [{
type: 'text',
text: `Weather in ${args.city}:\n` +
`${description}\n` +
`Temperature: ${temp}${unit} (feels like ${feelsLike}${unit})\n` +
`Humidity: ${humidity}%`,
}],
};
} catch (error) {
return {
content: [{
type: 'text',
text: `Failed to fetch weather: ${error.message}`,
}],
isError: true,
};
}
}
);
const weatherServer = createSdkMcpServer({
name: 'weather',
tools: [weatherTool],
});
async function main() {
const result = query({
prompt: 'What is the weather like in London and Tokyo?',
options: {
permissionMode: 'yolo',
env: {
OPENWEATHER_API_KEY: 'your-api-key-here',
},
mcpServers: {
weather: weatherServer,
},
},
});
for await (const message of result) {
if (message.type === 'assistant') {
console.log(message.message.content);
}
}
}
main().catch(console.error);
File Storage Server
Manage files with create, read, and list operations.file-storage.ts
import { z } from 'zod';
import { tool, createSdkMcpServer, query } from '@qwen-code/sdk';
import * as fs from 'fs/promises';
import * as path from 'path';
const STORAGE_DIR = './mcp-storage';
// Ensure storage directory exists
await fs.mkdir(STORAGE_DIR, { recursive: true });
const createFileTool = tool(
'create_file',
'Create a new file with content',
{
filename: z.string().describe('Name of the file'),
content: z.string().describe('Content to write'),
},
async (args) => {
try {
const filePath = path.join(STORAGE_DIR, args.filename);
await fs.writeFile(filePath, args.content, 'utf-8');
return {
content: [{
type: 'text',
text: `Created ${args.filename} (${args.content.length} bytes)`,
}],
};
} catch (error) {
return {
content: [{ type: 'text', text: `Error: ${error.message}` }],
isError: true,
};
}
}
);
const readFileTool = tool(
'read_file',
'Read content from a file',
{
filename: z.string().describe('Name of the file to read'),
},
async (args) => {
try {
const filePath = path.join(STORAGE_DIR, args.filename);
const content = await fs.readFile(filePath, 'utf-8');
return {
content: [{
type: 'text',
text: `Content of ${args.filename}:\n${content}`,
}],
};
} catch (error) {
return {
content: [{ type: 'text', text: `Error: ${error.message}` }],
isError: true,
};
}
}
);
const listFilesTool = tool(
'list_files',
'List all files in storage',
{},
async () => {
try {
const files = await fs.readdir(STORAGE_DIR);
if (files.length === 0) {
return {
content: [{ type: 'text', text: 'No files in storage' }],
};
}
const fileInfo = await Promise.all(
files.map(async (file) => {
const stats = await fs.stat(path.join(STORAGE_DIR, file));
return `- ${file} (${stats.size} bytes)`;
})
);
return {
content: [{
type: 'text',
text: `Files in storage:\n${fileInfo.join('\n')}`,
}],
};
} catch (error) {
return {
content: [{ type: 'text', text: `Error: ${error.message}` }],
isError: true,
};
}
}
);
const fileServer = createSdkMcpServer({
name: 'file-storage',
tools: [createFileTool, readFileTool, listFilesTool],
});
async function main() {
const result = query({
prompt: 'Create a file called notes.txt with "Hello from MCP!", ' +
'then list all files, and read it back',
options: {
permissionMode: 'yolo',
mcpServers: {
files: fileServer,
},
},
});
for await (const message of result) {
if (message.type === 'assistant') {
console.log(message.message.content);
}
}
}
main().catch(console.error);
Data Processing Server
Process and analyze data with multiple tools.data-processing.ts
import { z } from 'zod';
import { tool, createSdkMcpServer, query } from '@qwen-code/sdk';
// In-memory data store
const dataStore = new Map<string, number[]>();
const storeDataTool = tool(
'store_data',
'Store a dataset with a name',
{
name: z.string().describe('Dataset name'),
values: z.array(z.number()).describe('Array of numbers'),
},
async (args) => {
dataStore.set(args.name, args.values);
return {
content: [{
type: 'text',
text: `Stored dataset '${args.name}' with ${args.values.length} values`,
}],
};
}
);
const calculateStatsTool = tool(
'calculate_stats',
'Calculate statistics for a stored dataset',
{
name: z.string().describe('Dataset name'),
},
async (args) => {
const values = dataStore.get(args.name);
if (!values) {
return {
content: [{ type: 'text', text: `Dataset '${args.name}' not found` }],
isError: true,
};
}
const sum = values.reduce((a, b) => a + b, 0);
const mean = sum / values.length;
const min = Math.min(...values);
const max = Math.max(...values);
const variance = values.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / values.length;
const stdDev = Math.sqrt(variance);
return {
content: [{
type: 'text',
text: `Statistics for '${args.name}':\n` +
`Count: ${values.length}\n` +
`Sum: ${sum}\n` +
`Mean: ${mean.toFixed(2)}\n` +
`Min: ${min}\n` +
`Max: ${max}\n` +
`Std Dev: ${stdDev.toFixed(2)}`,
}],
};
}
);
const listDatasetsTool = tool(
'list_datasets',
'List all stored datasets',
{},
async () => {
if (dataStore.size === 0) {
return {
content: [{ type: 'text', text: 'No datasets stored' }],
};
}
const datasets = Array.from(dataStore.entries())
.map(([name, values]) => `- ${name} (${values.length} values)`);
return {
content: [{
type: 'text',
text: `Stored datasets:\n${datasets.join('\n')}`,
}],
};
}
);
const dataServer = createSdkMcpServer({
name: 'data-processor',
tools: [storeDataTool, calculateStatsTool, listDatasetsTool],
});
async function main() {
const result = query({
prompt: 'Store a dataset called "temperatures" with values [72, 75, 68, 71, 74, 73], ' +
'then calculate its statistics',
options: {
permissionMode: 'yolo',
mcpServers: {
data: dataServer,
},
},
});
for await (const message of result) {
if (message.type === 'assistant') {
console.log(message.message.content);
}
}
}
main().catch(console.error);
Multi-Server Application
Combine multiple specialized servers in one application.multi-server.ts
import { z } from 'zod';
import { tool, createSdkMcpServer, query } from '@qwen-code/sdk';
// Math server
const mathServer = createSdkMcpServer({
name: 'math',
tools: [
tool('add', 'Add numbers', {
a: z.number(), b: z.number()
}, async (args) => ({
content: [{ type: 'text', text: String(args.a + args.b) }],
})),
tool('factorial', 'Calculate factorial', {
n: z.number().int().min(0).max(20)
}, async (args) => {
let result = 1;
for (let i = 2; i <= args.n; i++) {
result *= i;
}
return {
content: [{ type: 'text', text: `${args.n}! = ${result}` }],
};
}),
],
});
// Time server
const timeServer = createSdkMcpServer({
name: 'time',
tools: [
tool('get_time', 'Get current time', {}, async () => ({
content: [{ type: 'text', text: new Date().toISOString() }],
})),
tool('get_timestamp', 'Get Unix timestamp', {}, async () => ({
content: [{ type: 'text', text: String(Date.now()) }],
})),
],
});
// Random server
const randomServer = createSdkMcpServer({
name: 'random',
tools: [
tool('random_number', 'Generate random number', {
min: z.number().default(0),
max: z.number().default(100),
}, async (args) => {
const num = Math.random() * (args.max - args.min) + args.min;
return {
content: [{ type: 'text', text: String(num.toFixed(2)) }],
};
}),
],
});
async function main() {
const result = query({
prompt: 'What time is it? Also, calculate 5 factorial and generate a random number between 1 and 10',
options: {
permissionMode: 'yolo',
mcpServers: {
math: mathServer,
time: timeServer,
random: randomServer,
},
},
});
for await (const message of result) {
if (message.type === 'assistant') {
console.log('\n', message.message.content);
} else if (message.type === 'result') {
console.log('\nCompleted in', message.duration_ms, 'ms');
}
}
}
main().catch(console.error);
Environment Configuration Server
Manage environment variables and configuration.env-config.ts
import { z } from 'zod';
import { tool, createSdkMcpServer, query } from '@qwen-code/sdk';
const getEnvTool = tool(
'get_env',
'Get an environment variable value',
{
key: z.string().describe('Environment variable name'),
},
async (args) => {
const value = process.env[args.key];
if (value === undefined) {
return {
content: [{ type: 'text', text: `${args.key} is not set` }],
};
}
return {
content: [{ type: 'text', text: `${args.key} = ${value}` }],
};
}
);
const listEnvTool = tool(
'list_env',
'List all environment variables matching a pattern',
{
pattern: z.string().optional().describe('Pattern to match (case-insensitive)'),
},
async (args) => {
const pattern = args.pattern?.toLowerCase();
const vars = Object.keys(process.env)
.filter(key => !pattern || key.toLowerCase().includes(pattern))
.sort();
if (vars.length === 0) {
return {
content: [{ type: 'text', text: 'No matching environment variables' }],
};
}
return {
content: [{
type: 'text',
text: `Environment variables${pattern ? ` matching '${pattern}'` : ''}:\n` +
vars.map(key => `- ${key}`).join('\n'),
}],
};
}
);
const envServer = createSdkMcpServer({
name: 'environment',
tools: [getEnvTool, listEnvTool],
});
async function main() {
const result = query({
prompt: 'List all PATH-related environment variables',
options: {
permissionMode: 'yolo',
mcpServers: {
env: envServer,
},
},
});
for await (const message of result) {
if (message.type === 'assistant') {
console.log(message.message.content);
}
}
}
main().catch(console.error);
Running the Examples
All examples can be run with:npx tsx example-name.ts
OPENWEATHER_API_KEY for the weather example).
Next Steps
tool() Function
Learn how to create tools
createSdkMcpServer()
Create server instances
MCP Overview
Understand MCP integration
SDK Examples
More SDK examples
