Amankan server MCP Anda: daftar periksa pengembang 8 poin
43 kerangka kerja agen dikirimkan dengan kerentanan yang tertanam pada tahun 2026. Delapan pemeriksaan untuk mengunci server MCP Anda sebelum agen AI menemukan celahnya.
Pada bulan November 2026, Barracuda melaporkan bahwa 43 komponen kerangka agen dikirimkan dengan kerentanan yang tertanam melalui kompromi rantai pasokan. Penyerang tidak membobol server. Mereka meracuni alat-alat yang dimiliki agen AI panggilan. 10 Teratas Aplikasi Agen OWASP sekarang mencantumkan Kerentanan Rantai Pasokan dan Penyalahgunaan Alat sebagai khusus kategori.
Server MCP (Model Context Protocol) mengekspos API Anda sebagai alat yang dapat dipanggil untuk asisten AI: Claude Desktop, Kursor, VS Code Copilot, Selancar Angin. Setiap alat yang Anda daftarkan menjadi permukaan serangan. Dan sebagian besar server MCP dikirimkan tanpa autentikasi, tanpa validasi input, dan tanpa pencatatan.
Posting ini adalah daftar periksa 8 poin untuk mengamankan server MCP Anda. Setiap item menyertakan kode kerja yang Anda bisa beradaptasi. Contohnya menggunakan API Botoi untuk validasi skema, hashing, dan decoding JWT, tetapi polanya berlaku untuk server MCP mana pun.
Masalah keamanan MCP dalam satu tabel
| Mempertaruhkan | Apa yang terjadi | Barang daftar periksa |
|---|---|---|
| Tidak ada autentikasi pada titik akhir MCP | Setiap klien di jaringan memanggil alat apa pun | #1 Tambahkan otentikasi |
| Semua alat terkena semua kunci | Agen pemantauan read-only memicu operasi yang merusak | #2 Alat cakupan per kunci |
| Tidak ada validasi masukan | Agen mengirim JSON dalam format yang salah; alat mogok atau menjalankan operasi yang tidak diinginkan | #3 Validasi dengan Zod |
| Anotasi alat tidak ada | Agen tidak dapat membedakan alat baca-saja dari alat destruktif | #4 Tetapkan anotasi |
| Tidak ada batasan tarif | Satu agen perulangan menghabiskan kuota API Anda dalam hitungan menit | #5 Batas tarif per agen |
| Tidak ada jejak audit | Anda tidak dapat melacak agen mana yang menyebabkan masalah produksi | #6 Catat pemanggilan |
| Gangguan nyata pada alat | Penyerang memodifikasi definisi alat untuk mengalihkan panggilan | #7 Pin dan manifes hash |
| Tidak ada konfirmasi untuk penulisan | Agen membuat, menghapus, atau memodifikasi data tanpa tinjauan manusia | #8 Operasi destruktif Sandbox |
1. Tambahkan autentikasi ke titik akhir MCP Anda
"Ada di localhost" bukan model keamanan. Ekstensi browser, proses lokal, dan kode apa pun yang berjalan
mesin yang sama dapat mencapainya localhost:3000. MCP jarak jauh berkembang pesat; Claude Desktop, Kursor,
dan Windsurf semuanya mendukung koneksi ke server MCP jarak jauh melalui HTTPS.
Memerlukan token Pembawa pada setiap permintaan. Server MCP Botoi di api.botoi.com/mcp menerima API
kunci melalui Authorization tajuk. Tanpa kunci yang valid, Anda mendapatkan 5 permintaan per menit
dan 100 per hari; dengan satu, batasannya sesuai dengan rencana Anda.
Jika agen Anda meneruskan JWT dan bukan kunci statis, dekodekan kode tersebut untuk mengekstrak cakupan dan identitas. Begini caranya untuk memeriksa JWT dari header permintaan MCP:
curl -s -X POST https://api.botoi.com/v1/jwt/decode \\
-H "Content-Type: application/json" \\
-d '{
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZ2VudC1jdXJzb3ItNDIiLCJzY29wZSI6InJlYWQ6ZG5zIHJlYWQ6c3NsIiwiaWF0IjoxNzE3MDAwMDAwfQ.signature"
}'
{
"success": true,
"data": {
"header": { "alg": "RS256", "typ": "JWT" },
"payload": {
"sub": "agent-cursor-42",
"scope": "read:dns read:ssl",
"iat": 1717000000
},
"signature": "signature"
}
}
Itu sub klaim mengidentifikasi agen. Itu scope klaim mencantumkan alat apa yang bisa digunakan
akses. Verifikasi sisi server tanda tangan sebelum memercayai nilai-nilai ini.
2. Alat cakupan per kunci API
Tidak semua agen membutuhkan semua alat. Agen pemantauan yang memeriksa catatan DNS tidak boleh mengakses a titik akhir pembuatan tempel. Buat daftar yang diizinkan yang memetakan setiap kunci API ke serangkaian alat tertentu.
// Scope tools per API key using an allowlist
interface AgentPermissions {
allowedTools: Set<string>;
maxBurst: number;
dailyLimit: number;
}
const AGENT_PERMISSIONS: Record<string, AgentPermissions> = {
"key_readonly_monitor": {
allowedTools: new Set(["lookup_dns", "lookup_ssl", "lookup_ip"]),
maxBurst: 10,
dailyLimit: 500,
},
"key_full_access": {
allowedTools: new Set(["*"]), // wildcard for all tools
maxBurst: 30,
dailyLimit: 5000,
},
};
function canUseTool(apiKey: string, toolName: string): boolean {
const perms = AGENT_PERMISSIONS[apiKey];
if (!perms) return false;
if (perms.allowedTools.has("*")) return true;
return perms.allowedTools.has(toolName);
}
Server MCP Botoi menampilkan 49 alat yang dikurasi dari 150+ titik akhir API. Kurasi itu sendiri adalah sebuah bentuk pelingkupan: hanya alat yang masuk akal untuk asisten AI yang terdaftar. Server Anda harus melakukan hal yang sama.
3. Validasi input alat dengan skema Zod
Alat MCP menerima JSON sewenang-wenang dari agen. Agen dapat mengirim dimana kamu
mengharapkan string, atau menyertakan bidang yang tidak dikenali alat Anda. Validasi setiap input sebelum mengeksekusi.
Server MCP Botoi mengubah definisi jalur OpenAPI menjadi skema Zod saat startup menggunakan
schema-builder.ts. Itu buildZodSchema fungsi membaca spesifikasi OpenAPI Anda, peta
setiap tipe properti ke tipe Zod, dan menandai bidang yang wajib diisi:
import { z } from "zod";
import { buildZodSchema } from "./schema-builder";
// Build a Zod schema from your OpenAPI spec for each tool
const dnsSchema = z.object(buildZodSchema("/v1/dns/lookup", "post"));
function validateToolInput(toolName: string, input: unknown) {
const schemas: Record<string, z.ZodTypeAny> = {
lookup_dns: dnsSchema,
// ... one schema per tool
};
const schema = schemas[toolName];
if (!schema) {
throw new Error(\`Unknown tool: \${toolName}\`);
}
const result = schema.safeParse(input);
if (!result.success) {
return {
error: "Invalid input",
issues: result.error.issues.map((i) => ({
path: i.path.join("."),
message: i.message,
})),
};
}
return { data: result.data };
}
Hasilkan skema Zod dari input sampel
Jika Anda tidak memiliki spesifikasi OpenAPI, buat skema Zod dari contoh input alat:
curl -s -X POST https://api.botoi.com/v1/schema/json-to-zod \\
-H "Content-Type: application/json" \\
-d '{
"json": {
"domain": "github.com",
"check_mx": true,
"timeout_ms": 5000
}
}'
{
"success": true,
"data": {
"schema": "z.object({ domain: z.string(), check_mx: z.boolean(), timeout_ms: z.number() })"
}
}
Validasi input terhadap Skema JSON saat runtime
Untuk validasi runtime tanpa Zod, gunakan Skema JSON. Kirim skema dan masukan agen ke
/v1/schema/validate:
curl -s -X POST https://api.botoi.com/v1/schema/validate \\
-H "Content-Type: application/json" \\
-d '{
"schema": {
"type": "object",
"required": ["domain"],
"properties": {
"domain": { "type": "string", "minLength": 1 },
"record_type": { "type": "string", "enum": ["A", "AAAA", "MX", "TXT", "CNAME", "NS"] }
},
"additionalProperties": false
},
"data": { "domain": "stripe.com", "record_type": "MX" }
}'
Pengembalian masukan yang valid:
{
"success": true,
"data": {
"valid": true,
"errors": []
}
}
Jika ada agen yang lewat "record_type": "INVALID", Anda mendapatkan kesalahan yang dapat ditindaklanjuti sebelum alat Anda berjalan:
{
"success": true,
"data": {
"valid": false,
"errors": [
{
"path": "/record_type",
"message": "must be equal to one of the allowed values"
}
]
}
}
4. Atur anotasi alat
Protokol MCP mendefinisikan empat petunjuk anotasi: readOnlyHint, destructiveHint,
idempotentHint, Dan openWorldHint. Ini memberi tahu agen apakah suatu alat membaca data,
mengubah status, aman untuk mencoba lagi, atau menghubungi layanan eksternal. Kebanyakan server MCP mengabaikannya.
Server MCP Botoi memberi anotasi pada seluruh 49 alat. Berikut tampilan praktiknya:
// curated-tools.ts (from Botoi's MCP server)
export const CURATED_TOOLS: Record<string, CuratedTool> = {
lookup_dns: {
path: "/v1/dns/lookup",
method: "post",
title: "DNS Lookup",
description: "Query DNS records for a domain.",
annotations: {
readOnlyHint: true, // reads data, changes nothing
openWorldHint: true, // contacts external DNS servers
},
},
storage_paste_create: {
path: "/v1/paste/create",
method: "post",
title: "Create Paste",
description: "Store text content and return a short URL.",
annotations: {
destructiveHint: true, // creates new data
idempotentHint: false, // each call creates a new paste
},
},
};
Agen yang menghormati anotasi akan menghindari memanggil alat yang merusak tanpa konfirmasi dan lebih memilih alat idempoten ketika mencoba kembali permintaan yang gagal. Atur di setiap alat.
| Anotasi | Arti | Contoh |
|---|---|---|
readOnlyHint: true |
Alat membaca data, tidak mengubah apa pun | Pencarian DNS, pemeriksaan SSL, geolokasi IP |
destructiveHint: true |
Alat membuat, memperbarui, atau menghapus data | Buat tempel, buat URL pendek, kirim webhook |
idempotentHint: true |
Aman untuk menelepon berkali-kali dengan masukan yang sama | Pembuatan hash, pemformatan JSON, konversi unit |
openWorldHint: true |
Alat menghubungi layanan eksternal | DNS melalui HTTPS, WHOIS, ekstraksi metadata URL |
5. Batas tarif per identitas agen
Satu agen nakal yang terjebak dalam putaran percobaan ulang tidak akan menghabiskan seluruh kuota API Anda. Pembatasan tarif standar berdasarkan alamat IP saja tidak cukup; beberapa agen dapat berbagi IP yang sama, dan satu agen dapat merotasi IP.
Ekstrak identitas agen dari kunci API atau JWT, lalu terapkan batas per identitas menggunakan jendela geser atau ember token yang disimpan di KV:
// Hono middleware for per-agent rate limiting
import type { Context, Next } from "hono";
const BURST_LIMIT = 5; // requests per minute
const DAILY_LIMIT = 100; // requests per day
async function rateLimitAgent(c: Context, next: Next) {
// Extract agent identity from API key or JWT
const apiKey = c.req.header("Authorization")?.replace("Bearer ", "");
const agentId = apiKey || c.req.header("X-Forwarded-For") || "anonymous";
// Check burst limit (sliding window in KV)
const burstKey = \`rate:\${agentId}:burst\
Middleware autentikasi Botoi menerapkan dua lapisan: batas burst (5 permintaan per menit) dan batas harian (100 permintaan per hari) untuk akses anonim. Kunci yang diautentikasi mendapatkan batas yang lebih tinggi berdasarkan kuncinya Tingkat berlangganan Stripe. Terapkan pola dua lapis yang sama ke server MCP Anda.
6. Catat setiap pemanggilan alat dengan atribusi agen
Ketika terjadi kesalahan dalam produksi, Anda perlu menjawab tiga pertanyaan: agen mana yang menelepon alat, kapan, dan dengan masukan apa. Tanpa log pemanggilan, Anda melakukan debug secara buta.
Hash masukan alih-alih menyimpan argumen mentah. Ini memberi Anda cukup untuk mengkorelasikan dan menghapus duplikat tanpa mencatat data sensitif:
// Log every tool invocation with agent identity
interface ToolInvocationLog {
timestamp: string;
agent_id: string;
tool_name: string;
input_hash: string; // SHA-256 of the input (not the raw input)
duration_ms: number;
status: "success" | "error";
}
async function logToolInvocation(
agentId: string,
toolName: string,
input: unknown,
startTime: number,
status: "success" | "error"
) {
const inputStr = JSON.stringify(input);
const inputHash = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(inputStr)
);
const hashHex = Array.from(new Uint8Array(inputHash))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
const log: ToolInvocationLog = {
timestamp: new Date().toISOString(),
agent_id: agentId,
tool_name: toolName,
input_hash: hashHex,
duration_ms: Date.now() - startTime,
status,
};
// Send to your logging pipeline (Datadog, Loki, Cloudflare Logpush)
console.log(JSON.stringify(log));
}
Kirim log terstruktur ini ke pipeline Anda yang ada (Datadog, Grafana Loki, Cloudflare Logpush). Buat peringatan untuk pola yang tidak biasa: agen tunggal melakukan 10x volume panggilan normal, atau hanya baca agen mencoba memanggil alat destruktif.
7. Sematkan definisi alat dan periksa integritasnya
Laporan Barracuda menemukan penyerang memasukkan definisi alat berbahaya ke dalam kerangka agen melalui ketergantungan yang dikompromikan. Jika seseorang mengubah manifes alat MCP Anda (nama, deskripsi, atau parameter skema), agen akan memanggil alat dengan perilaku berbeda dari yang Anda inginkan.
Hash manifes alat Anda pada waktu pembuatan. Saat memulai, hitung ulang hash dan bandingkan:
import crypto from "node:crypto";
import Botoi from "@botoi/sdk";
const botoi = new Botoi();
// Your tool manifest (the source of truth)
const tools = [
{ name: "dns_lookup", path: "/v1/dns/lookup" },
{ name: "ip_lookup", path: "/v1/ip/lookup" },
{ name: "email_validate", path: "/v1/email/validate" },
// ... all your tools
];
const manifest = JSON.stringify(tools);
// Hash it at build time and store the expected hash
const EXPECTED_HASH = "a3f2b8c1d4e5f6..."; // from your CI build
// At startup, verify integrity
function verifyManifestIntegrity() {
const currentHash = crypto
.createHash("sha256")
.update(manifest)
.digest("hex");
if (currentHash !== EXPECTED_HASH) {
throw new Error(
\`Tool manifest tampered. Expected \${EXPECTED_HASH}, got \${currentHash}\`
);
}
console.log("Tool manifest integrity verified.");
}
// Or use the Botoi API for environments without Node crypto
async function verifyWithApi() {
const result = await botoi.hash.sha256({ input: manifest });
if (result.data.hash !== EXPECTED_HASH) {
throw new Error("Tool manifest tampered.");
}
}
Hasilkan hash dengan Botoi API
Untuk lingkungan CI atau runtime edge tanpa node:crypto:
curl -s -X POST https://api.botoi.com/v1/hash \\
-H "Content-Type: application/json" \\
-d '{
"text": "[{\\"name\\":\\"dns_lookup\\",\\"path\\":\\"/v1/dns/lookup\\"},{\\"name\\":\\"ip_lookup\\",\\"path\\":\\"/v1/ip/lookup\\"}]",
"algorithm": "sha256"
}'
{
"success": true,
"data": {
"hash": "a3f2b8c1d4e5f67890abcdef1234567890abcdef1234567890abcdef12345678",
"algorithm": "sha256"
}
}
Simpan hash yang diharapkan sebagai variabel lingkungan. Bandingkan pada waktu penerapan. Jika hashnya berbeda, memblokir penerapan.
8. Operasi destruktif sandbox
Alat yang menulis data, memicu efek samping, atau menghubungi layanan eksternal memerlukan alur konfirmasi. Jangan biarkan agen membuat 1.000 pasta atau mengaktifkan webhook tanpa peninjauan manusia.
// Confirmation flow for destructive MCP tools
interface ToolResult {
content: Array<{ type: string; text: string }>;
isError?: boolean;
}
function handleDestructiveTool(
toolName: string,
input: Record<string, unknown>,
confirmed: boolean
): ToolResult {
const destructiveTools = new Set([
"paste_create",
"short_url_create",
"webhook_inbox_create",
]);
if (!destructiveTools.has(toolName)) {
// Non-destructive: execute immediately
return executeTool(toolName, input);
}
if (!confirmed) {
// Return a preview instead of executing
return {
content: [{
type: "text",
text: JSON.stringify({
action: "confirmation_required",
tool: toolName,
input,
message: \`This tool will create new data. Pass "confirmed": true to proceed.\`,
}),
}],
};
}
// Confirmed: execute the destructive operation
return executeTool(toolName, input);
}
Polanya jelas: alat destruktif mengembalikan pratinjau pada panggilan pertama. Agen itu menunjukkan
pratinjau kepada pengguna. Hanya setelah pengguna mengonfirmasi, agen mengirim panggilan kedua
"confirmed": true.
Untuk alat yang menghubungi layanan eksternal (openWorldHint: true), pertimbangkan untuk menambahkan
batas waktu dan pemutus sirkuit. Jika API eksternal lambat atau tidak berfungsi, server MCP Anda tidak akan berfungsi
bertahan selamanya menunggu jawaban.
Bagaimana server MCP Botoi menerapkan pemeriksaan ini
Server MCP Botoi di api.botoi.com/mcp berfungsi sebagai referensi kerja untuk ini
daftar periksa. Berikut cara setiap item dipetakan:
| Barang daftar periksa | Bagaimana Botoi melakukannya |
|---|---|
| Otentikasi | Kunci API melalui Authorization tajuk; akses anonim dengan batasan tarif yang ketat |
| Pelingkupan alat | 49 alat yang dikurasi dari 150+ titik akhir; hanya alat yang sesuai dengan agen yang terdaftar |
| Validasi masukan | schema-builder.ts mengubah skema OpenAPI menjadi Zod; memvalidasi sebelum dieksekusi |
| Anotasi alat | Setiap alat masuk curated-tools.ts memiliki readOnlyHint, destructiveHint, dll. |
| Pembatasan tarif | 5 permintaan/mnt burst + 100 permintaan/hari batas anonim melalui KV; batas yang lebih tinggi per tingkat kunci API |
| Pencatatan | Log observasi Cloudflare Workers untuk setiap permintaan dengan atribusi agen |
| Tunjukkan integritas | Definisi alat menggunakan TypeScript yang dikontrol versi; disebarkan melalui CI tanpa mutasi runtime |
| Kotak pasir yang merusak | Alat penyimpanan (tempel, url pendek, webhook) terpisah dari alat pencarian baca-saja; anotasi menandakan risiko |
Anda dapat terhubung ke server MCP Botoi dari Claude Desktop, Claude Code, Cursor, VS Code, atau Windsurf. Itu halaman pengaturan MCP memiliki konfigurasi untuk setiap klien.
Daftar periksa keamanan server MCP Anda
Berikut daftar periksa selengkapnya, ringkas. Cetak, sematkan, atau tempelkan ke runbook tim Anda:
- Memerlukan autentikasi pada setiap titik akhir MCP (Token pembawa, kunci API, atau JWT)
- Petakan setiap kunci API ke daftar alat yang diizinkan
- Validasi setiap input alat dengan skema Zod atau Skema JSON sebelum dieksekusi
- Beri anotasi pada setiap alat dengan
readOnlyHint,destructiveHint,idempotentHint, DanopenWorldHint - Batas tarif per identitas agen, bukan per IP; gunakan batas burst dan harian
- Catat setiap pemanggilan alat dengan ID agen, nama alat, hash masukan, durasi, dan status
- Hash manifes alat Anda pada waktu pembuatan; verifikasi saat startup dan blokir penerapan yang dirusak
- Kembalikan pratinjau dari alat perusak; memerlukan konfirmasi eksplisit sebelum mengeksekusi
43 kerangka kerja agen dikirimkan dengan kerentanan yang tertanam pada tahun 2026. Server MCP adalah target berikutnya. Kedelapan pemeriksaan di atas tidak akan membuat server Anda kebal, namun akan menutup celah dari penyerang eksploitasi terlebih dahulu: titik akhir terbuka, masukan yang tidak divalidasi, dan pemanggilan yang tidak terlihat.
FAQ
- Apakah server MCP memerlukan otentikasi?
- Ya. Kebanyakan server MCP dikirimkan tanpa autentikasi, artinya klien mana pun yang mencapai titik akhir dapat memanggil alat apa pun. Seiring berkembangnya adopsi MCP jarak jauh, Anda memerlukan kunci API atau autentikasi berbasis JWT di setiap titik akhir. Hanya localhost bukanlah jaminan keamanan; proses lokal dan ekstensi browser juga dapat menjangkau localhost.
- Apa yang dimaksud dengan anotasi alat MCP dan mengapa itu penting?
- Anotasi alat adalah petunjuk metadata yang ditentukan dalam protokol MCP: readOnlyHint, destruktifHint, idempotentHint, dan openWorldHint. Mereka memberi tahu agen AI apakah suatu alat membaca data, mengubah status, aman untuk dicoba ulang, atau menghubungi layanan eksternal. Agen menggunakan petunjuk ini untuk membuat keputusan yang lebih aman tentang alat mana yang harus dipanggil dan dalam urutan apa.
- Bagaimana cara saya membatasi tarif agen AI yang menelepon server MCP saya?
- Tetapkan identitas kepada setiap agen (atau kunci API) dan terapkan batas tingkat per identitas. Gunakan algoritma token bucket atau jendela geser. Lacak permintaan di toko KV atau Redis. Server MCP milik Botoi menerapkan 5 permintaan per menit burst dan 100 permintaan per hari untuk akses anonim, dengan batas lebih tinggi untuk kunci yang diautentikasi.
- Bisakah saya memvalidasi input alat MCP dengan Zod?
- Ya. Alat MCP menerima JSON sewenang-wenang dari agen. Tentukan skema Zod untuk bentuk masukan yang diharapkan dari setiap alat dan validasi sebelum mengeksekusi. Anda dapat membuat skema Zod dari sampel JSON menggunakan titik akhir Botoi /v1/schema/json-to-zod, atau mengonversi definisi jalur OpenAPI ke objek Zod seperti yang dilakukan oleh Schema-builder.ts Botoi.
- Bagaimana cara mendeteksi gangguan pada manifes alat MCP saya?
- Hash manifes alat Anda dengan SHA-256 dan simpan hashnya. Sebelum setiap server dimulai atau diterapkan, hitung ulang hashnya dan bandingkan. Jika hashnya berbeda, seseorang (atau sesuatu) mengubah definisi alat Anda. Anda dapat menghitung hash SHA-256 melalui titik akhir Botoi /v1/hash atau dengan pustaka kripto asli.
Mulai membangun dengan botoi
150+ endpoint API untuk pencarian, pemrosesan teks, pembuatan gambar, dan utilitas developer. Paket gratis, tanpa kartu kredit.