troxy-cli 1.0.2 → 1.0.4
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/package.json +1 -1
- package/src/api.js +1 -1
- package/src/init.js +93 -6
- package/src/mcp-server.js +5 -3
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -49,7 +49,7 @@ export const api = {
|
|
|
49
49
|
evaluate: (body, apiKey) => request('POST', '/evaluate', { apiKey, body }),
|
|
50
50
|
|
|
51
51
|
// MCP heartbeat (agent API key)
|
|
52
|
-
mcpHeartbeat: (apiKey) => request('POST', '/mcp/heartbeat', { apiKey }),
|
|
52
|
+
mcpHeartbeat: (apiKey, agentName) => request('POST', '/mcp/heartbeat', { apiKey, body: agentName ? { agent_name: agentName } : undefined }),
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
// Named export for backwards compat with init.js + mcp-server.js
|
package/src/init.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import fs
|
|
2
|
-
import os
|
|
3
|
-
import path
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import readline from 'readline';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
import { saveConfig } from './config.js';
|
|
7
|
+
import { evaluatePayment } from './api.js';
|
|
8
|
+
|
|
9
|
+
function prompt(question) {
|
|
10
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
11
|
+
return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans.trim()); }));
|
|
12
|
+
}
|
|
6
13
|
|
|
7
14
|
// MCP config locations per client and platform
|
|
8
15
|
const MCP_CLIENTS = [
|
|
@@ -66,8 +73,15 @@ export async function runInit({ key } = {}) {
|
|
|
66
73
|
console.log('✓');
|
|
67
74
|
}
|
|
68
75
|
|
|
76
|
+
// Ask for agent name
|
|
77
|
+
const agentName = await prompt(' What would you like to name this agent? (e.g. "Shopping Bot"): ');
|
|
78
|
+
if (!agentName) {
|
|
79
|
+
console.error('\n Error: agent name is required.\n');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
69
83
|
// Save config
|
|
70
|
-
saveConfig({ apiKey: key });
|
|
84
|
+
saveConfig({ apiKey: key, agentName });
|
|
71
85
|
console.log(' Config saved (~/.troxy/config.json) ✓');
|
|
72
86
|
|
|
73
87
|
// Detect and patch MCP clients
|
|
@@ -96,10 +110,83 @@ export async function runInit({ key } = {}) {
|
|
|
96
110
|
console.log('\n Restart your MCP client to activate Troxy.');
|
|
97
111
|
}
|
|
98
112
|
|
|
113
|
+
// Install background service so MCP server survives reboots
|
|
114
|
+
console.log('\n Setting up background service...');
|
|
115
|
+
try {
|
|
116
|
+
installService(key, agentName);
|
|
117
|
+
console.log(' Background service installed ✓');
|
|
118
|
+
} catch (err) {
|
|
119
|
+
console.log(` Background service ✗ (${err.message})`);
|
|
120
|
+
console.log(' You can start it manually with: troxy mcp &');
|
|
121
|
+
}
|
|
122
|
+
|
|
99
123
|
console.log('\n Your payments are now protected.');
|
|
100
124
|
console.log(' Dashboard → https://dashboard.troxy.ai\n');
|
|
101
125
|
}
|
|
102
126
|
|
|
127
|
+
function installService(apiKey, agentName) {
|
|
128
|
+
const platform = process.platform;
|
|
129
|
+
const troxy = process.execPath.replace(/node$/, 'troxy') ;
|
|
130
|
+
|
|
131
|
+
if (platform === 'linux') {
|
|
132
|
+
const unit = `[Unit]
|
|
133
|
+
Description=Troxy MCP Server
|
|
134
|
+
After=network.target
|
|
135
|
+
|
|
136
|
+
[Service]
|
|
137
|
+
ExecStart=${troxy} mcp
|
|
138
|
+
Restart=always
|
|
139
|
+
RestartSec=10
|
|
140
|
+
User=${os.userInfo().username}
|
|
141
|
+
Environment=TROXY_API_KEY=${apiKey}
|
|
142
|
+
Environment=TROXY_AGENT_NAME=${agentName}
|
|
143
|
+
|
|
144
|
+
[Install]
|
|
145
|
+
WantedBy=multi-user.target
|
|
146
|
+
`;
|
|
147
|
+
fs.writeFileSync('/tmp/troxy-mcp.service', unit);
|
|
148
|
+
execSync('sudo mv /tmp/troxy-mcp.service /etc/systemd/system/troxy-mcp.service');
|
|
149
|
+
execSync('sudo systemctl daemon-reload');
|
|
150
|
+
execSync('sudo systemctl enable troxy-mcp');
|
|
151
|
+
execSync('sudo systemctl restart troxy-mcp');
|
|
152
|
+
|
|
153
|
+
} else if (platform === 'darwin') {
|
|
154
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
155
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
156
|
+
<plist version="1.0">
|
|
157
|
+
<dict>
|
|
158
|
+
<key>Label</key>
|
|
159
|
+
<string>ai.troxy.mcp</string>
|
|
160
|
+
<key>ProgramArguments</key>
|
|
161
|
+
<array>
|
|
162
|
+
<string>${troxy}</string>
|
|
163
|
+
<string>mcp</string>
|
|
164
|
+
</array>
|
|
165
|
+
<key>EnvironmentVariables</key>
|
|
166
|
+
<dict>
|
|
167
|
+
<key>TROXY_API_KEY</key>
|
|
168
|
+
<string>${apiKey}</string>
|
|
169
|
+
<key>TROXY_AGENT_NAME</key>
|
|
170
|
+
<string>${agentName}</string>
|
|
171
|
+
</dict>
|
|
172
|
+
<key>RunAtLoad</key>
|
|
173
|
+
<true/>
|
|
174
|
+
<key>KeepAlive</key>
|
|
175
|
+
<true/>
|
|
176
|
+
</dict>
|
|
177
|
+
</plist>
|
|
178
|
+
`;
|
|
179
|
+
const plistPath = path.join(os.homedir(), 'Library/LaunchAgents/ai.troxy.mcp.plist');
|
|
180
|
+
fs.mkdirSync(path.dirname(plistPath), { recursive: true });
|
|
181
|
+
fs.writeFileSync(plistPath, plist);
|
|
182
|
+
try { execSync(`launchctl unload ${plistPath} 2>/dev/null`); } catch {}
|
|
183
|
+
execSync(`launchctl load ${plistPath}`);
|
|
184
|
+
|
|
185
|
+
} else {
|
|
186
|
+
throw new Error('Auto-start not supported on this platform. Start manually: troxy mcp &');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
103
190
|
function mcpEntry(apiKey) {
|
|
104
191
|
return {
|
|
105
192
|
troxy: {
|
package/src/mcp-server.js
CHANGED
|
@@ -8,8 +8,9 @@ import { loadConfig } from './config.js';
|
|
|
8
8
|
import { evaluatePayment, api } from './api.js';
|
|
9
9
|
|
|
10
10
|
export async function runMcp() {
|
|
11
|
-
const config
|
|
12
|
-
const apiKey
|
|
11
|
+
const config = loadConfig();
|
|
12
|
+
const apiKey = process.env.TROXY_API_KEY || config?.apiKey;
|
|
13
|
+
const agentName = process.env.TROXY_AGENT_NAME || config?.agentName;
|
|
13
14
|
|
|
14
15
|
if (!apiKey) {
|
|
15
16
|
process.stderr.write(
|
|
@@ -70,6 +71,7 @@ export async function runMcp() {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
const args = request.params.arguments ?? {};
|
|
74
|
+
if (agentName && !args.agent) args.agent = agentName;
|
|
73
75
|
const result = await evaluatePayment(args, apiKey);
|
|
74
76
|
|
|
75
77
|
if (result.error) {
|
|
@@ -109,7 +111,7 @@ export async function runMcp() {
|
|
|
109
111
|
// Must be set up before server.connect() since stdio transport keeps the
|
|
110
112
|
// event loop running but connect() may not return in all environments.
|
|
111
113
|
const sendHeartbeat = () =>
|
|
112
|
-
api.mcpHeartbeat(apiKey)
|
|
114
|
+
api.mcpHeartbeat(apiKey, agentName)
|
|
113
115
|
.then(() => process.stderr.write('[troxy] heartbeat ok\n'))
|
|
114
116
|
.catch(err => process.stderr.write(`[troxy] heartbeat failed: ${err.message}\n`));
|
|
115
117
|
sendHeartbeat();
|