mcp-express-bolierplate
Enables creation of MCP servers with both stdio and HTTP transports, providing CRUD tools, resources, and prompts for user management, along with a CLI client for testing and integration.
README
MCP Node.js Boilerplate
Boilerplate สำหรับสร้าง MCP server และ Gemini agent ด้วย Node.js + TypeScript โดยฝั่ง HTTP ใช้ Express รองรับทั้ง
stdio— client เปิด server เป็น child process เหมาะกับ MCP host ที่รันในเครื่อง- Streamable HTTP — endpoint อยู่ที่
/mcpและนำออกเป็น HTTPS ได้ด้วย Cloudflare Tunnel - mock tools สำหรับ CRUD users
- static resource
users://allและ resource templateusers://{id} - prompt
summarize-users - MCP Inspector สำหรับ discovery, เรียก tool, อ่าน resource และขอ prompt
- Gemini agent ที่รับภาษาธรรมชาติและเลือกเรียก MCP tools ผ่าน OpenAI-compatible API
ข้อมูลเริ่มต้นอยู่ที่ src/data/users.json และถูกโหลดเข้า memory เมื่อเปิด server การแก้ไขผ่าน CRUD จะไม่เขียนทับไฟล์ และจะ reset เมื่อ restart process
Requirements
- Node.js 22.19 ขึ้นไป
- npm
cloudflaredเฉพาะกรณีต้องการ HTTPS tunnel- Gemini API key เฉพาะกรณีรัน Agent client
ติดตั้ง
npm install
ตรวจ build และ test:
npm run check
โครงสร้างสำคัญ
src/
├── agent/
│ ├── agent.ts # Gemini tool-calling loop สำหรับภาษาธรรมชาติ
│ └── mcp-transport.ts # MCP transport สำหรับ Agent
├── data/
│ └── users.json # mock seed data
├── lib/
│ └── api-client.ts # shared Axios instance สำหรับ upstream APIs
├── services/
│ └── user-service.ts # business logic กลางสำหรับ MCP capabilities
└── server/
├── mcp.ts # ประกอบ server และ capability registrations
├── tools/
│ └── user-tools.ts
├── resources/
│ └── user-resources.ts
├── prompts/
│ └── user-prompts.ts
├── schemas/
│ └── user.ts # shared MCP output schema
├── repository.ts # in-memory CRUD repository
├── stdio.ts # stdio entry point
└── http.ts # Express + Streamable HTTP entry point
scripts/
└── build.mjs # compile TypeScript และ copy mock JSON ไป dist
Factory ใน mcp.ts ถูกใช้ร่วมกันทั้งสอง transport ทำให้ความสามารถของ server ไม่ต่างกัน โดย Tools, Resources และ Prompts เรียก UserService กลางแทนการผูกกับ repository โดยตรง
เรียก External API ด้วย Axios
โปรเจกต์มี shared Axios instance ที่ src/lib/api-client.ts พร้อม base URL, timeout และ optional Bearer token สามารถ import ไปใช้ใน tool หรือ service ได้:
import { apiClient } from "../../lib/api-client.js";
const response = await apiClient.get("/users");
console.log(response.data);
กำหนดค่าตอนเปิด server:
API_BASE_URL=https://api.example.com \
API_TIMEOUT_MS=10000 \
API_TOKEN=your-token \
npm run server:http
ตัวอย่างนำไปใช้ใน MCP tool:
server.registerTool(
"list-upstream-users",
{
description: "List users from the configured upstream API",
inputSchema: z.object({}),
},
async () => {
const { data } = await apiClient.get("/users");
return {
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
structuredContent: { users: data },
};
},
);
หากไม่กำหนด API_BASE_URL ยังสามารถส่ง absolute URL ให้ Axios ได้โดยตรง หลีกเลี่ยงการ log API_TOKEN และควรเก็บ token ใน secret manager เมื่อ deploy production
วิธีรันแบบ stdio
ปกติไม่ต้องเปิด stdio server แยก เพราะ Inspector, Agent หรือ MCP host จะ spawn process ให้เอง
เปิด MCP Inspector พร้อม stdio server:
npm run inspector:stdio
เปิด server ตรง ๆ เพื่อรอ MCP host:
npm run server:stdio
ข้อควรระวัง: stdio ใช้ stdout เป็นช่อง JSON-RPC ดังนั้น log ของ server ต้องเขียนผ่าน stderr เช่น console.error เท่านั้น
ตัวอย่าง config สำหรับ MCP host โดยเปลี่ยน /absolute/path/to/mcp-boilerplate เป็น path จริง:
{
"mcpServers": {
"mock-users": {
"command": "node",
"args": [
"--import",
"tsx",
"/absolute/path/to/mcp-boilerplate/src/server/stdio.ts"
],
"cwd": "/absolute/path/to/mcp-boilerplate"
}
}
}
หรือ build ก่อนแล้วใช้ JavaScript โดยไม่ต้องพึ่ง tsx ตอน runtime:
npm run build
npm run start:stdio
config หลัง build:
{
"mcpServers": {
"mock-users": {
"command": "node",
"args": [
"/absolute/path/to/mcp-boilerplate/dist/server/stdio.js"
],
"cwd": "/absolute/path/to/mcp-boilerplate"
}
}
}
วิธีรันแบบ Express HTTP
Terminal 1 — เปิด server:
npm run server:http
ค่า default:
- MCP endpoint:
http://127.0.0.1:3000/mcp - health check:
http://127.0.0.1:3000/health
Terminal 2 — เปิด MCP Inspector และเชื่อมต่อ /mcp:
npm run inspector:http
เปลี่ยน port หรือ host ได้ด้วย environment variables:
HOST=127.0.0.1 PORT=4000 npm run server:http
npx @modelcontextprotocol/inspector --server-url http://127.0.0.1:4000/mcp --transport http
สำหรับ production build:
npm run build
npm run start:http
เปิด HTTPS ด้วย Cloudflare Tunnel
HTTPS ในตัวอย่างนี้ terminate ที่ Cloudflare ส่วน Express server ยังฟัง HTTP เฉพาะในเครื่อง
macOS ติดตั้ง cloudflared:
brew install cloudflared
Terminal 1 — เปิด MCP HTTP server:
npm run server:http
Terminal 2 — เปิด Quick Tunnel:
cloudflared tunnel --url http://127.0.0.1:3000
cloudflared จะแสดง URL ชั่วคราว เช่น:
https://random-words.trycloudflare.com
MCP endpoint ภายนอกจึงเป็น:
https://random-words.trycloudflare.com/mcp
Terminal 3 — ทดสอบผ่าน HTTPS tunnel:
npx @modelcontextprotocol/inspector --server-url https://random-words.trycloudflare.com/mcp --transport http
Quick Tunnel เหมาะสำหรับ development เท่านั้น และ Cloudflare ระบุว่าไม่รองรับ SSE ดังนั้น boilerplate นี้ตั้ง response mode เป็น auto ซึ่งคำสั่ง CRUD/discovery ทั่วไปจะตอบ JSON ได้ แต่ไม่ควรใช้ Quick Tunnel ทดสอบฟีเจอร์ที่ต้อง stream เช่น subscription ระยะยาว สำหรับ production ให้ใช้ named tunnel, hostname ของตนเอง, authentication และ authorization
เมื่อใช้ custom hostname ให้เพิ่ม hostname ใน allowlist:
ALLOWED_HOSTS=mcp.example.com npm run server:http
หลาย hostname คั่นด้วย comma:
ALLOWED_HOSTS=mcp.example.com,mcp-staging.example.com npm run server:http
localhost, 127.0.0.1, ::1 และ *.trycloudflare.com ถูกอนุญาตไว้สำหรับ development แล้ว
MCP Inspector
Inspector เป็นเครื่องมือหลักสำหรับตรวจ Server โดยไม่ผ่านโมเดล ใช้ดูและเรียก Tools, Resources และ Prompts ผ่าน Web UI
stdio — Inspector จะ spawn server ให้:
npm run inspector:stdio
HTTP — เปิด npm run server:http ก่อน แล้วรัน:
npm run inspector:http
สำหรับ remote URL:
npx @modelcontextprotocol/inspector --server-url https://mcp.example.com/mcp --transport http
Inspector v2 ต้องใช้ Node.js 22.19 ขึ้นไป ตัว server และ Agent จึงกำหนด Node.js requirement เดียวกันเพื่อลดความต่างระหว่าง development กับ production
Gemini MCP Agent
agent.ts มี MCP Client อยู่ภายในเพื่อเชื่อม Server, ส่ง MCP tool schemas ให้ Gemini, รัน tool calls และส่งผลกลับให้โมเดลจนได้คำตอบสุดท้าย
User prompt → Gemini → MCP tool call → MCP Server → tool result → Gemini → answer
สร้างไฟล์ .env และใส่ API key:
cp .env.example .env
GEMINI_API_KEY=your_real_key
GEMINI_MODEL=gemini-3.7-flash
รัน interactive agent ผ่าน stdio โดยไม่ต้องเปิด server แยก:
npm run agent:stdio
หรือส่งคำถามครั้งเดียว:
npm run agent:stdio -- "แสดงผู้ใช้ทั้งหมด"
npm run agent:stdio -- "สร้างผู้ใช้ชื่อ John อีเมล john@example.com role developer"
สำหรับ HTTP ให้เปิด server ใน Terminal 1:
npm run server:http
แล้วเปิด Agent ใน Terminal 2:
npm run agent:http
หรือ one-shot:
npm run agent:http -- "ดูรายละเอียด user ID 1"
Agent ใช้ OpenAI SDK กับ Gemini OpenAI-compatible endpoint ค่า GEMINI_BASE_URL จึงสามารถเปลี่ยนได้หากต้องการใช้ compatible gateway อื่น แต่ tool-calling compatibility ของแต่ละ provider อาจไม่เหมือนกันทั้งหมด
Model compatibility
Agent ใน boilerplate นี้ยังไม่ได้ model-agnostic 100% โดยผูกกับ OpenAI-compatible Chat Completions API, โครงสร้าง tool_calls และ OpenAI SDK แต่ไม่ได้ผูกกับ Gemini SDK โดยตรง
- Gemini: ใช้ได้ทันทีผ่าน Gemini OpenAI-compatible endpoint ตามค่า default
- OpenAI: ใช้ได้โดยตั้ง
GEMINI_BASE_URLเป็น OpenAI API base URL และกำหนด API key/model ของ OpenAI ในตัวแปรเดิม - Anthropic native API: ยังใช้โดยตรงไม่ได้ เพราะ message และ tool-use schema ต่างจาก OpenAI-compatible API ต้องเพิ่ม Anthropic adapter หรือใช้ gateway ที่แปลงเป็น OpenAI-compatible API
ตัวแปรยังใช้ prefix GEMINI_ เพราะ Gemini เป็น provider ตัวอย่างของ boilerplate นี้ ตัวอย่างการชี้ไป OpenAI:
GEMINI_API_KEY=your_openai_api_key
GEMINI_MODEL=your_openai_model
GEMINI_BASE_URL=https://api.openai.com/v1/
หากต้องการรองรับหลาย provider ใน production ควรแยก interface เช่น ModelProvider แล้วสร้าง adapter สำหรับ Gemini/OpenAI/Anthropic โดยให้ MCP client และ tool execution loop ใช้ interface กลางร่วมกัน
Tools, resources และ prompt ที่มีให้
| ชนิด | ชื่อ | หน้าที่ |
|---|---|---|
| Tool | list-users |
ดู users ทั้งหมด |
| Tool | get-user |
ดู user ตาม ID |
| Tool | create-user |
สร้าง user |
| Tool | update-user |
แก้ไข user |
| Tool | delete-user |
ลบ user |
| Resource | users://all |
JSON snapshot ของ users ทั้งหมด |
| Resource template | users://{id} |
JSON ของ user รายคน พร้อม ID completion |
| Prompt | summarize-users |
สร้างข้อความให้โมเดลสรุปข้อมูล users |
Environment variables
| ตัวแปร | Default | ใช้กับ |
|---|---|---|
HOST |
127.0.0.1 |
Express server bind address |
PORT |
3000 |
Express server port |
MCP_URL |
http://127.0.0.1:3000/mcp |
HTTP endpoint ที่ Agent เชื่อมต่อ |
MCP_ACCESS_TOKEN |
ไม่กำหนด | Bearer token สำหรับ remote MCP server |
ALLOWED_HOSTS |
ว่าง | เพิ่ม custom Host/Origin ที่ server ยอมรับ |
GEMINI_API_KEY |
จำเป็นสำหรับ Agent | Gemini API key |
GEMINI_MODEL |
gemini-3.7-flash |
โมเดลที่ Agent ใช้ |
GEMINI_BASE_URL |
Gemini OpenAI-compatible URL | Model API endpoint |
AGENT_MAX_TOOL_STEPS |
10 |
จำนวน tool-call rounds สูงสุดต่อคำถาม |
API_BASE_URL |
ไม่กำหนด | Base URL ของ upstream API ที่ Axios เรียก |
API_TIMEOUT_MS |
10000 |
Axios request timeout หน่วยมิลลิวินาที |
API_TOKEN |
ไม่กำหนด | Bearer token ที่ Axios แนบให้อัตโนมัติ |
ตัวอย่างค่าอยู่ใน .env.example โดย Agent จะโหลด .env อัตโนมัติผ่าน dotenv ส่วน Server และ Inspector ให้ export ตัวแปรหรือใส่ไว้หน้าคำสั่งตามตัวอย่างด้านบน
Security notes
- ตัวอย่างนี้ยังไม่มี authentication และ authorization ห้ามเปิด public endpoint ที่มีข้อมูลจริง
- validation ของ
HostและOriginเปิดเฉพาะ localhost, TryCloudflare และค่าจากALLOWED_HOSTS - mock repository อยู่ใน memory และตั้งใจไม่ persist ข้อมูล
- สำหรับ production ควรเพิ่ม auth, rate limiting, audit logging, persistent database และ TLS/trust-proxy configuration ที่เหมาะกับระบบจริง
Scripts ทั้งหมด
npm run dev:stdio # stdio server พร้อม watch mode
npm run dev:http # Express HTTP server พร้อม watch mode
npm run server:stdio # stdio server จาก TypeScript
npm run server:http # Express HTTP server จาก TypeScript
npm run agent:stdio
npm run agent:http
npm run inspector:stdio
npm run inspector:http # ต้องเปิด server:http ก่อน
npm run build
npm run start:stdio # รัน dist หลัง build
npm run start:http # รัน dist หลัง build
npm run start:agent:stdio
npm run start:agent:http
npm test
npm run check
อ้างอิง: MCP TypeScript SDK, MCP Inspector, Gemini OpenAI compatibility, OpenAI Chat Completions, Cloudflare Quick Tunnels
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.