| 1 | enum McpIntegrationType { ephemeralMcp, plugin } |
| 2 | |
| 3 | class McpIntegration { |
| 4 | final McpIntegrationType type; |
| 5 | final String? serverLabel; |
| 6 | final String? serverUrl; |
| 7 | final String? pluginId; |
| 8 | final List<String>? allowedTools; |
| 9 | final Map<String, String>? headers; |
| 10 | final bool enabled; |
| 11 | |
| 12 | const McpIntegration({ |
| 13 | required this.type, |
| 14 | this.serverLabel, |
| 15 | this.serverUrl, |
| 16 | this.pluginId, |
| 17 | this.allowedTools, |
| 18 | this.headers, |
| 19 | this.enabled = true, |
| 20 | }); |
| 21 | |
| 22 | /// Returns the clean API payload expected by LM Studio native endpoint. |
| 23 | Map<String, dynamic> toApiJson() { |
| 24 | if (type == McpIntegrationType.plugin) { |
| 25 | return { |
| 26 | 'type': 'plugin', |
| 27 | 'id': pluginId, |
| 28 | if (allowedTools != null) 'allowed_tools': allowedTools, |
| 29 | }; |
| 30 | } |
| 31 | return { |
| 32 | 'type': 'ephemeral_mcp', |
| 33 | 'server_label': serverLabel, |
| 34 | 'server_url': serverUrl, |
| 35 | if (allowedTools != null) 'allowed_tools': allowedTools, |
| 36 | if (headers != null) 'headers': headers, |
| 37 | }; |
| 38 | } |
| 39 | |
| 40 | Map<String, dynamic> toJson() { |
| 41 | final map = toApiJson(); |
| 42 | map['enabled'] = enabled; |
| 43 | return map; |
| 44 | } |
| 45 | |
| 46 | factory McpIntegration.fromJson(Map<String, dynamic> json) { |
| 47 | final typeStr = json['type'] as String; |
| 48 | final type = typeStr == 'plugin' |
| 49 | ? McpIntegrationType.plugin |
| 50 | : McpIntegrationType.ephemeralMcp; |
| 51 | |
| 52 | return McpIntegration( |
| 53 | type: type, |
| 54 | serverLabel: json['server_label'] as String?, |
| 55 | serverUrl: json['server_url'] as String?, |
| 56 | pluginId: json['id'] as String?, |
| 57 | allowedTools: (json['allowed_tools'] as List?)?.cast<String>(), |
| 58 | headers: (json['headers'] as Map?)?.cast<String, String>(), |
| 59 | enabled: json['enabled'] as bool? ?? true, |
| 60 | ); |
| 61 | } |
| 62 | |
| 63 | McpIntegration copyWith({ |
| 64 | McpIntegrationType? type, |
| 65 | String? serverLabel, |
| 66 | String? serverUrl, |
| 67 | String? pluginId, |
| 68 | List<String>? allowedTools, |
| 69 | Map<String, String>? headers, |
| 70 | bool? enabled, |
| 71 | }) { |
| 72 | return McpIntegration( |
| 73 | type: type ?? this.type, |
| 74 | serverLabel: serverLabel ?? this.serverLabel, |
| 75 | serverUrl: serverUrl ?? this.serverUrl, |
| 76 | pluginId: pluginId ?? this.pluginId, |
| 77 | allowedTools: allowedTools ?? this.allowedTools, |
| 78 | headers: headers ?? this.headers, |
| 79 | enabled: enabled ?? this.enabled, |
| 80 | ); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | class ChatMcpConfig { |
| 85 | final List<McpIntegration> integrations; |
| 86 | final Map<String, String> activeMcpServers; |
| 87 | final bool enabled; |
| 88 | |
| 89 | const ChatMcpConfig({ |
| 90 | this.integrations = const [], |
| 91 | this.activeMcpServers = const {}, |
| 92 | this.enabled = true, |
| 93 | }); |
| 94 | |
| 95 | ChatMcpConfig copyWith({ |
| 96 | List<McpIntegration>? integrations, |
| 97 | Map<String, String>? activeMcpServers, |
| 98 | bool? enabled, |
| 99 | }) { |
| 100 | return ChatMcpConfig( |
| 101 | integrations: integrations ?? this.integrations, |
| 102 | activeMcpServers: activeMcpServers ?? this.activeMcpServers, |
| 103 | enabled: enabled ?? this.enabled, |
| 104 | ); |
| 105 | } |
| 106 | |
| 107 | Map<String, dynamic> toJson() { |
| 108 | return { |
| 109 | 'integrations': integrations.map((i) => i.toJson()).toList(), |
| 110 | 'activeMcpServers': activeMcpServers, |
| 111 | }; |
| 112 | } |
| 113 | |
| 114 | factory ChatMcpConfig.fromJson(Map<String, dynamic> json) { |
| 115 | return ChatMcpConfig( |
| 116 | integrations: |
| 117 | (json['integrations'] as List?) |
| 118 | ?.map((i) => McpIntegration.fromJson(i as Map<String, dynamic>)) |
| 119 | .toList() ?? |
| 120 | [], |
| 121 | activeMcpServers: |
| 122 | (json['activeMcpServers'] as Map?)?.cast<String, String>() ?? {}, |
| 123 | enabled: json['enabled'] as bool? ?? true, |
| 124 | ); |
| 125 | } |
| 126 | } |