Model Context Protocol (MCP) nodrošina spēcīgu, standartizētu veidu, kā LLM mijiedarboties ar ārējiem instrumentiem. bet, tiklīdz jūs pāriet no vietējā demo uz reālās pasaules pieteikumu, rodas kritisks jautājums: How do you secure it? MCP servera atklāšana bez drošības ir tāda, it kā jūsu mājas durvis būtu plaši atvērtas. ikviens varētu ieiet un izmantot jūsu rīkus, piekļūt jūsu datiem vai izraisīt haosu. Šis ceļvedis vadīs jūs, izmantojot Node.js MCP servera drošību no sākuma Mēs aptversim autentifikāciju (kas jūs esat?) un autorizāciju (ko jums ir atļauts darīt?), ar praktiskiem koda paraugiem, pamatojoties uz šo projektu, ko var atrast šeit . JSON Web Tokens (JWT) Azure paraugi/mcp konteineri Mērķis: no neaizsargāta līdz pilnīgi nodrošinātai Mūsu mērķis ir izmantot pamata MCP serveri un pievienot stabilu drošības slāni, kas: 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 Kāpēc JWT ir ideāls MCP drošībai JWT ir nozares standarts API drošībai, un tas ir ideāli piemērots MCP serveriem vairāku galveno iemeslu dēļ: 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: Drošības plūsmas vizualizācija Vizuālajiem skolēniem šī secību diagramma ilustrē pilnīgu autentifikācijas un autorizācijas plūsmu: Noteikumi par MCP specifikāciju atbilstību! Ir svarīgi atzīmēt, ka šis rokasgrāmata nodrošina praktisku, reālo īstenošanu MCP servera nodrošināšanai, bet tā Pilnībā īsteno . not Oficiālā MCP autorizācijas specifikācija Šajā īstenošanā galvenā uzmanība tiek pievērsta izturīgam, nepastāvīgam un plaši saprotamam modelim, izmantojot tradicionālos JWT un lomu balstītu piekļuves kontroli (RBAC), kas ir pietiekami daudziem lietošanas gadījumiem. Mēs iesakām skatīties uz palikt atjauninātiem un saņemt paziņojumus par turpmākiem uzlabojumiem. Github repozitorija 1. solis: Lomu un atļauju definēšana Pirms jebkura koda rakstīšanas mums ir jādefinē mūsu drošības noteikumi.Kādas lomas pastāv?Ko katra loma var darīt?Tā ir mūsu autorizācijas sistēmas pamats. Mūsu fails, mēs definējam un Tas padara mūsu kodu skaidru, lasāmu un mazāk pakļautu tipam. 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], }; 2. solis: izveidojiet JWT pakalpojumu Tālāk mums ir nepieciešams centralizēts pakalpojums, lai apstrādātu visu JWT saistīto loģiku: jaunu žetonu izveide testēšanai un, pats galvenais, ienākošo žetonu pārbaude. Šeit ir pilns fails. tā izmanto Bibliotēka, lai veiktu smago pacelšanu. 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."); } } 3. solis: Izveidojiet autentifikācijas vidusprogrammu "Middleware" ir funkcija, kas darbojas Jūsu galvenais pieprasījuma apstrādātājs.Tas ir ideāla vieta, kur ievietot mūsu drošības pārbaudi.Šī vidējā programmatūra pārbaudīs katru ienākošo pieprasījumu, meklē JWT Header, un pārbaudiet to. Pirms Authorization Ja tokens ir derīgs, tas pievieno lietotāja informāciju pieprasījuma objektam turpmākai lietošanai. kļūda un aptur pieprasījuma turpināšanu. 401 Unauthorized Lai padarītu šo tipu drošu, mēs arī paplašināsim Express Interfeiss, lai iekļautu mūsu Objekts ir. 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, }); } } 4. solis: MCP servera aizsardzība Tagad mums ir visi gabaliņi. Ļaujiet mums tos apvienot, lai aizsargātu mūsu serveri. Pirmkārt, mēs izmantojam mūsu middleware uz galveno MCP terminālu Tas nodrošina Pieprasījums Jums ir jābūt derīgam 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 Tālāk mēs izpildīsim mūsu smalko graudu atļaujas. Darbojas uz Mēs to mainīsim, lai pārbaudītu, vai autentificētajam lietotājam ir atļauju, pirms atgriežat rīku sarakstu. 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 } Ar šo izmaiņu, lietotājs ar Role var uzskaitīt rīkus, bet lietotājs bez Piekļuve tiks liegta. readonly LIST_TOOLS Secinājumi un turpmākie soļi Jūs esat veiksmīgi īstenojis stingru autentifikācijas un autorizācijas slāni jūsu MCP serverim. Skaidri definētas lomas un atļaujas. Izveidots centralizēts pakalpojums JWT apstrādei. Izveidojiet vidējo programmatūru, lai aizsargātu visus ienākošos pieprasījumus. Piespiedu granulu atļaujas rīka līmenī. Jūsu MCP serveris vairs nav atvērtas durvis – tas ir drošs pakalpojums.No šeit jūs varat paplašināt šīs koncepcijas, pievienojot vairāk lomu, vairāk atļauju un vēl sarežģītāku biznesa loģiku jūsu autorizācijas sistēmai. Mūsu zvaigzne palikt atjauninātiem un saņemt paziņojumus par turpmākiem uzlabojumiem. Github repozitorija