Initial commit

This commit is contained in:
CHE LIANG ZHAO
2026-01-16 18:21:32 +08:00
commit 6e8a93c8e9
27 changed files with 2441 additions and 0 deletions

1162
typescript/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

32
typescript/package.json Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "mcp-demo-server",
"version": "1.0.0",
"description": "A demo MCP server with example tools",
"type": "module",
"bin": {
"mcp-demo": "./build/index.js"
},
"scripts": {
"build": "tsc",
"start": "node build/index.js",
"dev": "tsc --watch"
},
"files": [
"build"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.0",
"zod": "^3.24.0"
},
"devDependencies": {
"@types/node": "^22.10.0",
"typescript": "^5.7.0"
},
"keywords": [
"mcp",
"model-context-protocol",
"ai",
"tools"
],
"license": "MIT"
}

29
typescript/src/index.ts Normal file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env node
/**
* MCP Demo Server - TypeScript
*
* A demonstration MCP server with modular architecture:
* - Tools: echo, calculator, time, random, string utilities
* - Resources: skills capabilities, tool info
* - Prompts: list-skills, process-text, math-helper
*/
import { server } from "./server.js";
import { registerAllTools } from "./tools/index.js";
import { registerAllResources } from "./resources/index.js";
import { registerAllPrompts } from "./prompts/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// Register all modules
registerAllTools();
registerAllResources();
registerAllPrompts();
// Start the server
async function main() {
await server.connect(new StdioServerTransport());
console.error("MCP Demo Server (TypeScript) running on stdio");
}
main().catch(console.error);

View File

@@ -0,0 +1,15 @@
import { registerListSkillsPrompt } from "./list-skills.js";
import { registerProcessTextPrompt } from "./process-text.js";
import { registerMathHelperPrompt } from "./math-helper.js";
export function registerAllPrompts() {
registerListSkillsPrompt();
registerProcessTextPrompt();
registerMathHelperPrompt();
}
export {
registerListSkillsPrompt,
registerProcessTextPrompt,
registerMathHelperPrompt,
};

View File

@@ -0,0 +1,74 @@
import { server } from "../server.js";
import { z } from "zod";
export function registerListSkillsPrompt() {
server.registerPrompt(
"list-skills",
{
description:
"List all available skills and capabilities of this MCP server",
argsSchema: {
format: z
.enum(["brief", "detailed"])
.optional()
.describe("Output format: 'brief' or 'detailed'"),
},
},
async ({ format }) => {
const isDetailed = format === "detailed";
const briefContent = `This MCP server provides 5 tools:
1. echo - Echo messages
2. calculator - Math operations (+, -, *, /)
3. get_current_time - Current time with timezone support
4. random_number - Random number generation
5. string_utils - String manipulation`;
const detailedContent = `# MCP Demo Server - Complete Skills Guide
## Tools Overview
### 1. echo
Echo back any message you send.
\`\`\`json
{"message": "Hello!"}
\`\`\`
### 2. calculator
Perform basic math: add, subtract, multiply, divide.
\`\`\`json
{"operation": "add", "a": 10, "b": 5}
\`\`\`
### 3. get_current_time
Get current time, optionally in a specific timezone.
\`\`\`json
{"timezone": "Asia/Shanghai"}
\`\`\`
### 4. random_number
Generate random numbers in a range.
\`\`\`json
{"min": 1, "max": 100}
\`\`\`
### 5. string_utils
String operations: uppercase, lowercase, reverse, length, word_count.
\`\`\`json
{"operation": "uppercase", "text": "hello world"}
\`\`\``;
return {
messages: [
{
role: "user",
content: {
type: "text",
text: isDetailed ? detailedContent : briefContent,
},
},
],
};
}
);
}

View File

