touchdesigner-mcp-server 1.4.8 → 1.4.10
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/dist/api/customInstance.d.ts +5 -0
- package/dist/cli.d.ts +50 -0
- package/dist/core/compatibility.d.ts +102 -0
- package/dist/core/constants.d.ts +29 -0
- package/dist/core/errorHandling.d.ts +18 -0
- package/dist/core/logger.d.ts +24 -0
- package/dist/core/result.d.ts +25 -0
- package/dist/core/version.d.ts +21 -0
- package/dist/features/prompts/handlers/td_prompts.d.ts +6 -0
- package/dist/features/prompts/index.d.ts +1 -0
- package/dist/features/prompts/register.d.ts +6 -0
- package/dist/features/tools/handlers/tdTools.d.ts +4 -0
- package/dist/features/tools/handlers/tdTools.js +23 -256
- package/dist/features/tools/index.d.ts +3 -0
- package/dist/features/tools/metadata/touchDesignerToolMetadata.d.ts +29 -0
- package/dist/features/tools/metadata/touchDesignerToolMetadata.js +96 -474
- package/dist/features/tools/presenter/classListFormatter.d.ts +29 -0
- package/dist/features/tools/presenter/index.d.ts +18 -0
- package/dist/features/tools/presenter/markdownRenderer.d.ts +3 -0
- package/dist/features/tools/presenter/moduleHelpFormatter.d.ts +12 -0
- package/dist/features/tools/presenter/nodeDetailsFormatter.d.ts +16 -0
- package/dist/features/tools/presenter/nodeErrorsFormatter.d.ts +4 -0
- package/dist/features/tools/presenter/nodeListFormatter.d.ts +22 -0
- package/dist/features/tools/presenter/operationFormatter.d.ts +16 -0
- package/dist/features/tools/presenter/presenter.d.ts +10 -0
- package/dist/features/tools/presenter/responseFormatter.d.ts +83 -0
- package/dist/features/tools/presenter/scriptResultFormatter.d.ts +23 -0
- package/dist/features/tools/presenter/toolMetadataFormatter.d.ts +7 -0
- package/dist/features/tools/register.d.ts +7 -0
- package/dist/features/tools/toolDefinitions.d.ts +38 -0
- package/dist/features/tools/toolDefinitions.js +317 -0
- package/dist/features/tools/types.d.ts +43 -0
- package/dist/features/tools/utils/toolUtils.d.ts +0 -0
- package/dist/gen/endpoints/TouchDesignerAPI.d.ts +510 -0
- package/dist/gen/endpoints/TouchDesignerAPI.js +18 -18
- package/dist/gen/mcp/touchDesignerAPI.zod.d.ts +253 -0
- package/dist/gen/mcp/touchDesignerAPI.zod.js +27 -27
- package/dist/index.d.ts +3 -0
- package/dist/server/connectionManager.d.ts +25 -0
- package/dist/server/touchDesignerServer.d.ts +59 -0
- package/dist/tdClient/index.d.ts +7 -0
- package/dist/tdClient/touchDesignerClient.d.ts +167 -0
- package/dist/transport/config.d.ts +96 -0
- package/dist/transport/expressHttpManager.d.ts +86 -0
- package/dist/transport/factory.d.ts +81 -0
- package/dist/transport/index.d.ts +15 -0
- package/dist/transport/sessionManager.d.ts +180 -0
- package/dist/transport/transportRegistry.d.ts +92 -0
- package/dist/transport/validator.d.ts +43 -0
- package/package.json +6 -21
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Transport types supported by the MCP server
|
|
4
|
+
*/
|
|
5
|
+
export type TransportType = "stdio" | "streamable-http";
|
|
6
|
+
/**
|
|
7
|
+
* Session configuration for Streamable HTTP transport
|
|
8
|
+
*/
|
|
9
|
+
export interface SessionConfig {
|
|
10
|
+
/**
|
|
11
|
+
* Enable session management (default: true)
|
|
12
|
+
*/
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Session TTL in milliseconds (default: 1 hour)
|
|
16
|
+
*/
|
|
17
|
+
ttl?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Interval for session cleanup in milliseconds (default: 5 minutes)
|
|
20
|
+
*/
|
|
21
|
+
cleanupInterval?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Configuration for stdio transport
|
|
25
|
+
*/
|
|
26
|
+
export interface StdioTransportConfig {
|
|
27
|
+
type: "stdio";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Configuration for Streamable HTTP transport
|
|
31
|
+
*/
|
|
32
|
+
export interface StreamableHttpTransportConfig {
|
|
33
|
+
type: "streamable-http";
|
|
34
|
+
/**
|
|
35
|
+
* Port to bind the HTTP server to
|
|
36
|
+
*/
|
|
37
|
+
port: number;
|
|
38
|
+
/**
|
|
39
|
+
* Host address to bind the HTTP server to (default: '127.0.0.1')
|
|
40
|
+
*/
|
|
41
|
+
host: string;
|
|
42
|
+
/**
|
|
43
|
+
* MCP endpoint path (default: '/mcp')
|
|
44
|
+
*/
|
|
45
|
+
endpoint: string;
|
|
46
|
+
/**
|
|
47
|
+
* Session management configuration
|
|
48
|
+
*/
|
|
49
|
+
sessionConfig?: SessionConfig;
|
|
50
|
+
/**
|
|
51
|
+
* Retry interval in milliseconds for SSE polling behavior (optional)
|
|
52
|
+
* When set, the server will send a retry field in SSE priming events
|
|
53
|
+
*/
|
|
54
|
+
retryInterval?: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Union type for all transport configurations
|
|
58
|
+
*/
|
|
59
|
+
export type TransportConfig = StdioTransportConfig | StreamableHttpTransportConfig;
|
|
60
|
+
/**
|
|
61
|
+
* Zod schema for TransportConfig validation (discriminated union)
|
|
62
|
+
*/
|
|
63
|
+
export declare const TransportConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
64
|
+
type: z.ZodLiteral<"stdio">;
|
|
65
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
66
|
+
endpoint: z.ZodString;
|
|
67
|
+
host: z.ZodString;
|
|
68
|
+
port: z.ZodNumber;
|
|
69
|
+
retryInterval: z.ZodOptional<z.ZodNumber>;
|
|
70
|
+
sessionConfig: z.ZodOptional<z.ZodObject<{
|
|
71
|
+
cleanupInterval: z.ZodOptional<z.ZodNumber>;
|
|
72
|
+
enabled: z.ZodBoolean;
|
|
73
|
+
ttl: z.ZodOptional<z.ZodNumber>;
|
|
74
|
+
}, z.core.$strict>>;
|
|
75
|
+
type: z.ZodLiteral<"streamable-http">;
|
|
76
|
+
}, z.core.$strict>], "type">;
|
|
77
|
+
/**
|
|
78
|
+
* Type guard to check if config is StdioTransportConfig
|
|
79
|
+
*/
|
|
80
|
+
export declare function isStdioTransportConfig(config: TransportConfig): config is StdioTransportConfig;
|
|
81
|
+
/**
|
|
82
|
+
* Type guard to check if config is StreamableHttpTransportConfig
|
|
83
|
+
*/
|
|
84
|
+
export declare function isStreamableHttpTransportConfig(config: TransportConfig): config is StreamableHttpTransportConfig;
|
|
85
|
+
/**
|
|
86
|
+
* Default values for SessionConfig
|
|
87
|
+
*/
|
|
88
|
+
export declare const DEFAULT_SESSION_CONFIG: Required<SessionConfig>;
|
|
89
|
+
/**
|
|
90
|
+
* Default values for StreamableHttpTransportConfig (excluding required fields)
|
|
91
|
+
*/
|
|
92
|
+
export declare const DEFAULT_HTTP_CONFIG: {
|
|
93
|
+
readonly endpoint: "/mcp";
|
|
94
|
+
readonly host: "127.0.0.1";
|
|
95
|
+
readonly sessionConfig: Required<SessionConfig>;
|
|
96
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { ILogger } from "../core/logger.js";
|
|
3
|
+
import type { Result } from "../core/result.js";
|
|
4
|
+
import type { StreamableHttpTransportConfig } from "./config.js";
|
|
5
|
+
/**
|
|
6
|
+
* Express HTTP Manager
|
|
7
|
+
*
|
|
8
|
+
* Manages HTTP server lifecycle for Streamable HTTP transport.
|
|
9
|
+
* Handles multiple concurrent sessions by creating per-session transport and server instances.
|
|
10
|
+
*
|
|
11
|
+
* Key Features:
|
|
12
|
+
* - /mcp endpoint → routes to appropriate transport via TransportRegistry
|
|
13
|
+
* - /health endpoint → reports active session count
|
|
14
|
+
* - Per-session isolation → each client gets independent MCP protocol state
|
|
15
|
+
* - Graceful shutdown → cleans up all active sessions
|
|
16
|
+
*
|
|
17
|
+
* Architecture:
|
|
18
|
+
* ```
|
|
19
|
+
* Client 1 → POST /mcp → TransportRegistry.getOrCreate() → Transport 1 + Server 1
|
|
20
|
+
* Client 2 → POST /mcp → TransportRegistry.getOrCreate() → Transport 2 + Server 2
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const manager = new ExpressHttpManager(
|
|
26
|
+
* config,
|
|
27
|
+
* () => TouchDesignerServer.create(), // Server factory
|
|
28
|
+
* sessionManager,
|
|
29
|
+
* logger
|
|
30
|
+
* );
|
|
31
|
+
*
|
|
32
|
+
* // Start server
|
|
33
|
+
* const result = await manager.start();
|
|
34
|
+
*
|
|
35
|
+
* // Graceful shutdown
|
|
36
|
+
* await manager.stop();
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class ExpressHttpManager {
|
|
40
|
+
private readonly config;
|
|
41
|
+
private readonly serverFactory;
|
|
42
|
+
private readonly logger;
|
|
43
|
+
private readonly registry;
|
|
44
|
+
private server;
|
|
45
|
+
/**
|
|
46
|
+
* Create ExpressHttpManager with server factory
|
|
47
|
+
*
|
|
48
|
+
* @param config - Streamable HTTP transport configuration
|
|
49
|
+
* @param serverFactory - Factory function to create new Server instances per session
|
|
50
|
+
* @param sessionManager - Session manager for TTL tracking (optional)
|
|
51
|
+
* @param logger - Logger instance
|
|
52
|
+
*/
|
|
53
|
+
constructor(config: StreamableHttpTransportConfig, serverFactory: () => McpServer, sessionManager: import("./sessionManager.js").ISessionManager | null, logger: ILogger);
|
|
54
|
+
/**
|
|
55
|
+
* Start HTTP server with Express app from SDK
|
|
56
|
+
*
|
|
57
|
+
* @returns Result indicating success or failure
|
|
58
|
+
*/
|
|
59
|
+
start(): Promise<Result<void, Error>>;
|
|
60
|
+
/**
|
|
61
|
+
* Graceful shutdown
|
|
62
|
+
*
|
|
63
|
+
* Stops HTTP server and cleans up all active sessions.
|
|
64
|
+
*
|
|
65
|
+
* @returns Result indicating success or failure
|
|
66
|
+
*/
|
|
67
|
+
stop(): Promise<Result<void, Error>>;
|
|
68
|
+
/**
|
|
69
|
+
* Check if server is running
|
|
70
|
+
*
|
|
71
|
+
* @returns True if server is running
|
|
72
|
+
*/
|
|
73
|
+
isRunning(): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Get active session count
|
|
76
|
+
*
|
|
77
|
+
* @returns Number of active sessions
|
|
78
|
+
*/
|
|
79
|
+
getActiveSessionCount(): number;
|
|
80
|
+
/**
|
|
81
|
+
* Get all active session IDs
|
|
82
|
+
*
|
|
83
|
+
* @returns Array of session IDs
|
|
84
|
+
*/
|
|
85
|
+
getActiveSessionIds(): string[];
|
|
86
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
2
|
+
import type { ILogger } from "../core/logger.js";
|
|
3
|
+
import type { Result } from "../core/result.js";
|
|
4
|
+
import type { TransportConfig } from "./config.js";
|
|
5
|
+
import type { ISessionManager } from "./sessionManager.js";
|
|
6
|
+
/**
|
|
7
|
+
* Factory for creating MCP transport instances based on configuration
|
|
8
|
+
*
|
|
9
|
+
* This factory implements the Factory pattern to encapsulate transport creation logic.
|
|
10
|
+
* It validates configuration and creates the appropriate transport type (stdio or HTTP).
|
|
11
|
+
*/
|
|
12
|
+
export declare class TransportFactory {
|
|
13
|
+
/**
|
|
14
|
+
* Reset the internal state of a StreamableHTTPServerTransport instance
|
|
15
|
+
*
|
|
16
|
+
* WARNING: This method manipulates the private field '_initialized' using Reflect.set().
|
|
17
|
+
* This is fragile and may break if the MCP SDK implementation changes.
|
|
18
|
+
* There is currently no public API to reset the initialized state, so this is required
|
|
19
|
+
* to ensure the transport can be reused safely after a session is closed.
|
|
20
|
+
* If the SDK adds a public reset/init method, use that instead.
|
|
21
|
+
* If the SDK changes the field name or its semantics, update this code accordingly.
|
|
22
|
+
*/
|
|
23
|
+
private static resetStreamableHttpState;
|
|
24
|
+
/**
|
|
25
|
+
* Create a transport instance from configuration
|
|
26
|
+
*
|
|
27
|
+
* @param config - Transport configuration (stdio or streamable-http)
|
|
28
|
+
* @param logger - Optional logger for HTTP transport session events (ignored for stdio)
|
|
29
|
+
* @param sessionManager - Optional session manager for HTTP transport (ignored for stdio)
|
|
30
|
+
* @returns Result with Transport instance or Error
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* // Create stdio transport
|
|
35
|
+
* const stdioResult = TransportFactory.create({ type: 'stdio' });
|
|
36
|
+
*
|
|
37
|
+
* // Create HTTP transport with logger and session manager
|
|
38
|
+
* const httpResult = TransportFactory.create({
|
|
39
|
+
* type: 'streamable-http',
|
|
40
|
+
* port: 6280,
|
|
41
|
+
* host: '127.0.0.1',
|
|
42
|
+
* endpoint: '/mcp'
|
|
43
|
+
* }, logger, sessionManager);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
static create(config: TransportConfig, logger?: ILogger, sessionManager?: ISessionManager | null): Result<Transport, Error>;
|
|
47
|
+
/**
|
|
48
|
+
* Create a stdio transport instance
|
|
49
|
+
*
|
|
50
|
+
* @param _config - Stdio transport configuration (unused, kept for API consistency)
|
|
51
|
+
* @returns Result with StdioServerTransport instance
|
|
52
|
+
*/
|
|
53
|
+
private static createStdio;
|
|
54
|
+
/**
|
|
55
|
+
* Create a streamable HTTP transport instance
|
|
56
|
+
*
|
|
57
|
+
* Creates a StreamableHTTPServerTransport with session management support.
|
|
58
|
+
* The transport instance is stateful and manages session lifecycle through callbacks.
|
|
59
|
+
*
|
|
60
|
+
* Note: DNS rebinding protection is handled by Express middleware (createMcpExpressApp)
|
|
61
|
+
* in the ExpressHttpManager, not by the transport itself.
|
|
62
|
+
*
|
|
63
|
+
* @param config - Streamable HTTP transport configuration
|
|
64
|
+
* @param logger - Optional logger for session lifecycle events
|
|
65
|
+
* @param sessionManager - Optional session manager for tracking sessions
|
|
66
|
+
* @returns Result with StreamableHTTPServerTransport instance or Error
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const config: StreamableHttpTransportConfig = {
|
|
71
|
+
* type: 'streamable-http',
|
|
72
|
+
* port: 6280,
|
|
73
|
+
* host: '127.0.0.1',
|
|
74
|
+
* endpoint: '/mcp',
|
|
75
|
+
* sessionConfig: { enabled: true }
|
|
76
|
+
* };
|
|
77
|
+
* const result = TransportFactory.createStreamableHttp(config, logger, sessionManager);
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
private static createStreamableHttp;
|
|
81
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport layer module exports
|
|
3
|
+
*
|
|
4
|
+
* This module provides type-safe configuration and validation for MCP transports:
|
|
5
|
+
* - stdio: Standard input/output transport
|
|
6
|
+
* - streamable-http: HTTP-based transport with SSE streaming
|
|
7
|
+
*/
|
|
8
|
+
export type { SessionConfig, StdioTransportConfig, StreamableHttpTransportConfig, TransportConfig, TransportType, } from "./config.js";
|
|
9
|
+
export { DEFAULT_HTTP_CONFIG, DEFAULT_SESSION_CONFIG, isStdioTransportConfig, isStreamableHttpTransportConfig, TransportConfigSchema, } from "./config.js";
|
|
10
|
+
export { ExpressHttpManager } from "./expressHttpManager.js";
|
|
11
|
+
export { TransportFactory } from "./factory.js";
|
|
12
|
+
export type { ISessionManager, Session } from "./sessionManager.js";
|
|
13
|
+
export { SessionManager } from "./sessionManager.js";
|
|
14
|
+
export type { ValidationError } from "./validator.js";
|
|
15
|
+
export { TransportConfigValidator } from "./validator.js";
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type { ILogger } from "../core/logger.js";
|
|
2
|
+
import type { Result } from "../core/result.js";
|
|
3
|
+
import type { SessionConfig } from "./config.js";
|
|
4
|
+
/**
|
|
5
|
+
* Session metadata
|
|
6
|
+
*/
|
|
7
|
+
export interface Session {
|
|
8
|
+
/**
|
|
9
|
+
* Unique session identifier (UUID v4)
|
|
10
|
+
*/
|
|
11
|
+
id: string;
|
|
12
|
+
/**
|
|
13
|
+
* Timestamp when session was created (milliseconds since epoch)
|
|
14
|
+
*/
|
|
15
|
+
createdAt: number;
|
|
16
|
+
/**
|
|
17
|
+
* Timestamp when session was last accessed (milliseconds since epoch)
|
|
18
|
+
*/
|
|
19
|
+
lastAccessedAt: number;
|
|
20
|
+
/**
|
|
21
|
+
* Optional metadata associated with the session
|
|
22
|
+
*/
|
|
23
|
+
metadata?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Session manager interface
|
|
27
|
+
*/
|
|
28
|
+
export interface ISessionManager {
|
|
29
|
+
/**
|
|
30
|
+
* Create a new session with auto-generated ID
|
|
31
|
+
*/
|
|
32
|
+
create(metadata?: Record<string, unknown>): string;
|
|
33
|
+
/**
|
|
34
|
+
* Refresh last access time for a session
|
|
35
|
+
*/
|
|
36
|
+
touch(sessionId: string): Result<void, Error>;
|
|
37
|
+
/**
|
|
38
|
+
* Register a callback invoked when a session expires via TTL cleanup.
|
|
39
|
+
*/
|
|
40
|
+
setExpirationHandler(handler: (sessionId: string) => Promise<void> | void): void;
|
|
41
|
+
/**
|
|
42
|
+
* Register an existing session (created by SDK)
|
|
43
|
+
*/
|
|
44
|
+
register(sessionId: string, metadata?: Record<string, unknown>): void;
|
|
45
|
+
/**
|
|
46
|
+
* Clean up a session by ID
|
|
47
|
+
*/
|
|
48
|
+
cleanup(sessionId: string): Result<void, Error>;
|
|
49
|
+
/**
|
|
50
|
+
* List all active sessions
|
|
51
|
+
*/
|
|
52
|
+
list(): Session[];
|
|
53
|
+
/**
|
|
54
|
+
* Start automatic TTL-based cleanup
|
|
55
|
+
*/
|
|
56
|
+
startTTLCleanup(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Stop automatic TTL-based cleanup
|
|
59
|
+
*/
|
|
60
|
+
stopTTLCleanup(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Get number of active sessions
|
|
63
|
+
*/
|
|
64
|
+
getActiveSessionCount(): number;
|
|
65
|
+
/**
|
|
66
|
+
* Clear all sessions (for testing or emergency cleanup)
|
|
67
|
+
*/
|
|
68
|
+
clearAll(): void;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Session Manager
|
|
72
|
+
*
|
|
73
|
+
* Manages client sessions for Streamable HTTP transport.
|
|
74
|
+
* Provides session creation, validation, TTL-based expiration, and automatic cleanup.
|
|
75
|
+
*
|
|
76
|
+
* Note: Session validation (checking if session ID exists) is now handled by
|
|
77
|
+
* StreamableHTTPServerTransport.handleRequest(). This SessionManager focuses on:
|
|
78
|
+
* - Session creation via SDK callbacks (onsessioninitialized)
|
|
79
|
+
* - Session cleanup via SDK callbacks (onsessionclosed) and TTL-based cleanup
|
|
80
|
+
* - Session tracking for health checks and monitoring
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const sessionManager = new SessionManager(
|
|
85
|
+
* { enabled: true, ttl: 60 * 60 * 1000 }, // 1 hour TTL
|
|
86
|
+
* logger
|
|
87
|
+
* );
|
|
88
|
+
*
|
|
89
|
+
* // Create session (typically called from SDK callback)
|
|
90
|
+
* const sessionId = sessionManager.create({ clientVersion: '1.0' });
|
|
91
|
+
*
|
|
92
|
+
* // Start automatic TTL-based cleanup
|
|
93
|
+
* sessionManager.startTTLCleanup();
|
|
94
|
+
*
|
|
95
|
+
* // Stop cleanup when done
|
|
96
|
+
* sessionManager.stopTTLCleanup();
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export declare class SessionManager implements ISessionManager {
|
|
100
|
+
private readonly sessions;
|
|
101
|
+
private readonly config;
|
|
102
|
+
private readonly logger;
|
|
103
|
+
private cleanupInterval;
|
|
104
|
+
private onSessionExpired;
|
|
105
|
+
constructor(config: SessionConfig, logger: ILogger);
|
|
106
|
+
/**
|
|
107
|
+
* Create a new session with optional metadata
|
|
108
|
+
*
|
|
109
|
+
* @param metadata - Optional metadata to associate with the session
|
|
110
|
+
* @returns Session ID (UUID v4)
|
|
111
|
+
*/
|
|
112
|
+
create(metadata?: Record<string, unknown>): string;
|
|
113
|
+
/**
|
|
114
|
+
* Update lastAccessedAt when a session receives activity
|
|
115
|
+
*
|
|
116
|
+
* @param sessionId - Session ID to refresh
|
|
117
|
+
*/
|
|
118
|
+
touch(sessionId: string): Result<void, Error>;
|
|
119
|
+
/**
|
|
120
|
+
* Register a callback to run when TTL cleanup expires a session.
|
|
121
|
+
*
|
|
122
|
+
* @param handler - Callback invoked with expired session ID
|
|
123
|
+
*/
|
|
124
|
+
setExpirationHandler(handler: (sessionId: string) => Promise<void> | void): void;
|
|
125
|
+
/**
|
|
126
|
+
* Register an SDK-created session for tracking
|
|
127
|
+
*
|
|
128
|
+
* This method registers sessions that were created by the MCP SDK's
|
|
129
|
+
* StreamableHTTPServerTransport. The SDK generates session IDs via the
|
|
130
|
+
* sessionIdGenerator callback, and then calls onsessioninitialized.
|
|
131
|
+
* This method creates a new tracking entry with current timestamps
|
|
132
|
+
* so the session can be managed for TTL cleanup and monitoring.
|
|
133
|
+
*
|
|
134
|
+
* @param sessionId - Session ID generated by SDK
|
|
135
|
+
* @param metadata - Optional metadata to associate with the session
|
|
136
|
+
*/
|
|
137
|
+
register(sessionId: string, metadata?: Record<string, unknown>): void;
|
|
138
|
+
/**
|
|
139
|
+
* Clean up (delete) a session by ID
|
|
140
|
+
*
|
|
141
|
+
* @param sessionId - Session ID to clean up
|
|
142
|
+
* @returns Result indicating success or failure
|
|
143
|
+
*/
|
|
144
|
+
cleanup(sessionId: string): Result<void, Error>;
|
|
145
|
+
/**
|
|
146
|
+
* List all active sessions
|
|
147
|
+
*
|
|
148
|
+
* @returns Array of all active sessions
|
|
149
|
+
*/
|
|
150
|
+
list(): Session[];
|
|
151
|
+
/**
|
|
152
|
+
* Start automatic TTL-based cleanup
|
|
153
|
+
*
|
|
154
|
+
* Runs cleanup task at an interval of TTL/2 to remove expired sessions.
|
|
155
|
+
* Does nothing if TTL is not configured or cleanup is already running.
|
|
156
|
+
*/
|
|
157
|
+
startTTLCleanup(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Stop automatic TTL-based cleanup
|
|
160
|
+
*/
|
|
161
|
+
stopTTLCleanup(): void;
|
|
162
|
+
/**
|
|
163
|
+
* Run a single cleanup task to remove expired sessions
|
|
164
|
+
*
|
|
165
|
+
* @private
|
|
166
|
+
*/
|
|
167
|
+
private runCleanupTask;
|
|
168
|
+
/**
|
|
169
|
+
* Get number of active sessions
|
|
170
|
+
*
|
|
171
|
+
* @returns Number of active sessions
|
|
172
|
+
*/
|
|
173
|
+
getActiveSessionCount(): number;
|
|
174
|
+
/**
|
|
175
|
+
* Clear all sessions
|
|
176
|
+
*
|
|
177
|
+
* Useful for testing or emergency cleanup.
|
|
178
|
+
*/
|
|
179
|
+
clearAll(): void;
|
|
180
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
|
+
import type { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import type { ILogger } from "../core/logger.js";
|
|
5
|
+
import type { Result } from "../core/result.js";
|
|
6
|
+
import type { StreamableHttpTransportConfig } from "./config.js";
|
|
7
|
+
import type { ISessionManager } from "./sessionManager.js";
|
|
8
|
+
/**
|
|
9
|
+
* Transport Registry
|
|
10
|
+
*
|
|
11
|
+
* Manages per-session transport and server instances for Streamable HTTP transport.
|
|
12
|
+
* Each session gets its own isolated transport and server to maintain independent MCP protocol state.
|
|
13
|
+
*
|
|
14
|
+
* Key Responsibilities:
|
|
15
|
+
* - Create new transport + server instances for new sessions
|
|
16
|
+
* - Reuse existing transport for requests with valid session IDs
|
|
17
|
+
* - Clean up sessions on close or expiration
|
|
18
|
+
* - Track active session count for health checks
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const registry = new TransportRegistry(config, sessionManager, logger);
|
|
23
|
+
*
|
|
24
|
+
* // In HTTP request handler
|
|
25
|
+
* const transport = await registry.getOrCreate(
|
|
26
|
+
* sessionId,
|
|
27
|
+
* requestBody,
|
|
28
|
+
* () => createTouchDesignerServer()
|
|
29
|
+
* );
|
|
30
|
+
*
|
|
31
|
+
* if (transport) {
|
|
32
|
+
* await transport.handleRequest(req, res, requestBody);
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* // On shutdown
|
|
36
|
+
* await registry.cleanup();
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class TransportRegistry {
|
|
40
|
+
private readonly sessions;
|
|
41
|
+
private readonly config;
|
|
42
|
+
private readonly sessionManager;
|
|
43
|
+
private readonly logger;
|
|
44
|
+
constructor(config: StreamableHttpTransportConfig, sessionManager: ISessionManager | null, logger: ILogger);
|
|
45
|
+
/**
|
|
46
|
+
* Get or create transport for a session
|
|
47
|
+
*
|
|
48
|
+
* Logic:
|
|
49
|
+
* 1. If sessionId exists and valid → return existing transport
|
|
50
|
+
* 2. If no sessionId and request is initialize → create new transport + server
|
|
51
|
+
* 3. Otherwise → return null (invalid session)
|
|
52
|
+
*
|
|
53
|
+
* @param sessionId - Session ID from mcp-session-id header (undefined for new sessions)
|
|
54
|
+
* @param requestBody - JSON-RPC request body
|
|
55
|
+
* @param serverFactory - Factory function to create new Server instances
|
|
56
|
+
* @returns Transport instance or null if session is invalid
|
|
57
|
+
*/
|
|
58
|
+
getOrCreate(sessionId: string | undefined, requestBody: JSONRPCMessage, serverFactory: () => McpServer): Promise<StreamableHTTPServerTransport | null>;
|
|
59
|
+
/**
|
|
60
|
+
* Create a new session with transport and server instances
|
|
61
|
+
*
|
|
62
|
+
* @param serverFactory - Factory function to create new Server instances
|
|
63
|
+
* @returns Transport instance for the new session
|
|
64
|
+
*/
|
|
65
|
+
private createSession;
|
|
66
|
+
/**
|
|
67
|
+
* Remove session from registry
|
|
68
|
+
*
|
|
69
|
+
* @param sessionId - Session ID to remove
|
|
70
|
+
*/
|
|
71
|
+
remove(sessionId: string): void;
|
|
72
|
+
/**
|
|
73
|
+
* Get number of active sessions
|
|
74
|
+
*
|
|
75
|
+
* @returns Active session count
|
|
76
|
+
*/
|
|
77
|
+
getCount(): number;
|
|
78
|
+
/**
|
|
79
|
+
* Get all session IDs
|
|
80
|
+
*
|
|
81
|
+
* @returns Array of session IDs
|
|
82
|
+
*/
|
|
83
|
+
getSessionIds(): string[];
|
|
84
|
+
/**
|
|
85
|
+
* Cleanup all sessions
|
|
86
|
+
*
|
|
87
|
+
* Called during graceful shutdown to close all active sessions
|
|
88
|
+
*
|
|
89
|
+
* @returns Result indicating success or failure
|
|
90
|
+
*/
|
|
91
|
+
cleanup(): Promise<Result<void, Error>>;
|
|
92
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Result } from "../core/result.js";
|
|
2
|
+
import type { TransportConfig } from "./config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Validation error details
|
|
5
|
+
*/
|
|
6
|
+
export interface ValidationError {
|
|
7
|
+
field: string;
|
|
8
|
+
message: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Transport configuration validator using Zod schemas
|
|
12
|
+
*/
|
|
13
|
+
export declare class TransportConfigValidator {
|
|
14
|
+
/**
|
|
15
|
+
* Validate a transport configuration
|
|
16
|
+
*
|
|
17
|
+
* @param config - The configuration to validate
|
|
18
|
+
* @returns Result with validated config or validation errors
|
|
19
|
+
*/
|
|
20
|
+
static validate(config: unknown): Result<TransportConfig, Error>;
|
|
21
|
+
/**
|
|
22
|
+
* Format Zod validation errors into structured ValidationError objects
|
|
23
|
+
*
|
|
24
|
+
* @param zodError - The Zod validation error
|
|
25
|
+
* @returns Array of structured validation errors
|
|
26
|
+
*/
|
|
27
|
+
private static formatZodErrors;
|
|
28
|
+
/**
|
|
29
|
+
* Build a comprehensive error message from validation errors
|
|
30
|
+
*
|
|
31
|
+
* @param errors - Array of validation errors
|
|
32
|
+
* @returns Formatted error message
|
|
33
|
+
*/
|
|
34
|
+
private static buildErrorMessage;
|
|
35
|
+
/**
|
|
36
|
+
* Validate and merge with defaults for HTTP transport
|
|
37
|
+
* This is a convenience method for applying default values after validation
|
|
38
|
+
*
|
|
39
|
+
* @param config - The configuration to validate
|
|
40
|
+
* @returns Result with validated and merged config
|
|
41
|
+
*/
|
|
42
|
+
static validateAndMergeDefaults(config: unknown): Result<TransportConfig, Error>;
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "touchdesigner-mcp-server",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.10",
|
|
4
4
|
"description": "MCP server for TouchDesigner",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,9 +27,6 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
30
|
-
"@mozilla/readability": "0.6.0",
|
|
31
|
-
"@types/ws": "8.18.1",
|
|
32
|
-
"@types/yargs": "17.0.35",
|
|
33
30
|
"axios": "1.17.0",
|
|
34
31
|
"express": "5.2.1",
|
|
35
32
|
"mustache": "4.2.0",
|
|
@@ -38,17 +35,15 @@
|
|
|
38
35
|
"zod": "4.4.3"
|
|
39
36
|
},
|
|
40
37
|
"devDependencies": {
|
|
41
|
-
"@biomejs/biome": "2.
|
|
42
|
-
"@
|
|
38
|
+
"@biomejs/biome": "2.5.0",
|
|
39
|
+
"@redocly/cli": "2.32.2",
|
|
43
40
|
"@types/express": "5.0.6",
|
|
44
|
-
"@types/jsdom": "28.0.3",
|
|
45
41
|
"@types/mustache": "4.2.6",
|
|
46
42
|
"@types/node": "25.9.3",
|
|
47
43
|
"@types/semver": "7.7.1",
|
|
48
44
|
"@vitest/coverage-v8": "4.1.8",
|
|
49
|
-
"msw": "2.14.6",
|
|
50
45
|
"npm-run-all": "4.1.5",
|
|
51
|
-
"orval": "8.
|
|
46
|
+
"orval": "8.17.0",
|
|
52
47
|
"prettier": "3.8.4",
|
|
53
48
|
"shx": "0.4.0",
|
|
54
49
|
"typescript": "6.0.3",
|
|
@@ -89,21 +84,11 @@
|
|
|
89
84
|
"version:api": "node ./scripts/syncApiServerVersions.ts",
|
|
90
85
|
"version:mcp": "node ./scripts/syncMcpServerVersions.ts",
|
|
91
86
|
"gen": "run-s gen:*",
|
|
92
|
-
"gen:
|
|
87
|
+
"gen:openapi": "redocly bundle ./src/api/index.yml -o ./td/modules/td_server/openapi_server/openapi/openapi.yaml",
|
|
93
88
|
"gen:handlers": "node td/genHandlers.js",
|
|
94
89
|
"gen:mcp": "orval --config ./orval.config.ts"
|
|
95
90
|
},
|
|
96
91
|
"files": [
|
|
97
92
|
"dist/**/*"
|
|
98
|
-
]
|
|
99
|
-
"overrides": {
|
|
100
|
-
"concurrently": {
|
|
101
|
-
"shell-quote": "1.8.4"
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
"msw": {
|
|
105
|
-
"workerDirectory": [
|
|
106
|
-
"public"
|
|
107
|
-
]
|
|
108
|
-
}
|
|
93
|
+
]
|
|
109
94
|
}
|