toolception 0.2.5 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +945 -21
  2. package/dist/core/DynamicToolManager.d.ts +45 -2
  3. package/dist/core/DynamicToolManager.d.ts.map +1 -1
  4. package/dist/core/ServerOrchestrator.d.ts +24 -2
  5. package/dist/core/ServerOrchestrator.d.ts.map +1 -1
  6. package/dist/http/FastifyTransport.d.ts +11 -0
  7. package/dist/http/FastifyTransport.d.ts.map +1 -1
  8. package/dist/index.d.ts +2 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +940 -237
  11. package/dist/index.js.map +1 -1
  12. package/dist/meta/registerMetaTools.d.ts +14 -0
  13. package/dist/meta/registerMetaTools.d.ts.map +1 -1
  14. package/dist/mode/ModeResolver.d.ts +7 -0
  15. package/dist/mode/ModeResolver.d.ts.map +1 -1
  16. package/dist/permissions/PermissionAwareFastifyTransport.d.ts +47 -0
  17. package/dist/permissions/PermissionAwareFastifyTransport.d.ts.map +1 -0
  18. package/dist/permissions/PermissionResolver.d.ts +43 -0
  19. package/dist/permissions/PermissionResolver.d.ts.map +1 -0
  20. package/dist/permissions/createPermissionAwareBundle.d.ts +58 -0
  21. package/dist/permissions/createPermissionAwareBundle.d.ts.map +1 -0
  22. package/dist/permissions/validatePermissionConfig.d.ts +9 -0
  23. package/dist/permissions/validatePermissionConfig.d.ts.map +1 -0
  24. package/dist/server/createMcpServer.d.ts +4 -3
  25. package/dist/server/createMcpServer.d.ts.map +1 -1
  26. package/dist/server/createPermissionBasedMcpServer.d.ts +65 -0
  27. package/dist/server/createPermissionBasedMcpServer.d.ts.map +1 -0
  28. package/dist/session/ClientResourceCache.d.ts +34 -3
  29. package/dist/session/ClientResourceCache.d.ts.map +1 -1
  30. package/dist/types/index.d.ts +229 -0
  31. package/dist/types/index.d.ts.map +1 -1
  32. package/package.json +7 -2
