Modelový kontextový protokol (MCP) poskytuje silný, standardizovaný způsob, jak LLM interagovat s externími nástroji. ale jakmile se přesunete z lokální demo do reálné aplikace, vzniká kritická otázka: How do you secure it? Vystavit server MCP bez zabezpečení je jako nechat přední dveře vašeho domu široko otevřené.Kdokoliv by mohl vstoupit a používat vaše nástroje, přístup k vašim datům nebo způsobit havárii. Tento průvodce vás provede zabezpečením serveru Node.js MCP od začátku pomocí Budeme pokrývat autentizaci (kdo jste vy?) a autorizaci (co můžete dělat?), s praktickými vzorky kódu založenými na tomto projektu, které lze nalézt na . JSON Web Tokens (JWT) Vzorky Azure/mcp-container-ts Cíl: Od nechráněného k plně zabezpečenému Naším cílem je mít základní server MCP a přidat robustní vrstvu zabezpečení, která: every request to ensure it comes from a known user. Authenticates the user, granting them specific permissions based on their role (e.g., vs. ). Authorizes admin readonly individual tools, so only authorized users can access them. Protects Proč je JWT ideální pro zabezpečení MCP JWT je průmyslový standard pro zabezpečení rozhraní API a je ideální pro servery MCP z několika klíčových důvodů: Each JWT contains all the information needed to verify a user. The server doesn't need to store session information, which makes it highly scalable—perfect for handling many concurrent requests from AI agents. Stateless: A JWT can carry user details, their role, and specific permissions directly within its payload. Self-Contained: JWTs are digitally signed. If a token is modified in any way, the signature becomes invalid, and the server will reject it. Tamper-Proof: A single JWT can be used to access multiple secured services, which is common in microservice architectures. Portable: Vizualizace bezpečnostního toku Pro vizuální učitele tento sériový diagram ilustruje úplný průběh ověřování a autorizace: Upozornění na dodržování specifikací MCP! Je důležité si uvědomit, že tato příručka poskytuje praktickou, reálnou implementaci pro zabezpečení serveru MCP, ale plně implementovat . not Oficiální specifikace autorizace MCP Tato implementace se zaměřuje na robustní, bezstátní a široce chápaný vzor používající tradiční JWT a kontrolu přístupu založenou na rolích (RBAC), což je dostatečné pro mnoho případů použití. Avšak pro plné dodržování specifikace MCP byste měli implementovat další funkce. Doporučujeme se podívat na zůstat aktuální a dostávat oznámení o budoucích vylepšeních. GitHub úložiště Krok 1: Definování rolí a oprávnění Před psaním jakéhokoli kódu musíme definovat naše bezpečnostní pravidla. Jaké role existují? Co může každá role dělat? V našem souboru, definujeme a To dělá náš kód jasný, čitelný a méně náchylný k typování. src/auth/authorization.ts UserRole Permission // src/auth/authorization.ts export enum UserRole { ADMIN = "admin", USER = "user", READONLY = "readonly", } export enum Permission { CREATE_TODOS = "create:todos", READ_TODOS = "read:todos", UPDATE_TODOS = "update:todos", DELETE_TODOS = "delete:todos", LIST_TOOLS = "list:tools", } // This interface defines the structure of our authenticated user export interface AuthenticatedUser { id: string; role: UserRole; permissions: Permission[]; } // A simple map to assign default permissions to each role const rolePermissions: Record<UserRole, Permission[]> = { [UserRole.ADMIN]: Object.values(Permission), // Admin gets all permissions [UserRole.USER]: [ Permission.CREATE_TODOS, Permission.READ_TODOS, Permission.UPDATE_TODOS, Permission.LIST_TOOLS, ], [UserRole.READONLY]: [Permission.READ_TODOS, Permission.LIST_TOOLS], }; Krok 2: Vytvoření služby JWT Dále potřebujeme centralizovanou službu pro zvládnutí veškeré logiky související s JWT: vytváření nových tokenů pro testování a, co je nejdůležitější, ověřování příchozích tokenů. Zde je kompletní Soubor - Používá se Knihovna se zabývá těžkým zvedáním. src/auth/jwt.ts jsonwebtoken // src/auth/jwt.ts import * as jwt from "jsonwebtoken"; import { AuthenticatedUser, getPermissionsForRole, UserRole, } from "./authorization.js"; // These values should come from environment variables for security const JWT_SECRET = process.env.JWT_SECRET!; const JWT_AUDIENCE = process.env.JWT_AUDIENCE!; const JWT_ISSUER = process.env.JWT_ISSUER!; const JWT_EXPIRY = process.env.JWT_EXPIRY || "2h"; if (!JWT_SECRET || !JWT_AUDIENCE || !JWT_ISSUER) { throw new Error("JWT environment variables are not set!"); } /** * Generates a new JWT for a given user payload. * Useful for testing or generating tokens on demand. */ export function generateToken( user: Partial<AuthenticatedUser> & { id: string } ): string { const payload = { id: user.id, role: user.role || UserRole.USER, permissions: user.permissions || getPermissionsForRole(user.role || UserRole.USER), }; return jwt.sign(payload, JWT_SECRET, { algorithm: "HS256", expiresIn: JWT_EXPIRY, audience: JWT_AUDIENCE, issuer: JWT_ISSUER, }); } /** * Verifies an incoming JWT and returns the authenticated user payload if valid. */ export function verifyToken(token: string): AuthenticatedUser { try { const decoded = jwt.verify(token, JWT_SECRET, { algorithms: ["HS256"], audience: JWT_AUDIENCE, issuer: JWT_ISSUER, }) as jwt.JwtPayload; // Ensure the decoded token has the fields we expect if (typeof decoded.id !== "string" || typeof decoded.role !== "string") { throw new Error("Token payload is missing required fields."); } return { id: decoded.id, role: decoded.role as UserRole, permissions: decoded.permissions || [], }; } catch (error) { // Log the specific error for debugging, but return a generic message console.error("JWT verification failed:", error.message); if (error instanceof jwt.TokenExpiredError) { throw new Error("Token has expired."); } if (error instanceof jwt.JsonWebTokenError) { throw new Error("Invalid token."); } throw new Error("Could not verify token."); } } Krok 3: Vytvoření Middleware pro autentizaci "Middleware" je funkce, která běží Je to ideální místo pro umístění naší bezpečnostní kontroly. Tento middleware bude kontrolovat každou příchozí žádost, hledat JWT v header a ověřte si to. Předtím Authorization Pokud je token platný, připojí informace uživatele k objektu požadavku pro pozdější použití. chybou a zastaví žádost z dalšího postupu. 401 Unauthorized Chceme-li tento typ-bezpečný, budeme také rozšířit Express Rozhraní zahrnuje naše předmětů . Request user // src/server-middlewares.ts import { Request, Response, NextFunction } from "express"; import { verifyToken, AuthenticatedUser } from "./auth/jwt.js"; // Extend the global Express Request interface to add our custom 'user' property declare global { namespace Express { interface Request { user?: AuthenticatedUser; } } } export function authenticateJWT( req: Request, res: Response, next: NextFunction ): void { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith("Bearer ")) { res.status(401).json({ error: "Authentication required", message: "Authorization header with 'Bearer' scheme must be provided.", }); return; } const token = authHeader.substring(7); // Remove "Bearer " try { const userPayload = verifyToken(token); req.user = userPayload; // Attach user payload to the request next(); // Proceed to the next middleware or request handler } catch (error) { res.status(401).json({ error: "Invalid token", message: error.message, }); } } Krok 4: Ochrana serveru MCP Nyní máme všechny kousky. Pojďme je spojit, abychom ochránili náš server. V první řadě používáme naše middleware k hlavnímu MCP koncovému bodu To zajišťuje Žádost o Musí mít platný JWT. authenticateJWT src/index.ts every /mcp // src/index.ts // ... other imports import { authenticateJWT } from "./server-middlewares.js"; // ... const MCP_ENDPOINT = "/mcp"; const app = express(); // Apply security middleware ONLY to the MCP endpoint app.use(MCP_ENDPOINT, authenticateJWT); // ... rest of the file Následně budeme prosazovat naše jemně zrnité oprávnění. Jedná se v Změníme jej, abychom zkontrolovali, zda ověřený uživatel má povolení před vrácením seznamu nástrojů. ListTools src/server.ts Permission.LIST_TOOLS // src/server.ts // ... other imports import { hasPermission, Permission } from "./auth/authorization.js"; // ... inside the StreamableHTTPServer class private setupServerRequestHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async (request) => { // The user is attached to the request by our middleware const user = this.currentUser; // 1. Check for an authenticated user if (!user) { return this.createRPCErrorResponse("Authentication required."); } // 2. Check if the user has the specific permission to list tools if (!hasPermission(user, Permission.LIST_TOOLS)) { return this.createRPCErrorResponse( "Insufficient permissions to list tools." ); } // 3. If checks pass, filter tools based on user's permissions const allowedTools = TodoTools.filter((tool) => { const requiredPermissions = this.getToolRequiredPermissions(tool.name); // The user must have at least one of the permissions required for the tool return requiredPermissions.some((p) => hasPermission(user, p)); }); return { jsonrpc: "2.0", tools: allowedTools, }; }); // ... other request handlers } S touto změnou, uživatel s Role může seznamovat nástroje, ale uživatel bez Povolení k přístupu bude odepřeno. readonly LIST_TOOLS Závěry a další kroky Gratulujeme! Úspěšně jste implementovali robustní úroveň ověřování a autorizace pro váš server MCP. Jasně definované role a oprávnění. Vytvořil centralizovanou službu pro manipulaci s JWT. Vytvořte middleware pro ochranu všech příchozích požadavků. Vynucená granulární oprávnění na úrovni nástroje. Váš server MCP již není otevřenými dveřmi – je to zabezpečená služba. Odtud můžete tyto koncepty rozšířit přidáním více rolí, více oprávnění a ještě složitější obchodní logiky do vašeho autorizačního systému. Naše hvězda zůstat aktuální a dostávat oznámení o budoucích vylepšeních. GitHub úložiště