MCP Security Best Practices: Authentication, Authorization & Supply Chain Protection
Security and privacy are paramount concerns when implementing Model Context Protocol (MCP) in production environments. As organizations connect AI systems to sensitive data sources and internal tools through MCP architecture, establishing robust security controls becomes essential for protecting data, maintaining compliance, and preventing unauthorized access.
Understanding MCP Security Model
MCP’s security model is built on clear trust boundaries between hosts (AI applications) and servers (context providers). Understanding these boundaries and implementing appropriate security controls at each layer enables organizations to safely leverage MCP’s capabilities while protecting sensitive resources.
Trust Boundaries in MCP
// MCP establishes clear trust boundaries
interface SecurityBoundaries {
// Host (AI application) boundary
host: {
authenticatesServers: boolean; // Host validates server identity
authorizesRequests: boolean; // Host controls what requests to make
sandboxesServers: boolean; // Host isolates server execution
};
// Server (context provider) boundary
server: {
authenticatesHosts: boolean; // Server validates host identity
authorizesAccess: boolean; // Server controls resource access
validatesInputs: boolean; // Server sanitizes all inputs
};
// Transport boundary
transport: {
encrypted: boolean; // Communication encrypted in transit
mutualTLS: boolean; // Both parties authenticate
};
}
Authentication Strategies
Server Authentication
Hosts must verify server identity before establishing connections to prevent man-in-the-middle attacks and unauthorized servers.
interface ServerAuthConfig {
// Certificate-based authentication
tls?: {
ca: string; // Certificate authority
cert?: string; // Client certificate
key?: string; // Client key
rejectUnauthorized: boolean; // Enforce certificate validation
};
// Token-based authentication
apiKey?: {
header: string; // Authorization header name
token: string; // API token value
prefix?: string; // Token prefix (e.g., "Bearer")
};
// OAuth 2.0 authentication
oauth?: {
tokenEndpoint: string;
clientId: string;
clientSecret: string;
scope: string[];
};
}
// Example: Secure server connection with TLS
const secureClient = new MCPClient({
serverConfig: {
command: 'mcp-server',
args: ['--secure'],
env: {
SERVER_API_KEY: process.env.MCP_SERVER_API_KEY
}
},
transport: {
type: 'https',
url: 'https://mcp-server.example.com',
tls: {
ca: fs.readFileSync('/path/to/ca-cert.pem'),
rejectUnauthorized: true
},
headers: {
'Authorization': `Bearer ${process.env.MCP_API_TOKEN}`
}
}
});
Host Authentication
Servers should authenticate hosts to ensure only authorized applications can access resources.
// Server-side host authentication
class SecureMCPServer implements MCPServer {
private authorizedHosts: Map<string, HostCredentials>;
async authenticateHost(request: ConnectionRequest): Promise<boolean> {
// Extract credentials from request
const apiKey = request.headers['authorization']?.replace('Bearer ', '');
if (!apiKey) {
throw new Error('Missing authentication credentials');
}
// Validate against known hosts
const hostCreds = this.authorizedHosts.get(apiKey);
if (!hostCreds) {
throw new Error('Invalid credentials');
}
// Verify credentials haven't expired
if (hostCreds.expiresAt < Date.now()) {
throw new Error('Credentials expired');
}
// Check IP allowlist if configured
if (hostCreds.allowedIPs && !hostCreds.allowedIPs.includes(request.ip)) {
throw new Error('IP not authorized');
}
return true;
}
async initialize(params: InitializeParams): Promise<ServerCapabilities> {
await this.authenticateHost(params.connectionRequest);
return this.capabilities;
}
}
Centralized Authentication Management
Centralized configuration management enables consistent authentication policies across all MCP deployments, reducing security risks from misconfiguration.
// Centralized authentication configuration
interface CentralAuthConfig {
defaultAuthMethod: 'apiKey' | 'oauth' | 'mtls';
// API key management
apiKeys: {
rotationPolicy: 'manual' | 'automatic';
rotationInterval?: number; // Days
keyLength: number;
allowedOrigins?: string[];
};
// OAuth configuration
oauth: {
provider: 'okta' | 'auth0' | 'custom';
tokenEndpoint: string;
scopes: string[];
tokenLifetime: number; // Seconds
};
// Mutual TLS configuration
mtls: {
caPath: string;
clientCertRequired: boolean;
allowedCertificates?: string[];
};
}
Organizations using Tetrate Agent Router Service (TARS) benefit from centralized authentication management that simplifies credential distribution and policy enforcement across all MCP servers and hosts.
Authorization and Access Control
Resource-Level Authorization
Implement fine-grained access controls to ensure hosts only access authorized resources.
interface ResourceACL {
resource: string; // Resource URI
allowedHosts: string[]; // Host identifiers
permissions: ResourcePermissions; // Read, write, execute
conditions?: AccessConditions; // Contextual conditions
}
interface ResourcePermissions {
read: boolean;
write: boolean;
execute: boolean;
}
interface AccessConditions {
timeRestrictions?: {
allowedHours: number[]; // 0-23
timezone: string;
};
ipRestrictions?: {
allowedCIDRs: string[];
};
rateLimit?: {
requestsPerMinute: number;
};
}
class AuthorizationService {
async authorizeResourceAccess(
hostId: string,
resourceUri: string,
permission: keyof ResourcePermissions,
context: RequestContext
): Promise<boolean> {
// Load ACL for resource
const acl = await this.loadResourceACL(resourceUri);
// Check if host is allowed
if (!acl.allowedHosts.includes(hostId)) {
this.auditLog.warn('Unauthorized resource access attempt', {
hostId,
resourceUri,
permission
});
return false;
}
// Check permission level
if (!acl.permissions[permission]) {
return false;
}
// Evaluate conditional access
if (acl.conditions) {
if (!await this.evaluateConditions(acl.conditions, context)) {
return false;
}
}
return true;
}
private async evaluateConditions(
conditions: AccessConditions,
context: RequestContext
): Promise<boolean> {
// Time-based restrictions
if (conditions.timeRestrictions) {
const hour = new Date().getHours();
if (!conditions.timeRestrictions.allowedHours.includes(hour)) {
return false;
}
}
// IP-based restrictions
if (conditions.ipRestrictions) {
const clientIP = context.clientIP;
const allowed = conditions.ipRestrictions.allowedCIDRs.some(cidr =>
this.ipInCIDR(clientIP, cidr)
);
if (!allowed) {
return false;
}
}
// Rate limiting
if (conditions.rateLimit) {
const requestCount = await this.getRequestCount(
context.hostId,
60 * 1000 // Last minute
);
if (requestCount >= conditions.rateLimit.requestsPerMinute) {
return false;
}
}
return true;
}
}
Tool-Level Authorization
Control which hosts can invoke specific tools to prevent unauthorized actions.
class ToolAuthorizationService {
private toolACLs: Map<string, ToolACL>;
async authorizeToolCall(
hostId: string,
toolName: string,
args: Record<string, unknown>
): Promise<boolean> {
const acl = this.toolACLs.get(toolName);
if (!acl) {
// Deny by default if no ACL defined
return false;
}
// Check host authorization
if (!acl.allowedHosts.includes(hostId)) {
return false;
}
// Validate argument constraints
if (acl.argumentConstraints) {
for (const [param, constraint] of Object.entries(acl.argumentConstraints)) {
const value = args[param];
// Type validation
if (constraint.type && typeof value !== constraint.type) {
return false;
}
// Range validation for numbers
if (constraint.min !== undefined && value < constraint.min) {
return false;
}
if (constraint.max !== undefined && value > constraint.max) {
return false;
}
// Pattern validation for strings
if (constraint.pattern && !new RegExp(constraint.pattern).test(String(value))) {
return false;
}
// Enum validation
if (constraint.allowedValues && !constraint.allowedValues.includes(value)) {
return false;
}
}
}
return true;
}
}
interface ToolACL {
toolName: string;
allowedHosts: string[];
argumentConstraints?: Record<string, ArgumentConstraint>;
}
interface ArgumentConstraint {
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
min?: number;
max?: number;
pattern?: string;
allowedValues?: unknown[];
}
TARS provides profile-based access control that enables teams to define granular permissions for resources and tools, ensuring principle of least privilege across MCP deployments.
Supply Chain Security
MCP’s extensible server ecosystem introduces supply chain risks similar to those seen in npm, PyPI, and other package ecosystems. The 2020 SolarWinds attack and numerous npm package compromises demonstrate the critical importance of supply chain security.
Server Provenance Verification
Verify the authenticity and integrity of MCP servers before deployment.
interface ServerProvenance {
name: string;
version: string;
publisher: string;
publisherVerified: boolean; // Publisher identity verified
signatures: {
algorithm: 'ed25519' | 'rsa';
publicKey: string;
signature: string;
}[];
checksums: {
algorithm: 'sha256' | 'sha512';
value: string;
}[];
buildAttestation?: {
builder: string; // CI/CD system
sourceRepo: string;
commitHash: string;
buildTime: string;
};
}
class ServerProvenanceVerifier {
async verifyServer(serverPath: string, provenance: ServerProvenance): Promise<boolean> {
// Verify checksums
const actualChecksum = await this.computeChecksum(serverPath, provenance.checksums.algorithm);
if (actualChecksum !== provenance.checksums.value) {
throw new Error('Checksum verification failed');
}
// Verify signatures
for (const sig of provenance.signatures) {
const valid = await this.verifySignature(
serverPath,
sig.publicKey,
sig.signature,
sig.algorithm
);
if (!valid) {
throw new Error('Signature verification failed');
}
}
// Verify publisher
if (provenance.publisherVerified) {
const trusted = await this.verifyPublisher(provenance.publisher);
if (!trusted) {
throw new Error('Publisher not trusted');
}
}
// Verify build provenance (SLSA compliance)
if (provenance.buildAttestation) {
const buildValid = await this.verifyBuildAttestation(
provenance.buildAttestation
);
if (!buildValid) {
throw new Error('Build attestation verification failed');
}
}
return true;
}
}
Trusted Server Catalog
Maintain a curated catalog of verified MCP servers to prevent malicious or vulnerable servers from being deployed.
interface TrustedServerCatalog {
servers: Map<string, TrustedServer>;
// Catalog management
addServer(server: TrustedServer): Promise<void>;
removeServer(serverName: string): Promise<void>;
updateServer(server: TrustedServer): Promise<void>;
// Verification
isServerTrusted(name: string, version: string): Promise<boolean>;
getServerInfo(name: string): Promise<TrustedServer | null>;
// Security scanning
scanServer(serverPath: string): Promise<ScanResults>;
}
interface TrustedServer {
name: string;
versions: {
version: string;
releaseDate: string;
securityScan: {
lastScanned: string;
vulnerabilities: Vulnerability[];
riskScore: number; // 0-100
};
provenance: ServerProvenance;
allowedEnvironments: ('dev' | 'staging' | 'production')[];
}[];
maintainer: {
name: string;
email: string;
verified: boolean;
};
repository: string;
license: string;
securityPolicy?: string; // URL to SECURITY.md
}
interface Vulnerability {
id: string; // CVE-ID or similar
severity: 'low' | 'medium' | 'high' | 'critical';
description: string;
affectedVersions: string[];
patchedVersion?: string;
mitigation?: string;
}
TARS includes a trusted MCP catalog that provides pre-vetted, security-scanned servers with verified provenance, reducing supply chain risks for enterprise deployments.
Dependency Scanning
Continuously scan MCP server dependencies for known vulnerabilities, similar to tools like Snyk, Dependabot, or FINOS’s security scanning initiatives.
class DependencyScannerService {
async scanServerDependencies(serverPath: string): Promise<ScanResults> {
// Parse dependency manifest (package.json, requirements.txt, etc.)
const dependencies = await this.parseDependencies(serverPath);
const vulnerabilities: Vulnerability[] = [];
for (const dep of dependencies) {
// Check against vulnerability databases
const cveResults = await this.checkNVD(dep.name, dep.version);
const ossIndexResults = await this.checkOSSIndex(dep.name, dep.version);
const ghAdvisories = await this.checkGitHubAdvisories(dep.name, dep.version);
vulnerabilities.push(
...cveResults,
...ossIndexResults,
...ghAdvisories
);
}
// Calculate risk score
const riskScore = this.calculateRiskScore(vulnerabilities);
// Check for known malicious packages
const maliciousChecks = await this.checkMaliciousPackages(dependencies);
return {
scannedAt: new Date().toISOString(),
dependencies,
vulnerabilities,
riskScore,
maliciousPackages: maliciousChecks.malicious,
recommendations: this.generateRecommendations(vulnerabilities)
};
}
private calculateRiskScore(vulnerabilities: Vulnerability[]): number {
const weights = {
critical: 40,
high: 20,
medium: 5,
low: 1
};
const score = vulnerabilities.reduce((sum, vuln) => {
return sum + weights[vuln.severity];
}, 0);
return Math.min(100, score);
}
}
Input Validation and Sanitization
Prevent injection attacks by validating and sanitizing all inputs at host and server boundaries.
class InputValidator {
// Validate resource URIs to prevent path traversal
validateResourceURI(uri: string): boolean {
// Prevent path traversal attempts
if (uri.includes('..') || uri.includes('~')) {
throw new SecurityError('Invalid resource URI: path traversal detected');
}
// Validate URI scheme
const allowedSchemes = ['file', 'http', 'https', 'db', 's3'];
const scheme = uri.split(':')[0];
if (!allowedSchemes.includes(scheme)) {
throw new SecurityError(`Invalid resource URI scheme: ${scheme}`);
}
// Validate against allowlist if configured
if (this.resourceAllowlist && !this.resourceAllowlist.test(uri)) {
throw new SecurityError('Resource URI not in allowlist');
}
return true;
}
// Validate tool arguments to prevent injection
validateToolArguments(
toolName: string,
args: Record<string, unknown>
): Record<string, unknown> {
const schema = this.toolSchemas.get(toolName);
if (!schema) {
throw new SecurityError(`No schema defined for tool: ${toolName}`);
}
// Type validation
for (const [key, value] of Object.entries(args)) {
const paramSchema = schema.properties[key];
if (!paramSchema) {
throw new SecurityError(`Unknown parameter: ${key}`);
}
// Check type
if (typeof value !== paramSchema.type) {
throw new SecurityError(
`Invalid type for ${key}: expected ${paramSchema.type}, got ${typeof value}`
);
}
// Sanitize strings
if (typeof value === 'string') {
args[key] = this.sanitizeString(value, paramSchema.sanitization);
}
// Validate ranges for numbers
if (typeof value === 'number' && paramSchema.range) {
if (value < paramSchema.range.min || value > paramSchema.range.max) {
throw new SecurityError(`Value for ${key} out of allowed range`);
}
}
}
return args;
}
private sanitizeString(input: string, rules?: SanitizationRules): string {
let sanitized = input;
if (rules?.maxLength) {
sanitized = sanitized.slice(0, rules.maxLength);
}
if (rules?.allowedCharacters) {
const regex = new RegExp(`[^${rules.allowedCharacters}]`, 'g');
sanitized = sanitized.replace(regex, '');
}
if (rules?.escapeHTML) {
sanitized = this.escapeHTML(sanitized);
}
if (rules?.disallowedPatterns) {
for (const pattern of rules.disallowedPatterns) {
if (new RegExp(pattern).test(sanitized)) {
throw new SecurityError('Input contains disallowed pattern');
}
}
}
return sanitized;
}
}
Data Privacy and Compliance
Sensitive Data Handling
Implement controls to prevent exposure of sensitive data through MCP.
interface DataClassification {
level: 'public' | 'internal' | 'confidential' | 'restricted';
categories: DataCategory[];
retentionPolicy: {
duration: number; // Days
deletionMethod: 'soft' | 'hard';
};
encryptionRequired: boolean;
accessLoggingRequired: boolean;
}
type DataCategory =
| 'PII' // Personally Identifiable Information
| 'PHI' // Protected Health Information
| 'PCI' // Payment Card Industry data
| 'ITAR' // International Traffic in Arms Regulations
| 'IP' // Intellectual Property
| 'FERPA'; // Education records
class DataPrivacyService {
async classifyResource(uri: string): Promise<DataClassification> {
const content = await this.readResource(uri);
// Scan for sensitive data patterns
const categories: DataCategory[] = [];
if (this.containsPII(content)) categories.push('PII');
if (this.containsPHI(content)) categories.push('PHI');
if (this.containsPCI(content)) categories.push('PCI');
// Determine classification level
const level = this.determineClassificationLevel(categories);
return {
level,
categories,
retentionPolicy: this.getRetentionPolicy(level),
encryptionRequired: level !== 'public',
accessLoggingRequired: categories.length > 0
};
}
private containsPII(content: string): boolean {
// SSN pattern
if (/\b\d{3}-\d{2}-\d{4}\b/.test(content)) return true;
// Email addresses
if (/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/.test(content)) return true;
// Phone numbers
if (/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/.test(content)) return true;
return false;
}
async redactSensitiveData(
content: string,
classification: DataClassification
): Promise<string> {
let redacted = content;
if (classification.categories.includes('PII')) {
// Redact SSNs
redacted = redacted.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '***-**-****');
// Redact email addresses
redacted = redacted.replace(
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
'[EMAIL REDACTED]'
);
}
if (classification.categories.includes('PCI')) {
// Redact credit card numbers
redacted = redacted.replace(
/\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
'****-****-****-****'
);
}
return redacted;
}
}
Audit Logging
Maintain comprehensive audit logs for compliance and security monitoring.
interface AuditLogEntry {
timestamp: string;
eventType: AuditEventType;
hostId: string;
userId?: string;
serverId: string;
resourceUri?: string;
toolName?: string;
action: string;
result: 'success' | 'failure';
errorMessage?: string;
dataClassification?: DataClassification;
ipAddress: string;
userAgent?: string;
}
type AuditEventType =
| 'authentication'
| 'authorization'
| 'resource_access'
| 'tool_invocation'
| 'configuration_change'
| 'security_event';
class AuditLogger {
async logEvent(entry: AuditLogEntry): Promise<void> {
// Add metadata
const enrichedEntry = {
...entry,
id: this.generateEventId(),
correlationId: this.getCorrelationId(),
sessionId: this.getSessionId()
};
// Write to secure audit log
await this.writeToAuditLog(enrichedEntry);
// Alert on security events
if (this.isSecurityEvent(entry)) {
await this.sendSecurityAlert(enrichedEntry);
}
// Check for compliance violations
if (await this.violatesCompliancePolicy(entry)) {
await this.handleComplianceViolation(enrichedEntry);
}
}
private isSecurityEvent(entry: AuditLogEntry): boolean {
return entry.eventType === 'security_event' ||
entry.result === 'failure' ||
(entry.dataClassification?.level === 'restricted');
}
}
TARS provides unified observability and audit logging across all MCP servers, enabling centralized security monitoring, compliance reporting, and threat detection.
Network Security
Transport Encryption
Always encrypt MCP communication in production environments.
// TLS configuration for production
const productionTransportConfig: TransportConfig = {
type: 'https',
url: 'https://mcp-server.example.com',
tls: {
minVersion: 'TLSv1.3',
ciphers: [
'TLS_AES_256_GCM_SHA384',
'TLS_AES_128_GCM_SHA256',
'TLS_CHACHA20_POLY1305_SHA256'
].join(':'),
ca: fs.readFileSync('/path/to/ca-bundle.pem'),
cert: fs.readFileSync('/path/to/client-cert.pem'),
key: fs.readFileSync('/path/to/client-key.pem'),
rejectUnauthorized: true,
checkServerIdentity: (hostname, cert) => {
// Custom certificate validation
return tls.checkServerIdentity(hostname, cert);
}
}
};
Rate Limiting
Implement rate limiting to prevent abuse and DoS attacks.
class RateLimiter {
private limits: Map<string, RateLimit>;
async checkRateLimit(hostId: string, operation: string): Promise<boolean> {
const key = `${hostId}:${operation}`;
const limit = this.limits.get(operation);
if (!limit) return true;
const current = await this.getCurrentCount(key, limit.window);
if (current >= limit.maxRequests) {
this.auditLog.warn('Rate limit exceeded', {
hostId,
operation,
current,
limit: limit.maxRequests
});
return false;
}
await this.incrementCount(key, limit.window);
return true;
}
}
interface RateLimit {
maxRequests: number;
window: number; // Seconds
}
Security Testing
Implement comprehensive testing and quality assurance for MCP security controls.
// Security test suite
describe('MCP Security', () => {
describe('Authentication', () => {
it('should reject connections without valid credentials', async () => {
const client = new MCPClient({ auth: { apiKey: 'invalid' } });
await expect(client.connect()).rejects.toThrow('Authentication failed');
});
it('should reject expired tokens', async () => {
const expiredToken = generateExpiredToken();
const client = new MCPClient({ auth: { token: expiredToken } });
await expect(client.connect()).rejects.toThrow('Token expired');
});
});
describe('Authorization', () => {
it('should prevent unauthorized resource access', async () => {
const client = await createLimitedClient();
await expect(
client.readResource('file:///etc/passwd')
).rejects.toThrow('Access denied');
});
it('should prevent unauthorized tool invocation', async () => {
const client = await createLimitedClient();
await expect(
client.callTool('delete_all_data', {})
).rejects.toThrow('Access denied');
});
});
describe('Input Validation', () => {
it('should prevent path traversal attacks', async () => {
const client = await createClient();
await expect(
client.readResource('file://../../etc/passwd')
).rejects.toThrow('Invalid resource URI');
});
it('should prevent SQL injection in tool arguments', async () => {
const client = await createClient();
await expect(
client.callTool('query_database', {
query: "'; DROP TABLE users; --"
})
).rejects.toThrow('Invalid input');
});
});
});
Best Practices
1. Implement Defense in Depth
Layer multiple security controls rather than relying on a single mechanism.
2. Follow Principle of Least Privilege
Grant minimum necessary permissions for each host and server.
3. Maintain Secure Defaults
Configure systems securely by default, requiring explicit opt-in for reduced security.
4. Monitor and Alert
Implement comprehensive performance monitoring with security event alerting.
5. Regular Security Audits
Conduct periodic security reviews of MCP configurations, ACLs, and audit logs.
6. Keep Dependencies Updated
Regularly update MCP servers and dependencies to patch vulnerabilities.
7. Implement Incident Response
Maintain documented procedures for responding to security incidents.
Conclusion
Securing MCP implementations requires a comprehensive approach encompassing authentication, authorization, supply chain security, data privacy, and continuous monitoring. By implementing robust security controls at each layer of the MCP architecture and following implementation best practices, organizations can safely leverage MCP’s capabilities while protecting sensitive resources and maintaining compliance.
Understanding how MCP security compares to alternatives helps inform security architecture decisions. Organizations should also consider cost optimization techniques that maintain security posture while maximizing efficiency.
Deploy MCP in Production with TARS
Enterprise-grade MCP infrastructure in minutes
- Native MCP Integration - Seamless protocol support out of the box
- Advanced Observability - Monitor and optimize your MCP implementations
- Optimized Routing - Intelligent request routing for maximum performance
- $5 Free Credit - Start with production features at no cost
Production-tested by leading AI development teams
Related MCP Topics
Explore these resources to strengthen your MCP security implementation:
- MCP Overview - Understand how security fits into the complete MCP framework
- MCP Architecture - Learn the architectural foundations that enable secure MCP implementations
- MCP Implementation Best Practices - Follow proven approaches for secure MCP deployment
- MCP Centralized Configuration - Implement consistent security policies across deployments
- MCP Integration with AI Infrastructure - Securely integrate MCP with existing AI platforms
- MCP Testing & Quality Assurance - Test and validate security controls
- MCP Performance Monitoring - Monitor security events and detect threats
- MCP Tool Filtering & Performance - Optimize security through strategic tool filtering
- MCP vs Alternatives - Compare security models across different approaches
- MCP Cost Optimization Techniques - Balance security investment with cost efficiency