@majkapp/majk-chat-mcp 1.0.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.
@@ -0,0 +1,24 @@
1
+ import { ToolRegistry } from '@majkapp/majk-chat-core/dist/tools/tool.interface';
2
+ import { MCPPluginOptions } from './types/config';
3
+ import { ToolFilter } from './tools/tool-filter';
4
+ import { MCPPermissionHandler } from './tools/permission-handler';
5
+ export declare class MCPPlugin {
6
+ private options;
7
+ private mcpClient;
8
+ private toolFilter;
9
+ private permissionHandler;
10
+ private registry;
11
+ private registeredTools;
12
+ constructor(options?: MCPPluginOptions);
13
+ initialize(registry: ToolRegistry): Promise<void>;
14
+ private registerDynamicServer;
15
+ private connectServer;
16
+ private discoverAndRegisterTools;
17
+ shutdown(): Promise<void>;
18
+ getRegisteredTools(): string[];
19
+ getToolFilter(): ToolFilter;
20
+ getPermissionHandler(): MCPPermissionHandler;
21
+ addServer(serverName: string, serverConfig: any): Promise<void>;
22
+ removeServer(serverName: string): Promise<void>;
23
+ }
24
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAgB,MAAM,mDAAmD,CAAC;AAG/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,qBAAa,SAAS;IAOR,OAAO,CAAC,OAAO;IAN3B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,eAAe,CAAwC;gBAE3C,OAAO,GAAE,gBAAqB;IAa5C,UAAU,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;YAwBzC,qBAAqB;YA2CrB,aAAa;YAMb,wBAAwB;IAoEhC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAW/B,kBAAkB,IAAI,MAAM,EAAE;IAI9B,aAAa,IAAI,UAAU;IAI3B,oBAAoB,IAAI,oBAAoB;IAItC,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/D,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAatD"}
package/dist/plugin.js ADDED
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MCPPlugin = void 0;
4
+ const mcp_client_1 = require("./client/mcp-client");
5
+ const parser_1 = require("./config/parser");
6
+ const mcp_tool_executor_1 = require("./tools/mcp-tool-executor");
7
+ const dynamic_executor_1 = require("./tools/dynamic-executor");
8
+ const tool_filter_1 = require("./tools/tool-filter");
9
+ const permission_handler_1 = require("./tools/permission-handler");
10
+ class MCPPlugin {
11
+ constructor(options = {}) {
12
+ this.options = options;
13
+ this.registry = null;
14
+ this.registeredTools = new Map();
15
+ this.mcpClient = new mcp_client_1.MCPClient(options.quiet || false);
16
+ this.toolFilter = new tool_filter_1.ToolFilter(options.allowedTools, options.disallowedTools);
17
+ this.permissionHandler = new permission_handler_1.MCPPermissionHandler(this.mcpClient, options.permissionPromptTool, options.quiet || false);
18
+ }
19
+ async initialize(registry) {
20
+ this.registry = registry;
21
+ const config = parser_1.MCPConfigParser.parseConfig(this.options);
22
+ for (const [serverName, serverConfig] of Object.entries(config.mcpServers)) {
23
+ try {
24
+ parser_1.MCPConfigParser.validateServerConfig(serverName, serverConfig);
25
+ if (parser_1.MCPConfigParser.isDynamicServer(serverConfig)) {
26
+ // Handle dynamic server directly
27
+ await this.registerDynamicServer(serverName, serverConfig);
28
+ }
29
+ else {
30
+ // Handle traditional MCP server
31
+ await this.connectServer(serverName, serverConfig);
32
+ }
33
+ }
34
+ catch (error) {
35
+ if (!this.options.quiet) {
36
+ console.error(`Failed to setup MCP server "${serverName}":`, error);
37
+ }
38
+ }
39
+ }
40
+ }
41
+ async registerDynamicServer(serverName, config) {
42
+ for (const command of config.commands) {
43
+ const executor = new dynamic_executor_1.DynamicCommandExecutor(serverName, command);
44
+ if (this.toolFilter.isAllowed(executor.name)) {
45
+ if (this.options.permissionPromptTool) {
46
+ const originalExecute = executor.execute.bind(executor);
47
+ executor.execute = async (args, context) => {
48
+ const permissionResult = await this.permissionHandler.requestPermissionWithUpdate(executor.name, args, context);
49
+ if (!permissionResult.allowed) {
50
+ return {
51
+ success: false,
52
+ error: `Permission denied for tool: ${executor.name}`
53
+ };
54
+ }
55
+ // Use updated input if provided by permission handler
56
+ const finalArgs = permissionResult.updatedInput !== undefined
57
+ ? permissionResult.updatedInput
58
+ : args;
59
+ return originalExecute(finalArgs, context);
60
+ };
61
+ }
62
+ this.registry?.register(executor);
63
+ this.registeredTools.set(executor.name, executor);
64
+ if (!this.options.quiet) {
65
+ console.log(`Registered dynamic MCP tool: ${executor.name}`);
66
+ }
67
+ }
68
+ else {
69
+ if (!this.options.quiet) {
70
+ console.log(`Filtered out dynamic MCP tool: ${executor.name}`);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ async connectServer(serverName, serverConfig) {
76
+ const connection = await this.mcpClient.connect(serverName, serverConfig);
77
+ await this.discoverAndRegisterTools(connection.serverName);
78
+ }
79
+ async discoverAndRegisterTools(serverName) {
80
+ const connection = this.mcpClient.getConnection(serverName);
81
+ if (!connection) {
82
+ throw new Error(`No connection found for server: ${serverName}`);
83
+ }
84
+ try {
85
+ const toolsResponse = await connection.client.listTools();
86
+ if (!toolsResponse.tools || !Array.isArray(toolsResponse.tools)) {
87
+ if (!this.options.quiet) {
88
+ console.warn(`No tools found for MCP server "${serverName}"`);
89
+ }
90
+ return;
91
+ }
92
+ for (const tool of toolsResponse.tools) {
93
+ const executor = new mcp_tool_executor_1.MCPToolExecutor(serverName, tool.name, tool, connection);
94
+ if (this.toolFilter.isAllowed(executor.name)) {
95
+ if (this.options.permissionPromptTool) {
96
+ const originalExecute = executor.execute.bind(executor);
97
+ executor.execute = async (args, context) => {
98
+ const permissionResult = await this.permissionHandler.requestPermissionWithUpdate(executor.name, args, context);
99
+ if (!permissionResult.allowed) {
100
+ return {
101
+ success: false,
102
+ error: `Permission denied for tool: ${executor.name}`
103
+ };
104
+ }
105
+ // Use updated input if provided by permission handler
106
+ const finalArgs = permissionResult.updatedInput !== undefined
107
+ ? permissionResult.updatedInput
108
+ : args;
109
+ return originalExecute(finalArgs, context);
110
+ };
111
+ }
112
+ this.registry?.register(executor);
113
+ this.registeredTools.set(executor.name, executor);
114
+ if (!this.options.quiet) {
115
+ console.log(`Registered MCP tool: ${executor.name}`);
116
+ }
117
+ }
118
+ else {
119
+ if (!this.options.quiet) {
120
+ console.log(`Filtered out MCP tool: ${executor.name}`);
121
+ }
122
+ }
123
+ }
124
+ }
125
+ catch (error) {
126
+ if (!this.options.quiet) {
127
+ console.error(`Failed to discover tools from server "${serverName}":`, error);
128
+ }
129
+ }
130
+ }
131
+ async shutdown() {
132
+ for (const toolName of this.registeredTools.keys()) {
133
+ if (!this.options.quiet) {
134
+ console.log(`Unregistering MCP tool: ${toolName}`);
135
+ }
136
+ }
137
+ this.registeredTools.clear();
138
+ await this.mcpClient.disconnectAll();
139
+ }
140
+ getRegisteredTools() {
141
+ return Array.from(this.registeredTools.keys());
142
+ }
143
+ getToolFilter() {
144
+ return this.toolFilter;
145
+ }
146
+ getPermissionHandler() {
147
+ return this.permissionHandler;
148
+ }
149
+ async addServer(serverName, serverConfig) {
150
+ parser_1.MCPConfigParser.validateServerConfig(serverName, serverConfig);
151
+ await this.connectServer(serverName, serverConfig);
152
+ }
153
+ async removeServer(serverName) {
154
+ const toolsToRemove = Array.from(this.registeredTools.entries())
155
+ .filter(([name]) => name.startsWith(`mcp__${serverName}__`));
156
+ for (const [toolName] of toolsToRemove) {
157
+ this.registeredTools.delete(toolName);
158
+ if (!this.options.quiet) {
159
+ console.log(`Unregistered MCP tool: ${toolName}`);
160
+ }
161
+ }
162
+ await this.mcpClient.disconnect(serverName);
163
+ }
164
+ }
165
+ exports.MCPPlugin = MCPPlugin;
@@ -0,0 +1,32 @@
1
+ import { ToolExecutor, ToolDefinition, ToolResult } from '@majkapp/majk-chat-core/dist/tools/tool.interface';
2
+ import { RequestContext } from '@majkapp/majk-chat-core/dist/types/requests';
3
+ import { DynamicCommand } from '../types/config';
4
+ export declare class DynamicCommandExecutor implements ToolExecutor {
5
+ readonly name: string;
6
+ readonly definition: ToolDefinition;
7
+ private command;
8
+ constructor(serverName: string, command: DynamicCommand);
9
+ execute(args: any, context: RequestContext): Promise<ToolResult>;
10
+ validateArgs(args: any): boolean;
11
+ /**
12
+ * Resolve template variables in strings using {{variable}} syntax
13
+ * Supports conditionals: {{#if variable}}text{{/if}}
14
+ * Supports loops: {{#each array}}{{this}}{{/each}}
15
+ */
16
+ private resolveTemplate;
17
+ /**
18
+ * Resolve environment variables, supporting $VAR syntax
19
+ */
20
+ private resolveEnv;
21
+ /**
22
+ * Resolve file paths, expanding ~ to home directory
23
+ */
24
+ private resolvePath;
25
+ /**
26
+ * Execute command and return result
27
+ */
28
+ private executeCommand;
29
+ private inferSideEffects;
30
+ private shouldRequireConfirmation;
31
+ }
32
+ //# sourceMappingURL=dynamic-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamic-executor.d.ts","sourceRoot":"","sources":["../../src/tools/dynamic-executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mDAAmD,CAAC;AAC7G,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKjD,qBAAa,sBAAuB,YAAW,YAAY;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,OAAO,CAAC,OAAO,CAAiB;gBAEpB,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;IAiBjD,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IAmEtE,YAAY,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO;IAYhC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IA2CvB;;OAEG;IACH,OAAO,CAAC,UAAU;IAoBlB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,cAAc;IA4CtB,OAAO,CAAC,gBAAgB;IA6BxB,OAAO,CAAC,yBAAyB;CAIlC"}
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DynamicCommandExecutor = void 0;
37
+ const child_process_1 = require("child_process");
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ class DynamicCommandExecutor {
41
+ constructor(serverName, command) {
42
+ this.name = `mcp__${serverName}__${command.name}`;
43
+ this.command = command;
44
+ this.definition = {
45
+ type: 'function',
46
+ function: {
47
+ name: this.name,
48
+ description: command.description,
49
+ parameters: command.parameters
50
+ },
51
+ serverInvocable: true,
52
+ sideEffects: this.inferSideEffects(command),
53
+ requiresConfirmation: this.shouldRequireConfirmation(command)
54
+ };
55
+ }
56
+ async execute(args, context) {
57
+ try {
58
+ // Resolve template variables in command path and args
59
+ const resolvedPath = this.resolveTemplate(this.command.exec.path, args);
60
+ const resolvedArgs = this.command.exec.args.map(arg => this.resolveTemplate(arg, args)).filter(arg => arg.length > 0); // Remove empty args from conditionals
61
+ // Prepare environment
62
+ const env = {
63
+ ...process.env,
64
+ ...this.resolveEnv(this.command.exec.env || {}, args)
65
+ };
66
+ // Resolve working directory
67
+ const cwd = this.command.exec.cwd
68
+ ? this.resolvePath(this.command.exec.cwd)
69
+ : process.cwd();
70
+ const timeout = this.command.exec.timeoutMs || 30000;
71
+ const expectFormat = this.command.exec.expect || 'text';
72
+ // Execute command
73
+ const result = await this.executeCommand(resolvedPath, resolvedArgs, { env, cwd, timeout });
74
+ // Parse result based on expected format
75
+ let output;
76
+ if (expectFormat === 'json') {
77
+ try {
78
+ output = JSON.parse(result.stdout);
79
+ }
80
+ catch (e) {
81
+ return {
82
+ success: false,
83
+ error: `Failed to parse JSON output: ${e}. Raw output: ${result.stdout}`
84
+ };
85
+ }
86
+ }
87
+ else {
88
+ output = result.stdout;
89
+ }
90
+ // Check for errors
91
+ if (result.code !== 0) {
92
+ return {
93
+ success: false,
94
+ error: `Command failed with exit code ${result.code}: ${result.stderr}`
95
+ };
96
+ }
97
+ return {
98
+ success: true,
99
+ output,
100
+ metadata: {
101
+ command: resolvedPath,
102
+ args: resolvedArgs,
103
+ exitCode: result.code,
104
+ stderr: result.stderr
105
+ }
106
+ };
107
+ }
108
+ catch (error) {
109
+ return {
110
+ success: false,
111
+ error: error instanceof Error ? error.message : String(error)
112
+ };
113
+ }
114
+ }
115
+ validateArgs(args) {
116
+ const schema = this.command.parameters;
117
+ if (schema.required) {
118
+ for (const requiredField of schema.required) {
119
+ if (!(requiredField in args)) {
120
+ return false;
121
+ }
122
+ }
123
+ }
124
+ return true;
125
+ }
126
+ /**
127
+ * Resolve template variables in strings using {{variable}} syntax
128
+ * Supports conditionals: {{#if variable}}text{{/if}}
129
+ * Supports loops: {{#each array}}{{this}}{{/each}}
130
+ */
131
+ resolveTemplate(template, args) {
132
+ let result = template;
133
+ let prevResult = '';
134
+ // Process templates recursively until no more changes occur (handles nested templates)
135
+ while (result !== prevResult) {
136
+ prevResult = result;
137
+ // Handle conditionals: {{#if variable}}text{{/if}}
138
+ result = result.replace(/\{\{#if\s+(\w+)\}\}(.*?)\{\{\/if\}\}/g, (match, variable, content) => {
139
+ return args[variable] ? content : '';
140
+ });
141
+ // Handle each loops: {{#each array}}{{this}}{{/each}}
142
+ result = result.replace(/\{\{#each\s+(\w+)\}\}(.*?)\{\{\/each\}\}/g, (match, variable, content) => {
143
+ const array = args[variable];
144
+ if (Array.isArray(array)) {
145
+ return array.map(item => content.replace(/\{\{this\}\}/g, String(item))).join(' ');
146
+ }
147
+ return '';
148
+ });
149
+ // Handle simple variables: {{variable}} (including nested properties like config.debug)
150
+ result = result.replace(/\{\{([\w.]+)\}\}/g, (match, variable) => {
151
+ // Handle nested properties
152
+ if (variable.includes('.')) {
153
+ return ''; // Don't resolve nested properties as per test expectation
154
+ }
155
+ return args[variable] !== undefined ? String(args[variable]) : '';
156
+ });
157
+ // Handle environment variables: $VAR
158
+ result = result.replace(/\$(\w+)/g, (match, variable) => {
159
+ return process.env[variable] || '';
160
+ });
161
+ }
162
+ // Clean up multiple consecutive spaces but preserve other characters
163
+ result = result.replace(/ {2,}/g, ' ');
164
+ return result;
165
+ }
166
+ /**
167
+ * Resolve environment variables, supporting $VAR syntax
168
+ */
169
+ resolveEnv(envConfig, args) {
170
+ const resolved = {};
171
+ for (const [key, value] of Object.entries(envConfig)) {
172
+ let resolvedValue = value;
173
+ // Replace $VAR with process.env.VAR
174
+ resolvedValue = resolvedValue.replace(/\$(\w+)/g, (match, varName) => {
175
+ return process.env[varName] || '';
176
+ });
177
+ // Replace template variables
178
+ resolvedValue = this.resolveTemplate(resolvedValue, args);
179
+ resolved[key] = resolvedValue;
180
+ }
181
+ return resolved;
182
+ }
183
+ /**
184
+ * Resolve file paths, expanding ~ to home directory
185
+ */
186
+ resolvePath(inputPath) {
187
+ if (inputPath.startsWith('~')) {
188
+ return path.join(os.homedir(), inputPath.slice(1));
189
+ }
190
+ return path.resolve(inputPath);
191
+ }
192
+ /**
193
+ * Execute command and return result
194
+ */
195
+ executeCommand(command, args, options) {
196
+ return new Promise((resolve, reject) => {
197
+ const child = (0, child_process_1.spawn)(command, args, {
198
+ env: options.env,
199
+ cwd: options.cwd,
200
+ stdio: ['pipe', 'pipe', 'pipe']
201
+ });
202
+ let stdout = '';
203
+ let stderr = '';
204
+ child.stdout?.on('data', (data) => {
205
+ stdout += data.toString();
206
+ });
207
+ child.stderr?.on('data', (data) => {
208
+ stderr += data.toString();
209
+ });
210
+ const timeout = setTimeout(() => {
211
+ child.kill('SIGKILL');
212
+ reject(new Error(`Command timed out after ${options.timeout}ms`));
213
+ }, options.timeout);
214
+ child.on('close', (code) => {
215
+ clearTimeout(timeout);
216
+ resolve({
217
+ code: code || 0,
218
+ stdout: stdout.trim(),
219
+ stderr: stderr.trim()
220
+ });
221
+ });
222
+ child.on('error', (error) => {
223
+ clearTimeout(timeout);
224
+ reject(error);
225
+ });
226
+ });
227
+ }
228
+ inferSideEffects(command) {
229
+ const name = command.name.toLowerCase();
230
+ const description = command.description.toLowerCase();
231
+ const path = command.exec.path.toLowerCase();
232
+ // Check for external operations first (network calls, APIs)
233
+ if (path.includes('curl') || path.includes('wget') || path.includes('http') ||
234
+ name.includes('api') || description.includes('api') || description.includes('http') ||
235
+ description.includes('network') || description.includes('download')) {
236
+ return 'external';
237
+ }
238
+ if (name.includes('write') || name.includes('create') ||
239
+ name.includes('update') || name.includes('delete') ||
240
+ description.includes('write') || description.includes('create') ||
241
+ description.includes('update') || description.includes('delete')) {
242
+ return 'write';
243
+ }
244
+ if (name.includes('read') || name.includes('get') ||
245
+ name.includes('list') || name.includes('fetch') ||
246
+ description.includes('read') || description.includes('get') ||
247
+ description.includes('list') || description.includes('fetch')) {
248
+ return 'read';
249
+ }
250
+ return 'external'; // Dynamic commands are typically external
251
+ }
252
+ shouldRequireConfirmation(command) {
253
+ const sideEffects = this.inferSideEffects(command);
254
+ return sideEffects === 'write' || sideEffects === 'external';
255
+ }
256
+ }
257
+ exports.DynamicCommandExecutor = DynamicCommandExecutor;
@@ -0,0 +1,16 @@
1
+ import { ToolExecutor, ToolDefinition, ToolResult } from '@majkapp/majk-chat-core/dist/tools/tool.interface';
2
+ import { RequestContext } from '@majkapp/majk-chat-core/dist/types/requests';
3
+ import { MCPConnection } from '../client/mcp-client';
4
+ export declare class MCPToolExecutor implements ToolExecutor {
5
+ readonly name: string;
6
+ readonly definition: ToolDefinition;
7
+ private connection;
8
+ private originalToolName;
9
+ private inputSchema;
10
+ constructor(serverName: string, toolName: string, definition: any, connection: MCPConnection);
11
+ execute(args: any, context: RequestContext): Promise<ToolResult>;
12
+ validateArgs(args: any): boolean;
13
+ private inferSideEffects;
14
+ private shouldRequireConfirmation;
15
+ }
16
+ //# sourceMappingURL=mcp-tool-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-tool-executor.d.ts","sourceRoot":"","sources":["../../src/tools/mcp-tool-executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mDAAmD,CAAC;AAC7G,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,qBAAa,eAAgB,YAAW,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,WAAW,CAAM;gBAGvB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,GAAG,EACf,UAAU,EAAE,aAAa;IAoBrB,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA8BtE,YAAY,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO;IAiBhC,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,yBAAyB;CAIlC"}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MCPToolExecutor = void 0;
4
+ const parser_1 = require("../config/parser");
5
+ class MCPToolExecutor {
6
+ constructor(serverName, toolName, definition, connection) {
7
+ this.originalToolName = toolName;
8
+ this.name = parser_1.MCPConfigParser.formatToolName(serverName, toolName);
9
+ this.connection = connection;
10
+ this.inputSchema = definition.inputSchema || definition.parameters || {};
11
+ this.definition = {
12
+ type: 'function',
13
+ function: {
14
+ name: this.name,
15
+ description: definition.description || '',
16
+ parameters: this.inputSchema
17
+ },
18
+ serverInvocable: true,
19
+ sideEffects: this.inferSideEffects(definition),
20
+ requiresConfirmation: this.shouldRequireConfirmation(definition)
21
+ };
22
+ }
23
+ async execute(args, context) {
24
+ try {
25
+ const result = await this.connection.client.callTool({
26
+ name: this.originalToolName,
27
+ arguments: args
28
+ });
29
+ if (result.isError) {
30
+ return {
31
+ success: false,
32
+ error: result.text || 'Tool execution failed'
33
+ };
34
+ }
35
+ return {
36
+ success: true,
37
+ output: result.content,
38
+ metadata: {
39
+ serverName: this.connection.serverName,
40
+ originalToolName: this.originalToolName
41
+ }
42
+ };
43
+ }
44
+ catch (error) {
45
+ return {
46
+ success: false,
47
+ error: error instanceof Error ? error.message : String(error)
48
+ };
49
+ }
50
+ }
51
+ validateArgs(args) {
52
+ const schema = this.inputSchema;
53
+ if (!schema || typeof schema !== 'object') {
54
+ return true;
55
+ }
56
+ if (schema.type === 'object' && schema.required) {
57
+ for (const requiredField of schema.required) {
58
+ if (!(requiredField in args)) {
59
+ return false;
60
+ }
61
+ }
62
+ }
63
+ return true;
64
+ }
65
+ inferSideEffects(definition) {
66
+ const name = definition.name?.toLowerCase() || '';
67
+ const description = definition.description?.toLowerCase() || '';
68
+ if (name.includes('write') || name.includes('create') ||
69
+ name.includes('update') || name.includes('delete') ||
70
+ description.includes('write') || description.includes('create') ||
71
+ description.includes('update') || description.includes('delete')) {
72
+ return 'write';
73
+ }
74
+ if (name.includes('read') || name.includes('get') ||
75
+ name.includes('list') || name.includes('fetch') ||
76
+ description.includes('read') || description.includes('get') ||
77
+ description.includes('list') || description.includes('fetch')) {
78
+ return 'read';
79
+ }
80
+ if (name.includes('http') || name.includes('api') ||
81
+ name.includes('request') || name.includes('call') ||
82
+ description.includes('http') || description.includes('api') ||
83
+ description.includes('request') || description.includes('external')) {
84
+ return 'external';
85
+ }
86
+ return 'none';
87
+ }
88
+ shouldRequireConfirmation(definition) {
89
+ const sideEffects = this.inferSideEffects(definition);
90
+ return sideEffects === 'write' || sideEffects === 'external';
91
+ }
92
+ }
93
+ exports.MCPToolExecutor = MCPToolExecutor;
@@ -0,0 +1,18 @@
1
+ import { PermissionHandler } from '@majkapp/majk-chat-core/dist/tools/tool.interface';
2
+ import { RequestContext } from '@majkapp/majk-chat-core/dist/types/requests';
3
+ import { MCPClient } from '../client/mcp-client';
4
+ export interface PermissionResult {
5
+ allowed: boolean;
6
+ updatedInput?: any;
7
+ }
8
+ export declare class MCPPermissionHandler implements PermissionHandler {
9
+ private quiet;
10
+ private mcpClient;
11
+ private permissionTool;
12
+ constructor(mcpClient: MCPClient, permissionToolName?: string, quiet?: boolean);
13
+ requestPermission(toolName: string, args: any, context: RequestContext): Promise<boolean>;
14
+ requestPermissionWithUpdate(toolName: string, args: any, context: RequestContext): Promise<PermissionResult>;
15
+ setPermissionTool(toolName: string): void;
16
+ getPermissionTool(): string | null;
17
+ }
18
+ //# sourceMappingURL=permission-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-handler.d.ts","sourceRoot":"","sources":["../../src/tools/permission-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mDAAmD,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAiB,MAAM,sBAAsB,CAAC;AAIhE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,GAAG,CAAC;CACpB;AAED,qBAAa,oBAAqB,YAAW,iBAAiB;IAIG,OAAO,CAAC,KAAK;IAH5E,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,cAAc,CAAqC;gBAE/C,SAAS,EAAE,SAAS,EAAE,kBAAkB,CAAC,EAAE,MAAM,EAAU,KAAK,GAAE,OAAe;IAWvF,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,GAAG,EACT,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC;IAKb,2BAA2B,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,GAAG,EACT,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,gBAAgB,CAAC;IAmE5B,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOzC,iBAAiB,IAAI,MAAM,GAAG,IAAI;CAGnC"}