This document describes three powerful new features added to the Claude Code SDK TypeScript library:
- MCP Server-Level Permission Management
- Configuration File Support
- Roles/Personas System
- MCP Server-Level Permissions
- Configuration File Support
- Roles/Personas System
- Integration Examples
- API Reference
Control permissions at the MCP server level, managing all tools from a specific MCP server as a group.
import { claude } from '@instantlyeasy/claude-code-sdk-ts';
// Set individual MCP server permissions
const response = await claude()
.withMCPServerPermission('file-system-mcp', 'whitelist')
.withMCPServerPermission('database-mcp', 'ask')
.withMCPServerPermission('external-api-mcp', 'blacklist')
.query('Analyze the codebase')
.asText();// Set multiple permissions at once
const response = await claude()
.withMCPServerPermissions({
'file-system-mcp': 'whitelist',
'git-mcp': 'whitelist',
'database-mcp': 'blacklist',
'external-api-mcp': 'ask'
})
.query('Show git status')
.asText();whitelist- All tools from this MCP server are automatically allowedblacklist- All tools from this MCP server are automatically deniedask- Prompt user for each tool usage from this MCP server
Load permissions and settings from external JSON configuration files.
Create an mcpconfig.json file:
{
"version": "1.0",
"globalSettings": {
"model": "opus",
"timeout": 60000,
"permissionMode": "acceptEdits",
"cwd": "${HOME}/projects",
"env": {
"NODE_ENV": "development"
}
},
"mcpServers": {
"file-system-mcp": {
"defaultPermission": "allow",
"tools": {
"Read": "allow",
"Write": "deny",
"Edit": "ask"
}
},
"database-mcp": {
"defaultPermission": "deny",
"tools": {
"Query": "ask"
}
}
},
"tools": {
"allowed": ["Read", "Grep", "LS"],
"denied": ["Bash", "WebSearch"]
}
}// Load from file
const response = await claude()
.withConfigFile('./mcpconfig.json')
.query('Analyze project')
.asText();
// Or use inline configuration
const response = await claude()
.withConfig({
version: '1.0',
globalSettings: {
model: 'sonnet',
timeout: 30000
}
})
.query('Hello')
.asText();Configuration files support environment variable expansion:
{
"globalSettings": {
"cwd": "${HOME}/projects",
"env": {
"AUTH_TOKEN": "${MY_SECRET_TOKEN}"
}
}
}Define comprehensive roles with permissions, models, and prompting templates.
const dataAnalystRole = {
name: 'dataAnalyst',
description: 'Expert data analyst',
model: 'opus',
permissions: {
mode: 'acceptEdits',
mcpServers: {
'database-mcp': 'whitelist'
},
tools: {
allowed: ['Read', 'Query', 'Analyze'],
denied: ['Write', 'Delete']
}
},
promptingTemplate: 'You are a ${domain} analyst specializing in ${specialty}.',
systemPrompt: 'Provide data-driven insights.',
context: {
maxTokens: 4000,
temperature: 0.2
}
};
// Use with template variables
const response = await claude()
.withRole(dataAnalystRole, {
domain: 'financial',
specialty: 'risk assessment'
})
.query('Analyze quarterly revenue')
.asText();Create a roles.json file:
{
"version": "1.0",
"defaultRole": "developer",
"roles": {
"developer": {
"model": "sonnet",
"permissions": {
"mode": "default",
"tools": {
"allowed": ["Read", "Write", "Edit"],
"denied": ["Delete"]
}
}
},
"seniorDeveloper": {
"extends": "developer",
"model": "opus",
"permissions": {
"mode": "acceptEdits",
"tools": {
"allowed": ["TodoRead", "TodoWrite"]
}
}
}
}
}Load and use roles:
const response = await claude()
.withRolesFile('./roles.json')
.withRole('seniorDeveloper')
.query('Review this code')
.asText();Roles support single inheritance through the extends field:
{
"roles": {
"baseAnalyst": {
"model": "sonnet",
"permissions": {
"tools": {
"allowed": ["Read", "Grep"]
}
}
},
"seniorAnalyst": {
"extends": "baseAnalyst",
"model": "opus",
"permissions": {
"tools": {
"allowed": ["Write", "Query"]
}
}
}
}
}Child roles inherit and can override parent properties. Tool permissions are merged.
const response = await claude()
// Load configuration
.withConfigFile('./mcpconfig.json')
// Load roles
.withRolesFile('./roles.json')
// Apply a role
.withRole('securityAuditor')
// Add specific MCP permission
.withMCPServerPermission('logging-mcp', 'whitelist')
// Additional settings
.debug(true)
.onToolUse(tool => console.log(`Using: ${tool.name}`))
.query('Audit authentication system')
.asText();When combining features, settings are applied in this order (highest precedence first):
- Programmatic API calls (e.g.,
.withModel()) - Role-based settings
- Configuration file settings
- Default values
// Create a restricted role for untrusted operations
const restrictedRole = {
name: 'restricted',
model: 'haiku',
permissions: {
mode: 'default',
mcpServers: {
'file-system-mcp': 'blacklist',
'database-mcp': 'blacklist',
'external-api-mcp': 'blacklist'
},
tools: {
allowed: ['Read'],
denied: ['Write', 'Edit', 'Delete', 'Bash', 'WebFetch']
}
},
context: {
maxTokens: 1000
}
};// Set single permission
.withMCPServerPermission(serverName: string, permission: MCPServerPermission): this
// Set multiple permissions
.withMCPServerPermissions(permissions: MCPServerPermissionConfig): this// Load from file (async)
.withConfigFile(filePath: string): Promise<this>
// Apply configuration object
.withConfig(config: MCPConfigSchema): this// Load roles from file (async)
.withRolesFile(filePath: string): Promise<this>
// Apply role by name
.withRole(roleName: string): this
// Apply role definition with template variables
.withRole(role: RoleDefinition, templateVariables?: Record<string, string>): this// MCP Server Permission
type MCPServerPermission = 'whitelist' | 'blacklist' | 'ask';
// Tool Permission
type ToolPermission = 'allow' | 'deny' | 'ask';
// Configuration Schema
interface MCPConfigSchema {
version: '1.0';
globalSettings?: GlobalConfigSettings;
mcpServers?: Record<string, MCPServerConfig>;
tools?: {
allowed?: ToolName[];
denied?: ToolName[];
};
}
// Role Definition
interface RoleDefinition {
name: string;
model: string;
permissions: {
mode?: PermissionMode;
mcpServers?: MCPServerPermissionConfig;
tools?: {
allowed?: ToolName[];
denied?: ToolName[];
};
};
promptingTemplate?: string;
systemPrompt?: string;
context?: {
maxTokens?: number;
temperature?: number;
additionalContext?: string[];
};
extends?: string;
}The new features include comprehensive error handling:
try {
await claude()
.withConfigFile('./invalid.json')
.query('test');
} catch (error) {
// Handle configuration errors
console.error('Config error:', error.message);
}
try {
await claude()
.withRole('nonExistentRole')
.query('test');
} catch (error) {
// Handle role errors
console.error('Role error:', error.message);
}These features are fully backward compatible. Existing code continues to work without changes:
// Original API still works
const response = await query('Hello', { model: 'sonnet' });
// New features are additive
const response = await claude()
.withModel('sonnet') // Existing method
.withRole('developer') // New feature
.query('Hello')
.asText();