@@ -0,0 +1,43 @@
1
+ import { PermissionConfig } from '../types/index.js';
2
+ /**
3
+ * Resolves and caches client permissions based on configured permission sources.
4
+ * Supports both header-based and config-based permission resolution with caching
5
+ * for performance optimization.
6
+ */
7
+ export declare class PermissionResolver {
8
+ #private;
9
+ private config;
10
+ private cache;
11
+ private readonly normalizedHeaderName;
12
+ /**
13
+ * Creates a new PermissionResolver instance.
14
+ * @param config - The permission configuration defining how permissions are resolved
15
+ */
16
+ constructor(config: PermissionConfig);
17
+ /**
18
+ * Resolves permissions for a client based on the configured source.
19
+ * Results are cached to improve performance for subsequent requests from the same client.
20
+ * Handles all errors gracefully by returning empty permissions on failure.
21
+ *
22
+ * Note on caching: For header-based permissions, permissions are cached by clientId.
23
+ * This means subsequent requests from the same client will use cached permissions,
24
+ * even if headers change. Use invalidateCache(clientId) to force re-resolution.
25
+ *
26
+ * @param clientId - The unique identifier for the client
27
+ * @param headers - Optional request headers (required for header-based permissions)
28
+ * @returns Array of toolset names the client is allowed to access
29
+ */
30
+ resolvePermissions(clientId: string, headers?: Record<string, string>): string[];
31
+ /**
32
+ * Invalidates cached permissions for a specific client.
33
+ * Call this when you know a client's permissions have changed.
34
+ * @param clientId - The client ID to invalidate
35
+ */
36
+ invalidateCache(clientId: string): void;
37
+ /**
38
+ * Clears the permission cache.
39
+ * Useful for cleanup during server shutdown or when permissions need to be refreshed.
40
+ */
41
+ clearCache(): void;
42
+ }
43
+ //# sourceMappingURL=PermissionResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionResolver.d.ts","sourceRoot":"","sources":["../../src/permissions/PermissionResolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;GAIG;AACH,qBAAa,kBAAkB;;IAQjB,OAAO,CAAC,MAAM;IAP1B,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAE9C;;;OAGG;gBACiB,MAAM,EAAE,gBAAgB;IAO5C;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,EAAE;IAyCX;;;;OAIG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IA6IvC;;;OAGG;IACH,UAAU,IAAI,IAAI;CAGnB"}
@@ -0,0 +1,58 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { ServerOrchestrator } from '../core/ServerOrchestrator.js';
3
+ import { PermissionResolver } from './PermissionResolver.js';
4
+ /**
5
+ * Context information extracted from a client request.
6
+ * Used to identify the client and resolve their permissions.
7
+ */
8
+ export interface ClientRequestContext {
9
+ /**
10
+ * Unique identifier for the client making the request.
11
+ * May be provided via mcp-client-id header or generated as anonymous ID.
12
+ */
13
+ clientId: string;
14
+ /**
15
+ * Request headers that may contain permission data.
16
+ * Used for header-based permission resolution.
17
+ */
18
+ headers?: Record<string, string>;
19
+ }
20
+ /**
21
+ * Result of permission-aware bundle creation, including the resolved permissions.
22
+ */
23
+ export interface PermissionAwareBundle {
24
+ /**
25
+ * The MCP server instance for this client.
26
+ */
27
+ server: McpServer;
28
+ /**
29
+ * The orchestrator managing toolsets for this client.
30
+ */
31
+ orchestrator: ServerOrchestrator;
32
+ /**
33
+ * The resolved permissions (allowed toolsets) for this client.
34
+ * Contains only the toolsets that were successfully enabled.
35
+ */
36
+ allowedToolsets: string[];
37
+ /**
38
+ * Toolsets that failed to enable (e.g., invalid names).
39
+ * Empty if all requested toolsets were enabled successfully.
40
+ */
41
+ failedToolsets: string[];
42
+ }
43
+ /**
44
+ * Creates a permission-aware bundle creation function that wraps the original
45
+ * createBundle function with permission resolution and enforcement.
46
+ *
47
+ * This function resolves client permissions and passes them to the bundle creator,
48
+ * which creates a server with STATIC mode configured to only those toolsets.
49
+ *
50
+ * @param originalCreateBundle - Bundle creation function that accepts allowed toolsets
51
+ * @param permissionResolver - Resolver instance for determining client permissions
52
+ * @returns Enhanced bundle creation function that accepts client context
53
+ */
54
+ export declare function createPermissionAwareBundle(originalCreateBundle: (allowedToolsets: string[]) => {
55
+ server: McpServer;
56
+ orchestrator: ServerOrchestrator;
57
+ }, permissionResolver: PermissionResolver): (context: ClientRequestContext) => Promise<PermissionAwareBundle>;
58
+ //# sourceMappingURL=createPermissionAwareBundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPermissionAwareBundle.d.ts","sourceRoot":"","sources":["../../src/permissions/createPermissionAwareBundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,MAAM,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,YAAY,EAAE,kBAAkB,CAAC;IAEjC;;;OAGG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;IAE1B;;;OAGG;IACH,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,oBAAoB,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK;IACnD,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,kBAAkB,CAAC;CAClC,EACD,kBAAkB,EAAE,kBAAkB,IAcpC,SAAS,oBAAoB,KAC5B,OAAO,CAAC,qBAAqB,CAAC,CAkDlC"}
@@ -0,0 +1,9 @@
1
+ import { PermissionConfig } from '../types/index.js';
2
+ /**
3
+ * Validates a permission configuration object to ensure it meets all requirements.
4
+ * Throws descriptive errors for any validation failures.
5
+ * @param config - The permission configuration to validate
6
+ * @throws {Error} If the configuration is invalid or missing required fields
7
+ */
8
+ export declare function validatePermissionConfig(config: PermissionConfig): void;
9
+ //# sourceMappingURL=validatePermissionConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validatePermissionConfig.d.ts","sourceRoot":"","sources":["../../src/permissions/validatePermissionConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAKvE"}
@@ -1,9 +1,9 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { ExposurePolicy, Mode, ToolSetCatalog } from '../types/index.js';
2
+ import { ExposurePolicy, Mode, ModuleLoader, ToolSetCatalog } from '../types/index.js';
3
3
  import { FastifyTransportOptions } from '../http/FastifyTransport.js';
