คุณสามารถสร้าง AI workflows ได้อย่างง่ายดายด้วย Anakin AI โดยไม่ต้องมีความรู้เกี่ยวกับการเขียนโค้ด เชื่อมต่อกับ LLM APIs เช่น: GPT-4, Claude 3.5 Sonnet, Uncensored Dolphin-Mixtral, Stable Diffusion, DALLE, Web Scraping.... ใน Workflow เดียว!
ลืมเรื่องการเขียนโค้ดที่ซับซ้อน ไปอัตโนมัติงานที่น่าเบื่อของคุณด้วย Anakin AI!
ในช่วงเวลาจำกัด คุณยังสามารถใช้ Google Gemini 1.5 และ Stable Diffusion ฟรีได้!

บทนำ
Model Context Protocol (MCP) แสดงถึงความก้าวหน้าที่สำคัญในระบบนิเวศ AI โดยเสนอวิธีการมาตรฐานในการสื่อสารกับโมเดลภาษาขนาดใหญ่ แทนที่แต่ละแพลตฟอร์ม AI จะใช้รูปแบบที่ไม่เหมือนกัน MCP มีเป้าหมายเพื่อให้มีอินเทอร์เฟซที่สอดคล้องกันสำหรับการสอบถาม การตอบกลับ และการเรียกฟังก์ชันข้ามโมเดลและแพลตฟอร์มที่แตกต่างกัน
ในขณะที่โปรโตคอลเองกำลังพัฒนา การสร้างเซิร์ฟเวอร์พื้นฐานที่เข้ากันได้กับ MCP อาจทำได้ง่าย ในคู่มือนี้ ฉันจะพาคุณไปสร้างเซิร์ฟเวอร์ที่เรียบง่ายแต่ใช้งานได้ซึ่งปฏิบัติตามหลักการพื้นฐานของการจัดการข้อความในระบบ AI สมัยใหม่ การใช้งานของเราจะมุ่งเน้นไปที่การสร้างพื้นฐานที่คุณสามารถขยายเพิ่มเติมด้วยฟีเจอร์ที่ซับซ้อนมากขึ้น
10 นาทีเพียงพอไหม? สำหรับระบบที่พร้อมใช้งานในเชิงพาณิชย์ แน่นอนว่าไม่ แต่สำหรับโพรโตไทป์ที่ทำงานได้ซึ่งแสดงให้เห็นถึงแนวคิดหลัก? แน่นอน มาลองกันเถอะ!
สิ่งที่ต้องเตรียม
ก่อนที่เราจะเริ่ม คุณจะต้อง:
- ติดตั้ง Node.js (v16+) บนระบบของคุณ
- มีความรู้พื้นฐานเกี่ยวกับ JavaScript/TypeScript
- คุ้นเคยกับ Express.js หรือเฟรมเวิร์กเว็บที่คล้ายกัน
- มีโปรแกรมแก้ไขโค้ด (แนะนำ VS Code)
- เข้าถึงเทอร์มินัล/บรรทัดคำสั่ง
- มี npm หรือ yarn package manager
ขั้นตอนที่ 1: ตั้งค่าโปรเจกต์ของคุณ (2 นาที)
เริ่มต้นโดยการสร้างไดเรกทอรีใหม่และเริ่มต้นโปรเจกต์ของเรา:
mkdir mcp-server
cd mcp-server
npm init -y
ตอนนี้ ติดตั้ง Dependencies ที่จำเป็น:
npm install express cors typescript ts-node @types/node @types/express @types/cors
npm install --save-dev nodemon
สร้างไฟล์กำหนดค่าของ TypeScript:
npx tsc --init
แก้ไขไฟล์ tsconfig.json
ที่ถูกสร้างขึ้นเพื่อลงทะเบียนการตั้งค่าที่สำคัญเหล่านี้:
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
อัปเดตส่วน scripts ใน package.json
ของคุณ:
"scripts": {
"start": "node dist/index.js",
"dev": "nodemon --exec ts-node src/index.ts",
"build": "tsc"
}
ขั้นตอนที่ 2: สร้างเซิร์ฟเวอร์หลัก (3 นาที)
สร้างไดเรกทอรีที่ใช้และไฟล์เซิร์ฟเวอร์หลัก:
mkdir -p src/handlers
touch src/index.ts
touch src/handlers/messageHandler.ts
touch src/types.ts
เรามากำหนดประเภทของเราก่อนใน src/types.ts
:
// โครงสร้างข้อความพื้นฐาน
export interface Content {
type: string;
text?: string;
}
export interface Message {
role: "user" | "assistant" | "system";
content: Content[] | string;
}
// โครงสร้างคำขอและการตอบสนอง
export interface ModelRequest {
messages: Message[];
max_tokens?: number;
temperature?: number;
stream?: boolean;
}
export interface ModelResponse {
message: Message;
}
// อินเตอร์เฟสการเรียกเครื่องมือ
export interface Tool {
name: string;
description: string;
input_schema: {
type: string;
properties: Record<string, any>;
required?: string[];
};
}
export interface ToolCall {
type: "tool_call";
id: string;
name: string;
input: Record<string, any>;
}
export interface ToolResult {
type: "tool_result";
tool_call_id: string;
content: string;
}
ตอนนี้ให้ดำเนินการเซิร์ฟเวอร์พื้นฐานใน src/index.ts
:
import express from 'express';
import cors from 'cors';
import { handleMessageRequest } from './handlers/messageHandler';
const app = express();
const PORT = process.env.PORT || 3000;
// มิดเดิลแวร์
app.use(cors());
app.use(express.json({ limit: '10mb' }));
// จุดเชื่อมหลักสำหรับการประมวลผลข้อความ
app.post('/v1/messages', handleMessageRequest);
// จุดเช็คสุขภาพ
app.get('/health', (req, res) => {
res.status(200).json({ status: 'ok' });
});
// เริ่มเซิร์ฟเวอร์
app.listen(PORT, () => {
console.log(`เซิร์ฟเวอร์กำลังทำงานที่พอร์ต ${PORT}`);
console.log(`เช็คสุขภาพ: http://localhost:${PORT}/health`);
console.log(`จุดเชื่อมข้อความ: http://localhost:${PORT}/v1/messages`);
});
ถัดไป ดำเนินการจัดการข้อความใน src/handlers/messageHandler.ts
:
import { Request, Response } from 'express';
import { ModelRequest, ModelResponse, Message, Content } from '../types';
export async function handleMessageRequest(req: Request, res: Response) {
try {
const request = req.body as ModelRequest;
// การตรวจสอบพื้นฐาน
if (!request.messages || !Array.isArray(request.messages) || request.messages.length === 0) {
return res.status(400).json({ error: 'รูปแบบคำขอไม่ถูกต้อง อาร์เรย์ข้อความจำเป็นต้องมี' });
}
// บันทึกคำขอที่เข้ามา (สำหรับการดีบัก)
console.log('ได้รับคำขอที่มี', request.messages.length, 'ข้อความ');
// ประมวลผลข้อความ
const response = processMessages(request.messages);
// ส่งคืนการตอบสนอง
return res.status(200).json(response);
} catch (error) {
console.error('เกิดข้อผิดพลาดในการประมวลผลคำขอ:', error);
return res.status(500).json({ error: 'ข้อผิดพลาดของเซิร์ฟเวอร์' });
}
}
function processMessages(messages: Message[]): ModelResponse {
// ดึงข้อความที่ผู้ใช้ส่งมาเป็นล่าสุด
const lastUserMessage = findLastUserMessage(messages);
if (!lastUserMessage) {
return createErrorResponse("ไม่พบข้อความจากผู้ใช้ในการสนทนา");
}
const userQuery = extractTextContent(lastUserMessage);
// ลอจิกการสร้างการตอบสนองพื้นฐาน
let responseText = "";
if (userQuery.toLowerCase().includes('hello') || userQuery.toLowerCase().includes('hi')) {
responseText = "สวัสดี! ฉันสามารถช่วยเหลือคุณได้อย่างไรในวันนี้?";
} else if (userQuery.toLowerCase().includes('weather')) {
responseText = "ฉันไม่มีข้อมูลสภาพอากาศแบบเรียลไทม์ แต่ฉันสามารถช่วยคุณเข้าใจรูปแบบสภาพอากาศโดยรวมได้";
} else if (userQuery.toLowerCase().includes('time')) {
responseText = `เวลาปัจจุบันบนเซิร์ฟเวอร์คือ ${new Date().toLocaleTimeString()}.`;
} else {
responseText = "ฉันได้รับข้อความของคุณแล้ว นี่คือการตอบสนองเป็นเซิร์ฟเวอร์เบื้องต้น";
}
// สร้างและส่งคืนการตอบสนอง
return {
message: {
role: "assistant",
content: [{
type: "text",
text: responseText
}]
}
};
}
function findLastUserMessage(messages: Message[]): Message | undefined {
// ค้นหาข้อความล่าสุดที่มีบทบาทเป็น 'ผู้ใช้'
for (let i = messages.length - 1; i >= 0; i--) {
if (messages[i].role === 'user') {
return messages[i];
}
}
return undefined;
}
function extractTextContent(message: Message): string {
if (typeof message.content === 'string') {
return message.content;
} else if (Array.isArray(message.content)) {
return message.content
.filter(item => item.type === 'text' && item.text)
.map(item => item.text)
.join(' ');
}
return '';
}
function createErrorResponse(errorMessage: string): ModelResponse {
return {
message: {
role: "assistant",
content: [{
type: "text",
text: `ข้อผิดพลาด: ${errorMessage}`
}]
}
};
}
ขั้นตอนที่ 3: เพิ่มความสามารถในการเรียกเครื่องมือ (3 นาที)
สร้างไฟล์ใหม่สำหรับการกำหนดและการใช้งานเครื่องมือ:
touch src/tools.ts
ดำเนินการเครื่องมือพื้นฐานใน src/tools.ts
:
import { Tool } from './types';
// การกำหนดเครื่องมือ
export const availableTools: Tool[] = [
{
name: "get_current_time",
description: "รับเวลาปัจจุบันจากเซิร์ฟเวอร์",
input_schema: {
type: "object",
properties: {
timezone: {
type: "string",
description: "เขตเวลา (เป็นตัวเลือก เริ่มต้นที่เขตเวลาเซิร์ฟเวอร์)"
}
}
}
},
{
name: "calculate",
description: "ทำการคำนวณทางคณิตศาสตร์",
input_schema: {
type: "object",
properties: {
expression: {
type: "string",
description: "นิพจน์ทางคณิตศาสตร์ที่ต้องการประเมิน"
}
},
required: ["expression"]
}
}
];
// การติดตั้งเครื่องมือ
export function executeToolCall(name: string, params: Record<string, any>): string {
switch (name) {
case "get_current_time":
return getTime(params.timezone);
case "calculate":
return calculate(params.expression);
default:
throw new Error(`เครื่องมือที่ไม่รู้จัก: ${name}`);
}
}
function getTime(timezone?: string): string {
const options: Intl.DateTimeFormatOptions = {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
timeZoneName: 'short'
};
try {
if (timezone) {
options.timeZone = timezone;
}
return new Date().toLocaleTimeString('en-US', options);
} catch (error) {
return `${new Date().toLocaleTimeString()} (เวลาเซิร์ฟเวอร์)`;
}
}
function calculate(expression: string): string {
try {
// ระวัง: ในแอปพลิเคชันจริง คุณควรใช้วิธีการประเมินที่ปลอดภัยกว่า
// นี่คือตัวอย่างที่เรียบง่ายเพื่อการสาธิตเท่านั้น
const sanitizedExpression = expression.replace(/[^0-9+\-*/().\s]/g, '');
const result = eval(sanitizedExpression);
return `${expression} = ${result}`;
} catch (error) {
return `ข้อผิดพลาดในการคำนวณ ${expression}: ${error instanceof Error ? error.message : String(error)}`;
}
}
ตอนนี้ อัปเดตการจัดการข้อความเพื่อสนับสนุนการเรียกเครื่องมือโดยการปรับปรุง src/handlers/messageHandler.ts
:
// เพิ่มการนำเข้าดังต่อไปนี้ที่ด้านบน
import { availableTools, executeToolCall } from '../tools';
import { ToolCall, ToolResult } from '../types';
// อัปเดตฟังก์ชัน handleMessageRequest
export async function handleMessageRequest(req: Request, res: Response) {
try {
const request = req.body as ModelRequest;
// การตรวจสอบพื้นฐาน
if (!request.messages || !Array.isArray(request.messages) || request.messages.length === 0) {
return res.status(400).json({ error: 'รูปแบบคำขอไม่ถูกต้อง อาร์เรย์ข้อความจำเป็นต้องมี' });
}
// ตรวจสอบว่าคำขอนี้มีผลลัพธ์จากเครื่องมือหรือไม่
const lastMessage = request.messages[request.messages.length - 1];
if (lastMessage.role === 'assistant' && Array.isArray(lastMessage.content)) {
const toolCalls = lastMessage.content.filter(item =>
item.type === 'tool_call') as ToolCall[];
if (toolCalls.length > 0) {
// นี่เป็นการติดตามผลด้วยผลลัพธ์จากเครื่องมือ
return handleToolResultsResponse(request, res);
}
}
// ประมวลผลเป็นข้อความทั่วไป
const response = processMessages(request.messages);
// ส่งคืนการตอบสนอง
return res.status(200).json(response);
} catch (error) {
console.error('เกิดข้อผิดพลาดในการประมวลผลคำขอ:', error);
return res.status(500).json({ error: 'ข้อผิดพลาดของเซิร์ฟเวอร์' });
}
}
// เพิ่มฟังก์ชันนี้เพื่อตอบสนองต่อการเรียกเครื่องมือ
function handleToolResultsResponse(request: ModelRequest, res: Response) {
const messages = request.messages;
const lastAssistantMessage = messages[messages.length - 1];
if (lastAssistantMessage.role !== 'assistant' || !Array.isArray(lastAssistantMessage.content)) {
return res.status(400).json({ error: 'รูปแบบผลลัพธ์จากเครื่องมือไม่ถูกต้อง' });
}
// ค้นหาการเรียกเครื่องมือและผลลัพธ์
const toolCalls = lastAssistantMessage.content.filter(
item => item.type === 'tool_call'
) as ToolCall[];
const toolResults = lastAssistantMessage.content.filter(
item => item.type === 'tool_result'
) as ToolResult[];
// ประมวลผลผลลัพธ์
let finalResponse = "ฉันได้ประมวลผลข้อมูลดังต่อไปนี้:\n\n";
toolResults.forEach(result => {
const relatedCall = toolCalls.find(call => call.id === result.tool_call_id);
if (relatedCall) {
finalResponse += `- ${relatedCall.name}: ${result.content}\n`;
}
});
return res.status(200).json({
message: {
role: "assistant",
content: [{ type: "text", text: finalResponse }]
}
});
}
// ปรับเปลี่ยนฟังก์ชัน processMessages เพื่อจัดการกับการเรียกเครื่องมือที่อาจเกิดขึ้น
function processMessages(messages: Message[]): ModelResponse {
const lastUserMessage = findLastUserMessage(messages);
if (!lastUserMessage) {
return createErrorResponse("ไม่พบข้อความจากผู้ใช้ในการสนทนา");
}
const userQuery = extractTextContent(lastUserMessage);
// ค้นหาคำสำคัญที่อาจกระตุ้นการใช้เครื่องมือ
if (userQuery.toLowerCase().includes('time')) {
return {
message: {
role: "assistant",
content: [
{ type: "tool_call", id: "call_001", name: "get_current_time", input: {} },
{
type: "text",
text: "ฉันจะตรวจสอบเวลาปัจจุบันให้คุณ."
}
]
}
};
} else if (userQuery.toLowerCase().match(/calculate|compute|what is \d+[\+\-\*\/]/)) {
// ดึงนิพจน์การคำนวณที่อาจเกิดขึ้น
const expression = userQuery.match(/(\d+[\+\-\*\/\(\)\.]*\d+)/)?.[0] || "1+1";
return {
message: {
role: "assistant",
content: [
{
type: "tool_call",
id: "call_002",
name: "calculate",
input: { expression }
},
{
type: "text",
text: `ฉันจะคำนวณ ${expression} ให้คุณ.`
}
]
}
};
}
// การตอบสนองเริ่มต้นสำหรับคำถามอื่น ๆ
return {
message: {
role: "assistant",
content: [{
type: "text",
text: `ฉันได้รับข้อความของคุณ: "${userQuery}" ฉันสามารถช่วยคุณได้อย่างไรต่อไป?`
}]
}
};
}
ขั้นตอนที่ 4: การทดสอบและการนำไปใช้งาน (2 นาที)
มาสร้างสคริปต์การทดสอบง่าย ๆ เพื่อตรวจสอบเซิร์ฟเวอร์ของเรากัน สร้างไฟล์ test.js
ในไดเรกทอรีหลัก:
const fetch = require('node-fetch');
async function testServer() {
const url = 'http://localhost:3000/v1/messages';
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
messages: [
{
role: "user",
content: [
{
type: "text",
text: "ตอนนี้เวลาเท่าไหร่?"
}
]
}
]
})
});
const data = await response.json();
console.log(JSON.stringify(data, null, 2));
}
testServer().catch(console.error);
เพื่อตรวจสอบเซิร์ฟเวอร์ของคุณ:
# เริ่มเซิร์ฟเวอร์
npm run dev
# ในเทอร์มินัลอื่น เรียกใช้การทดสอบ
node test.js
เพื่อการนำไปใช้งานอย่างรวดเร็ว เรามาสร้างไฟล์ Dockerfile ง่าย ๆ:
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
สร้างและรันคอนเทนเนอร์:
docker build -t mcp-server .
docker run -p 3000:3000 mcp-server
บทสรุป
ในเวลาเพียง 10 นาที เราได้สร้างเซิร์ฟเวอร์พื้นฐานที่นำเสนอแนวคิดหลักของโปรโตคอลข้อความ AI สมัยใหม่ เซิร์ฟเวอร์ของเราสามารถ:
- ประมวลผลคำขอข้อความที่มีโครงสร้าง
- ตอบสนองในรูปแบบมาตรฐาน
- จัดการฟังก์ชันการเรียกเครื่องมือพื้นฐาน
- ประมวลผลและตอบสนองต่อผลลัพธ์จากเครื่องมือ
แม้การใช้งานนี้จะถูกทำให้เรียบง่าย แต่มันให้พื้นฐานที่มั่นคงสำหรับการพัฒนาต่อไป เพื่อขยายเซิร์ฟเวอร์นี้ให้ใช้ในงานผลิตจริง ให้นึกถึง:
- การเพิ่มการตรวจสอบสิทธิ์และการจำกัดอัตรา
- การดำเนินการจัดการข้อผิดพลาดและการตรวจสอบให้ถูกต้องอย่างเหมาะสม
- การเชื่อมต่อกับโมเดล AI ที่แท้จริงสำหรับการประมวลผล
- การเพิ่มเครื่องมือที่ซับซ้อนมากขึ้น
- การดำเนินการส่งข้อมูลแบบสตรีม
- การเพิ่มบันทึกและการตรวจสอบอย่างครอบคลุม
จำไว้ว่าขณะที่การใช้งานของเราสอดคล้องกับหลักการทั่วไปของโปรโตคอลข้อความ AI สมัยใหม่ การใช้งานเฉพาะอย่างของ OpenAI's API หรือ Anthropic's Claude API อาจมีข้อกำหนดเพิ่มเติมหรือลักษณะเฉพาะที่แตกต่างกันในรูปแบบที่คาดหวังของพวกเขาเสมอ ตรวจสอบเอกสารทางการสำหรับบริการเฉพาะที่คุณกำลังเชื่อมต่อ
สาขาของโปรโตคอลข้อความ AI กำลังพัฒนาอย่างรวดเร็ว ดังนั้นให้ติดตามความก้าวหน้าล่าสุดและเตรียมตัวปรับเปลี่ยนการใช้งานของคุณเมื่อมาตรฐานพัฒนาไปเรื่อย ๆ โดยการเข้าใจแนวคิดหลักที่แสดงให้เห็นในคู่มือนี้ คุณจะมีความพร้อมในการทำงานกับความก้าวหน้าใหม่ ๆ ที่เกิดขึ้นในสาขาที่น่าตื่นเต้นนี้