Die Model Context Protocol (MCP) bied 'n kragtige, gestandaardiseerde manier vir LLMs om met eksterne gereedskap te interaksieer.Maar sodra jy van 'n plaaslike demo na 'n werklike aansoek beweeg, ontstaan 'n kritieke vraag: How do you secure it? Om 'n MCP-bediener sonder sekuriteit bloot te stel, is soos om die voordeur van jou huis heeltemal oop te laat. Hierdie gids sal jou deur die beveiliging van 'n Node.js MCP-bediener van die grond af met behulp van Ons sal authenticasie dek (wie is jy?) en autorisasie (wat is jy toegelaat om te doen?), met praktiese kode monsters gebaseer op hierdie projek wat gevind kan word by . JSON Web Tokens (JWT) Azure-monsters / mcp-container-ts Die doel: Van onbeskermde tot ten volle beskerm Ons doel is om 'n basiese MCP-bediener te neem en 'n robuuste sekuriteitslaag by te voeg wat: 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 Hoekom JWT ideaal is vir MCP Sekuriteit JWT is die industrie standaard vir die beveiliging van API's, en dit is 'n ideale pas vir MCP-servers vir 'n paar belangrike redes: 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: Visualisering van die sekuriteitsstroom Vir visuele leerlinge, hierdie volgorde diagram illustreer die volledige outentiek en autorisasie vloei: 'N Aantekening op MCP spesifikasie ooreenstemming! Dit is belangrik om op te let dat hierdie gids 'n praktiese, werklike implementasie bied vir die beveiliging van 'n MCP-bediener, maar dit doen dit. Volledige implementering van die . not Offisiële MCP-autorisasie spesifikasie Hierdie implementasie fokus op 'n robuuste, staatloze en algemeen verstaan patroon met behulp van tradisionele JWT's en rolgebaseerde toegangsbeheer (RBAC), wat genoeg is vir baie gebruik gevalle. Ons beveel aan om die om opgedateer te bly en kennisgewing te ontvang oor toekomstige verbeterings. Die GitHub repository Stap 1: Definieer rolle en toestemmings Voordat ons enige kode skryf, moet ons ons veiligheidsreëls definieer. Watter rolle bestaan? Wat kan elke rol doen? In ons Filter, ons definieer en Dit maak ons kode duidelik, leesbaar en minder geneig om te typ. 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], }; Stap 2: Skep 'n JWT-diens Volgende, ons benodig 'n sentrale diens om al die JWT-verwante logika te hanteer: die skep van nuwe tokens vir toetsing en, die belangrikste, die verifikasie van inkomende tokens. Hier is die volledige Die lêer gebruik die die biblioteek om die swaar lyf te doen. 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."); } } Stap 3: Bou die Authentification Middleware 'N 'middleware' is 'n funksie wat Dit is die perfekte plek om ons sekuriteitskoers te plaas. Hierdie middleware sal elke inkomende versoek inspekteer, kyk vir 'n JWT in die Header, en kyk na dit. Voordat Authorization As die token geldig is, voeg dit die gebruiker se inligting by die versoek voorwerp vir latere gebruik. 'n fout en stop die versoek om verder te gaan. 401 Unauthorized Om hierdie tipe-veilig te maak, sal ons ook Express se Interface om ons te sluit die voorwerp. 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, }); } } Stap 4: Beskerm die MCP-bediener Nou het ons al die stukke. Laat ons hulle saamstel om ons bediener te beskerm. Eerstens gebruik ons ons Middelware na die hoof MCP-endepunt in Dit verseker Vra vir Jy moet 'n geldig JWT hê. 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 Vervolgens sal ons ons goedgekeurde toestemmings handhaaf. Handel in Ons sal dit verander om te kyk of die geauthentifiseerde gebruiker die toestemming voordat jy die lys van gereedskap terugkeer. 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 } Met hierdie verandering, 'n gebruiker met 'n 'n rol kan gereedskap lys, maar 'n gebruiker sonder die Die toegang word geweier. readonly LIST_TOOLS Konklusie en volgende stappe Gelukwens! Jy het suksesvol implementeer 'n robuuste outentiek en autorisasie laag vir jou MCP-bediener. Definieer duidelike rolle en toestemmings. Skep 'n sentrale diens vir die hantering van JWT's. Gebou 'n middleware om alle inkomende versoekings te beskerm. Gedwingde granulêre toestemmings op die gereedskapsvlak. U MCP-bediener is nie meer 'n oop deur nie - dit is 'n veilige diens.Van hier af kan u hierdie konsepte uitbrei deur meer rolle, meer toestemmings en selfs meer komplekse besigheidslogika aan u autorisasie-stelsel toe te voeg. Ons sterre om opgedateer te bly en kennisgewing te ontvang oor toekomstige verbeterings. Die GitHub repository