Skip to content

Commit f1a2223

Browse files
feat: add lerna and prepare package for publication (#12)
1 parent c17d40b commit f1a2223

File tree

121 files changed

+7816
-779
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+7816
-779
lines changed

.github/scripts/validate-config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ console.log('🔍 Validating MCP configuration...\n');
77
// Load mcps.json
88
let mcpsConfig;
99
try {
10-
const configPath = path.join(process.cwd(), 'packages/mcps/mcps.json');
10+
const configPath = path.join(process.cwd(), 'packages/mcp/mcps.json');
1111
mcpsConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
1212
console.log('✅ mcps.json loaded successfully');
1313
} catch (error) {

.github/scripts/validate-tools.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const { spawn } = require('child_process');
66
console.log('🧪 Testing MCP tool registration...\n');
77

88
const mcpsConfig = JSON.parse(
9-
fs.readFileSync('packages/mcps/mcps.json', 'utf8')
9+
fs.readFileSync('packages/mcp/mcps.json', 'utf8')
1010
);
1111

1212
async function getMCPTools(mcpName) {

CONTRIBUTING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ async function main() {
9494
main().catch(console.error);
9595
```
9696

97-
## Register in packages/mcps/mcps.json
97+
## Register in packages/mcp/mcps.json
9898

9999
```json
100100
{
@@ -126,11 +126,11 @@ import('../build/index.js').catch(console.error);
126126

127127
## Environment Variables
128128

129-
The MCP system now supports dynamic environment variable loading. Each MCP can specify required environment variables in the `packages/mcps/mcps.json` configuration.
129+
The MCP system now supports dynamic environment variable loading. Each MCP can specify required environment variables in the `packages/mcp/mcps.json` configuration.
130130

131131
### Environment Variable Configuration
132132

133-
Environment variables are configured in the `packages/mcps/mcps.json` file under each MCP's `client.env` section:
133+
Environment variables are configured in the `packages/mcp/mcps.json` file under each MCP's `client.env` section:
134134

135135
```json
136136
{

lerna.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"version": "independent",
3+
"npmClient": "pnpm",
4+
"command": {
5+
"publish": {
6+
"ignoreChanges": ["*.md", "*.test.ts", "*.spec.ts"],
7+
"message": "chore(release): publish %s",
8+
"gitTagVersion": true,
9+
"push": true
10+
},
11+
"version": {
12+
"allowBranch": "main",
13+
"message": "chore(release): version packages",
14+
"gitTagVersion": false,
15+
"push": false
16+
}
17+
}
18+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"eslint-config-prettier": "^9.1.0",
5050
"eslint-plugin-prettier": "^5.2.3",
5151
"globals": "^15.15.0",
52+
"lerna": "^9.0.0",
5253
"prettier": "^3.6.1",
5354
"turbo": "^2.4.4",
5455
"typescript": "^5.7.3",

packages/core/package.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "@ask-starknet/core",
3-
"version": "1.0.0",
2+
"name": "@kasarlabs/ask-starknet-core",
3+
"version": "0.1.0",
44
"description": "Core utilities and shared functionality for the Ask Starknet MCP ecosystem",
55
"main": "build/index.js",
66
"types": "build/index.d.ts",
@@ -23,16 +23,19 @@
2323
],
2424
"author": "kasarlabs",
2525
"license": "MIT",
26+
"publishConfig": {
27+
"access": "public"
28+
},
2629
"dependencies": {
27-
"zod": "^3.24.2",
30+
"starknet": "^7.6.4",
2831
"winston": "^3.17.0",
29-
"starknet": "^7.6.4"
32+
"zod": "^3.24.2"
3033
},
3134
"devDependencies": {
35+
"@types/jest": "^29.0.0",
3236
"@types/node": "^22.13.10",
33-
"typescript": "^5.8.2",
3437
"jest": "^29.0.0",
35-
"@types/jest": "^29.0.0"
38+
"typescript": "^5.8.2"
3639
},
3740
"exports": {
3841
".": {

packages/mcp/__test__/e2e/env.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ try {
2626
name: 'ask_starknet',
2727
arguments: {
2828
userInput:
29-
'I want to transfer 0.000001 STRK to account 0x07b67cA77BC41CB7DD972eb0Dc2bBAbCfCE9d586570e609f70E73C746D6565E8',
29+
'can you transfer 0.000001 ETH to 0x0590612320bCC4C7735007e67674902969b9A0F9546B786BDeA46b11Cca8c5AC?',
3030
},
3131
});
3232

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
#!/usr/bin/env node
2+
// Test all MCP servers to ensure they can be launched via npx and list tools
3+
4+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
5+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
6+
import { readFileSync } from 'fs';
7+
import { join, dirname } from 'path';
8+
import { fileURLToPath } from 'url';
9+
10+
const __filename = fileURLToPath(import.meta.url);
11+
const __dirname = dirname(__filename);
12+
13+
// Load mcps.json configuration
14+
const mcpsConfigPath = join(__dirname, '../../mcps.json');
15+
const mcpsConfig = JSON.parse(readFileSync(mcpsConfigPath, 'utf-8'));
16+
17+
// Simple queries for each MCP (read-only operations that don't require private keys)
18+
const testQueries = {
19+
argent: {
20+
tool: 'create_new_argent_account',
21+
description: 'Create Argent account',
22+
},
23+
erc20: {
24+
tool: 'erc20_get_balance',
25+
description: 'Get ERC20 balance',
26+
args: {
27+
token_address:
28+
'0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
29+
account_address: '0x1',
30+
},
31+
},
32+
braavos: {
33+
tool: 'create_new_braavos_account',
34+
description: 'Create Braavos account',
35+
},
36+
avnu: {
37+
tool: 'avnu_get_route',
38+
description: 'Get AVNU route',
39+
args: {
40+
sell_token_address:
41+
'0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
42+
buy_token_address:
43+
'0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8',
44+
sell_amount: '1000000000000000000',
45+
},
46+
},
47+
erc721: {
48+
tool: 'erc721_get_balance',
49+
description: 'Get ERC721 balance',
50+
args: { contract_address: '0x1', owner: '0x1' },
51+
},
52+
transaction: {
53+
tool: 'simulate_transaction',
54+
description: 'Simulate transaction',
55+
},
56+
artpeace: { tool: 'place_pixel', description: 'Place pixel' },
57+
contract: {
58+
tool: 'get_constructor_params',
59+
description: 'Get constructor params',
60+
args: { contract_path: './test.cairo' },
61+
},
62+
fibrous: {
63+
tool: 'fibrous_get_route',
64+
description: 'Get Fibrous route',
65+
args: {
66+
token_in_address:
67+
'0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
68+
token_out_address:
69+
'0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8',
70+
amount: '1000000000000000000',
71+
},
72+
},
73+
okx: { tool: 'create_new_okx_account', description: 'Create OKX account' },
74+
openzeppelin: {
75+
tool: 'create_new_openzeppelin_account',
76+
description: 'Create OpenZeppelin account',
77+
},
78+
opus: {
79+
tool: 'get_user_troves',
80+
description: 'Get user troves',
81+
args: { user_address: '0x1' },
82+
},
83+
'starknet-rpc': { tool: 'get_chain_id', description: 'Get chain ID' },
84+
scarb: { tool: 'install_scarb', description: 'Install Scarb' },
85+
unruggable: {
86+
tool: 'is_memecoin',
87+
description: 'Check if memecoin',
88+
args: { token_address: '0x1' },
89+
},
90+
vesu: { tool: 'vesu_deposit_earn', description: 'Deposit on Vesu' },
91+
ekubo: {
92+
tool: 'get_pool_info',
93+
description: 'Get pool info',
94+
args: {
95+
token0:
96+
'0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
97+
token1:
98+
'0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8',
99+
fee: '170141183460469235273462165868118016',
100+
},
101+
},
102+
extended: { tool: 'extended_get_markets', description: 'Get markets' },
103+
endurfi: {
104+
tool: 'get_total_staked',
105+
description: 'Get total staked',
106+
args: { pool: 'xstrk' },
107+
},
108+
'cairo-coder': {
109+
tool: 'starknet_general_knowledge',
110+
description: 'Starknet knowledge',
111+
args: { question: 'What is Starknet?' },
112+
},
113+
};
114+
115+
async function testMCP(mcpName, mcpConfig) {
116+
console.log(`\n🧪 Testing ${mcpName}...`);
117+
118+
const client = new Client({
119+
name: 'test-client',
120+
version: '1.0.0',
121+
});
122+
123+
try {
124+
// Create transport using npx with -y flag
125+
const transport = new StdioClientTransport({
126+
command: mcpConfig.client.command,
127+
args: mcpConfig.client.args,
128+
env: {
129+
...process.env,
130+
// Set dummy values for required env vars to avoid errors during connection
131+
STARKNET_RPC_URL:
132+
process.env.STARKNET_RPC_URL ||
133+
'https://starknet-mainnet.public.blastapi.io',
134+
STARKNET_ACCOUNT_ADDRESS: process.env.STARKNET_ACCOUNT_ADDRESS || '0x1',
135+
STARKNET_PRIVATE_KEY: process.env.STARKNET_PRIVATE_KEY || '0x1',
136+
EXTENDED_API_KEY: process.env.EXTENDED_API_KEY || 'test',
137+
EXTENDED_API_URL:
138+
process.env.EXTENDED_API_URL ||
139+
'https://api.starknet.extended.exchange',
140+
EXTENDED_PRIVATE_KEY: process.env.EXTENDED_PRIVATE_KEY || '0x1',
141+
CAIRO_CODER_API_KEY: process.env.CAIRO_CODER_API_KEY || 'test',
142+
PATH_UPLOAD_DIR: process.env.PATH_UPLOAD_DIR || '/tmp',
143+
SECRET_PHRASE: process.env.SECRET_PHRASE || 'test',
144+
},
145+
});
146+
147+
// Connect to the MCP server
148+
await client.connect(transport);
149+
console.log(` ✅ Connection established`);
150+
151+
// List available tools
152+
const tools = await client.listTools();
153+
console.log(` ✅ Tools available: ${tools.tools.length} tools`);
154+
155+
// Show first few tool names
156+
const toolNames = tools.tools
157+
.slice(0, 3)
158+
.map((t) => t.name)
159+
.join(', ');
160+
console.log(
161+
` 📋 Sample tools: ${toolNames}${tools.tools.length > 3 ? '...' : ''}`
162+
);
163+
164+
// Verify expected tool exists (if defined in testQueries)
165+
const testConfig = testQueries[mcpName];
166+
if (testConfig && testConfig.tool) {
167+
const hasExpectedTool = tools.tools.some(
168+
(t) => t.name === testConfig.tool
169+
);
170+
if (hasExpectedTool) {
171+
console.log(` ✅ Expected tool "${testConfig.tool}" found`);
172+
} else {
173+
console.log(` ⚠️ Expected tool "${testConfig.tool}" not found`);
174+
}
175+
}
176+
177+
await client.close();
178+
return { success: true, toolCount: tools.tools.length };
179+
} catch (error) {
180+
console.log(` ❌ Error: ${error.message}`);
181+
try {
182+
await client.close();
183+
} catch (closeError) {
184+
// Ignore close errors
185+
}
186+
return { success: false, error: error.message };
187+
}
188+
}
189+
190+
async function main() {
191+
console.log('🚀 Testing all MCP servers via npx...\n');
192+
console.log('This will download and test each MCP package from npm.\n');
193+
194+
const results = {};
195+
const mcpNames = Object.keys(mcpsConfig);
196+
197+
for (const mcpName of mcpNames) {
198+
const mcpConfig = mcpsConfig[mcpName];
199+
const result = await testMCP(mcpName, mcpConfig);
200+
results[mcpName] = result;
201+
202+
// Small delay between tests to avoid overwhelming npm
203+
await new Promise((resolve) => setTimeout(resolve, 1000));
204+
}
205+
206+
// Summary
207+
console.log('\n' + '='.repeat(60));
208+
console.log('📊 Test Summary\n');
209+
210+
const successful = Object.entries(results).filter(([_, r]) => r.success);
211+
const failed = Object.entries(results).filter(([_, r]) => !r.success);
212+
213+
console.log(`✅ Successful: ${successful.length}/${mcpNames.length}`);
214+
successful.forEach(([name, result]) => {
215+
console.log(` - ${name} (${result.toolCount} tools)`);
216+
});
217+
218+
if (failed.length > 0) {
219+
console.log(`\n❌ Failed: ${failed.length}/${mcpNames.length}`);
220+
failed.forEach(([name, result]) => {
221+
console.log(` - ${name}: ${result.error}`);
222+
});
223+
}
224+
225+
console.log('\n' + '='.repeat(60));
226+
227+
if (failed.length > 0) {
228+
console.log('\n⚠️ Some MCP servers failed to load!');
229+
process.exit(1);
230+
} else {
231+
console.log('\n✅ All MCP servers are working correctly!');
232+
process.exit(0);
233+
}
234+
}
235+
236+
main().catch((error) => {
237+
console.error('Fatal error:', error);
238+
process.exit(1);
239+
});

0 commit comments

Comments
 (0)