fraim-framework 2.0.82 → 2.0.83

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.
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ // IDE Format Adapters - transform logical server structure to IDE-specific formats
3
+ // Uses the centralized registry to determine server types
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.IDE_FORMATS = exports.CodexFormat = exports.WindsurfFormat = exports.ClaudeCodeFormat = exports.ClaudeFormat = exports.VSCodeFormat = exports.KiroFormat = exports.StandardFormat = void 0;
6
+ exports.getIDEFormat = getIDEFormat;
7
+ const mcp_server_registry_1 = require("./mcp-server-registry");
8
+ const provider_registry_1 = require("../providers/provider-registry");
9
+ // Standard format (Cursor, Kiro, Antigravity, etc.)
10
+ class StandardFormat {
11
+ constructor() {
12
+ this.name = 'standard';
13
+ }
14
+ transform(servers) {
15
+ const mcpServers = {};
16
+ for (const [key, server] of servers) {
17
+ if (server.url) {
18
+ // HTTP server - use serverUrl for standard format
19
+ mcpServers[key] = {
20
+ serverUrl: server.url,
21
+ headers: server.headers
22
+ };
23
+ }
24
+ else {
25
+ // stdio server
26
+ mcpServers[key] = {
27
+ command: server.command,
28
+ ...(server.args && { args: server.args }),
29
+ ...(server.env && { env: server.env })
30
+ };
31
+ }
32
+ }
33
+ return { mcpServers };
34
+ }
35
+ }
36
+ exports.StandardFormat = StandardFormat;
37
+ // Kiro format (also used by Cursor)
38
+ class KiroFormat {
39
+ constructor() {
40
+ this.name = 'kiro';
41
+ }
42
+ transform(servers) {
43
+ const mcpServers = {};
44
+ for (const [key, server] of servers) {
45
+ if (server.url) {
46
+ // HTTP server - use url (not serverUrl)
47
+ mcpServers[key] = {
48
+ url: server.url,
49
+ headers: server.headers
50
+ };
51
+ }
52
+ else {
53
+ // stdio server
54
+ mcpServers[key] = {
55
+ command: server.command,
56
+ ...(server.args && { args: server.args }),
57
+ ...(server.env && { env: server.env })
58
+ };
59
+ }
60
+ }
61
+ return { mcpServers };
62
+ }
63
+ }
64
+ exports.KiroFormat = KiroFormat;
65
+ // VSCode format
66
+ class VSCodeFormat {
67
+ constructor() {
68
+ this.name = 'vscode';
69
+ }
70
+ transform(servers) {
71
+ const vscodeServers = {};
72
+ for (const [key, server] of servers) {
73
+ if (server.url) {
74
+ // HTTP server
75
+ vscodeServers[key] = {
76
+ type: 'http',
77
+ url: server.url,
78
+ headers: server.headers
79
+ };
80
+ }
81
+ else {
82
+ // stdio server
83
+ vscodeServers[key] = {
84
+ type: 'stdio',
85
+ command: server.command,
86
+ ...(server.args && { args: server.args }),
87
+ ...(server.env && { env: server.env })
88
+ };
89
+ }
90
+ }
91
+ return { servers: vscodeServers };
92
+ }
93
+ }
94
+ exports.VSCodeFormat = VSCodeFormat;
95
+ // Claude Desktop format (excludes provider servers - Issue #132)
96
+ class ClaudeFormat {
97
+ constructor() {
98
+ this.name = 'claude';
99
+ }
100
+ async transform(servers) {
101
+ const mcpServers = {};
102
+ for (const [key, server] of servers) {
103
+ // Skip all provider servers - they break Claude Desktop
104
+ // See: https://github.com/mathursrus/FRAIM/issues/132
105
+ if (await (0, mcp_server_registry_1.isProviderServer)(key)) {
106
+ continue;
107
+ }
108
+ // Only include base servers (git, playwright, fraim)
109
+ mcpServers[key] = {
110
+ command: server.command,
111
+ ...(server.args && { args: server.args }),
112
+ ...(server.env && { env: server.env })
113
+ };
114
+ }
115
+ return { mcpServers };
116
+ }
117
+ }
118
+ exports.ClaudeFormat = ClaudeFormat;
119
+ // Claude Code format (supports HTTP servers with VSCode-style format)
120
+ class ClaudeCodeFormat {
121
+ constructor() {
122
+ this.name = 'claude-code';
123
+ }
124
+ transform(servers) {
125
+ const mcpServers = {};
126
+ for (const [key, server] of servers) {
127
+ if (server.url) {
128
+ // HTTP server - use VSCode-style format
129
+ mcpServers[key] = {
130
+ type: 'http',
131
+ url: server.url,
132
+ headers: server.headers
133
+ };
134
+ }
135
+ else {
136
+ // stdio server
137
+ mcpServers[key] = {
138
+ command: server.command,
139
+ ...(server.args && { args: server.args }),
140
+ ...(server.env && { env: server.env })
141
+ };
142
+ }
143
+ }
144
+ return { mcpServers };
145
+ }
146
+ }
147
+ exports.ClaudeCodeFormat = ClaudeCodeFormat;
148
+ // Windsurf format (uses server-fetch wrapper for HTTP servers)
149
+ class WindsurfFormat {
150
+ constructor() {
151
+ this.name = 'windsurf';
152
+ }
153
+ async transform(servers) {
154
+ const mcpServers = {};
155
+ for (const [key, server] of servers) {
156
+ if (server.url) {
157
+ // HTTP server - wrap with server-fetch
158
+ const provider = await (0, provider_registry_1.getProvider)(key);
159
+ const tokenEnvVar = provider?.id ? `${provider.id.toUpperCase()}_TOKEN` : undefined;
160
+ if (tokenEnvVar && server.headers?.Authorization) {
161
+ const token = server.headers.Authorization.replace('Bearer ', '');
162
+ mcpServers[key] = {
163
+ command: 'npx',
164
+ args: ['-y', '@modelcontextprotocol/server-fetch', server.url],
165
+ env: {
166
+ [tokenEnvVar]: token
167
+ }
168
+ };
169
+ }
170
+ }
171
+ else {
172
+ // stdio server
173
+ mcpServers[key] = {
174
+ command: server.command,
175
+ ...(server.args && { args: server.args }),
176
+ ...(server.env && { env: server.env })
177
+ };
178
+ }
179
+ }
180
+ return { mcpServers };
181
+ }
182
+ }
183
+ exports.WindsurfFormat = WindsurfFormat;
184
+ // Codex format (TOML)
185
+ class CodexFormat {
186
+ constructor() {
187
+ this.name = 'codex';
188
+ }
189
+ transform(servers) {
190
+ const sections = [];
191
+ for (const [key, server] of servers) {
192
+ if (server.url) {
193
+ // HTTP server
194
+ const token = server.headers?.Authorization?.replace('Bearer ', '') || '';
195
+ const escapedToken = this.escapeToml(token);
196
+ const escapedUrl = this.escapeToml(server.url);
197
+ sections.push(`[mcp_servers.${key}]`);
198
+ sections.push(`url = "${escapedUrl}"`);
199
+ sections.push(`http_headers = { Authorization = "Bearer ${escapedToken}" }`);
200
+ sections.push('');
201
+ }
202
+ else {
203
+ // stdio server
204
+ sections.push(`[mcp_servers.${key}]`);
205
+ sections.push(`command = "${this.escapeToml(server.command || '')}"`);
206
+ if (server.args && server.args.length > 0) {
207
+ const argsStr = server.args.map(arg => `"${this.escapeToml(arg)}"`).join(', ');
208
+ sections.push(`args = [${argsStr}]`);
209
+ }
210
+ if (server.env) {
211
+ sections.push('');
212
+ sections.push(`[mcp_servers.${key}.env]`);
213
+ for (const [envKey, envValue] of Object.entries(server.env)) {
214
+ sections.push(`${envKey} = "${this.escapeToml(envValue)}"`);
215
+ }
216
+ }
217
+ sections.push('');
218
+ }
219
+ }
220
+ return sections.join('\n');
221
+ }
222
+ escapeToml(value) {
223
+ return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
224
+ }
225
+ }
226
+ exports.CodexFormat = CodexFormat;
227
+ // Format registry
228
+ exports.IDE_FORMATS = {
229
+ standard: new StandardFormat(),
230
+ kiro: new KiroFormat(),
231
+ vscode: new VSCodeFormat(),
232
+ claude: new ClaudeFormat(),
233
+ 'claude-code': new ClaudeCodeFormat(),
234
+ windsurf: new WindsurfFormat(),
235
+ codex: new CodexFormat()
236
+ };
237
+ function getIDEFormat(configType) {
238
+ const format = exports.IDE_FORMATS[configType];
239
+ if (!format) {
240
+ throw new Error(`Unsupported IDE format: ${configType}`);
241
+ }
242
+ return format;
243
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ // MCP Server Builder - builds logical server structure (format-agnostic)
3
+ // Uses the centralized registry for all server definitions
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.MCPServerBuilder = void 0;
6
+ const mcp_server_registry_1 = require("./mcp-server-registry");
7
+ class MCPServerBuilder {
8
+ constructor() {
9
+ this.servers = new Map();
10
+ }
11
+ addBaseServers(fraimKey) {
12
+ const baseServers = (0, mcp_server_registry_1.buildAllBaseServers)(fraimKey);
13
+ for (const [id, server] of baseServers) {
14
+ this.servers.set(id, server);
15
+ }
16
+ return this;
17
+ }
18
+ async addProvider(providerId, token, config) {
19
+ try {
20
+ const server = await (0, mcp_server_registry_1.buildProviderMCPServer)(providerId, token, config);
21
+ this.servers.set(providerId, server);
22
+ }
23
+ catch (error) {
24
+ // Always warn user when MCP server can't be built
25
+ // Common case: Jira without baseUrl/email config
26
+ const errorMessage = error instanceof Error ? error.message : String(error);
27
+ console.warn(`⚠️ Skipping ${providerId} MCP server: ${errorMessage}`);
28
+ }
29
+ return this;
30
+ }
31
+ // Legacy methods for backward compatibility - delegate to addProvider
32
+ async addGitHub(token) {
33
+ return await this.addProvider('github', token);
34
+ }
35
+ async addGitLab(token) {
36
+ return await this.addProvider('gitlab', token);
37
+ }
38
+ async addJira(token, config) {
39
+ return await this.addProvider('jira', token, config);
40
+ }
41
+ getServers() {
42
+ return new Map(this.servers);
43
+ }
44
+ toObject() {
45
+ return Object.fromEntries(this.servers);
46
+ }
47
+ }
48
+ exports.MCPServerBuilder = MCPServerBuilder;
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ // MCP Server Registry - Builds MCP servers from provider definitions
3
+ // This file NO LONGER contains hardcoded server configurations
4
+ // All provider MCP server configs come from the provider registry (server or local fallback)
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BASE_MCP_SERVERS = void 0;
7
+ exports.buildProviderMCPServer = buildProviderMCPServer;
8
+ exports.getBaseMCPServer = getBaseMCPServer;
9
+ exports.getProviderMCPServerIds = getProviderMCPServerIds;
10
+ exports.getAllMCPServerIds = getAllMCPServerIds;
11
+ exports.isProviderServer = isProviderServer;
12
+ exports.isHTTPServer = isHTTPServer;
13
+ exports.buildAllBaseServers = buildAllBaseServers;
14
+ const provider_registry_1 = require("../providers/provider-registry");
15
+ exports.BASE_MCP_SERVERS = [
16
+ {
17
+ id: 'git',
18
+ name: 'Git',
19
+ description: 'Git repository operations (commit, branch, merge, etc.)',
20
+ buildServer: () => ({
21
+ command: 'npx',
22
+ args: ['-y', '@cyanheads/git-mcp-server']
23
+ })
24
+ },
25
+ {
26
+ id: 'playwright',
27
+ name: 'Playwright',
28
+ description: 'Browser automation and testing',
29
+ buildServer: () => ({
30
+ command: 'npx',
31
+ args: ['-y', '@playwright/mcp']
32
+ })
33
+ },
34
+ {
35
+ id: 'fraim',
36
+ name: 'FRAIM',
37
+ description: 'FRAIM workflow orchestration and mentoring',
38
+ buildServer: (fraimKey) => ({
39
+ command: 'fraim-mcp',
40
+ env: {
41
+ FRAIM_API_KEY: fraimKey,
42
+ FRAIM_REMOTE_URL: 'https://fraim.wellnessatwork.me'
43
+ }
44
+ })
45
+ }
46
+ ];
47
+ // ============================================================================
48
+ // PROVIDER MCP SERVER BUILDER (uses provider registry)
49
+ // ============================================================================
50
+ /**
51
+ * Build an MCP server for a provider using its definition from the registry
52
+ */
53
+ async function buildProviderMCPServer(providerId, token, config) {
54
+ // Get provider definition from registry (server or local fallback)
55
+ const provider = await (0, provider_registry_1.getProvider)(providerId);
56
+ if (!provider) {
57
+ throw new Error(`Unknown provider: ${providerId}`);
58
+ }
59
+ if (!provider.mcpServer) {
60
+ throw new Error(`Provider ${providerId} does not have an MCP server configuration`);
61
+ }
62
+ const mcpConfig = provider.mcpServer;
63
+ // Validate config if provider requires additional config
64
+ if (provider.hasAdditionalConfig) {
65
+ const validation = await (0, provider_registry_1.validateProviderConfig)(providerId, config || {});
66
+ if (!validation.valid) {
67
+ throw new Error(`${provider.displayName} requires additional configuration: ${validation.missing.join(', ')}`);
68
+ }
69
+ }
70
+ // Build MCP server based on type
71
+ if (mcpConfig.type === 'http') {
72
+ return buildHTTPServer(mcpConfig, token);
73
+ }
74
+ else {
75
+ return buildStdioServer(mcpConfig, token, config);
76
+ }
77
+ }
78
+ /**
79
+ * Build an HTTP MCP server
80
+ */
81
+ function buildHTTPServer(mcpConfig, token) {
82
+ if (!mcpConfig.url) {
83
+ throw new Error('HTTP MCP server requires url');
84
+ }
85
+ const authHeader = mcpConfig.authHeaderTemplate?.replace('{token}', token) || `Bearer ${token}`;
86
+ return {
87
+ url: mcpConfig.url,
88
+ headers: {
89
+ Authorization: authHeader
90
+ }
91
+ };
92
+ }
93
+ /**
94
+ * Build a stdio MCP server
95
+ */
96
+ function buildStdioServer(mcpConfig, token, config) {
97
+ if (!mcpConfig.command) {
98
+ throw new Error('Stdio MCP server requires command');
99
+ }
100
+ // Build environment variables from template
101
+ const env = {};
102
+ if (mcpConfig.envTemplate) {
103
+ for (const [key, template] of Object.entries(mcpConfig.envTemplate)) {
104
+ let value = template;
105
+ // Replace {token} placeholder
106
+ value = value.replace('{token}', token);
107
+ // Replace {config.key} placeholders
108
+ if (config) {
109
+ for (const [configKey, configValue] of Object.entries(config)) {
110
+ value = value.replace(`{config.${configKey}}`, String(configValue));
111
+ }
112
+ }
113
+ // Handle URL normalization for Jira
114
+ if (key === 'JIRA_URL' && value && !value.startsWith('http')) {
115
+ value = `https://${value}`;
116
+ }
117
+ env[key] = value;
118
+ }
119
+ }
120
+ return {
121
+ command: mcpConfig.command,
122
+ args: mcpConfig.args || [],
123
+ env
124
+ };
125
+ }
126
+ // ============================================================================
127
+ // REGISTRY LOOKUP FUNCTIONS
128
+ // ============================================================================
129
+ function getBaseMCPServer(id) {
130
+ return exports.BASE_MCP_SERVERS.find(server => server.id === id);
131
+ }
132
+ async function getProviderMCPServerIds() {
133
+ // This would need to fetch all providers and filter those with MCP servers
134
+ // For now, return empty array - this function is not critical
135
+ return [];
136
+ }
137
+ function getAllMCPServerIds() {
138
+ // Return only base server IDs
139
+ // Provider server IDs are dynamic and come from the registry
140
+ return exports.BASE_MCP_SERVERS.map(s => s.id);
141
+ }
142
+ async function isProviderServer(serverId) {
143
+ const provider = await (0, provider_registry_1.getProvider)(serverId);
144
+ return provider !== undefined && provider.mcpServer !== undefined;
145
+ }
146
+ async function isHTTPServer(serverId) {
147
+ const provider = await (0, provider_registry_1.getProvider)(serverId);
148
+ return provider?.mcpServer?.type === 'http';
149
+ }
150
+ // ============================================================================
151
+ // BUILDER HELPERS
152
+ // ============================================================================
153
+ function buildAllBaseServers(fraimKey) {
154
+ const servers = new Map();
155
+ for (const def of exports.BASE_MCP_SERVERS) {
156
+ servers.set(def.id, def.buildServer(fraimKey));
157
+ }
158
+ return servers;
159
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ // Shared types for MCP configuration
3
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ // Local provider registry - fallback when server is unavailable
3
+ // This is the original provider metadata that was in provider-registry.ts
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.getLocalProvider = getLocalProvider;
6
+ exports.getAllLocalProviders = getAllLocalProviders;
7
+ exports.getAllLocalProviderIds = getAllLocalProviderIds;
8
+ exports.isValidLocalProviderId = isValidLocalProviderId;
9
+ exports.getLocalProviderDisplayName = getLocalProviderDisplayName;
10
+ exports.getLocalProviderSetupInstructions = getLocalProviderSetupInstructions;
11
+ exports.getLocalProviderConfigRequirements = getLocalProviderConfigRequirements;
12
+ exports.localRequiresAdditionalConfig = localRequiresAdditionalConfig;
13
+ exports.validateLocalProviderConfig = validateLocalProviderConfig;
14
+ exports.getLocalProvidersWithCapability = getLocalProvidersWithCapability;
15
+ exports.getLocalProviderIdsWithCapability = getLocalProviderIdsWithCapability;
16
+ exports.localProviderHasCapability = localProviderHasCapability;
17
+ // Local provider definitions (fallback data)
18
+ const LOCAL_PROVIDERS = [
19
+ {
20
+ id: 'github',
21
+ displayName: 'GitHub',
22
+ description: 'GitHub repository and issue management',
23
+ capabilities: ['code', 'issues', 'integrated'],
24
+ docsUrl: 'https://docs.github.com',
25
+ setupInstructions: 'Create a Personal Access Token at https://github.com/settings/tokens',
26
+ hasAdditionalConfig: false,
27
+ mcpServer: {
28
+ type: 'http',
29
+ url: 'https://api.githubcopilot.com/mcp/',
30
+ authHeaderTemplate: 'Bearer {token}'
31
+ }
32
+ },
33
+ {
34
+ id: 'gitlab',
35
+ displayName: 'GitLab',
36
+ description: 'GitLab repository and issue management',
37
+ capabilities: ['code', 'issues', 'integrated'],
38
+ docsUrl: 'https://docs.gitlab.com',
39
+ setupInstructions: 'Create a Personal Access Token in your GitLab settings',
40
+ hasAdditionalConfig: false,
41
+ mcpServer: {
42
+ type: 'http',
43
+ url: 'https://gitlab.com/api/v4/mcp',
44
+ authHeaderTemplate: 'Bearer {token}'
45
+ }
46
+ },
47
+ {
48
+ id: 'ado',
49
+ displayName: 'Azure DevOps',
50
+ description: 'Azure DevOps repository and issue management',
51
+ capabilities: ['code', 'issues', 'integrated'],
52
+ docsUrl: 'https://docs.microsoft.com/azure/devops',
53
+ setupInstructions: 'Create a Personal Access Token in Azure DevOps',
54
+ hasAdditionalConfig: false
55
+ },
56
+ {
57
+ id: 'jira',
58
+ displayName: 'Jira',
59
+ description: 'Jira issue tracking and project management',
60
+ capabilities: ['issues'],
61
+ docsUrl: 'https://support.atlassian.com/jira',
62
+ setupInstructions: 'Create an API token at https://id.atlassian.com/manage-profile/security/api-tokens',
63
+ hasAdditionalConfig: true,
64
+ mcpServer: {
65
+ type: 'stdio',
66
+ command: 'uvx',
67
+ args: ['mcp-atlassian'],
68
+ envTemplate: {
69
+ JIRA_URL: '{config.baseUrl}',
70
+ JIRA_USERNAME: '{config.email}',
71
+ JIRA_API_TOKEN: '{token}'
72
+ }
73
+ }
74
+ }
75
+ ];
76
+ const JIRA_CONFIG_REQUIREMENTS = [
77
+ {
78
+ key: 'baseUrl',
79
+ displayName: 'Jira Instance URL',
80
+ description: 'Your Jira instance URL (e.g., mycompany.atlassian.net)',
81
+ required: true,
82
+ type: 'url',
83
+ cliOptionName: 'url'
84
+ },
85
+ {
86
+ key: 'email',
87
+ displayName: 'Email Address',
88
+ description: 'Your Jira account email address',
89
+ required: true,
90
+ type: 'email'
91
+ }
92
+ ];
93
+ function getLocalProvider(id) {
94
+ return LOCAL_PROVIDERS.find(p => p.id === id);
95
+ }
96
+ function getAllLocalProviders() {
97
+ return [...LOCAL_PROVIDERS];
98
+ }
99
+ function getAllLocalProviderIds() {
100
+ return LOCAL_PROVIDERS.map(p => p.id);
101
+ }
102
+ function isValidLocalProviderId(id) {
103
+ return LOCAL_PROVIDERS.some(p => p.id === id);
104
+ }
105
+ function getLocalProviderDisplayName(providerId) {
106
+ const provider = getLocalProvider(providerId);
107
+ return provider?.displayName || providerId;
108
+ }
109
+ function getLocalProviderSetupInstructions(providerId) {
110
+ const provider = getLocalProvider(providerId);
111
+ return provider?.setupInstructions || '';
112
+ }
113
+ function getLocalProviderConfigRequirements(providerId) {
114
+ if (providerId === 'jira') {
115
+ return JIRA_CONFIG_REQUIREMENTS;
116
+ }
117
+ return [];
118
+ }
119
+ function localRequiresAdditionalConfig(providerId) {
120
+ return getLocalProviderConfigRequirements(providerId).length > 0;
121
+ }
122
+ function validateLocalProviderConfig(providerId, config) {
123
+ const requirements = getLocalProviderConfigRequirements(providerId);
124
+ const missing = [];
125
+ for (const req of requirements) {
126
+ if (req.required && !config[req.key]) {
127
+ missing.push(req.key);
128
+ }
129
+ }
130
+ return {
131
+ valid: missing.length === 0,
132
+ missing
133
+ };
134
+ }
135
+ function getLocalProvidersWithCapability(capability) {
136
+ return LOCAL_PROVIDERS.filter(provider => provider.capabilities.includes(capability));
137
+ }
138
+ function getLocalProviderIdsWithCapability(capability) {
139
+ const providers = getLocalProvidersWithCapability(capability);
140
+ return providers.map(p => p.id);
141
+ }
142
+ function localProviderHasCapability(providerId, capability) {
143
+ const provider = getLocalProvider(providerId);
144
+ return provider ? provider.capabilities.includes(capability) : false;
145
+ }