MCP TypeScript Security Checks
These checks are specific to Model Context Protocol (MCP) servers written in TypeScript or JavaScript. They identify common security issues and best practice violations in MCP server implementations.
mcp-excessive-tools
Severity: Medium
What It Detects
MCP servers that expose more than 10 tools.
Why It's Concerning
Many tools:
- Increase attack surface
- Make security auditing harder
- May indicate overly broad capabilities
- Could expose unintended functionality
Example Finding
// Server with many tools
server.tool('readFile', ...);
server.tool('writeFile', ...);
server.tool('deleteFile', ...);
server.tool('execute', ...);
// ... 20+ more toolsHow to Address
- Split into focused MCP servers
- Remove unused tools
- Consider if all tools are necessary
- Document why many tools are needed
mcp-dangerous-tool
Severity: High
What It Detects
Tools with dangerous-sounding names:
exec,execute,rundelete,remove,dropadmin,sudo,rootshell,bash,cmd
Why It's Concerning
Tools with these names often:
- Execute arbitrary commands
- Delete data destructively
- Have elevated privileges
- Bypass security controls
Example Finding
server.tool('executeCommand', async ({ command }) => {
// Executes arbitrary shell commands
return await exec(command);
});How to Address
// Instead of generic "execute"
// Create specific, limited tools
server.tool('runBuild', async () => {
// Fixed command, no user input
return await exec('npm run build');
});
server.tool('listFiles', async ({ directory }) => {
// Validate and limit scope
const safePath = validatePath(directory);
return await fs.readdir(safePath);
});mcp-missing-description
Severity: Low
What It Detects
MCP tools registered without descriptions.
Why It's Important
Tool descriptions:
- Help AI models use tools correctly
- Provide transparency to users
- Document intended behavior
- Enable better error messages
Example Finding
// Tool without description
server.tool('processData', async ({ data }) => {
return process(data);
});How to Fix
server.tool('processData', {
description: 'Processes JSON data and returns formatted output',
inputSchema: {
type: 'object',
properties: {
data: {
type: 'string',
description: 'JSON string to process'
}
},
required: ['data']
}
}, async ({ data }) => {
return process(data);
});mcp-unbounded-operation
Severity: Medium
What It Detects
Operations without limits:
fetch()without timeout- Infinite loops
- Unbounded recursion
Why It's Dangerous
Unbounded operations can:
- Hang indefinitely
- Consume all resources
- Create denial of service
- Make debugging difficult
Example Finding
server.tool('fetchData', async ({ url }) => {
// No timeout - could hang forever
const response = await fetch(url);
return response.text();
});How to Fix
server.tool('fetchData', async ({ url }) => {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000); // 10s timeout
try {
const response = await fetch(url, { signal: controller.signal });
return response.text();
} finally {
clearTimeout(timeout);
}
});mcp-missing-validation
Severity: Medium
What It Detects
Tool handlers that don't validate input:
- No type checking
- No schema validation
- Direct use of input without verification
Why It's Important
Missing validation can:
- Allow injection attacks
- Cause unexpected errors
- Lead to data corruption
- Enable privilege escalation
Example Finding
server.tool('writeFile', async ({ path, content }) => {
// No validation of path or content
await fs.writeFile(path, content);
});How to Fix
import { z } from 'zod';
const writeFileSchema = z.object({
path: z.string()
.max(255)
.refine(p => !p.includes('..'), 'Path traversal not allowed'),
content: z.string().max(1000000) // 1MB limit
});
server.tool('writeFile', {
inputSchema: writeFileSchema
}, async (input) => {
const { path, content } = writeFileSchema.parse(input);
const safePath = validateAndResolvePath(path);
await fs.writeFile(safePath, content);
});mcp-sensitive-exposure
Severity: High
What It Detects
Potential exposure of sensitive data in tool responses:
- Returning credentials
- Exposing internal paths
- Leaking configuration
Why It's Dangerous
Exposed data can:
- Leak to AI logs
- Be visible to end users
- Enable further attacks
- Violate privacy regulations
Example Finding
server.tool('getConfig', async () => {
return {
apiKey: process.env.API_KEY, // Exposes credential!
dbPassword: config.database.password // Exposes password!
};
});How to Fix
server.tool('getConfig', async () => {
return {
// Only expose non-sensitive config
apiEndpoint: config.apiEndpoint,
timeout: config.timeout,
// Indicate credentials are set without exposing them
hasApiKey: !!process.env.API_KEY,
hasDatabaseConfig: !!config.database?.host
};
});Summary
| Check | Severity | Key Fix | |-------|----------|---------| | mcp-excessive-tools | Medium | Split into focused servers | | mcp-dangerous-tool | High | Create specific, limited tools | | mcp-missing-description | Low | Add descriptions to all tools | | mcp-unbounded-operation | Medium | Add timeouts and limits | | mcp-missing-validation | Medium | Validate all inputs | | mcp-sensitive-exposure | High | Never expose credentials in responses |
MCP Security Best Practices
1. Principle of Least Privilege
Only expose tools that are absolutely necessary:
// Bad: Generic file access
server.tool('readFile', ...);
server.tool('writeFile', ...);
// Good: Specific, limited operations
server.tool('readConfig', ...); // Only reads specific config file
server.tool('saveUserPrefs', ...); // Only saves to user directory2. Validate All Input
import { z } from 'zod';
const schema = z.object({
filename: z.string().max(100),
options: z.object({
format: z.enum(['json', 'yaml', 'text'])
}).optional()
});3. Sanitize All Output
// Remove sensitive fields before returning
const sanitize = (data) => {
const { password, apiKey, ...safe } = data;
return safe;
};4. Add Timeouts
const withTimeout = (promise, ms) => {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
)
]);
};Next Steps
- Python Security - Python security checks
- MCP Python - MCP checks for Python
- Reviewing Findings - How to fix issues