Skip to content

Conversation

@imbenrabi
Copy link
Contributor

@imbenrabi imbenrabi commented Oct 5, 2025

Permission-Based Toolset Access Control

Overview
This PR introduces a new permission system for Toolception that enables per-client access control to toolsets. Server operators can now restrict which toolsets each client can access, supporting multi-tenant deployments and security-sensitive environments.

Key Features
Per-Client Toolset Permissions
Each client receives only the toolsets they're authorized to access. Permissions are resolved at connection time and enforced throughout the session lifecycle.

Two Permission Sources
Header-Based Permissions

Clients send their allowed toolsets via HTTP headers
Useful for proxy-based authorization or API gateway integration
Default header: mcp-toolset-permissions (configurable)
Config-Based Permissions

Server-side permission resolution using static maps or custom resolver functions
Supports fallback chains: resolver → static map → defaults
Ideal for centralized permission management

API

createPermissionBasedMcpServer(options)
New server creation function specifically for permission-based deployments.

import { createPermissionBasedMcpServer } from 'toolception';

// Header-based permissions
const server = await createPermissionBasedMcpServer({
  createServer: () => new McpServer({ name: "my-server", version: "1.0.0" }),
  catalog: {
    admin: { name: "Admin Tools", tools: [...] },
    user: { name: "User Tools", tools: [...] }
  },
  permissions: {
    source: 'headers',
    headerName: 'mcp-toolset-permissions' // optional
  }
});

// Config-based with static map
const server = await createPermissionBasedMcpServer({
  createServer: () => new McpServer({ name: "my-server", version: "1.0.0" }),
  catalog: { /* ... */ },
  permissions: {
    source: 'config',
    staticMap: {
      'client-admin': ['admin', 'user'],
      'client-user': ['user']
    },
    defaultPermissions: [] // optional fallback
  }
});

// Config-based with resolver function
const server = await createPermissionBasedMcpServer({
  createServer: () => new McpServer({ name: "my-server", version: "1.0.0" }),
  catalog: { /* ... */ },
  permissions: {
    source: 'config',
    resolver: (clientId) => {
      // Custom logic: database lookup, JWT validation, etc.
      return getUserPermissions(clientId);
    },
    staticMap: { /* fallback */ },
    defaultPermissions: ['public']
  }
});

await server.start();
Permission Configuration
interface PermissionConfig {
  // Permission source: 'headers' or 'config'
  source: 'headers' | 'config';
  
  // For header-based: custom header name (default: 'mcp-toolset-permissions')
  headerName?: string;
  
  // For config-based: static client-to-toolsets mapping
  staticMap?: Record<string, string[]>;
  
  // For config-based: dynamic resolver function
  resolver?: (clientId: string) => string[];
  
  // For config-based: fallback permissions
  defaultPermissions?: string[];
}

@imbenrabi imbenrabi marked this pull request as ready for review October 9, 2025 07:08
@imbenrabi imbenrabi merged commit 9782b2a into main Oct 9, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants