lokicms-plugin-mcp-auth
v1.1.0
Published
Role-based authentication and tool filtering plugin for LokiCMS MCP servers
Maintainers
Readme
lokicms-plugin-mcp-auth
Role-based authentication and tool filtering for MCP (Model Context Protocol) servers.
Features
- Role-Based Access Control (RBAC) - Define roles with specific tool permissions
- Tool Filtering - Automatically filter available tools based on agent role
- Flexible Authentication - Support for environment variables and API key prefixes
- TypeScript Native - Full type safety and IntelliSense support
- Zero Dependencies - Only requires
zodfor schema validation - Extensible - Add custom roles and API key mappings at runtime
- MCP SDK Compatible - Works with
@modelcontextprotocol/sdk
Installation
npm install lokicms-plugin-mcp-authyarn add lokicms-plugin-mcp-authpnpm add lokicms-plugin-mcp-authQuick Start
import { createMCPAuth } from 'lokicms-plugin-mcp-auth';
// Create auth instance with default roles
const auth = createMCPAuth();
// Check if a tool is allowed for current role
if (auth.isToolAllowed('create_user')) {
// Execute the tool
}
// Get filtered tools for MCP ListTools response
const filteredTools = auth.filterTools(allTools);
// Get current agent info
const info = auth.getAgentInfo();
console.log(`Role: ${info.role}, Allowed: ${info.allowedToolCount} tools`);Configuration
Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| AGENT_ROLE | Direct role specification | viewer |
| AGENT_API_KEY | API key for role lookup | - |
The plugin checks AGENT_ROLE first, then falls back to AGENT_API_KEY prefix matching.
Custom Configuration
import { createMCPAuth } from 'lokicms-plugin-mcp-auth';
const auth = createMCPAuth({
// Add or override roles
roles: {
custom_role: {
name: 'Custom Role',
description: 'A custom role with specific permissions',
accessLevel: 'limited',
tools: ['list_entries', 'get_entry', 'search'],
},
},
// Default role when no auth is provided
defaultRole: 'viewer',
// Map API key prefixes to roles
apiKeyMap: {
'myapp_admin_': 'admin',
'myapp_user_': 'editor',
},
// List of all known tools (for admin '*' access)
knownTools: ['list_entries', 'create_entry', 'delete_entry'],
// Custom environment variable names
roleEnvVar: 'MY_AGENT_ROLE',
apiKeyEnvVar: 'MY_API_KEY',
});Default Roles
| Role | Access Level | Tools | Description |
|------|--------------|-------|-------------|
| admin | full | All (*) | Full access to all operations |
| editor | limited | 26 | Read/write content, no structure changes |
| author | limited | 15 | Create and manage own content |
| viewer | limited | 13 | Read-only access |
Editor Role Permissions
Structure (read-only):
list_content_types, get_content_type, get_structure_summary
Entries (CRUD):
list_entries, get_entry, create_entry, update_entry, delete_entry
publish_entry, unpublish_entry
Taxonomies (read-only):
list_taxonomies, get_taxonomy, list_terms, get_term
assign_terms, get_entries_by_term
Search:
search, search_in_content_type, search_suggest
Scheduler:
scheduler_status, scheduler_upcoming, schedule_entry, cancel_schedule
Revisions:
revision_list, revision_compare, revision_statsAPI Reference
createMCPAuth(config?)
Creates a new MCP Auth instance.
const auth = createMCPAuth({
roles?: Record<string, RoleConfig>,
defaultRole?: string,
apiKeyMap?: Record<string, string>,
knownTools?: string[],
roleEnvVar?: string,
apiKeyEnvVar?: string,
});Instance Methods
auth.isToolAllowed(toolName, role?)
Check if a tool is allowed for a role.
auth.isToolAllowed('create_user'); // Check for current role
auth.isToolAllowed('create_user', 'editor'); // Check for specific roleauth.filterTools(tools, role?)
Filter a tools object, keeping only allowed tools.
const allTools = { tool1: {...}, tool2: {...}, tool3: {...} };
const filtered = auth.filterTools(allTools); // Only allowed toolsauth.getAllowedTools(role)
Get array of allowed tool names for a role.
const tools = auth.getAllowedTools('editor');
// ['list_entries', 'get_entry', ...]auth.getBlockedTools(role)
Get array of blocked tool names for a role.
const blocked = auth.getBlockedTools('editor');
// ['create_user', 'delete_user', ...]auth.getRoleFromEnv()
Get current role from environment.
const role = auth.getRoleFromEnv(); // 'admin', 'editor', etc.auth.getAgentInfo()
Get current agent information.
const info = auth.getAgentInfo();
// {
// role: 'editor',
// name: 'Editor',
// description: 'Can read/write content but not modify structure',
// allowedToolCount: 26,
// blockedToolCount: 30
// }auth.getRoles()
Get all available roles.
const roles = auth.getRoles();
// [
// { key: 'admin', name: 'Admin', toolCount: 56, accessLevel: 'full' },
// { key: 'editor', name: 'Editor', toolCount: 26, accessLevel: 'limited' },
// ...
// ]auth.registerRole(key, config)
Register a new role at runtime.
auth.registerRole('moderator', {
name: 'Moderator',
description: 'Can moderate content',
accessLevel: 'limited',
tools: ['list_entries', 'update_entry', 'delete_entry'],
});auth.mapApiKey(prefix, role)
Map an API key prefix to a role.
auth.mapApiKey('mod_key_', 'moderator');MCP Server Integration
Using Middleware
import { createMCPMiddleware } from 'lokicms-plugin-mcp-auth';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
ListToolsRequestSchema,
CallToolRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
// Your tools
const tools = {
list_entries: { description: '...', inputSchema: z.object({}), handler: async () => {} },
create_entry: { description: '...', inputSchema: z.object({}), handler: async () => {} },
// ...
};
// Create middleware
const middleware = createMCPMiddleware(tools, {
onAccessDenied: (tool, role) => {
console.error(`[Auth] Blocked: ${tool} for role ${role}`);
},
onToolExecuted: (tool, role) => {
console.log(`[Auth] Executed: ${tool} by ${role}`);
},
});
// Create server
const server = new Server(
{ name: 'my-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
// Use middleware in handlers
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: middleware.getToolsList(),
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
return middleware.executeTool(request.params.name, request.params.arguments);
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);Using Pre-built Handlers
import { createMCPHandlers } from 'lokicms-plugin-mcp-auth';
const { handleListTools, handleCallTool, middleware } = createMCPHandlers(tools);
server.setRequestHandler(ListToolsRequestSchema, handleListTools);
server.setRequestHandler(CallToolRequestSchema, handleCallTool);
console.log(`Running as: ${middleware.getRole()}`);MCP Configuration
Configure multiple server instances with different roles in .mcp.json:
{
"mcpServers": {
"myapp-admin": {
"command": "node",
"args": ["./dist/server.js"],
"env": {
"AGENT_ROLE": "admin"
}
},
"myapp-client": {
"command": "node",
"args": ["./dist/server.js"],
"env": {
"AGENT_ROLE": "editor"
}
},
"myapp-readonly": {
"command": "node",
"args": ["./dist/server.js"],
"env": {
"AGENT_ROLE": "viewer"
}
}
}
}Architecture
┌─────────────────────────────────────────────────────────┐
│ AI Agent (Claude) │
└────────────────────────┬────────────────────────────────┘
│
┌──────────┴──────────┐
│ MCP Connection │
│ (role: editor) │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ MCP Auth │
│ │
│ ├─ filterTools() │ ← Only 26 tools exposed
│ ├─ isToolAllowed() │ ← Block unauthorized calls
│ └─ getAgentInfo() │ ← Role information
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ MCP Server │
│ (your tools) │
└─────────────────────┘Security
- Tool filtering happens server-side, not client-side
- Blocked tools are not exposed in ListTools response
- Attempting to execute blocked tools returns access denied error
- API keys are validated by prefix matching
- Default role is
viewer(most restrictive) - All access attempts are loggable via callbacks
TypeScript
Full TypeScript support with exported types:
import type {
RoleConfig,
RoleInfo,
AgentInfo,
AuthResult,
ToolFilter,
MCPAuthConfig,
MCPAuthInstance,
MCPTool,
} from 'lokicms-plugin-mcp-auth';Examples
Custom Role for Moderation
const auth = createMCPAuth({
roles: {
moderator: {
name: 'Moderator',
description: 'Can review and moderate content',
accessLevel: 'limited',
tools: [
'list_entries',
'get_entry',
'update_entry', // Can edit
'unpublish_entry', // Can unpublish
'search',
],
},
},
});API Key Based Authentication
const auth = createMCPAuth({
apiKeyMap: {
'admin_': 'admin',
'editor_': 'editor',
'readonly_': 'viewer',
},
});
// Set via environment
// AGENT_API_KEY=admin_abc123xyz
// Result: role = 'admin'Dynamic Role Registration
const auth = createMCPAuth();
// Add roles at runtime
auth.registerRole('premium_user', {
name: 'Premium User',
description: 'Premium tier access',
accessLevel: 'limited',
tools: [...auth.getAllowedTools('editor'), 'export_data'],
});
// Map new API keys
auth.mapApiKey('premium_', 'premium_user');License
MIT
Contributing
Contributions are welcome! Please read our contributing guidelines.