@@ -0,0 +1,35 @@
import { server } from "../server.js";
import { z } from "zod";
export function registerMathHelperPrompt() {
server.registerPrompt(
"math-helper",
{
description: "Generate a prompt for mathematical calculations",
argsSchema: {
problem: z.string().describe("The math problem to solve"),
},
},
async ({ problem }) => {
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Please help solve this math problem: ${problem}
Use the calculator tool to perform the calculations. Show your work step by step.
Available operations:
- add (a + b)
- subtract (a - b)
- multiply (a * b)
- divide (a / b)`,
},
},
],
};
}
);
}

View File

@@ -0,0 +1,59 @@
import { server } from "../server.js";
import { z } from "zod";
export function registerProcessTextPrompt() {
server.registerPrompt(
"process-text",
{
description: "Generate a prompt for text processing tasks",
argsSchema: {
text: z.string().describe("The text to process"),
task: z
.enum(["analyze", "transform", "summarize"])
.optional()
.describe("Processing task: 'analyze', 'transform', or 'summarize'"),
},
},
async ({ text, task }) => {
const taskType = task || "analyze";
const prompts: Record<string, string> = {
analyze: `Please analyze the following text and provide insights:
Text: "${text}"
Use the string_utils tool to:
1. Get the length of the text
2. Count the words
3. Show the text in uppercase and lowercase`,
transform: `Please transform the following text:
Text: "${text}"
Use the string_utils tool to:
1. Convert to UPPERCASE
2. Convert to lowercase
3. Reverse the text`,
summarize: `Please provide a summary of the following text:
Text: "${text}"
First, use string_utils to get basic stats (length, word_count), then provide your analysis.`,
};
return {
messages: [
{
role: "user",
content: {
type: "text",
text: prompts[taskType] || prompts["analyze"],
},
},
],
};
}
);
}

View File

@@ -0,0 +1,9 @@
import { registerSkillsResource } from "./skills.js";
import { registerToolInfoResource, AVAILABLE_TOOLS } from "./tool-info.js";
export function registerAllResources() {
registerSkillsResource();
registerToolInfoResource();
}
export { registerSkillsResource, registerToolInfoResource, AVAILABLE_TOOLS };

View File

@@ -0,0 +1,56 @@
import { server } from "../server.js";
const SKILLS_CONTENT = `# MCP Demo Server Skills
## Available Tools
### 1. echo
- **Description**: Echo back the provided message
- **Use Case**: Testing connectivity, message relay
### 2. calculator
- **Description**: Perform basic mathematical operations (add, subtract, multiply, divide)
- **Use Case**: Mathematical calculations
### 3. get_current_time
- **Description**: Get the current date and time with optional timezone
- **Use Case**: Time queries, timezone conversions
### 4. random_number
- **Description**: Generate a random number within a specified range
- **Use Case**: Random selection, gaming, testing
### 5. string_utils
- **Description**: Perform string operations (uppercase, lowercase, reverse, length, word_count)
- **Use Case**: Text processing, string manipulation
## Capabilities Summary
- Basic I/O operations
- Mathematical calculations
- Time and date handling
- Random number generation
- String manipulation
## How to Use
Call any tool with its required parameters. Use the \`list-skills\` prompt for interactive guidance.
`;
export function registerSkillsResource() {
server.registerResource(
"skills-capabilities",
"mcp-demo://skills/capabilities",
{
description: "Complete list of server capabilities and skills",
mimeType: "text/markdown",
},
async () => ({
contents: [
{
uri: "mcp-demo://skills/capabilities",
mimeType: "text/markdown",
text: SKILLS_CONTENT,
},
],
})
);
}

View File

@@ -0,0 +1,123 @@
import { server } from "../server.js";
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
interface ToolMetadata {
name: string;
description: string;
parameters: Record<string, string>;
examples: string[];
}
const TOOL_METADATA: Record<string, ToolMetadata> = {
echo: {
name: "echo",
description: "Echo back the provided message",
parameters: {
message: "string - The message to echo back",
},
examples: ['{"message": "Hello, World!"}'],
},
calculator: {
name: "calculator",
description: "Perform basic mathematical operations",
parameters: {
operation: "enum - add, subtract, multiply, divide",
a: "number - First operand",
b: "number - Second operand",
},
examples: [
'{"operation": "add", "a": 10, "b": 5}',
'{"operation": "multiply", "a": 3, "b": 7}',
],
},
get_current_time: {
name: "get_current_time",
description: "Get the current date and time",
parameters: {
timezone: "string (optional) - Timezone like 'Asia/Shanghai'",
},
examples: ["{}", '{"timezone": "America/New_York"}'],
},
random_number: {
name: "random_number",
description: "Generate a random number within a range",
parameters: {
min: "number - Minimum value (inclusive)",
max: "number - Maximum value (inclusive)",
},
examples: ['{"min": 1, "max": 100}'],
},
string_utils: {
name: "string_utils",
description: "Perform string operations",
parameters: {
operation: "enum - uppercase, lowercase, reverse, length, word_count",
text: "string - The text to process",
},
examples: [
'{"operation": "uppercase", "text": "hello"}',
'{"operation": "word_count", "text": "Hello World"}',
],
},
};
export const AVAILABLE_TOOLS = Object.keys(TOOL_METADATA);
export function registerToolInfoResource() {
server.registerResource(
"tool-info",
new ResourceTemplate("mcp-demo://tools/{toolName}", {
list: async () => ({
resources: AVAILABLE_TOOLS.map((name) => ({
uri: `mcp-demo://tools/${name}`,
name: `Tool: ${name}`,
description: TOOL_METADATA[name].description,
mimeType: "application/json",
})),
}),
complete: {
toolName: async (value: string) =>
AVAILABLE_TOOLS.filter((name) =>
name.toLowerCase().startsWith(value.toLowerCase())
),
},
}),
{
description: "Detailed information about a specific tool",
mimeType: "application/json",
},
async (uri: URL) => {
const toolName = uri.pathname.split("/").pop() || "";
const metadata = TOOL_METADATA[toolName];
if (!metadata) {
return {
contents: [
{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(
{
error: `Tool '${toolName}' not found`,
availableTools: AVAILABLE_TOOLS,
},
null,
2
),
},
],
};
}
return {
contents: [
{
uri: uri.href,
mimeType: "application/json",
text: JSON.stringify(metadata, null, 2),
},
],
};
}
);
}

7
typescript/src/server.ts Normal file
View File

@@ -0,0 +1,7 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
// 创建 MCP Server 实例
export const server = new McpServer({
name: "mcp-demo-server",
version: "1.0.0",
});

View File

@@ -0,0 +1,56 @@
import { server } from "../server.js";
import { z } from "zod";
export function registerCalculatorTool() {
server.registerTool(
"calculator",
{
description: "Perform basic mathematical operations",
inputSchema: {
operation: z
.enum(["add", "subtract", "multiply", "divide"])
.describe("The operation to perform"),
a: z.number().describe("First operand"),
b: z.number().describe("Second operand"),
},
},
async ({ operation, a, b }) => {
let result: number;
switch (operation) {
case "add":
result = a + b;
break;
case "subtract":
result = a - b;
break;
case "multiply":
result = a * b;
break;
case "divide":
if (b === 0) {
return {
content: [
{
type: "text",
text: "Error: Division by zero is not allowed",
},
],
isError: true,
};
}
result = a / b;
break;
}
return {
content: [
{
type: "text",
text: `${a} ${operation} ${b} = ${result}`,
},
],
};
}
);
}

View File

@@ -0,0 +1,24 @@
import { server } from "../server.js";
import { z } from "zod";
export function registerEchoTool() {
server.registerTool(
"echo",
{
description: "Echo back the provided message",
inputSchema: {
message: z.string().describe("The message to echo back"),
},
},
async ({ message }) => {
return {
content: [
{
type: "text",
text: `Echo: ${message}`,
},
],
};
}
);
}

View File

@@ -0,0 +1,21 @@
import { registerEchoTool } from "./echo.js";
import { registerCalculatorTool } from "./calculator.js";
import { registerTimeTool } from "./time.js";
import { registerRandomTool } from "./random.js";
import { registerStringTool } from "./string.js";
export function registerAllTools() {
registerEchoTool();
registerCalculatorTool();
registerTimeTool();
registerRandomTool();
registerStringTool();
}
export {
registerEchoTool,
registerCalculatorTool,
registerTimeTool,
registerRandomTool,
registerStringTool,
};

View File

@@ -0,0 +1,39 @@
import { server } from "../server.js";
import { z } from "zod";
export function registerRandomTool() {
server.registerTool(
"random_number",
{
description: "Generate a random number within a specified range",
inputSchema: {
min: z.number().describe("Minimum value (inclusive)"),
max: z.number().describe("Maximum value (inclusive)"),
},
},
async ({ min, max }) => {
if (min > max) {
return {
content: [
{
type: "text",
text: "Error: min must be less than or equal to max",
},
],
isError: true,
};
}
const randomNum = Math.floor(Math.random() * (max - min + 1)) + min;
return {
content: [
{
type: "text",
text: `Random number between ${min} and ${max}: ${randomNum}`,
},
],
};
}
);
}

View File

@@ -0,0 +1,51 @@
import { server } from "../server.js";
import { z } from "zod";
export function registerStringTool() {
server.registerTool(
"string_utils",
{
description: "Perform various string operations",
inputSchema: {
operation: z
.enum(["uppercase", "lowercase", "reverse", "length", "word_count"])
.describe("The string operation to perform"),
text: z.string().describe("The text to process"),
},
},
async ({ operation, text }) => {
let result: string;
switch (operation) {
case "uppercase":
result = text.toUpperCase();
break;
case "lowercase":
result = text.toLowerCase();
break;
case "reverse":
result = text.split("").reverse().join("");
break;
case "length":
result = `Length: ${text.length} characters`;
break;
case "word_count":
const words = text
.trim()
.split(/\s+/)
.filter((w) => w.length > 0);
result = `Word count: ${words.length}`;
break;
}
return {
content: [
{
type: "text",
text: result,
},
],
};
}
);
}

View File

@@ -0,0 +1,48 @@
import { server } from "../server.js";
import { z } from "zod";
export function registerTimeTool() {
server.registerTool(
"get_current_time",
{
description: "Get the current date and time",
inputSchema: {
timezone: z
.string()
.optional()
.describe("Timezone (e.g., 'Asia/Shanghai', 'America/New_York')"),
},
},
async ({ timezone }) => {
const now = new Date();
let timeString: string;
if (timezone) {
try {
timeString = now.toLocaleString("en-US", { timeZone: timezone });
} catch {
return {
content: [
{
type: "text",
text: `Error: Invalid timezone '${timezone}'`,
},
],
isError: true,
};
}
} else {
timeString = now.toISOString();
}
return {
content: [
{
type: "text",
text: `Current time: ${timeString}`,
},
],
};
}
);
}

23
typescript/tsconfig.json Normal file
View File

@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"build"
]
}