Skip to content

Commit 5cf445d

Browse files
committed
Merge branch 'mcp' into deploy_mcp
2 parents 35490d1 + 89e2913 commit 5cf445d

File tree

16 files changed

+2286
-73
lines changed

16 files changed

+2286
-73
lines changed
Lines changed: 397 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,397 @@
1+
import { NightwatchBrowser } from 'nightwatch'
2+
import init from '../../helpers/init'
3+
4+
const testContract = `
5+
// SPDX-License-Identifier: MIT
6+
pragma solidity ^0.8.0;
7+
8+
contract RemixMCPServerTest {
9+
uint256 public testValue;
10+
string public testString;
11+
12+
constructor(uint256 _value, string memory _str) {
13+
testValue = _value;
14+
testString = _str;
15+
}
16+
17+
function updateValue(uint256 _newValue) public {
18+
testValue = _newValue;
19+
}
20+
21+
function updateString(string memory _newString) public {
22+
testString = _newString;
23+
}
24+
}
25+
`;
26+
27+
module.exports = {
28+
'@disabled': false,
29+
before: function (browser: NightwatchBrowser, done: VoidFunction) {
30+
init(browser, done)
31+
},
32+
33+
'Should verify RemixMCPServer initialization': function (browser: NightwatchBrowser) {
34+
browser
35+
.waitForElementVisible('*[data-id="verticalIconsKindfilePanel"]')
36+
.click('*[data-id="verticalIconsKindaiTab"]')
37+
.waitForElementVisible('*[data-id="aiTabPanel"]')
38+
.execute(function () {
39+
const aiPlugin = (window as any).getRemixAIPlugin();
40+
if (!aiPlugin?.remixMCPServer) {
41+
return { error: 'RemixMCPServer not available' };
42+
}
43+
44+
const server = aiPlugin.remixMCPServer;
45+
return {
46+
hasRemixMcpServer: !!server,
47+
serverName: server.serverName || null,
48+
version: server.version || null,
49+
isInitialized: !!server.toolRegistry && !!server.resourceProviders,
50+
hasToolRegistry: !!server.toolRegistry,
51+
hasResourceProviders: !!server.resourceProviders,
52+
capabilities: server.capabilities || null
53+
};
54+
}, [], function (result) {
55+
const data = result.value as any;
56+
if (data.error) {
57+
console.error('RemixMCPServer error:', data.error);
58+
return;
59+
}
60+
browser.assert.ok(data.hasRemixMcpServer, 'Should have RemixMCPServer instance');
61+
browser.assert.ok(data.isInitialized, 'Server should be properly initialized');
62+
browser.assert.ok(data.hasToolRegistry, 'Should have tool registry');
63+
browser.assert.ok(data.hasResourceProviders, 'Should have resource providers');
64+
});
65+
},
66+
67+
'Should test RemixMCPServer tool registration': function (browser: NightwatchBrowser) {
68+
browser
69+
.execute(function () {
70+
const aiPlugin = (window as any).getRemixAIPlugin();
71+
if (!aiPlugin?.remixMCPServer?.toolRegistry) {
72+
return { error: 'Tool registry not available' };
73+
}
74+
75+
const allTools = aiPlugin.remixMCPServer.tools;
76+
const compilationTools = allTools.filter((t: any) =>
77+
t.name.includes('compile') || t.category === 'COMPILATION'
78+
);
79+
80+
const deploymentTools = allTools.filter((t: any) =>
81+
t.name.includes('deploy') || t.name.includes('account') || t.category === 'DEPLOYMENT'
82+
);
83+
84+
const fileTools = allTools.filter((t: any) =>
85+
t.name.includes('file') || t.category === 'FILE_SYSTEM'
86+
);
87+
88+
return {
89+
totalTools: allTools.length,
90+
compilationToolCount: compilationTools.length,
91+
deploymentToolCount: deploymentTools.length,
92+
fileToolCount: fileTools.length,
93+
sampleTools: allTools.slice(0, 3).map((t: any) => ({
94+
name: t.name,
95+
category: t.category,
96+
hasHandler: !!t.handler
97+
}))
98+
};
99+
}, [], function (result) {
100+
const data = result.value as any;
101+
if (data.error) {
102+
console.error('Tool registry error:', data.error);
103+
return;
104+
}
105+
browser.assert.ok(data.totalTools > 0, 'Should have registered tools');
106+
browser.assert.ok(data.compilationToolCount > 0, 'Should have compilation tools');
107+
browser.assert.ok(data.deploymentToolCount > 0, 'Should have deployment tools');
108+
});
109+
},
110+
111+
'Should test RemixMCPServer resource providers': function (browser: NightwatchBrowser) {
112+
browser
113+
.execute(function () {
114+
const aiPlugin = (window as any).getRemixAIPlugin();
115+
if (!aiPlugin?.remixMCPServer?.resources) {
116+
return { error: 'Resource providers not available' };
117+
}
118+
119+
const resourceProviders = aiPlugin.remixMCPServer.resources.providers;
120+
const deploymentProvider = resourceProviders.get('deployment');
121+
const projectProvider = resourceProviders.get('project');
122+
const compilerProvider = resourceProviders.get('compiler');
123+
124+
return {
125+
totalProviders: resourceProviders.size,
126+
hasDeploymentProvider: !!deploymentProvider,
127+
hasProjectProvider: !!projectProvider,
128+
hasCompilerProvider: !!compilerProvider,
129+
deploymentProviderMethods: deploymentProvider ? Object.getOwnPropertyNames(Object.getPrototypeOf(deploymentProvider)) : [],
130+
projectProviderMethods: projectProvider ? Object.getOwnPropertyNames(Object.getPrototypeOf(projectProvider)) : []
131+
};
132+
}, [], function (result) {
133+
const data = result.value as any;
134+
if (data.error) {
135+
console.error('Resource providers error:', data.error);
136+
return;
137+
}
138+
browser.assert.ok(data.totalProviders > 0, 'Should have resource providers');
139+
browser.assert.ok(data.hasDeploymentProvider, 'Should have deployment provider');
140+
browser.assert.ok(data.hasProjectProvider, 'Should have project provider');
141+
});
142+
},
143+
144+
'Should test RemixMCPServer solidity compile tool execution via server': function (browser: NightwatchBrowser) {
145+
browser
146+
.addFile('contracts/RemixMCPServerTest.sol', { content: testContract })
147+
.pause(1000)
148+
.execute(async function () {
149+
const aiPlugin = (window as any).getRemixAIPlugin();
150+
if (!aiPlugin?.remixMCPServer) {
151+
return { error: 'RemixMCPServer not available' };
152+
}
153+
154+
try {
155+
const server = aiPlugin.remixMCPServer;
156+
157+
const compileResult = await server.executeTool({
158+
name: 'solidity_compile',
159+
arguments: {
160+
file: 'contracts/RemixMCPServerTest.sol',
161+
version: '0.8.20',
162+
optimize: true,
163+
runs: 200
164+
}
165+
});
166+
167+
const configResult = await server.executeTool({
168+
name: 'get_compiler_config',
169+
arguments: {}
170+
});
171+
172+
return {
173+
compileExecuted: !compileResult.isError,
174+
configExecuted: !configResult.isError,
175+
compileContent: compileResult.content?.[0]?.text || null,
176+
configContent: configResult.content?.[0]?.text || null,
177+
compileError: compileResult.isError ? compileResult.content?.[0]?.text : null,
178+
configError: configResult.isError ? configResult.content?.[0]?.text : null
179+
};
180+
} catch (error) {
181+
return { error: error.message };
182+
}
183+
}, [], function (result) {
184+
const data = result.value as any;
185+
if (data.error) {
186+
console.error('Server tool execution error:', data.error);
187+
return;
188+
}
189+
browser.assert.ok(data.compileExecuted, 'Should execute compile tool successfully');
190+
browser.assert.ok(data.configExecuted, 'Should execute config tool successfully');
191+
});
192+
},
193+
194+
'Should test RemixMCPServer main resources reading via server': function (browser: NightwatchBrowser) {
195+
browser
196+
.execute(async function () {
197+
const aiPlugin = (window as any).getRemixAIPlugin();
198+
if (!aiPlugin?.remixMCPServer) {
199+
return { error: 'RemixMCPServer not available' };
200+
}
201+
202+
try {
203+
const server = aiPlugin.remixMCPServer;
204+
205+
// Test resource reading through server
206+
const historyResource = await server.readResource('deployment://history');
207+
const structureResource = await server.readResource('project://structure');
208+
const configResource = await server.readResource('compiler://config');
209+
210+
return {
211+
historyRead: !!historyResource,
212+
structureRead: !!structureResource,
213+
configRead: !!configResource,
214+
historyMimeType: historyResource?.mimeType || null,
215+
structureMimeType: structureResource?.mimeType || null,
216+
configMimeType: configResource?.mimeType || null,
217+
historyHasContent: !!historyResource?.text,
218+
structureHasContent: !!structureResource?.text,
219+
configHasContent: !!configResource?.text
220+
};
221+
} catch (error) {
222+
return { error: error.message };
223+
}
224+
}, [], function (result) {
225+
const data = result.value as any;
226+
if (data.error) {
227+
console.error('Server resource reading error:', data.error);
228+
return;
229+
}
230+
browser.assert.ok(data.historyRead, 'Should read deployment history resource');
231+
browser.assert.ok(data.structureRead, 'Should read project structure resource');
232+
browser.assert.ok(data.configRead, 'Should read compiler config resource');
233+
});
234+
},
235+
236+
'Should test RemixMCPServer capabilities and metadata': function (browser: NightwatchBrowser) {
237+
browser
238+
.execute(function () {
239+
const aiPlugin = (window as any).getRemixAIPlugin();
240+
if (!aiPlugin?.remixMCPServer) {
241+
return { error: 'RemixMCPServer not available' };
242+
}
243+
244+
const server = aiPlugin.remixMCPServer;
245+
246+
// Test server metadata and capabilities
247+
const capabilities = server.capabilities || {};
248+
const serverInfo = {
249+
name: server.serverName,
250+
version: server.version,
251+
capabilities: capabilities
252+
};
253+
254+
// Test tool and resource listing capabilities
255+
const toolList = server.listTools ? server.listTools() : null;
256+
const resourceList = server.listResources ? server.listResources() : null;
257+
258+
return {
259+
serverInfo,
260+
hasCapabilities: Object.keys(capabilities).length > 0,
261+
supportsTools: !!capabilities.tools,
262+
supportsResources: !!capabilities.resources,
263+
toolListAvailable: !!toolList,
264+
resourceListAvailable: !!resourceList,
265+
toolCount: toolList ? toolList.length : 0,
266+
resourceCount: resourceList ? resourceList.length : 0
267+
};
268+
}, [], function (result) {
269+
const data = result.value as any;
270+
if (data.error) {
271+
console.error('Server capabilities error:', data.error);
272+
return;
273+
}
274+
browser.assert.ok(data.hasCapabilities, 'Should have server capabilities');
275+
browser.assert.ok(data.supportsTools, 'Should support tools');
276+
browser.assert.ok(data.toolCount > 0, 'Should tools');
277+
browser.assert.ok(data.resourceCount > 0, 'Should resources');
278+
browser.assert.ok(data.supportsResources, 'Should support resources');
279+
});
280+
},
281+
282+
'Should test RemixMCPServer error handling invalid tool execution': function (browser: NightwatchBrowser) {
283+
browser
284+
.execute(async function () {
285+
const aiPlugin = (window as any).getRemixAIPlugin();
286+
if (!aiPlugin?.remixMCPServer) {
287+
return { error: 'RemixMCPServer not available' };
288+
}
289+
290+
try {
291+
const server = aiPlugin.remixMCPServer;
292+
293+
let invalidToolResult;
294+
try {
295+
invalidToolResult = await server.executeTool({
296+
name: 'non_existent_tool',
297+
arguments: {}
298+
});
299+
} catch (error) {
300+
invalidToolResult = { isError: true, content: [{ text: error.message }] };
301+
}
302+
303+
let invalidResourceResult;
304+
try {
305+
invalidResourceResult = await server.readResource('invalid://resource');
306+
} catch (error) {
307+
invalidResourceResult = null;
308+
}
309+
310+
let invalidArgsResult;
311+
try {
312+
invalidArgsResult = await server.executeTool({
313+
name: 'solidity_compile',
314+
arguments: {
315+
runs: 99999 // Invalid: too high
316+
}
317+
});
318+
} catch (error) {
319+
invalidArgsResult = { isError: true, content: [{ text: error.message }] };
320+
}
321+
322+
return {
323+
invalidToolHandled: invalidToolResult?.isError === true,
324+
invalidResourceHandled: invalidResourceResult === null,
325+
invalidArgsHandled: invalidArgsResult?.isError === true,
326+
systemStable: true,
327+
invalidToolMessage: invalidToolResult?.content?.[0]?.text || 'No message',
328+
invalidArgsMessage: invalidArgsResult?.content?.[0]?.text || 'No message'
329+
};
330+
} catch (error) {
331+
return { error: error.message };
332+
}
333+
}, [], function (result) {
334+
const data = result.value as any;
335+
if (data.error) {
336+
console.error('Server error handling test error:', data.error);
337+
return;
338+
}
339+
browser.assert.ok(data.invalidToolHandled, 'Should handle invalid tools gracefully');
340+
browser.assert.ok(data.invalidResourceHandled, 'Should handle invalid resources gracefully');
341+
browser.assert.ok(data.invalidArgsHandled, 'Should handle invalid arguments gracefully');
342+
browser.assert.ok(data.systemStable, 'System should remain stable after errors');
343+
});
344+
},
345+
346+
'Should test RemixMCPServer performance and caching': function (browser: NightwatchBrowser) {
347+
browser
348+
.execute(async function () {
349+
const aiPlugin = (window as any).getRemixAIPlugin();
350+
if (!aiPlugin?.remixMCPServer) {
351+
return { error: 'RemixMCPServer not available' };
352+
}
353+
354+
try {
355+
const server = aiPlugin.remixMCPServer;
356+
const startTime = Date.now();
357+
358+
// Test multiple operations for performance
359+
const operations = await Promise.all([
360+
server.readResource('deployment://history'),
361+
server.readResource('project://structure'),
362+
]);
363+
364+
const endTime = Date.now();
365+
const totalTime = endTime - startTime;
366+
367+
// Test caching behavior
368+
const cachingStart = Date.now();
369+
const cachedResource1 = await server.readResource('deployment://history');
370+
const cachedResource2 = await server.readResource('project://structure');
371+
const cachingEnd = Date.now();
372+
const cachingTime = cachingEnd - cachingStart;
373+
374+
return {
375+
operationsCompleted: operations.length,
376+
totalExecutionTime: totalTime,
377+
averageOperationTime: totalTime / operations.length,
378+
cachingTime,
379+
allOperationsSucceeded: operations.every(op => !!op),
380+
performanceAcceptable: totalTime < 1000, // Should complete within 5 seconds
381+
cachingWorking: cachingTime < totalTime // Caching should be faster
382+
};
383+
} catch (error) {
384+
return { error: error.message };
385+
}
386+
}, [], function (result) {
387+
const data = result.value as any;
388+
if (data.error) {
389+
console.error('Performance test error:', data.error);
390+
return;
391+
}
392+
browser.assert.ok(data.allOperationsSucceeded, 'All operations should succeed');
393+
browser.assert.ok(data.performanceAcceptable, 'Performance should be acceptable');
394+
browser.assert.equal(data.operationsCompleted, 5, 'Should complete all test operations');
395+
});
396+
}
397+
};

0 commit comments

Comments
 (0)