opencode-toolbox 0.9.0 → 0.10.3
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/README.md +27 -7
- package/dist/index.js +118 -13
- package/package.json +5 -1
- package/toolbox.schema.json +2 -0
package/README.md
CHANGED
|
@@ -168,6 +168,9 @@ Returns a comprehensive status object:
|
|
|
168
168
|
{
|
|
169
169
|
"plugin": {
|
|
170
170
|
"initialized": true,
|
|
171
|
+
"initState": "ready",
|
|
172
|
+
"initMode": "eager",
|
|
173
|
+
"initDurationMs": 1234,
|
|
171
174
|
"configPath": "/Users/username/.config/opencode/toolbox.jsonc",
|
|
172
175
|
"uptime": 123.45,
|
|
173
176
|
"searches": 23,
|
|
@@ -185,8 +188,9 @@ Returns a comprehensive status object:
|
|
|
185
188
|
"name": "time",
|
|
186
189
|
"status": "connected",
|
|
187
190
|
"type": "local",
|
|
188
|
-
"toolCount":
|
|
191
|
+
"toolCount": 2,
|
|
189
192
|
"error": null,
|
|
193
|
+
"commandString": "uvx mcp-server-time",
|
|
190
194
|
"healthy": true
|
|
191
195
|
},
|
|
192
196
|
{
|
|
@@ -195,6 +199,7 @@ Returns a comprehensive status object:
|
|
|
195
199
|
"type": "local",
|
|
196
200
|
"toolCount": 12,
|
|
197
201
|
"error": null,
|
|
202
|
+
"commandString": "npx -y @anthropic/mcp-github",
|
|
198
203
|
"healthy": true
|
|
199
204
|
},
|
|
200
205
|
{
|
|
@@ -202,16 +207,25 @@ Returns a comprehensive status object:
|
|
|
202
207
|
"status": "error",
|
|
203
208
|
"type": "remote",
|
|
204
209
|
"toolCount": 0,
|
|
205
|
-
"error": "
|
|
210
|
+
"error": "Connection timeout after 5000ms",
|
|
211
|
+
"url": "https://mcp.example.com/weather",
|
|
206
212
|
"healthy": false
|
|
207
213
|
}
|
|
208
214
|
]
|
|
209
215
|
},
|
|
210
216
|
"tools": {
|
|
211
|
-
"total":
|
|
212
|
-
"
|
|
217
|
+
"total": 14,
|
|
218
|
+
"indexed": 14,
|
|
213
219
|
"serversWithTools": 2
|
|
214
220
|
},
|
|
221
|
+
"toolboxTools": [
|
|
222
|
+
"toolbox_search_bm25",
|
|
223
|
+
"toolbox_search_regex",
|
|
224
|
+
"toolbox_execute",
|
|
225
|
+
"toolbox_status",
|
|
226
|
+
"toolbox_perf",
|
|
227
|
+
"toolbox_test"
|
|
228
|
+
],
|
|
215
229
|
"health": {
|
|
216
230
|
"status": "degraded",
|
|
217
231
|
"message": "1 server(s) failed to connect"
|
|
@@ -226,7 +240,7 @@ Returns a comprehensive status object:
|
|
|
226
240
|
|
|
227
241
|
### /toolbox-status Slash Command
|
|
228
242
|
|
|
229
|
-
The plugin automatically creates
|
|
243
|
+
The plugin automatically creates and maintains the `/toolbox-status` slash command:
|
|
230
244
|
|
|
231
245
|
```
|
|
232
246
|
~/.config/opencode/command/toolbox-status.md
|
|
@@ -234,6 +248,8 @@ The plugin automatically creates a `/toolbox-status` slash command on first laun
|
|
|
234
248
|
|
|
235
249
|
Use it in OpenCode by typing `/toolbox-status` to get a formatted status report.
|
|
236
250
|
|
|
251
|
+
> **Note:** The command file auto-updates when the plugin version changes.
|
|
252
|
+
|
|
237
253
|
### toolbox_perf
|
|
238
254
|
|
|
239
255
|
Get detailed performance metrics for the toolbox plugin:
|
|
@@ -340,8 +356,10 @@ grep "WARN" ~/.local/share/opencode/toolbox.log
|
|
|
340
356
|
**Log format:**
|
|
341
357
|
```
|
|
342
358
|
2026-01-08T12:34:56.789Z [INFO] Toolbox plugin loaded successfully {"configPath":"...","serverCount":6}
|
|
343
|
-
2026-01-08T12:34:57.
|
|
344
|
-
2026-01-08T12:34:57.
|
|
359
|
+
2026-01-08T12:34:57.100Z [INFO] time - connection time: 648.12ms, indexed 2 tools in 0.07ms
|
|
360
|
+
2026-01-08T12:34:57.200Z [INFO] github - connection time: 892.45ms, indexed 12 tools in 0.15ms
|
|
361
|
+
2026-01-08T12:34:58.500Z [INFO] Initialization complete in 1723.45ms: 2/3 servers, 14 tools indexed
|
|
362
|
+
2026-01-08T12:34:58.501Z [WARN] Server weather failed: Connection timeout after 5000ms
|
|
345
363
|
2026-01-08T12:35:00.456Z [INFO] BM25 search completed: "web search" -> 3 results
|
|
346
364
|
```
|
|
347
365
|
|
|
@@ -384,6 +402,8 @@ This shows:
|
|
|
384
402
|
4. For remote servers, verify URL is accessible
|
|
385
403
|
5. Check environment variables are set correctly
|
|
386
404
|
|
|
405
|
+
> **Note:** Connection retries use exponential backoff (100ms → 200ms → 400ms..., max 30s) before failing.
|
|
406
|
+
|
|
387
407
|
### Execute fails
|
|
388
408
|
|
|
389
409
|
1. Run `toolbox_status({})` to check server health
|
package/dist/index.js
CHANGED
|
@@ -19267,7 +19267,7 @@ function tool(input) {
|
|
|
19267
19267
|
}
|
|
19268
19268
|
tool.schema = exports_external;
|
|
19269
19269
|
// src/plugin.ts
|
|
19270
|
-
import { appendFile, mkdir, writeFile,
|
|
19270
|
+
import { appendFile, mkdir as mkdir2, writeFile as writeFile2, readFile } from "fs/promises";
|
|
19271
19271
|
|
|
19272
19272
|
// node_modules/zod/v4/classic/external.js
|
|
19273
19273
|
var exports_external2 = {};
|
|
@@ -32812,10 +32812,14 @@ var RemoteServerConfigSchema = exports_external2.object({
|
|
|
32812
32812
|
url: exports_external2.string().url().describe("Remote MCP endpoint URL"),
|
|
32813
32813
|
headers: exports_external2.record(exports_external2.string(), exports_external2.string()).optional().describe("HTTP headers for authentication")
|
|
32814
32814
|
});
|
|
32815
|
-
var ServerConfigSchema = exports_external2.
|
|
32815
|
+
var ServerConfigSchema = exports_external2.object({
|
|
32816
|
+
type: exports_external2.enum(["local", "remote"], {
|
|
32817
|
+
error: 'Server "type" must be "local" or "remote"'
|
|
32818
|
+
})
|
|
32819
|
+
}).passthrough().pipe(exports_external2.discriminatedUnion("type", [
|
|
32816
32820
|
LocalServerConfigSchema,
|
|
32817
32821
|
RemoteServerConfigSchema
|
|
32818
|
-
]);
|
|
32822
|
+
]));
|
|
32819
32823
|
var ConnectionConfigSchema = exports_external2.object({
|
|
32820
32824
|
connectTimeout: exports_external2.number().min(100).max(60000).default(5000),
|
|
32821
32825
|
requestTimeout: exports_external2.number().min(100).max(300000).default(30000),
|
|
@@ -32828,6 +32832,7 @@ var SettingsConfigSchema = exports_external2.object({
|
|
|
32828
32832
|
connection: ConnectionConfigSchema.optional()
|
|
32829
32833
|
});
|
|
32830
32834
|
var ConfigSchema = exports_external2.object({
|
|
32835
|
+
$schema: exports_external2.string().optional(),
|
|
32831
32836
|
mcp: exports_external2.record(exports_external2.string(), ServerConfigSchema),
|
|
32832
32837
|
settings: SettingsConfigSchema.optional()
|
|
32833
32838
|
});
|
|
@@ -33636,6 +33641,47 @@ var ParseErrorCode;
|
|
|
33636
33641
|
})(ParseErrorCode || (ParseErrorCode = {}));
|
|
33637
33642
|
|
|
33638
33643
|
// src/config/loader.ts
|
|
33644
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
33645
|
+
import { dirname } from "path";
|
|
33646
|
+
var NPM_PACKAGE = "opencode-toolbox";
|
|
33647
|
+
function getSchemaUrl(_version) {
|
|
33648
|
+
return `https://unpkg.com/${NPM_PACKAGE}@latest/toolbox.schema.json`;
|
|
33649
|
+
}
|
|
33650
|
+
function generateDefaultConfig(version3) {
|
|
33651
|
+
const schemaUrl = getSchemaUrl(version3);
|
|
33652
|
+
return `{
|
|
33653
|
+
"$schema": "${schemaUrl}",
|
|
33654
|
+
"mcp": {
|
|
33655
|
+
// Add your MCP servers here
|
|
33656
|
+
// Example:
|
|
33657
|
+
// "time": {
|
|
33658
|
+
// "type": "local",
|
|
33659
|
+
// "command": ["npx", "-y", "@anthropic/mcp-time"]
|
|
33660
|
+
// }
|
|
33661
|
+
},
|
|
33662
|
+
"settings": {
|
|
33663
|
+
"defaultLimit": 5,
|
|
33664
|
+
"initMode": "eager"
|
|
33665
|
+
}
|
|
33666
|
+
}
|
|
33667
|
+
`;
|
|
33668
|
+
}
|
|
33669
|
+
async function createDefaultConfigIfMissing(filePath, version3) {
|
|
33670
|
+
try {
|
|
33671
|
+
const file3 = Bun.file(filePath);
|
|
33672
|
+
const exists = await file3.exists();
|
|
33673
|
+
if (exists) {
|
|
33674
|
+
return false;
|
|
33675
|
+
}
|
|
33676
|
+
const dir = dirname(filePath);
|
|
33677
|
+
await mkdir(dir, { recursive: true });
|
|
33678
|
+
const content = generateDefaultConfig(version3);
|
|
33679
|
+
await writeFile(filePath, content, "utf-8");
|
|
33680
|
+
return true;
|
|
33681
|
+
} catch {
|
|
33682
|
+
return false;
|
|
33683
|
+
}
|
|
33684
|
+
}
|
|
33639
33685
|
function interpolateEnvVars(obj) {
|
|
33640
33686
|
if (typeof obj === "string") {
|
|
33641
33687
|
return obj.replace(/\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, varName) => {
|
|
@@ -38343,7 +38389,10 @@ class MCPManager extends EventEmitter {
|
|
|
38343
38389
|
} catch (error92) {
|
|
38344
38390
|
lastError = error92 instanceof Error ? error92 : new Error(String(error92));
|
|
38345
38391
|
if (attempt < maxAttempts) {
|
|
38346
|
-
|
|
38392
|
+
const baseDelay = this.connectionConfig.retryDelay;
|
|
38393
|
+
const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
|
|
38394
|
+
const delayMs = Math.min(exponentialDelay, 30000);
|
|
38395
|
+
await sleep(delayMs);
|
|
38347
38396
|
}
|
|
38348
38397
|
}
|
|
38349
38398
|
}
|
|
@@ -38379,7 +38428,7 @@ class MCPManager extends EventEmitter {
|
|
|
38379
38428
|
});
|
|
38380
38429
|
this.clients.set(name, client);
|
|
38381
38430
|
globalProfiler.recordServerConnect(name, connectTime, catalogTools.length, "connected");
|
|
38382
|
-
this.emit("server:connected", name, catalogTools);
|
|
38431
|
+
this.emit("server:connected", name, catalogTools, connectTime);
|
|
38383
38432
|
this.checkPartialReady();
|
|
38384
38433
|
}
|
|
38385
38434
|
checkPartialReady() {
|
|
@@ -38693,6 +38742,7 @@ function generateSignature(tool3) {
|
|
|
38693
38742
|
return `${tool3.id.name}(${argList})`;
|
|
38694
38743
|
}
|
|
38695
38744
|
// src/plugin.ts
|
|
38745
|
+
var PACKAGE_VERSION = "0.8.0";
|
|
38696
38746
|
var DEFAULT_CONFIG_PATH = `${process.env.HOME}/.config/opencode/toolbox.jsonc`;
|
|
38697
38747
|
var LOG_FILE_PATH = `${process.env.HOME}/.local/share/opencode/toolbox.log`;
|
|
38698
38748
|
var LOG_DIR = `${process.env.HOME}/.local/share/opencode`;
|
|
@@ -38702,6 +38752,13 @@ var COMMAND_CONTENT = `---
|
|
|
38702
38752
|
description: Check toolbox plugin status and server health
|
|
38703
38753
|
---
|
|
38704
38754
|
Run toolbox_status({}) tool and show me the results in a readable format.
|
|
38755
|
+
|
|
38756
|
+
Include:
|
|
38757
|
+
1. MCP Servers table (name, type, tools, status)
|
|
38758
|
+
2. Tool distribution chart
|
|
38759
|
+
3. Toolbox's own tools list (from toolboxTools field)
|
|
38760
|
+
4. Health status
|
|
38761
|
+
|
|
38705
38762
|
Highlight any failed servers or issues.
|
|
38706
38763
|
`;
|
|
38707
38764
|
function parseToolName(fullName) {
|
|
@@ -38833,14 +38890,16 @@ function log(level, message, extra) {
|
|
|
38833
38890
|
const extraStr = extra ? ` ${JSON.stringify(extra)}` : "";
|
|
38834
38891
|
const line = `${timestamp} [${level.toUpperCase()}] ${message}${extraStr}
|
|
38835
38892
|
`;
|
|
38836
|
-
|
|
38893
|
+
mkdir2(LOG_DIR, { recursive: true }).then(() => appendFile(LOG_FILE_PATH, line)).catch(() => {});
|
|
38837
38894
|
}
|
|
38838
38895
|
function ensureCommandFile() {
|
|
38839
38896
|
if (isTestEnv)
|
|
38840
38897
|
return;
|
|
38841
|
-
|
|
38842
|
-
|
|
38843
|
-
|
|
38898
|
+
mkdir2(COMMAND_DIR, { recursive: true }).then(() => readFile(COMMAND_FILE_PATH, "utf-8").catch(() => "")).then((existing) => {
|
|
38899
|
+
if (existing !== COMMAND_CONTENT) {
|
|
38900
|
+
return writeFile2(COMMAND_FILE_PATH, COMMAND_CONTENT).then(() => log("info", existing ? "Updated /toolbox-status command file" : "Created /toolbox-status command file"));
|
|
38901
|
+
}
|
|
38902
|
+
}).catch(() => {});
|
|
38844
38903
|
}
|
|
38845
38904
|
function generateSystemPrompt(configuredServers) {
|
|
38846
38905
|
const registry3 = configuredServers.length > 0 ? configuredServers.map((s) => `${s}_*`).join(`
|
|
@@ -38897,9 +38956,19 @@ var ToolboxPlugin = async (ctx) => {
|
|
|
38897
38956
|
const pluginLoadStart = performance.now();
|
|
38898
38957
|
const { client } = ctx;
|
|
38899
38958
|
const configPath = process.env.OPENCODE_TOOLBOX_CONFIG || DEFAULT_CONFIG_PATH;
|
|
38959
|
+
if (!isTestEnv) {
|
|
38960
|
+
const created = await createDefaultConfigIfMissing(configPath, PACKAGE_VERSION);
|
|
38961
|
+
if (created) {
|
|
38962
|
+
log("info", `Created default config file at ${configPath}`);
|
|
38963
|
+
}
|
|
38964
|
+
}
|
|
38900
38965
|
const configResult = await loadConfig(configPath);
|
|
38901
38966
|
if (!configResult.success) {
|
|
38902
|
-
const
|
|
38967
|
+
const formattedErrors = configResult.error.issues.map((issue3) => {
|
|
38968
|
+
const path = issue3.path.length > 0 ? `at "${issue3.path.join(".")}"` : "";
|
|
38969
|
+
return `${issue3.message} ${path}`.trim();
|
|
38970
|
+
}).join("; ");
|
|
38971
|
+
const errorMsg = `Failed to load config from ${configPath}: ${formattedErrors}`;
|
|
38903
38972
|
log("error", errorMsg);
|
|
38904
38973
|
return {};
|
|
38905
38974
|
}
|
|
@@ -38927,12 +38996,12 @@ var ToolboxPlugin = async (ctx) => {
|
|
|
38927
38996
|
initMode,
|
|
38928
38997
|
loadDurationMs: Math.round(pluginLoadDuration * 100) / 100
|
|
38929
38998
|
});
|
|
38930
|
-
mcpManager.on("server:connected", (serverName, tools) => {
|
|
38999
|
+
mcpManager.on("server:connected", (serverName, tools, connectTime) => {
|
|
38931
39000
|
const startTime = performance.now();
|
|
38932
39001
|
bm25Index.addToolsBatch(tools);
|
|
38933
39002
|
const indexTime = performance.now() - startTime;
|
|
38934
39003
|
globalProfiler.recordIncrementalUpdate(tools.length);
|
|
38935
|
-
log("info",
|
|
39004
|
+
log("info", `${serverName} - connection time: ${connectTime.toFixed(2)}ms, indexed ${tools.length} tools in ${indexTime.toFixed(2)}ms`);
|
|
38936
39005
|
});
|
|
38937
39006
|
mcpManager.on("server:error", (serverName, error92) => {
|
|
38938
39007
|
log("warn", `Server ${serverName} failed: ${error92}`);
|
|
@@ -39103,9 +39172,34 @@ var ToolboxPlugin = async (ctx) => {
|
|
|
39103
39172
|
error: errorMsg,
|
|
39104
39173
|
durationMs: duration5
|
|
39105
39174
|
});
|
|
39175
|
+
const server = mcpManager.getServer(parsed.serverName);
|
|
39176
|
+
const configuredServer = config3.mcp[parsed.serverName];
|
|
39177
|
+
const serverInfo = server ? {
|
|
39178
|
+
name: server.name,
|
|
39179
|
+
status: server.status,
|
|
39180
|
+
type: server.config.type,
|
|
39181
|
+
error: server.error || null,
|
|
39182
|
+
command: server.config.type === "local" ? server.config.command || null : undefined,
|
|
39183
|
+
commandString: server.config.type === "local" && server.config.command ? server.config.command.join(" ") : undefined,
|
|
39184
|
+
url: server.config.type === "remote" ? server.config.url || null : undefined
|
|
39185
|
+
} : configuredServer ? {
|
|
39186
|
+
name: parsed.serverName,
|
|
39187
|
+
status: "unknown",
|
|
39188
|
+
type: configuredServer.type,
|
|
39189
|
+
error: null,
|
|
39190
|
+
command: configuredServer.type === "local" ? configuredServer.command || null : undefined,
|
|
39191
|
+
commandString: configuredServer.type === "local" && configuredServer.command ? configuredServer.command.join(" ") : undefined,
|
|
39192
|
+
url: configuredServer.type === "remote" ? configuredServer.url || null : undefined
|
|
39193
|
+
} : {
|
|
39194
|
+
name: parsed.serverName,
|
|
39195
|
+
status: "unknown",
|
|
39196
|
+
type: "unknown",
|
|
39197
|
+
error: null
|
|
39198
|
+
};
|
|
39106
39199
|
return JSON.stringify({
|
|
39107
39200
|
success: false,
|
|
39108
|
-
error: errorMsg
|
|
39201
|
+
error: errorMsg,
|
|
39202
|
+
server: serverInfo
|
|
39109
39203
|
});
|
|
39110
39204
|
}
|
|
39111
39205
|
}
|
|
@@ -39155,6 +39249,9 @@ var ToolboxPlugin = async (ctx) => {
|
|
|
39155
39249
|
type: server.config.type,
|
|
39156
39250
|
toolCount: server.tools.length,
|
|
39157
39251
|
error: server.error || null,
|
|
39252
|
+
command: server.config.type === "local" ? server.config.command || null : undefined,
|
|
39253
|
+
commandString: server.config.type === "local" && server.config.command ? server.config.command.join(" ") : undefined,
|
|
39254
|
+
url: server.config.type === "remote" ? server.config.url || null : undefined,
|
|
39158
39255
|
healthy: server.status === "connected"
|
|
39159
39256
|
}))
|
|
39160
39257
|
},
|
|
@@ -39163,6 +39260,14 @@ var ToolboxPlugin = async (ctx) => {
|
|
|
39163
39260
|
indexed: bm25Index.size,
|
|
39164
39261
|
serversWithTools: servers.filter((s) => s.tools.length > 0).length
|
|
39165
39262
|
},
|
|
39263
|
+
toolboxTools: [
|
|
39264
|
+
"toolbox_search_bm25",
|
|
39265
|
+
"toolbox_search_regex",
|
|
39266
|
+
"toolbox_execute",
|
|
39267
|
+
"toolbox_status",
|
|
39268
|
+
"toolbox_perf",
|
|
39269
|
+
"toolbox_test"
|
|
39270
|
+
],
|
|
39166
39271
|
health: {
|
|
39167
39272
|
status: failedServers.length === 0 && servers.length > 0 ? "healthy" : failedServers.length > 0 ? "degraded" : "unknown",
|
|
39168
39273
|
message: servers.length === 0 ? "No servers configured" : failedServers.length === 0 ? "All servers connected" : `${failedServers.length} server(s) failed to connect`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-toolbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.3",
|
|
4
4
|
"description": "Tool Search Tool Plugin for OpenCode - search and execute tools from MCP servers on-demand",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"mcp"
|
|
35
35
|
],
|
|
36
36
|
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/assagman/opencode-toolbox"
|
|
40
|
+
},
|
|
37
41
|
"devDependencies": {
|
|
38
42
|
"@types/bun": "latest",
|
|
39
43
|
"typescript": "^5.9.3"
|
package/toolbox.schema.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://unpkg.com/opencode-toolbox@latest/toolbox.schema.json",
|
|
4
|
+
"allowTrailingCommas": true,
|
|
5
|
+
"allowComments": true,
|
|
4
6
|
"title": "OpenCode Toolbox Configuration",
|
|
5
7
|
"description": "Configuration schema for opencode-toolbox plugin",
|
|
6
8
|
"type": "object",
|