4
4
  export interface CreateMcpServerOptions {
5
5
  catalog: ToolSetCatalog;
6
- moduleLoaders?: Record<string, any>;
6
+ moduleLoaders?: Record<string, ModuleLoader>;
7
7
  exposurePolicy?: ExposurePolicy;
8
8
  context?: unknown;
9
9
  startup?: {
@@ -12,7 +12,8 @@ export interface CreateMcpServerOptions {
12
12
  };
13
13
  registerMetaTools?: boolean;
14
14
  http?: FastifyTransportOptions;
15
- /** Factory to create an MCP server instance. Required.
15
+ /**
16
+ * Factory to create an MCP server instance. Required.
16
17
  * In DYNAMIC mode, a new instance is created per client bundle.
17
18
  * In STATIC mode, a single instance is created and reused across bundles.
18
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"createMcpServer.d.ts","sourceRoot":"","sources":["../../src/server/createMcpServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE9E,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,6BAA6B,CAAC;AAErC,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,cAAc,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;KAAE,CAAC;IACvE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,EAAE,uBAAuB,CAAC;IAC/B;;;OAGG;IACH,YAAY,EAAE,MAAM,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB;;;;GAkFpE"}
1
+ {"version":3,"file":"createMcpServer.d.ts","sourceRoot":"","sources":["../../src/server/createMcpServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EACV,cAAc,EACd,IAAI,EACJ,YAAY,EACZ,cAAc,EACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,6BAA6B,CAAC;AAErC,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,cAAc,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC7C,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;KAAE,CAAC;IACvE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,EAAE,uBAAuB,CAAC;IAC/B;;;;OAIG;IACH,YAAY,EAAE,MAAM,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB;;;;GA0FpE"}
@@ -0,0 +1,65 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { CreatePermissionBasedMcpServerOptions } from '../types/index.js';
3
+ /**
4
+ * Creates an MCP server with permission-based toolset access control.
5
+ *
6
+ * This function provides a separate API for creating servers where each client receives
7
+ * only the toolsets they're authorized to access. Each client gets a fresh server instance
8
+ * with STATIC mode configured to their allowed toolsets, ensuring per-client isolation
9
+ * without meta-tools or dynamic loading.
10
+ *
11
+ * The server supports two permission sources:
12
+ * - **Header-based**: Permissions are read from request headers (e.g., `mcp-toolset-permissions`)
13
+ * - **Config-based**: Permissions are resolved server-side using static maps or resolver functions
14
+ *
15
+ * @param options - Configuration options including permission settings, catalog, and HTTP transport options
16
+ * @returns Server instance with `server`, `start()`, and `close()` methods matching the createMcpServer interface
17
+ * @throws {Error} If permission configuration is invalid, missing, or if startup.mode is provided
18
+ *
19
+ * @example
20
+ * // Header-based permissions
21
+ * const server = await createPermissionBasedMcpServer({
22
+ * createServer: () => new McpServer({ name: "my-server", version: "1.0.0" }),
23
+ * catalog: { toolsetA: { name: "Toolset A", tools: [...] } },
24
+ * permissions: {
25
+ * source: 'headers',
26
+ * headerName: 'mcp-toolset-permissions' // optional, this is the default
27
+ * }
28
+ * });
29
+ *
30
+ * @example
31
+ * // Config-based permissions with static map
32
+ * const server = await createPermissionBasedMcpServer({
33
+ * createServer: () => new McpServer({ name: "my-server", version: "1.0.0" }),
34
+ * catalog: { toolsetA: { name: "Toolset A", tools: [...] } },
35
+ * permissions: {
36
+ * source: 'config',
37
+ * staticMap: {
38
+ * 'client-1': ['toolsetA', 'toolsetB'],
39
+ * 'client-2': ['toolsetC']
40
+ * },
41
+ * defaultPermissions: [] // optional, defaults to empty array
42
+ * }
43
+ * });
44
+ *
45
+ * @example
46
+ * // Config-based permissions with resolver function
47
+ * const server = await createPermissionBasedMcpServer({
48
+ * createServer: () => new McpServer({ name: "my-server", version: "1.0.0" }),
49
+ * catalog: { toolsetA: { name: "Toolset A", tools: [...] } },
50
+ * permissions: {
51
+ * source: 'config',
52
+ * resolver: (clientId) => {
53
+ * // Your custom logic to determine permissions
54
+ * return clientId.startsWith('admin-') ? ['toolsetA', 'toolsetB'] : ['toolsetA'];
55
+ * },
56
+ * defaultPermissions: ['toolsetA'] // fallback if resolver fails
57
+ * }
58
+ * });
59
+ */
60
+ export declare function createPermissionBasedMcpServer(options: CreatePermissionBasedMcpServerOptions): Promise<{
61
+ server: McpServer;
62
+ start: () => Promise<void>;
63
+ close: () => Promise<void>;
64
+ }>;
65
+ //# sourceMappingURL=createPermissionBasedMcpServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPermissionBasedMcpServer.d.ts","sourceRoot":"","sources":["../../src/server/createPermissionBasedMcpServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EACV,qCAAqC,EAEtC,MAAM,mBAAmB,CAAC;AAoD3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,qCAAqC;;;;GAkG/C"}
@@ -1,22 +1,53 @@
1
- export interface ClientResourceCacheOptions {
1
+ export interface ClientResourceCacheOptions<T> {
2
2
  maxSize?: number;
3
3
  ttlMs?: number;
4
4
  pruneIntervalMs?: number;
5
+ /**
6
+ * Optional cleanup callback called when a resource is removed from the cache.
7
+ * Use this to close connections, clean up sessions, etc.
8
+ * @param key - The cache key being removed
9
+ * @param resource - The resource being removed
10
+ */
11
+ onEvict?: (key: string, resource: T) => void | Promise<void>;
5
12
  }
6
13
  export declare class ClientResourceCache<T> {
14
+ #private;
7
15
  private storage;
8
16
  private maxSize;
9
17
  private ttlMs;
18
+ private onEvict?;
10
19
  private pruneInterval?;
11
- constructor(options?: ClientResourceCacheOptions);
20
+ constructor(options?: ClientResourceCacheOptions<T>);
12
21
  getEntryCount(): number;
13
22
  getMaxSize(): number;
14
23
  getTtl(): number;
15
24
  get(key: string): T | null;
16
25
  set(key: string, resource: T): void;
26
+ /**
27
+ * Removes an entry from the cache.
28
+ * Calls the onEvict callback if configured.
29
+ * @param key - The key to remove
30
+ */
17
31
  delete(key: string): void;
18
- stop(): void;
32
+ /**
33
+ * Stops the background pruning interval and optionally clears all entries.
34
+ * @param clearEntries - If true, also removes all entries and calls onEvict for each
35
+ */
36
+ stop(clearEntries?: boolean): void;
37
+ /**
38
+ * Clears all entries from the cache.
39
+ * Calls onEvict for each entry being removed.
40
+ */
41
+ clear(): void;
42
+ /**
43
+ * Evicts the least recently used entry from the cache.
44
+ * @private
45
+ */
19
46
  private evictLeastRecentlyUsed;
47
+ /**
48
+ * Removes all expired entries from the cache.
49
+ * @private
50
+ */
20
51
  private pruneExpired;
21
52
  }
22
53
  //# sourceMappingURL=ClientResourceCache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ClientResourceCache.d.ts","sourceRoot":"","sources":["../../src/session/ClientResourceCache.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,0BAA0B;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAOD,qBAAa,mBAAmB,CAAC,CAAC;IAChC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IAEtB,OAAO,CAAC,aAAa,CAAC,CAAiC;gBAE3C,OAAO,GAAE,0BAA+B;IAO7C,aAAa,IAAI,MAAM;IAIvB,UAAU,IAAI,MAAM;IAIpB,MAAM,IAAI,MAAM;IAIhB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAa1B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;IAQnC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,IAAI,IAAI,IAAI;IAOnB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,YAAY;CAQrB"}
1
+ {"version":3,"file":"ClientResourceCache.d.ts","sourceRoot":"","sources":["../../src/session/ClientResourceCache.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,0BAA0B,CAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAOD,qBAAa,mBAAmB,CAAC,CAAC;;IAChC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAC,CAAqD;IAErE,OAAO,CAAC,aAAa,CAAC,CAAiC;gBAE3C,OAAO,GAAE,0BAA0B,CAAC,CAAC,CAAM;IAQhD,aAAa,IAAI,MAAM;IAIvB,UAAU,IAAI,MAAM;IAIpB,MAAM,IAAI,MAAM;IAIhB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAa1B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;IAQ1C;;;;OAIG;IACI,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQhC;;;OAGG;IACI,IAAI,CAAC,YAAY,UAAQ,GAAG,IAAI;IAUvC;;;OAGG;IACI,KAAK,IAAI,IAAI;IASpB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAO9B;;;OAGG;IACH,OAAO,CAAC,YAAY;CAkCrB"}
@@ -1,3 +1,4 @@
1
+ import { CreateMcpServerOptions } from '../server/createMcpServer.js';
1
2
  export type McpToolDefinition = {
2
3
  name: string;
3
4
  description: string;
@@ -22,4 +23,232 @@ export type ExposurePolicy = {
22
23
  };
23
24
  export type ToolingErrorCode = "E_VALIDATION" | "E_POLICY_MAX_ACTIVE" | "E_TOOL_NAME_CONFLICT" | "E_NOTIFY_FAILED" | "E_INTERNAL";
24
25
  export type ModuleLoader = (context?: unknown) => Promise<McpToolDefinition[]> | McpToolDefinition[];
26
+ /**
27
+ * Configuration for permission-based toolset access control.
28
+ *
29
+ * Defines how client permissions are resolved and applied when using
30
+ * `createPermissionBasedMcpServer`. Supports two permission sources:
31
+ *
32
+ * **Header-based permissions**: Permissions are extracted from request headers.
33
+ * This approach is simpler but requires proper authentication/authorization in your
34
+ * application layer to prevent header tampering.
35
+ *
36
+ * **Config-based permissions**: Permissions are resolved server-side using either
37
+ * a static map or a resolver function. This provides stronger security by not
38
+ * trusting client-provided permission data.
39
+ *
40
+ * @example Header-based configuration
41
+ * ```typescript
42
+ * const config: PermissionConfig = {
43
+ * source: 'headers',
44
+ * headerName: 'mcp-toolset-permissions' // optional, this is the default
45
+ * };
46
+ * // Client sends: mcp-toolset-permissions: toolset-a,toolset-b
47
+ * ```
48
+ *
49
+ * @example Config-based with static map
50
+ * ```typescript
51
+ * const config: PermissionConfig = {
52
+ * source: 'config',
53
+ * staticMap: {
54
+ * 'client-1': ['toolset-a', 'toolset-b'],
55
+ * 'client-2': ['toolset-c']
56
+ * },
57
+ * defaultPermissions: [] // optional, for unknown clients
58
+ * };
59
+ * ```
60
+ *
61
+ * @example Config-based with resolver function
62
+ * ```typescript
63
+ * const config: PermissionConfig = {
64
+ * source: 'config',
65
+ * resolver: (clientId: string) => {
66
+ * // Custom logic to determine permissions
67
+ * if (clientId.startsWith('admin-')) {
68
+ * return ['toolset-a', 'toolset-b', 'toolset-c'];
69
+ * }
70
+ * return ['toolset-a'];
71
+ * },
72
+ * defaultPermissions: ['toolset-a'] // fallback if resolver fails
73
+ * };
74
+ * ```
75
+ */
76
+ export type PermissionConfig = {
77
+ /**
78
+ * The source of permission data.
79
+ *
80
+ * - `'headers'`: Read permissions from request headers. Requires proper authentication
81
+ * in your application layer to prevent tampering.
82
+ * - `'config'`: Use server-side permission configuration via staticMap or resolver.
83
+ * Provides stronger security by not trusting client-provided data.
84
+ */
85
+ source: "headers" | "config";
86
+ /**
87
+ * Name of the header containing permission data (for header-based permissions).
88
+ *
89
+ * The header value should be a comma-separated list of toolset names.
90
+ * Only used when `source` is `'headers'`.
91
+ *
92
+ * @default 'mcp-toolset-permissions'
93
+ * @example
94
+ * ```typescript
95
+ * // With default header name
96
+ * { source: 'headers' }
97
+ * // Client sends: mcp-toolset-permissions: toolset-a,toolset-b
98
+ *
99
+ * // With custom header name
100
+ * { source: 'headers', headerName: 'x-allowed-toolsets' }
101
+ * // Client sends: x-allowed-toolsets: toolset-a,toolset-b
102
+ * ```
103
+ */
104
+ headerName?: string;
105
+ /**
106
+ * Static mapping of client IDs to their allowed toolsets (for config-based permissions).
107
+ *
108
+ * Each key is a client ID, and the value is an array of toolset names the client can access.
109
+ * Only used when `source` is `'config'`. At least one of `staticMap` or `resolver` must
110
+ * be provided for config-based permissions.
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * {
115
+ * source: 'config',
116
+ * staticMap: {
117
+ * 'client-1': ['toolset-a', 'toolset-b'],
118
+ * 'client-2': ['toolset-c'],
119
+ * 'admin-user': ['toolset-a', 'toolset-b', 'toolset-c']
120
+ * }
121
+ * }
122
+ * ```
123
+ */
124
+ staticMap?: Record<string, string[]>;
125
+ /**
126
+ * Synchronous function to resolve permissions for a client (for config-based permissions).
127
+ *
128
+ * Called with the client ID and should return an array of allowed toolset names.
129
+ * Only used when `source` is `'config'`. If both `staticMap` and `resolver` are provided,
130
+ * the resolver takes precedence with staticMap as fallback.
131
+ *
132
+ * The function should be synchronous and deterministic. If it throws an error or returns
133
+ * a non-array value, the system falls back to `staticMap` or `defaultPermissions`.
134
+ *
135
+ * @param clientId - The unique identifier for the client requesting access
136
+ * @returns Array of toolset names the client is allowed to access
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * {
141
+ * source: 'config',
142
+ * resolver: (clientId: string) => {
143
+ * // Integrate with your auth system
144
+ * const user = getUserFromCache(clientId);
145
+ * if (user.role === 'admin') {
146
+ * return ['toolset-a', 'toolset-b', 'toolset-c'];
147
+ * } else if (user.role === 'user') {
148
+ * return ['toolset-a'];
149
+ * }
150
+ * return [];
151
+ * }
152
+ * }
153
+ * ```
154
+ */
155
+ resolver?: (clientId: string) => string[];
156
+ /**
157
+ * Default permissions to apply when a client is not found in staticMap or resolver fails.
158
+ *
159
+ * Used as a fallback when:
160
+ * - Client ID is not found in `staticMap`
161
+ * - `resolver` function throws an error or returns invalid data
162
+ * - No other permission source provides valid permissions
163
+ *
164
+ * If not specified, defaults to an empty array (no toolsets allowed).
165
+ *
166
+ * @default []
167
+ * @example
168
+ * ```typescript
169
+ * {
170
+ * source: 'config',
171
+ * staticMap: { 'known-client': ['toolset-a'] },
172
+ * defaultPermissions: ['public-toolset'] // Unknown clients get this
173
+ * }
174
+ * ```
175
+ */
176
+ defaultPermissions?: string[];
177
+ };
178
+ /**
179
+ * Options for creating a permission-based MCP server.
180
+ *
181
+ * Extends `CreateMcpServerOptions` but removes the `startup` field and requires
182
+ * a `permissions` configuration. Permission-based servers automatically use DYNAMIC
183
+ * mode internally to ensure per-client isolation, with each client receiving only
184
+ * their authorized toolsets.
185
+ *
186
+ * All standard options from `CreateMcpServerOptions` are supported, including:
187
+ * - `createServer`: Factory function to create MCP server instances
188
+ * - `catalog`: Toolset catalog defining available toolsets
189
+ * - `moduleLoaders`: Optional lazy-loading modules for toolsets
190
+ * - `exposurePolicy`: Optional policy for toolset exposure control
191
+ * - `http`: HTTP transport configuration (host, port, CORS, etc.)
192
+ * - `context`: Optional context passed to module loaders
193
+ *
194
+ * @example Basic header-based server
195
+ * ```typescript
196
+ * const options: CreatePermissionBasedMcpServerOptions = {
197
+ * createServer: () => new McpServer({ name: "my-server", version: "1.0.0" }),
198
+ * catalog: {
199
+ * 'toolset-a': { name: 'Toolset A', tools: [...] },
200
+ * 'toolset-b': { name: 'Toolset B', tools: [...] }
201
+ * },
202
+ * permissions: {
203
+ * source: 'headers'
204
+ * },
205
+ * http: {
206
+ * port: 3000,
207
+ * cors: true
208
+ * }
209
+ * };
210
+ * ```
211
+ *
212
+ * @example Config-based server with static map
213
+ * ```typescript
214
+ * const options: CreatePermissionBasedMcpServerOptions = {
215
+ * createServer: () => new McpServer({ name: "my-server", version: "1.0.0" }),
216
+ * catalog: {
217
+ * 'toolset-a': { name: 'Toolset A', tools: [...] },
218
+ * 'toolset-b': { name: 'Toolset B', tools: [...] }
219
+ * },
220
+ * permissions: {
221
+ * source: 'config',
222
+ * staticMap: {
223
+ * 'client-1': ['toolset-a'],
224
+ * 'client-2': ['toolset-a', 'toolset-b']
225
+ * },
226
+ * defaultPermissions: []
227
+ * }
228
+ * };
229
+ * ```
230
+ */
231
+ export type CreatePermissionBasedMcpServerOptions = Omit<CreateMcpServerOptions, "startup"> & {
232
+ /**
233
+ * Permission configuration defining how client access control is enforced.
234
+ *
235
+ * This field is required for permission-based servers. It determines whether
236
+ * permissions are read from request headers or resolved server-side using
237
+ * static maps or resolver functions.
238
+ *
239
+ * @see {@link PermissionConfig} for detailed configuration options and examples
240
+ */
241
+ permissions: PermissionConfig;
242
+ /**
243
+ * Startup configuration is not allowed for permission-based servers.
244
+ *
245
+ * Permission-based servers automatically determine which toolsets to load for
246
+ * each client based on the `permissions` configuration. The server internally
247
+ * uses STATIC mode per client to ensure isolation and prevent dynamic toolset
248
+ * changes during a session.
249
+ *
250
+ * @deprecated Do not use - permission-based servers determine toolsets from client permissions
251
+ */
252
+ startup?: never;
253
+ };
25
254
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAE5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAE/D,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,qBAAqB,GACrB,sBAAsB,GACtB,iBAAiB,GACjB,YAAY,CAAC;AAKjB,MAAM,MAAM,YAAY,GAAG,CACzB,OAAO,CAAC,EAAE,OAAO,KACd,OAAO,CAAC,iBAAiB,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAI3E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAE5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAE/D,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,qBAAqB,GACrB,sBAAsB,GACtB,iBAAiB,GACjB,YAAY,CAAC;AAKjB,MAAM,MAAM,YAAY,GAAG,CACzB,OAAO,CAAC,EAAE,OAAO,KACd,OAAO,CAAC,iBAAiB,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;;;;OAOG;IACH,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAE7B;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAErC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IAE1C;;;;;;;;;;;;;;;;;;;OAmBG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,MAAM,MAAM,qCAAqC,GAAG,IAAI,CACtD,sBAAsB,EACtB,SAAS,CACV,GAAG;IACF;;;;;;;;OAQG;IACH,WAAW,EAAE,gBAAgB,CAAC;IAE9B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolception",
3
- "version": "0.2.5",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -34,7 +34,7 @@
34
34
  "@vitest/coverage-v8": "^3.2.4",
35
35
  "tsx": "^4.19.0",
36
36
  "typescript": "^5.9.2",
37
- "vite": "^5.3.1",
37
+ "vite": "^7.2.4",
38
38
  "vite-plugin-dts": "^4.5.4",
39
39
  "vitest": "^3.2.4"
40
40
  },
@@ -58,6 +58,11 @@
58
58
  "dynamic-tools",
59
59
  "toolset",
60
60
  "tool-management",
61
+ "permissions",
62
+ "authentication",
63
+ "access-control",
64
+ "security",
65
+ "authorization",
61
66
  "json-rpc",
62
67
  "fastify",
63
68
  "zod",