@otwa/mcp-server 0.1.0 → 0.3.0
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/CHANGELOG.md +24 -1
- package/README.md +70 -3
- package/dist/http/index.js +8 -7
- package/dist/http/index.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/server.js +12 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/_register.js +37 -1
- package/dist/tools/_register.js.map +1 -1
- package/dist/tools/reseller.js +19 -0
- package/dist/tools/reseller.js.map +1 -0
- package/dist/util/env.js +5 -1
- package/dist/util/env.js.map +1 -1
- package/dist/util/telemetry.js +88 -0
- package/dist/util/telemetry.js.map +1 -0
- package/package.json +8 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.3.0 — 2026-05-26
|
|
4
|
+
|
|
5
|
+
- **🔧 Fix: default API base now includes `/api` global-prefix** (`https://api.otwa.cloud/api`). otwa-cloud-api uses NestJS `setGlobalPrefix('api')` so every endpoint is under `/api/v1/*`. v0.1.x + v0.2.0 shipped with the prefix missing — every stdio tool call 404'd. Latent bug closed.
|
|
6
|
+
- **Optional fire-and-forget telemetry** for tool calls. Posts `{toolName, transport, success, errorCode?, durationMs, clientLabel?}` to `api.otwa.cloud/api/v1/integrations/mcp/usage` after every invocation, using the caller's own API key.
|
|
7
|
+
- **Hosted** (`mcp.otwa.cloud`): always on. We already see every request server-side; logging metadata has no privacy delta.
|
|
8
|
+
- **stdio**: OFF by default. Set `OTWA_TELEMETRY=1` to opt in. The local CLI never makes surprise network calls without an explicit env flip.
|
|
9
|
+
- Single integration point: `instrumentRegisterTool()` in `_register.ts` monkey-patches `server.registerTool` so every tool — current and future — is auto-instrumented. Per-surface tool files don't need to know about telemetry at all.
|
|
10
|
+
- Failure classification: `classifyErrorFromResult()` maps `isError: true` results back to typed codes (`unauthorized | forbidden | payment_required | not_found | conflict | validation_failed | rate_limited | upstream_error | error`) so dashboard counters bucket failures meaningfully.
|
|
11
|
+
|
|
12
|
+
> v0.2.0 tag exists on GitHub but never published to npm (Actions outage 2026-05-26 dropped the event). v0.3.0 supersedes it with all 0.2.0 content + the prefix fix above.
|
|
13
|
+
|
|
14
|
+
## 0.2.0 — 2026-05-26
|
|
15
|
+
|
|
16
|
+
- New tool `otwa_get_reseller_state` (scope: `account:read`) — returns reseller tier, discount %, rolling 30-day GMV, and next-tier progression. Useful for resellers asking the AI "how close am I to the next tier?"
|
|
17
|
+
- Expanded README install instructions: now covers Claude Code, **Claude Desktop**, Cursor, Windsurf, **VS Code (Copilot Agent Mode)**, Zed, Continue, and **OpenCode**.
|
|
18
|
+
- Added README status badges: npm version, CI, license, Node engines, MCP transport.
|
|
19
|
+
- Added vitest scaffold under `test/` — 16 smoke tests for `_helpers`, `errors`, and the full tool-registration surface. CI now runs `pnpm test` on every push (Node 20 + 22 matrix).
|
|
20
|
+
|
|
21
|
+
## 0.1.1 — 2026-05-25
|
|
22
|
+
|
|
23
|
+
- Renamed bin entries from `otwa-mcp` / `otwa-mcp-http` to `mcp-server` / `mcp-server-http` so the unscoped package name matches the default bin — this makes `npx -y @otwa/mcp-server` resolve correctly (npx requires the bin name to match the unscoped package name when multiple bins exist).
|
|
24
|
+
- Help text now references `npx @otwa/mcp-server` instead of the old `otwa-mcp` binary.
|
|
25
|
+
|
|
26
|
+
## 0.1.0 — 2026-05-25
|
|
4
27
|
|
|
5
28
|
Initial release.
|
|
6
29
|
|
package/README.md
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
# @otwa/mcp-server
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@otwa/mcp-server)
|
|
4
|
+
[](https://github.com/otwacloud/mcp-server/actions/workflows/ci.yml)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
[](https://modelcontextprotocol.io)
|
|
8
|
+
|
|
3
9
|
Official Model Context Protocol server for [otwa.cloud](https://otwa.cloud).
|
|
4
|
-
Provision and manage servers from Claude Code, Cursor, Windsurf,
|
|
5
|
-
other MCP-capable AI tool — just by
|
|
10
|
+
Provision and manage servers from Claude Code, Claude Desktop, Cursor, Windsurf,
|
|
11
|
+
VS Code, Zed, Continue, OpenCode, or any other MCP-capable AI tool — just by
|
|
12
|
+
talking to it.
|
|
6
13
|
|
|
7
14
|
```
|
|
8
15
|
> "Spin up a 4 vCPU Ubuntu 22 box in Frankfurt called prod-api-01"
|
|
@@ -61,6 +68,26 @@ claude mcp add otwa npx -y @otwa/mcp-server
|
|
|
61
68
|
claude mcp env otwa OTWA_API_KEY=otwa_xxxxxxxxxxxxxxxxxxxx
|
|
62
69
|
```
|
|
63
70
|
|
|
71
|
+
#### Claude Desktop
|
|
72
|
+
|
|
73
|
+
Add to your `claude_desktop_config.json`
|
|
74
|
+
(`~/Library/Application Support/Claude/` on macOS,
|
|
75
|
+
`%APPDATA%\Claude\` on Windows):
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"mcpServers": {
|
|
80
|
+
"otwa": {
|
|
81
|
+
"command": "npx",
|
|
82
|
+
"args": ["-y", "@otwa/mcp-server"],
|
|
83
|
+
"env": {
|
|
84
|
+
"OTWA_API_KEY": "otwa_xxxxxxxxxxxxxxxxxxxx"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
64
91
|
#### Cursor
|
|
65
92
|
|
|
66
93
|
Add to `~/.cursor/mcp.json`:
|
|
@@ -97,6 +124,25 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
|
97
124
|
}
|
|
98
125
|
```
|
|
99
126
|
|
|
127
|
+
#### VS Code (Copilot Agent Mode)
|
|
128
|
+
|
|
129
|
+
Add to `.vscode/mcp.json` in your workspace:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"servers": {
|
|
134
|
+
"otwa": {
|
|
135
|
+
"type": "stdio",
|
|
136
|
+
"command": "npx",
|
|
137
|
+
"args": ["-y", "@otwa/mcp-server"],
|
|
138
|
+
"env": {
|
|
139
|
+
"OTWA_API_KEY": "otwa_xxxxxxxxxxxxxxxxxxxx"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
100
146
|
#### Zed
|
|
101
147
|
|
|
102
148
|
Add to `~/.config/zed/settings.json`:
|
|
@@ -136,6 +182,24 @@ Add to `~/.continue/config.json` under `experimental.modelContextProtocolServers
|
|
|
136
182
|
}
|
|
137
183
|
```
|
|
138
184
|
|
|
185
|
+
#### OpenCode
|
|
186
|
+
|
|
187
|
+
Add to `opencode.json` (or `opencode.jsonc`) in your config directory:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"$schema": "https://opencode.ai/config.json",
|
|
192
|
+
"mcp": {
|
|
193
|
+
"otwa": {
|
|
194
|
+
"type": "local",
|
|
195
|
+
"command": ["npx", "-y", "@otwa/mcp-server"],
|
|
196
|
+
"environment": { "OTWA_API_KEY": "otwa_xxxxxxxxxxxxxxxxxxxx" },
|
|
197
|
+
"enabled": true
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
139
203
|
### 3. Try it
|
|
140
204
|
|
|
141
205
|
Restart your client and ask:
|
|
@@ -147,7 +211,7 @@ Restart your client and ask:
|
|
|
147
211
|
|
|
148
212
|
## Tools
|
|
149
213
|
|
|
150
|
-
|
|
214
|
+
26 tools across seven surfaces:
|
|
151
215
|
|
|
152
216
|
### Account & catalogue (read-only, `account:read`)
|
|
153
217
|
- `otwa_account` — current account, balance, tier
|
|
@@ -184,6 +248,9 @@ Restart your client and ask:
|
|
|
184
248
|
- `otwa_create_webhook` *(webhooks:write)*
|
|
185
249
|
- `otwa_delete_webhook` *(webhooks:write)*
|
|
186
250
|
|
|
251
|
+
### Reseller
|
|
252
|
+
- `otwa_get_reseller_state` — reseller tier, discount, rolling 30-day GMV, next-tier progression *(account:read)*
|
|
253
|
+
|
|
187
254
|
## Safety
|
|
188
255
|
|
|
189
256
|
Destructive tools (`otwa_destroy_server`, `otwa_reinstall_server`) require:
|
package/dist/http/index.js
CHANGED
|
@@ -7,13 +7,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const express_1 = __importDefault(require("express"));
|
|
8
8
|
const crypto_1 = require("crypto");
|
|
9
9
|
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
10
|
-
const
|
|
11
|
-
const http_1 = require("../client/http");
|
|
12
|
-
const _register_1 = require("../tools/_register");
|
|
10
|
+
const server_1 = require("../server");
|
|
13
11
|
const version_1 = require("../util/version");
|
|
14
12
|
const PORT = parseInt(process.env.PORT || '3210', 10);
|
|
15
13
|
const HOST = process.env.HOST || '127.0.0.1';
|
|
16
|
-
|
|
14
|
+
// See note in src/util/env.ts — default MUST include the /api globalPrefix.
|
|
15
|
+
const API_BASE = (process.env.OTWA_API_BASE?.trim() || 'https://api.otwa.cloud/api').replace(/\/+$/, '');
|
|
17
16
|
const app = (0, express_1.default)();
|
|
18
17
|
app.disable('x-powered-by');
|
|
19
18
|
app.set('trust proxy', 'loopback');
|
|
@@ -74,9 +73,11 @@ app.post('/mcp', async (req, res) => {
|
|
|
74
73
|
sessionIdGenerator: undefined,
|
|
75
74
|
enableJsonResponse: true,
|
|
76
75
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
// Capture User-Agent (truncated) as the telemetry client label so the SA
|
|
77
|
+
// dashboard can show "X% Claude Code, Y% Cursor, …" without a separate
|
|
78
|
+
// header. Header is optional + untrusted — only kept as a labelling hint.
|
|
79
|
+
const clientLabel = (req.header('user-agent') || '').slice(0, 200) || null;
|
|
80
|
+
const server = (0, server_1.createServer)({ apiKey, apiBase: API_BASE, telemetry: true }, { transport: 'http', clientLabel });
|
|
80
81
|
res.on('close', () => {
|
|
81
82
|
transport.close().catch(() => { });
|
|
82
83
|
server.close().catch(() => { });
|
package/dist/http/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":";;;;;;AACA,sDAA8B;AAE9B,mCAAoC;AACpC,0FAAmG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -53,10 +53,10 @@ function printHelp() {
|
|
|
53
53
|
'Official Model Context Protocol server for otwa.cloud.\n' +
|
|
54
54
|
'\n' +
|
|
55
55
|
'Usage:\n' +
|
|
56
|
-
' otwa-
|
|
57
|
-
'
|
|
58
|
-
' otwa-
|
|
59
|
-
' otwa-
|
|
56
|
+
' npx @otwa/mcp-server Start the stdio MCP server (the normal case —\n' +
|
|
57
|
+
' spawned by Claude Code, Cursor, Windsurf, Zed)\n' +
|
|
58
|
+
' npx @otwa/mcp-server --version Print version and exit\n' +
|
|
59
|
+
' npx @otwa/mcp-server --help Show this help\n' +
|
|
60
60
|
'\n' +
|
|
61
61
|
'Environment:\n' +
|
|
62
62
|
' OTWA_API_KEY Required. Generate at https://otwa.cloud/dashboard/settings/api-keys\n' +
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,wEAAiF;AACjF,qCAAwC;AACxC,oCAAqC;AACrC,4CAA6C;AAE7C,KAAK,UAAU,IAAI;IACjB,2EAA2E;IAC3E,gEAAgE;IAChE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,GAAG,GAAG,IAAA,qBAAW,GAAE,CAAC;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,SAAS,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,IAAI,GAAG,CAAC;IACR,IAAI,CAAC;QACH,GAAG,GAAG,IAAA,aAAO,GAAE,CAAC;IAClB,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,sEAAsE;QACtE,8CAA8C;QAC9C,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC,GAAG,CAAC,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,+BAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;QACvD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,MAAM,IAAI,CAAC,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,IAAA,qBAAW,GAAE,CAAC;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,IAAI;QAC5B,IAAI;QACJ,0DAA0D;QAC1D,IAAI;QACJ,UAAU;QACV
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -5,7 +5,8 @@ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
|
5
5
|
const http_1 = require("./client/http");
|
|
6
6
|
const _register_1 = require("./tools/_register");
|
|
7
7
|
const version_1 = require("./util/version");
|
|
8
|
-
|
|
8
|
+
const telemetry_1 = require("./util/telemetry");
|
|
9
|
+
function createServer(env, opts = {}) {
|
|
9
10
|
const pkg = (0, version_1.packageInfo)();
|
|
10
11
|
const server = new mcp_js_1.McpServer({
|
|
11
12
|
name: pkg.name,
|
|
@@ -15,7 +16,16 @@ function createServer(env) {
|
|
|
15
16
|
apiKey: env.apiKey,
|
|
16
17
|
apiBase: env.apiBase,
|
|
17
18
|
});
|
|
18
|
-
|
|
19
|
+
const transport = opts.transport ?? 'stdio';
|
|
20
|
+
const telemetry = (0, telemetry_1.createTelemetry)({
|
|
21
|
+
apiKey: env.apiKey,
|
|
22
|
+
apiBase: env.apiBase,
|
|
23
|
+
transport,
|
|
24
|
+
// Hosted transport always records; stdio respects OTWA_TELEMETRY env opt-in.
|
|
25
|
+
enabled: transport === 'http' ? true : env.telemetry,
|
|
26
|
+
clientLabel: opts.clientLabel ?? null,
|
|
27
|
+
});
|
|
28
|
+
(0, _register_1.registerAllTools)(server, client, telemetry);
|
|
19
29
|
return server;
|
|
20
30
|
}
|
|
21
31
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;AAgBA,oCAwBC;AAxCD,oEAAoE;AACpE,wCAA2C;AAC3C,iDAAqD;AACrD,4CAA6C;AAE7C,gDAAmD;AAWnD,SAAgB,YAAY,CAAC,GAAY,EAAE,OAA4B,EAAE;IACvE,MAAM,GAAG,GAAG,IAAA,qBAAW,GAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,IAAI,kBAAS,CAAC;QAC3B,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;KACrB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,iBAAU,CAAC;QAC5B,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,OAAO;KACrB,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAA,2BAAe,EAAC;QAChC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS;QACT,6EAA6E;QAC7E,OAAO,EAAE,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS;QACpD,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI;KACtC,CAAC,CAAC;IAEH,IAAA,4BAAgB,EAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/tools/_register.js
CHANGED
|
@@ -1,18 +1,54 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerAllTools = registerAllTools;
|
|
4
|
+
const telemetry_1 = require("../util/telemetry");
|
|
4
5
|
const account_1 = require("./account");
|
|
5
6
|
const billing_1 = require("./billing");
|
|
6
7
|
const catalog_1 = require("./catalog");
|
|
7
8
|
const networking_1 = require("./networking");
|
|
9
|
+
const reseller_1 = require("./reseller");
|
|
8
10
|
const servers_1 = require("./servers");
|
|
9
11
|
const webhooks_1 = require("./webhooks");
|
|
10
|
-
|
|
12
|
+
/** Wrap `server.registerTool` so every tool handler is automatically
|
|
13
|
+
* instrumented with start/finish timing + fire-and-forget telemetry.
|
|
14
|
+
* Single integration point — none of the per-surface tool files need
|
|
15
|
+
* to know about telemetry at all. */
|
|
16
|
+
function instrumentRegisterTool(server, telemetry) {
|
|
17
|
+
if (!telemetry.enabled)
|
|
18
|
+
return;
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
const original = server.registerTool.bind(server);
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
server.registerTool = (name, config, handler) => {
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
const wrapped = async (...args) => {
|
|
25
|
+
const startMs = Date.now();
|
|
26
|
+
try {
|
|
27
|
+
const result = await handler(...args);
|
|
28
|
+
const durationMs = Date.now() - startMs;
|
|
29
|
+
const success = !result?.isError;
|
|
30
|
+
const errorCode = success ? null : (0, telemetry_1.classifyErrorFromResult)(result);
|
|
31
|
+
telemetry.record({ toolName: name, success, errorCode, durationMs });
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
const durationMs = Date.now() - startMs;
|
|
36
|
+
telemetry.record({ toolName: name, success: false, errorCode: 'thrown', durationMs });
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return original(name, config, wrapped);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function registerAllTools(server, client, telemetry) {
|
|
44
|
+
if (telemetry)
|
|
45
|
+
instrumentRegisterTool(server, telemetry);
|
|
11
46
|
(0, account_1.registerAccountTools)(server, client);
|
|
12
47
|
(0, catalog_1.registerCatalogTools)(server, client);
|
|
13
48
|
(0, servers_1.registerServerTools)(server, client);
|
|
14
49
|
(0, networking_1.registerNetworkingTools)(server, client);
|
|
15
50
|
(0, billing_1.registerBillingTools)(server, client);
|
|
16
51
|
(0, webhooks_1.registerWebhookTools)(server, client);
|
|
52
|
+
(0, reseller_1.registerResellerTools)(server, client);
|
|
17
53
|
}
|
|
18
54
|
//# sourceMappingURL=_register.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_register.js","sourceRoot":"","sources":["../../src/tools/_register.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"_register.js","sourceRoot":"","sources":["../../src/tools/_register.ts"],"names":[],"mappings":";;AAyCA,4CAaC;AApDD,iDAAuE;AACvE,uCAAiD;AACjD,uCAAiD;AACjD,uCAAiD;AACjD,6CAAuD;AACvD,yCAAmD;AACnD,uCAAgD;AAChD,yCAAkD;AAElD;;;sCAGsC;AACtC,SAAS,sBAAsB,CAAC,MAAiB,EAAE,SAAoB;IACrE,IAAI,CAAC,SAAS,CAAC,OAAO;QAAE,OAAO;IAC/B,8DAA8D;IAC9D,MAAM,QAAQ,GAAI,MAAc,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3D,8DAA8D;IAC7D,MAAc,CAAC,YAAY,GAAG,CAAC,IAAY,EAAE,MAAW,EAAE,OAAY,EAAE,EAAE;QACzE,8DAA8D;QAC9D,MAAM,OAAO,GAAG,KAAK,EAAE,GAAG,IAAW,EAAE,EAAE;YACvC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;gBACtC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;gBACxC,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;gBACjC,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAA,mCAAuB,EAAC,MAAM,CAAC,CAAC;gBACnE,SAAS,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;gBACrE,OAAO,MAAM,CAAC;YAChB,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;gBACxC,SAAS,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;gBACtF,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;QACF,OAAO,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,gBAAgB,CAC9B,MAAiB,EACjB,MAAkB,EAClB,SAAqB;IAErB,IAAI,SAAS;QAAE,sBAAsB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzD,IAAA,8BAAoB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,IAAA,8BAAoB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,IAAA,6BAAmB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,IAAA,oCAAuB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,IAAA,8BAAoB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,IAAA,+BAAoB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,IAAA,gCAAqB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerResellerTools = registerResellerTools;
|
|
4
|
+
const _helpers_1 = require("./_helpers");
|
|
5
|
+
function registerResellerTools(server, client) {
|
|
6
|
+
server.registerTool('otwa_get_reseller_state', {
|
|
7
|
+
title: 'Get reseller program state',
|
|
8
|
+
description: "Returns the caller's reseller program state: whether they're enrolled, " +
|
|
9
|
+
'current tier and discount percentage, rolling 30-day GMV, next tier ' +
|
|
10
|
+
'progression (GMV required + remaining), and minimum balance threshold. ' +
|
|
11
|
+
'Use this when the user asks about their reseller status, commission, ' +
|
|
12
|
+
'tier, discount, or how close they are to the next tier. Read-only.',
|
|
13
|
+
inputSchema: {},
|
|
14
|
+
}, (0, _helpers_1.safeHandler)(async () => {
|
|
15
|
+
const state = await client.request('/v1/reseller');
|
|
16
|
+
return (0, _helpers_1.jsonResult)(state);
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=reseller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reseller.js","sourceRoot":"","sources":["../../src/tools/reseller.ts"],"names":[],"mappings":";;AAKA,sDAkBC;AApBD,yCAAqD;AAErD,SAAgB,qBAAqB,CAAC,MAAiB,EAAE,MAAkB;IACzE,MAAM,CAAC,YAAY,CACjB,yBAAyB,EACzB;QACE,KAAK,EAAE,4BAA4B;QACnC,WAAW,EACT,yEAAyE;YACzE,sEAAsE;YACtE,yEAAyE;YACzE,uEAAuE;YACvE,oEAAoE;QACtE,WAAW,EAAE,EAAE;KAChB,EACD,IAAA,sBAAW,EAAC,KAAK,IAAI,EAAE;QACrB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAwB,cAAc,CAAC,CAAC;QAC1E,OAAO,IAAA,qBAAU,EAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
package/dist/util/env.js
CHANGED
|
@@ -11,7 +11,11 @@ function readEnv() {
|
|
|
11
11
|
throw new Error('OTWA_API_KEY does not look like an otwa.cloud API key (expected prefix "otwa_"). ' +
|
|
12
12
|
'Generate a new key at https://otwa.cloud/dashboard/settings/api-keys.');
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
// otwa-cloud-api uses NestJS setGlobalPrefix('api'), so the public surface is
|
|
15
|
+
// https://api.otwa.cloud/api/v1/*. The default below must include the prefix
|
|
16
|
+
// or every tool call 404s. v0.1.x shipped with the prefix missing — that bug
|
|
17
|
+
// is closed here. Override via OTWA_API_BASE for staging / dev only.
|
|
18
|
+
const apiBase = (process.env.OTWA_API_BASE?.trim() || 'https://api.otwa.cloud/api').replace(/\/+$/, '');
|
|
15
19
|
const telemetry = /^(1|true|yes)$/i.test(process.env.OTWA_TELEMETRY?.trim() || '');
|
|
16
20
|
return { apiKey, apiBase, telemetry };
|
|
17
21
|
}
|
package/dist/util/env.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/util/env.ts"],"names":[],"mappings":";;AAMA,
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/util/env.ts"],"names":[],"mappings":";;AAMA,0BAqBC;AArBD,SAAgB,OAAO;IACrB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACtD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,wFAAwF;YACtF,8EAA8E,CACjF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACb,mFAAmF;YACjF,uEAAuE,CAC1E,CAAC;IACJ,CAAC;IACD,8EAA8E;IAC9E,6EAA6E;IAC7E,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,4BAA4B,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxG,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Optional fire-and-forget telemetry for MCP tool calls.
|
|
3
|
+
*
|
|
4
|
+
* Hosted transport (mcp.otwa.cloud) always records — we already see every
|
|
5
|
+
* request server-side, logging metadata to our own DB has no privacy delta.
|
|
6
|
+
*
|
|
7
|
+
* Stdio transport is OFF by default and only records when the user sets
|
|
8
|
+
* OTWA_TELEMETRY=1. Stdio runs on the user's machine and we want to be a
|
|
9
|
+
* good neighbour — no surprise network calls per tool invocation. */
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.createTelemetry = createTelemetry;
|
|
12
|
+
exports.classifyErrorFromResult = classifyErrorFromResult;
|
|
13
|
+
exports.classifyErrorFromException = classifyErrorFromException;
|
|
14
|
+
const errors_1 = require("../client/errors");
|
|
15
|
+
function createTelemetry(opts) {
|
|
16
|
+
if (!opts.enabled) {
|
|
17
|
+
return {
|
|
18
|
+
enabled: false,
|
|
19
|
+
transport: opts.transport,
|
|
20
|
+
record: () => undefined,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const url = `${opts.apiBase.replace(/\/+$/, '')}/v1/integrations/mcp/usage`;
|
|
24
|
+
const headers = {
|
|
25
|
+
'content-type': 'application/json',
|
|
26
|
+
authorization: `Bearer ${opts.apiKey}`,
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
enabled: true,
|
|
30
|
+
transport: opts.transport,
|
|
31
|
+
record: (event) => {
|
|
32
|
+
const body = JSON.stringify({
|
|
33
|
+
toolName: event.toolName,
|
|
34
|
+
transport: opts.transport,
|
|
35
|
+
success: event.success,
|
|
36
|
+
errorCode: event.errorCode ?? undefined,
|
|
37
|
+
durationMs: event.durationMs,
|
|
38
|
+
clientLabel: opts.clientLabel ?? undefined,
|
|
39
|
+
});
|
|
40
|
+
// Fire-and-forget. We never await this — the tool result must never be
|
|
41
|
+
// delayed by telemetry. We swallow errors entirely; one missed log row
|
|
42
|
+
// is cheaper than surfacing infrastructure noise to the LLM.
|
|
43
|
+
void fetch(url, { method: 'POST', headers, body, signal: AbortSignal.timeout(2_000) })
|
|
44
|
+
.catch(() => undefined);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Read the error_code from an `isError: true` CallToolResult so we can bucket
|
|
49
|
+
* failures meaningfully in the dashboard (forbidden / not_found / rate_limited
|
|
50
|
+
* / etc) rather than just counting "failed".
|
|
51
|
+
* Returns null if the failure didn't come from OtwaApiError (e.g. a generic
|
|
52
|
+
* JS throw inside the handler). */
|
|
53
|
+
function classifyErrorFromResult(result) {
|
|
54
|
+
if (!result || typeof result !== 'object')
|
|
55
|
+
return null;
|
|
56
|
+
const r = result;
|
|
57
|
+
if (!r.isError)
|
|
58
|
+
return null;
|
|
59
|
+
// We re-classify by message string because OtwaApiError instances are lost
|
|
60
|
+
// by the time safeHandler has stringified them into the content array. The
|
|
61
|
+
// strings are fixed in errors.ts so this stays accurate.
|
|
62
|
+
const text = r.content?.[0]?.text || '';
|
|
63
|
+
if (text.includes('OTWA_API_KEY is invalid'))
|
|
64
|
+
return 'unauthorized';
|
|
65
|
+
if (text.includes('missing a required scope') || text.includes('missing required scope'))
|
|
66
|
+
return 'forbidden';
|
|
67
|
+
if (text.includes('Account balance is too low'))
|
|
68
|
+
return 'payment_required';
|
|
69
|
+
if (text.includes('Resource not found') || text.startsWith('Not found'))
|
|
70
|
+
return 'not_found';
|
|
71
|
+
if (text.startsWith('Conflict'))
|
|
72
|
+
return 'conflict';
|
|
73
|
+
if (text.startsWith('Validation failed'))
|
|
74
|
+
return 'validation_failed';
|
|
75
|
+
if (text.includes('Rate-limited'))
|
|
76
|
+
return 'rate_limited';
|
|
77
|
+
if (text.includes('otwa-cloud-api returned 5'))
|
|
78
|
+
return 'upstream_error';
|
|
79
|
+
return 'error';
|
|
80
|
+
}
|
|
81
|
+
/** Stamp a tool name onto an OtwaApiError-derived classification, only used
|
|
82
|
+
* when an exception leaks past safeHandler. */
|
|
83
|
+
function classifyErrorFromException(err) {
|
|
84
|
+
if (err instanceof errors_1.OtwaApiError)
|
|
85
|
+
return err.code;
|
|
86
|
+
return 'thrown';
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/util/telemetry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otwa/mcp-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Official Model Context Protocol server for otwa.cloud — provision and manage servers from Claude Code, Cursor, Windsurf and other MCP-capable AI tools.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Official Model Context Protocol server for otwa.cloud — provision and manage servers from Claude Code, Claude Desktop, Cursor, Windsurf, VS Code, Zed, Continue, OpenCode and other MCP-capable AI tools.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://otwa.cloud/docs/integrations/mcp",
|
|
7
7
|
"repository": {
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"type": "commonjs",
|
|
29
29
|
"main": "dist/index.js",
|
|
30
30
|
"bin": {
|
|
31
|
-
"
|
|
32
|
-
"
|
|
31
|
+
"mcp-server": "dist/index.js",
|
|
32
|
+
"mcp-server-http": "dist/http/index.js"
|
|
33
33
|
},
|
|
34
34
|
"files": [
|
|
35
35
|
"dist",
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
"@types/express": "^4.17.21",
|
|
50
50
|
"@types/node": "^22.0.0",
|
|
51
51
|
"tsx": "^4.19.0",
|
|
52
|
-
"typescript": "^5.7.2"
|
|
52
|
+
"typescript": "^5.7.2",
|
|
53
|
+
"vitest": "^4.0.0"
|
|
53
54
|
},
|
|
54
55
|
"scripts": {
|
|
55
56
|
"dev": "tsx watch src/index.ts",
|
|
@@ -58,6 +59,8 @@
|
|
|
58
59
|
"start:http": "node dist/http/index.js",
|
|
59
60
|
"build": "tsc -p tsconfig.json",
|
|
60
61
|
"type-check": "tsc -p tsconfig.json --noEmit",
|
|
62
|
+
"test": "tsc -p tsconfig.test.json && vitest run",
|
|
63
|
+
"test:watch": "vitest",
|
|
61
64
|
"clean": "rm -rf dist"
|
|
62
65
|
}
|
|
63
66
|
}
|