finoptima 1.2.2 → 1.3.1

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.
package/index.js CHANGED
@@ -13,6 +13,7 @@
13
13
  *
14
14
  * Environment variables:
15
15
  * ECOCHAIN_API_URL — Optional. API base URL (default: https://api.toutcreer.com)
16
+ * ECOCHAIN_API_KEY — Optional. API key for agent auth (skips phone login)
16
17
  */
17
18
 
18
19
  const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
@@ -30,6 +31,14 @@ const POLL_TIMEOUT_MS = 120000;
30
31
 
31
32
  let authenticated = false;
32
33
 
34
+ // API key auth — skip phone login if ECOCHAIN_API_KEY is set (DEC-2026-050)
35
+ const API_KEY = process.env.ECOCHAIN_API_KEY;
36
+ if (API_KEY) {
37
+ apiClient.setApiKey(API_KEY);
38
+ authenticated = true;
39
+ console.error('[EcoChain MCP] Authenticated via API key (no phone login required)');
40
+ }
41
+
33
42
  /**
34
43
  * EcoAuth login flow
35
44
  */
@@ -97,7 +106,11 @@ const loginTool = {
97
106
  },
98
107
  handler: async ({ phone_number }) => {
99
108
  if (authenticated) {
100
- return JSON.stringify({ status: 'already_authenticated', user_id: process.env.ECOCHAIN_USER_ID });
109
+ return JSON.stringify({
110
+ status: 'already_authenticated',
111
+ auth_method: API_KEY ? 'api_key' : 'ecoauth',
112
+ user_id: process.env.ECOCHAIN_USER_ID
113
+ });
101
114
  }
102
115
 
103
116
  const result = await loginWithEcoAuth(phone_number);
@@ -118,7 +131,7 @@ const loginTool = {
118
131
  const allToolsWithLogin = [loginTool, ...allTools];
119
132
 
120
133
  // Server instructions — shown to the AI to explain how to use FINOPTIMA
121
- const SERVER_INSTRUCTIONS = `FINOPTIMA — EcoChain AI Finance Agent (v1.2.0, 30 tools)
134
+ const SERVER_INSTRUCTIONS = `FINOPTIMA — EcoChain AI Finance Agent (v1.3.0, ${allTools.length + 1} tools)
122
135
 
123
136
  ## Setup
124
137
  If the user doesn't have FINOPTIMA installed, they can add it to their MCP config:
@@ -135,29 +148,56 @@ If the user doesn't have FINOPTIMA installed, they can add it to their MCP confi
135
148
  \`\`\`
136
149
 
137
150
  ## Authentication
151
+ Two authentication methods are supported:
152
+
153
+ ### Method 1: EcoAuth (interactive — for users)
138
154
  1. Ask the user for their phone number (format: +33...)
139
155
  2. Call the \`login\` tool — a push notification is sent to their EcoAuth mobile app
140
156
  3. The user approves on their phone — JWT session is established
141
157
  4. All other tools are now active
142
158
 
159
+ ### Method 2: API Key (non-interactive — for agents)
160
+ Set \`ECOCHAIN_API_KEY\` in the MCP config env:
161
+ \`\`\`json
162
+ {
163
+ "env": {
164
+ "ECOCHAIN_API_URL": "https://api.toutcreer.com",
165
+ "ECOCHAIN_API_KEY": "eco_ak_..."
166
+ }
167
+ }
168
+ \`\`\`
169
+ No login call needed — all tools are immediately available.
170
+ API keys are scoped (read/trade/swap/liquidity/send/strategy) and rate-limited.
171
+ Requires a Pro or API subscription plan.
172
+
143
173
  ## Available Capabilities
144
174
  - **Portfolio**: get_balances, get_portfolio, get_prices, get_lp_positions, get_transaction_history
145
175
  - **Market**: get_pools, get_pool_details, get_orderbook, get_ticker, get_candles, get_trading_pairs
146
176
  - **Trading**: place_order, cancel_order, get_my_orders, get_trade_history
147
- - **Swap (AMM)**: get_swap_quote, execute_swap (0.3% fee)
177
+ - **Swap (AMM)**: get_swap_quote, execute_swap (0.3% fee, multi-hop routing supported)
148
178
  - **Liquidity**: add_liquidity, remove_liquidity
149
179
  - **Transfer**: send_funds
150
180
  - **AI Strategies**: create_strategy, list_strategies, get_strategy, activate_strategy, pause_strategy
181
+ - **Marketplace**: get_templates, subscribe_template, get_leaderboard, follow_strategy, unfollow_strategy
151
182
  - **Intents**: create_intent, list_intents
152
183
  - **Performance**: get_strategy_performance
153
184
 
185
+ ## Multi-Pool AMM
186
+ Multiple liquidity pools supported (ECO/BTC, ECO/ETH). Swaps between non-direct pairs (e.g., BTC↔ETH) are automatically routed via ECO as a hub token (2-hop swap).
187
+
154
188
  ## AI Trading Strategies
155
- 3 automated strategies available: LP Yield, DCA, BTC Hedge.
189
+ 4 strategy types: LP Yield, DCA, BTC Hedge, Eco Pilot.
156
190
  Pipeline: Create (draft) → Activate → Runner evaluates every 60s → Creates intents → Policy validation (8 rules) → Auto-approve if < 0.01 BTC, else manual approval → Execute.
157
191
  Modes: "auto" (auto-approve small trades) or "watch" (all manual approval).
158
192
 
193
+ ## Strategy Marketplace
194
+ - Browse public strategy templates (\`get_templates\`)
195
+ - Subscribe to a template to clone its config (\`subscribe_template\`)
196
+ - Follow a provider's live trades with copy trading (\`follow_strategy\`)
197
+ - View top-performing strategies (\`get_leaderboard\`)
198
+
159
199
  ## Rules
160
- - Always call \`login\` first before any other tool
200
+ - Always call \`login\` first before any other tool (unless using API key auth)
161
201
  - Always confirm financial actions (trade, swap, send) with the user before executing
162
202
  - Use \`get_swap_quote\` before \`execute_swap\` to show expected outcome
163
203
  - Platform: https://www.toutcreer.com/trading
@@ -167,7 +207,7 @@ Modes: "auto" (auto-approve small trades) or "watch" (all manual approval).
167
207
  const server = new Server(
168
208
  {
169
209
  name: 'ecochain',
170
- version: '1.2.0',
210
+ version: '1.3.0',
171
211
  },
172
212
  {
173
213
  capabilities: {
@@ -203,7 +243,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
203
243
  // Block all tools except login if not authenticated
204
244
  if (!authenticated && name !== 'login') {
205
245
  return {
206
- content: [{ type: 'text', text: 'Not authenticated. Please ask the user for their phone number and call the `login` tool first.' }],
246
+ content: [{ type: 'text', text: 'Not authenticated. Either set ECOCHAIN_API_KEY env var or ask the user for their phone number and call the `login` tool first.' }],
207
247
  isError: true,
208
248
  };
209
249
  }
package/lib/api-client.js CHANGED
@@ -12,6 +12,7 @@ class ApiClient {
12
12
  constructor() {
13
13
  this.apiUrl = process.env.ECOCHAIN_API_URL || 'https://api.toutcreer.com';
14
14
  this.jwtToken = null; // Set after EcoAuth login
15
+ this.apiKey = null; // Set via ECOCHAIN_API_KEY env var (DEC-2026-050)
15
16
 
16
17
  const parsed = new URL(this.apiUrl);
17
18
  this.hostname = parsed.hostname;
@@ -27,6 +28,13 @@ class ApiClient {
27
28
  this.jwtToken = token;
28
29
  }
29
30
 
31
+ /**
32
+ * Set API key for agent authentication (DEC-2026-050)
33
+ */
34
+ setApiKey(key) {
35
+ this.apiKey = key;
36
+ }
37
+
30
38
  /**
31
39
  * Make an HTTP request to the backend API
32
40
  */
@@ -38,7 +46,9 @@ class ApiClient {
38
46
  'X-Client-Type': 'mcp-agent',
39
47
  };
40
48
 
41
- if (this.jwtToken) {
49
+ if (this.apiKey) {
50
+ headers['X-API-Key'] = this.apiKey;
51
+ } else if (this.jwtToken) {
42
52
  headers['Authorization'] = `Bearer ${this.jwtToken}`;
43
53
  }
44
54
 
@@ -0,0 +1,3 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MC4CAQAwBQYDK2VwBCIEIJ9Ouq7yDU4Qqpm8doI3i5KHM6044kKTPjpd0o2dIZ0i
3
+ -----END PRIVATE KEY-----
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "finoptima",
3
- "version": "1.2.2",
4
- "description": "FINOPTIMA — EcoChain AI Finance Agent via MCP. Portfolio optimization, AMM liquidity, AI trading strategies, swaps. Secured by EcoAuth 2FA.",
3
+ "version": "1.3.1",
4
+ "mcpName": "com.toutcreer/finoptima",
5
+ "description": "FINOPTIMA — EcoChain AI Finance Agent via MCP. Multi-pool AMM (ECO/BTC, ECO/ETH), 4 AI strategies, strategy marketplace, copy trading, leaderboard. 35 tools. API key auth. Secured by EcoAuth 2FA.",
5
6
  "main": "index.js",
6
7
  "bin": {
7
8
  "finoptima": "index.js"
package/server.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "com.toutcreer/finoptima",
4
+ "title": "FINOPTIMA",
5
+ "description": "AI trading agent: multi-pool AMM, 4 strategies, marketplace, copy trading. 35 tools.",
6
+ "version": "1.3.1",
7
+ "repository": {
8
+ "url": "https://github.com/toutcreer/finoptima",
9
+ "source": "github"
10
+ },
11
+ "packages": [
12
+ {
13
+ "registryType": "npm",
14
+ "registryBaseUrl": "https://registry.npmjs.org",
15
+ "identifier": "finoptima",
16
+ "version": "1.3.1",
17
+ "transport": {
18
+ "type": "stdio"
19
+ },
20
+ "environmentVariables": [
21
+ {
22
+ "name": "ECOCHAIN_API_URL",
23
+ "description": "EcoChain API endpoint (default: https://api.toutcreer.com)",
24
+ "isRequired": false,
25
+ "isSecret": false
26
+ },
27
+ {
28
+ "name": "ECOCHAIN_API_KEY",
29
+ "description": "API key for autonomous agent authentication (format: eco_ak_...). Optional — alternative to EcoAuth 2FA login. Available on Pro and API subscription plans.",
30
+ "isRequired": false,
31
+ "isSecret": true
32
+ }
33
+ ],
34
+ "arguments": ["-y", "finoptima"]
35
+ }
36
+ ],
37
+ "_meta": {
38
+ "io.modelcontextprotocol.registry/publisher-provided": {
39
+ "homepage": "https://www.toutcreer.com/finoptima",
40
+ "documentation": "https://www.toutcreer.com/trading/finoptima.md",
41
+ "categories": ["finance", "trading", "defi", "portfolio"],
42
+ "toolCount": 35,
43
+ "features": [
44
+ "Multi-pool AMM (ECO/BTC, ECO/ETH) with smart router",
45
+ "4 AI trading strategies (DCA, BTC Hedge, LP Yield, Eco Pilot)",
46
+ "Strategy marketplace with templates and copy trading",
47
+ "Policy engine with 8 security rules",
48
+ "EcoAuth 2FA + API key authentication"
49
+ ],
50
+ "pricing": {
51
+ "free": "0 EUR — browse marketplace",
52
+ "pilot": "9 EUR/mo — 5 strategies, follow",
53
+ "pro": "29 EUR/mo — 20 strategies, publish, 3 API keys",
54
+ "api": "99 EUR/mo — unlimited, 10 API keys"
55
+ }
56
+ }
57
+ }
58
+ }
package/tools/index.js CHANGED
@@ -393,6 +393,92 @@ const sendTools = [
393
393
  }
394
394
  ];
395
395
 
396
+ // ============================================
397
+ // MARKETPLACE TOOLS (DEC-2026-050)
398
+ // ============================================
399
+
400
+ const marketplaceTools = [
401
+ {
402
+ name: 'get_leaderboard',
403
+ description: 'Get top performing public strategies. Returns strategy name, type, total return, max drawdown, follower count, and provider name.',
404
+ inputSchema: {
405
+ type: 'object',
406
+ properties: {
407
+ limit: { type: 'number', description: 'Max results (default 50)' }
408
+ },
409
+ required: []
410
+ },
411
+ handler: withLogging('get_leaderboard', async ({ limit }) => {
412
+ const params = limit ? `?limit=${limit}` : '';
413
+ const data = await apiClient.get(`/performance/leaderboard${params}`);
414
+ return JSON.stringify(data);
415
+ })
416
+ },
417
+ {
418
+ name: 'get_templates',
419
+ description: 'List all active strategy templates in the marketplace. Returns template name, type, parameters, return, subscribers, and provider.',
420
+ inputSchema: {
421
+ type: 'object',
422
+ properties: {},
423
+ required: []
424
+ },
425
+ handler: withLogging('get_templates', async () => {
426
+ const data = await apiClient.get('/strategies/templates');
427
+ return JSON.stringify(data);
428
+ })
429
+ },
430
+ {
431
+ name: 'subscribe_template',
432
+ description: 'Subscribe to a strategy template. Clones the template config into a new strategy for the user. Requires pilot+ plan.',
433
+ inputSchema: {
434
+ type: 'object',
435
+ properties: {
436
+ template_id: { type: 'string', description: 'The UUID of the template to subscribe to' }
437
+ },
438
+ required: ['template_id']
439
+ },
440
+ handler: withLogging('subscribe_template', async ({ template_id }) => {
441
+ const data = await apiClient.post(`/strategies/templates/${template_id}/subscribe`);
442
+ return JSON.stringify(data);
443
+ })
444
+ },
445
+ {
446
+ name: 'follow_strategy',
447
+ description: 'Start copy trading a public strategy. Creates a shadow strategy that mirrors the provider\'s trades with optional scaling. Requires pilot+ plan.',
448
+ inputSchema: {
449
+ type: 'object',
450
+ properties: {
451
+ strategy_id: { type: 'string', description: 'The UUID of the public strategy to follow' },
452
+ scale_factor: { type: 'number', description: 'Trade size multiplier (0.1-2.0, default 1.0)' },
453
+ max_trade_btc: { type: 'number', description: 'Maximum trade size in BTC (default 0.01)' }
454
+ },
455
+ required: ['strategy_id']
456
+ },
457
+ handler: withLogging('follow_strategy', async ({ strategy_id, scale_factor, max_trade_btc }) => {
458
+ const body = {};
459
+ if (scale_factor !== undefined) body.scale_factor = scale_factor;
460
+ if (max_trade_btc !== undefined) body.max_trade_btc = max_trade_btc;
461
+ const data = await apiClient.post(`/strategies/${strategy_id}/follow`, body);
462
+ return JSON.stringify(data);
463
+ })
464
+ },
465
+ {
466
+ name: 'unfollow_strategy',
467
+ description: 'Stop copy trading a strategy. Pauses the shadow strategy and removes the copy trading link.',
468
+ inputSchema: {
469
+ type: 'object',
470
+ properties: {
471
+ strategy_id: { type: 'string', description: 'The UUID of the strategy to unfollow' }
472
+ },
473
+ required: ['strategy_id']
474
+ },
475
+ handler: withLogging('unfollow_strategy', async ({ strategy_id }) => {
476
+ const data = await apiClient.delete(`/strategies/${strategy_id}/follow`);
477
+ return JSON.stringify(data);
478
+ })
479
+ },
480
+ ];
481
+
396
482
  // Export all tools grouped by scope
397
483
  module.exports = {
398
484
  readTools,
@@ -403,6 +489,7 @@ module.exports = {
403
489
  strategyTools,
404
490
  intentTools,
405
491
  performanceTools,
492
+ marketplaceTools,
406
493
  allTools: [
407
494
  ...readTools,
408
495
  ...tradeTools,
@@ -411,6 +498,7 @@ module.exports = {
411
498
  ...sendTools,
412
499
  ...strategyTools,
413
500
  ...intentTools,
414
- ...performanceTools
501
+ ...performanceTools,
502
+ ...marketplaceTools,
415
503
  ]
416
504
  };
@@ -14,7 +14,7 @@ const intentTools = [
14
14
  type: 'object',
15
15
  properties: {
16
16
  strategy_id: { type: 'string', description: 'Optional: link to a strategy' },
17
- action: { type: 'string', description: 'Trading action', enum: ['execute_swap', 'add_liquidity', 'remove_liquidity', 'place_order'] },
17
+ action: { type: 'string', description: 'Trading action', enum: ['execute_swap', 'add_liquidity', 'remove_liquidity', 'zap_liquidity', 'place_order', 'vault_to_hot'] },
18
18
  params: {
19
19
  type: 'object',
20
20
  description: 'Action parameters. Swap: {token_in, token_out, amount_in, max_slippage_bps}. Liquidity: {pool_id, amount_a, amount_b}. Order: {pair_id, side, type, amount, price}.'