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.
- package/README.md +945 -21
- package/dist/core/DynamicToolManager.d.ts +45 -2
- package/dist/core/DynamicToolManager.d.ts.map +1 -1
- package/dist/core/ServerOrchestrator.d.ts +24 -2
- package/dist/core/ServerOrchestrator.d.ts.map +1 -1
- package/dist/http/FastifyTransport.d.ts +11 -0
- package/dist/http/FastifyTransport.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +940 -237
- package/dist/index.js.map +1 -1
- package/dist/meta/registerMetaTools.d.ts +14 -0
- package/dist/meta/registerMetaTools.d.ts.map +1 -1
- package/dist/mode/ModeResolver.d.ts +7 -0
- package/dist/mode/ModeResolver.d.ts.map +1 -1
- package/dist/permissions/PermissionAwareFastifyTransport.d.ts +47 -0
- package/dist/permissions/PermissionAwareFastifyTransport.d.ts.map +1 -0
- package/dist/permissions/PermissionResolver.d.ts +43 -0
- package/dist/permissions/PermissionResolver.d.ts.map +1 -0
- package/dist/permissions/createPermissionAwareBundle.d.ts +58 -0
- package/dist/permissions/createPermissionAwareBundle.d.ts.map +1 -0
- package/dist/permissions/validatePermissionConfig.d.ts +9 -0
- package/dist/permissions/validatePermissionConfig.d.ts.map +1 -0
- package/dist/server/createMcpServer.d.ts +4 -3
- package/dist/server/createMcpServer.d.ts.map +1 -1
- package/dist/server/createPermissionBasedMcpServer.d.ts +65 -0
- package/dist/server/createPermissionBasedMcpServer.d.ts.map +1 -0
- package/dist/session/ClientResourceCache.d.ts +34 -3
- package/dist/session/ClientResourceCache.d.ts.map +1 -1
- package/dist/types/index.d.ts +229 -0
- package/dist/types/index.d.ts.map +1 -1
- 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,
|
|
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
|
-
/**
|
|
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,
|
|
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
|
-
|
|
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;
|
|
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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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":"
|
|
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.
|
|
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": "^
|
|
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",
|