@kadoa/mcp 0.3.7 → 0.3.9-rc.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/README.md +6 -114
- package/dist/index.js +156 -310
- package/package.json +2 -6
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Use [Kadoa](https://kadoa.com) from ChatGPT, Claude.ai, Claude Code, Cursor, and
|
|
|
4
4
|
|
|
5
5
|
## Remote Server (no install needed)
|
|
6
6
|
|
|
7
|
-
A hosted MCP server is available at `https://mcp.kadoa.com/mcp`. Connect from any MCP client — no local install
|
|
7
|
+
A hosted MCP server is available at `https://mcp.kadoa.com/mcp`. Connect from any MCP client — no local install needed. You sign in with your Kadoa account via OAuth.
|
|
8
8
|
|
|
9
9
|
### Claude Code
|
|
10
10
|
|
|
@@ -24,7 +24,7 @@ claude mcp add kadoa --transport http https://mcp.kadoa.com/mcp
|
|
|
24
24
|
2. Enter the URL: `https://mcp.kadoa.com/mcp`
|
|
25
25
|
3. Sign in with your Kadoa account via OAuth
|
|
26
26
|
|
|
27
|
-
### Cursor
|
|
27
|
+
### Cursor
|
|
28
28
|
|
|
29
29
|
Add to `.cursor/mcp.json`:
|
|
30
30
|
|
|
@@ -43,101 +43,6 @@ Add to `.cursor/mcp.json`:
|
|
|
43
43
|
|
|
44
44
|
Point your client to `https://mcp.kadoa.com/mcp` with OAuth authentication.
|
|
45
45
|
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Local Setup (stdio)
|
|
49
|
-
|
|
50
|
-
If you prefer to run the MCP server locally (e.g., for development or to use your own API key), install via npx:
|
|
51
|
-
|
|
52
|
-
### Claude Code
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
claude mcp add --transport stdio -e KADOA_API_KEY=tk-your_api_key kadoa -- npx -y @kadoa/mcp
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Add `-s user` to enable for all projects. If you have the [Kadoa CLI](https://www.npmjs.com/package/@kadoa/cli) installed, you can skip the `-e` flag — just run `kadoa login` and the MCP will use your saved key automatically.
|
|
59
|
-
|
|
60
|
-
### Claude Desktop
|
|
61
|
-
|
|
62
|
-
Add to `~/.config/Claude/claude_desktop_config.json`:
|
|
63
|
-
|
|
64
|
-
```json
|
|
65
|
-
{
|
|
66
|
-
"mcpServers": {
|
|
67
|
-
"kadoa": {
|
|
68
|
-
"command": "npx",
|
|
69
|
-
"args": ["-y", "@kadoa/mcp"],
|
|
70
|
-
"env": {
|
|
71
|
-
"KADOA_API_KEY": "tk-your_api_key"
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Restart Claude Desktop.
|
|
79
|
-
|
|
80
|
-
### Cursor
|
|
81
|
-
|
|
82
|
-
Add to `.cursor/mcp.json`:
|
|
83
|
-
|
|
84
|
-
```json
|
|
85
|
-
{
|
|
86
|
-
"mcpServers": {
|
|
87
|
-
"kadoa": {
|
|
88
|
-
"command": "npx",
|
|
89
|
-
"args": ["-y", "@kadoa/mcp"],
|
|
90
|
-
"env": {
|
|
91
|
-
"KADOA_API_KEY": "tk-your_api_key"
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Codex
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
codex mcp add kadoa -- npx -y @kadoa/mcp
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Or add to `~/.codex/config.toml`:
|
|
105
|
-
|
|
106
|
-
```toml
|
|
107
|
-
[mcp_servers.kadoa]
|
|
108
|
-
command = "npx"
|
|
109
|
-
args = ["-y", "@kadoa/mcp"]
|
|
110
|
-
|
|
111
|
-
[mcp_servers.kadoa.env]
|
|
112
|
-
KADOA_API_KEY = "tk-your_api_key"
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Gemini CLI
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
gemini mcp add -t stdio kadoa npx -- -y @kadoa/mcp
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Or add to `~/.gemini/settings.json`:
|
|
122
|
-
|
|
123
|
-
```json
|
|
124
|
-
{
|
|
125
|
-
"mcpServers": {
|
|
126
|
-
"kadoa": {
|
|
127
|
-
"command": "npx",
|
|
128
|
-
"args": ["-y", "@kadoa/mcp"],
|
|
129
|
-
"env": {
|
|
130
|
-
"KADOA_API_KEY": "tk-your_api_key"
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Get Your API Key
|
|
138
|
-
|
|
139
|
-
Get your API key from [kadoa.com/settings](https://kadoa.com/settings).
|
|
140
|
-
|
|
141
46
|
## Tools
|
|
142
47
|
|
|
143
48
|
| Tool | Description |
|
|
@@ -214,14 +119,10 @@ delete_workflow for each, confirming before proceeding.
|
|
|
214
119
|
|
|
215
120
|
## Troubleshooting
|
|
216
121
|
|
|
217
|
-
**"No API key found"**
|
|
218
|
-
- Run `kadoa login` (requires `npm i -g @kadoa/cli`), or
|
|
219
|
-
- Set `KADOA_API_KEY` in your MCP config or environment
|
|
220
|
-
- API keys start with `tk-`
|
|
221
|
-
|
|
222
122
|
**Claude says "I don't have access to Kadoa"**
|
|
223
123
|
- Verify the MCP server is configured correctly
|
|
224
124
|
- Restart your MCP client
|
|
125
|
+
- Re-authenticate via OAuth if prompted
|
|
225
126
|
|
|
226
127
|
## Deploying the Remote Server
|
|
227
128
|
|
|
@@ -256,24 +157,15 @@ bun run build # Build for distribution
|
|
|
256
157
|
|
|
257
158
|
To develop and test against a local Kadoa backend (instead of the production API), point the MCP at your local `public-api` service using the `KADOA_PUBLIC_API_URI` environment variable.
|
|
258
159
|
|
|
259
|
-
**Prerequisites:** the `public-api` service must be running locally (default port `12380`).
|
|
160
|
+
**Prerequisites:** the `public-api` service must be running locally (default port `12380`).
|
|
260
161
|
|
|
261
162
|
**Run the MCP server locally:**
|
|
262
163
|
|
|
263
164
|
```bash
|
|
264
|
-
KADOA_PUBLIC_API_URI=http://localhost:12380
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
**Add as a local MCP in Claude Code** (alongside the remote one):
|
|
268
|
-
|
|
269
|
-
```bash
|
|
270
|
-
claude mcp add --transport stdio \
|
|
271
|
-
-e KADOA_PUBLIC_API_URI=http://localhost:12380 \
|
|
272
|
-
-e KADOA_API_KEY=tk-your_local_api_key \
|
|
273
|
-
kadoa-local -- bun /path/to/kadoa-mcp/src/index.ts
|
|
165
|
+
KADOA_PUBLIC_API_URI=http://localhost:12380 bun run dev
|
|
274
166
|
```
|
|
275
167
|
|
|
276
|
-
|
|
168
|
+
The server starts in HTTP mode. You authenticate via OAuth the same way as with the remote server.
|
|
277
169
|
|
|
278
170
|
## License
|
|
279
171
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -28800,102 +28800,6 @@ var init_mcp = __esm(() => {
|
|
|
28800
28800
|
};
|
|
28801
28801
|
});
|
|
28802
28802
|
|
|
28803
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
28804
|
-
class ReadBuffer {
|
|
28805
|
-
append(chunk) {
|
|
28806
|
-
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
28807
|
-
}
|
|
28808
|
-
readMessage() {
|
|
28809
|
-
if (!this._buffer) {
|
|
28810
|
-
return null;
|
|
28811
|
-
}
|
|
28812
|
-
const index = this._buffer.indexOf(`
|
|
28813
|
-
`);
|
|
28814
|
-
if (index === -1) {
|
|
28815
|
-
return null;
|
|
28816
|
-
}
|
|
28817
|
-
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
28818
|
-
this._buffer = this._buffer.subarray(index + 1);
|
|
28819
|
-
return deserializeMessage(line);
|
|
28820
|
-
}
|
|
28821
|
-
clear() {
|
|
28822
|
-
this._buffer = undefined;
|
|
28823
|
-
}
|
|
28824
|
-
}
|
|
28825
|
-
function deserializeMessage(line) {
|
|
28826
|
-
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
28827
|
-
}
|
|
28828
|
-
function serializeMessage(message) {
|
|
28829
|
-
return JSON.stringify(message) + `
|
|
28830
|
-
`;
|
|
28831
|
-
}
|
|
28832
|
-
var init_stdio = __esm(() => {
|
|
28833
|
-
init_types2();
|
|
28834
|
-
});
|
|
28835
|
-
|
|
28836
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
28837
|
-
import process3 from "node:process";
|
|
28838
|
-
|
|
28839
|
-
class StdioServerTransport {
|
|
28840
|
-
constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
|
|
28841
|
-
this._stdin = _stdin;
|
|
28842
|
-
this._stdout = _stdout;
|
|
28843
|
-
this._readBuffer = new ReadBuffer;
|
|
28844
|
-
this._started = false;
|
|
28845
|
-
this._ondata = (chunk) => {
|
|
28846
|
-
this._readBuffer.append(chunk);
|
|
28847
|
-
this.processReadBuffer();
|
|
28848
|
-
};
|
|
28849
|
-
this._onerror = (error48) => {
|
|
28850
|
-
this.onerror?.(error48);
|
|
28851
|
-
};
|
|
28852
|
-
}
|
|
28853
|
-
async start() {
|
|
28854
|
-
if (this._started) {
|
|
28855
|
-
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
28856
|
-
}
|
|
28857
|
-
this._started = true;
|
|
28858
|
-
this._stdin.on("data", this._ondata);
|
|
28859
|
-
this._stdin.on("error", this._onerror);
|
|
28860
|
-
}
|
|
28861
|
-
processReadBuffer() {
|
|
28862
|
-
while (true) {
|
|
28863
|
-
try {
|
|
28864
|
-
const message = this._readBuffer.readMessage();
|
|
28865
|
-
if (message === null) {
|
|
28866
|
-
break;
|
|
28867
|
-
}
|
|
28868
|
-
this.onmessage?.(message);
|
|
28869
|
-
} catch (error48) {
|
|
28870
|
-
this.onerror?.(error48);
|
|
28871
|
-
}
|
|
28872
|
-
}
|
|
28873
|
-
}
|
|
28874
|
-
async close() {
|
|
28875
|
-
this._stdin.off("data", this._ondata);
|
|
28876
|
-
this._stdin.off("error", this._onerror);
|
|
28877
|
-
const remainingDataListeners = this._stdin.listenerCount("data");
|
|
28878
|
-
if (remainingDataListeners === 0) {
|
|
28879
|
-
this._stdin.pause();
|
|
28880
|
-
}
|
|
28881
|
-
this._readBuffer.clear();
|
|
28882
|
-
this.onclose?.();
|
|
28883
|
-
}
|
|
28884
|
-
send(message) {
|
|
28885
|
-
return new Promise((resolve) => {
|
|
28886
|
-
const json2 = serializeMessage(message);
|
|
28887
|
-
if (this._stdout.write(json2)) {
|
|
28888
|
-
resolve();
|
|
28889
|
-
} else {
|
|
28890
|
-
this._stdout.once("drain", resolve);
|
|
28891
|
-
}
|
|
28892
|
-
});
|
|
28893
|
-
}
|
|
28894
|
-
}
|
|
28895
|
-
var init_stdio2 = __esm(() => {
|
|
28896
|
-
init_stdio();
|
|
28897
|
-
});
|
|
28898
|
-
|
|
28899
28803
|
// node_modules/axios/lib/helpers/bind.js
|
|
28900
28804
|
function bind(fn, thisArg) {
|
|
28901
28805
|
return function wrap() {
|
|
@@ -49043,83 +48947,47 @@ var init_dist2 = __esm(() => {
|
|
|
49043
48947
|
});
|
|
49044
48948
|
|
|
49045
48949
|
// src/client.ts
|
|
49046
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
49047
|
-
import { dirname, join } from "node:path";
|
|
49048
|
-
import { homedir } from "node:os";
|
|
49049
|
-
function getConfigPath() {
|
|
49050
|
-
const home = process.env.HOME || homedir();
|
|
49051
|
-
return join(home, ".kadoa", "config.json");
|
|
49052
|
-
}
|
|
49053
|
-
function loadConfig() {
|
|
49054
|
-
const configFile = getConfigPath();
|
|
49055
|
-
if (!existsSync(configFile))
|
|
49056
|
-
return {};
|
|
49057
|
-
try {
|
|
49058
|
-
return JSON.parse(readFileSync(configFile, "utf-8"));
|
|
49059
|
-
} catch {
|
|
49060
|
-
return {};
|
|
49061
|
-
}
|
|
49062
|
-
}
|
|
49063
|
-
function loadApiKeyFromConfig() {
|
|
49064
|
-
return loadConfig().apiKey;
|
|
49065
|
-
}
|
|
49066
|
-
function resolveApiKey(apiKey) {
|
|
49067
|
-
const key = apiKey || process.env.KADOA_API_KEY || loadApiKeyFromConfig();
|
|
49068
|
-
if (!key) {
|
|
49069
|
-
throw new Error("No API key found. Set KADOA_API_KEY env var or run 'kadoa login' (npm i -g @kadoa/cli).");
|
|
49070
|
-
}
|
|
49071
|
-
return key;
|
|
49072
|
-
}
|
|
49073
48950
|
function createKadoaClient(auth) {
|
|
49074
|
-
|
|
49075
|
-
let teamId;
|
|
49076
|
-
if (typeof auth === "object" && auth !== null) {
|
|
49077
|
-
if ("jwt" in auth) {
|
|
49078
|
-
client = new KadoaClient({ bearerToken: auth.jwt });
|
|
49079
|
-
teamId = auth.teamId;
|
|
49080
|
-
} else {
|
|
49081
|
-
client = new KadoaClient({ apiKey: auth.apiKey });
|
|
49082
|
-
}
|
|
49083
|
-
} else {
|
|
49084
|
-
client = new KadoaClient({ apiKey: resolveApiKey(auth) });
|
|
49085
|
-
}
|
|
48951
|
+
const client = new KadoaClient({ bearerToken: auth.jwt });
|
|
49086
48952
|
client.axiosInstance.interceptors.request.use((config2) => {
|
|
49087
48953
|
config2.headers["x-kadoa-source"] = "mcp";
|
|
49088
|
-
if (teamId) {
|
|
49089
|
-
config2.headers["x-team-id"] = teamId;
|
|
48954
|
+
if (auth.teamId) {
|
|
48955
|
+
config2.headers["x-team-id"] = auth.teamId;
|
|
49090
48956
|
}
|
|
49091
48957
|
return config2;
|
|
49092
48958
|
});
|
|
49093
48959
|
return client;
|
|
49094
48960
|
}
|
|
49095
|
-
var ctxRefreshMutex;
|
|
48961
|
+
var refreshRawMutex, ctxRefreshMutex;
|
|
49096
48962
|
var init_client = __esm(() => {
|
|
49097
48963
|
init_dist2();
|
|
48964
|
+
refreshRawMutex = new Map;
|
|
49098
48965
|
ctxRefreshMutex = new WeakMap;
|
|
49099
48966
|
});
|
|
49100
48967
|
|
|
49101
48968
|
// src/client.ts
|
|
49102
|
-
|
|
49103
|
-
|
|
49104
|
-
|
|
49105
|
-
|
|
49106
|
-
|
|
49107
|
-
|
|
49108
|
-
|
|
49109
|
-
|
|
49110
|
-
|
|
49111
|
-
|
|
49112
|
-
|
|
49113
|
-
|
|
49114
|
-
|
|
49115
|
-
|
|
49116
|
-
|
|
49117
|
-
|
|
49118
|
-
|
|
49119
|
-
|
|
49120
|
-
|
|
49121
|
-
|
|
49122
|
-
|
|
48969
|
+
var exports_client = {};
|
|
48970
|
+
__export(exports_client, {
|
|
48971
|
+
refreshSupabaseJwtRaw: () => refreshSupabaseJwtRaw,
|
|
48972
|
+
refreshSupabaseJwt: () => refreshSupabaseJwt,
|
|
48973
|
+
isJwtExpired: () => isJwtExpired,
|
|
48974
|
+
getValidJwt: () => getValidJwt,
|
|
48975
|
+
decodeJwtClaims: () => decodeJwtClaims,
|
|
48976
|
+
createKadoaClient: () => createKadoaClient2,
|
|
48977
|
+
SessionExpiredError: () => SessionExpiredError,
|
|
48978
|
+
KadoaSdkException: () => KadoaSdkException,
|
|
48979
|
+
KadoaClient: () => KadoaClient
|
|
48980
|
+
});
|
|
48981
|
+
function createKadoaClient2(auth) {
|
|
48982
|
+
const client = new KadoaClient({ bearerToken: auth.jwt });
|
|
48983
|
+
client.axiosInstance.interceptors.request.use((config2) => {
|
|
48984
|
+
config2.headers["x-kadoa-source"] = "mcp";
|
|
48985
|
+
if (auth.teamId) {
|
|
48986
|
+
config2.headers["x-team-id"] = auth.teamId;
|
|
48987
|
+
}
|
|
48988
|
+
return config2;
|
|
48989
|
+
});
|
|
48990
|
+
return client;
|
|
49123
48991
|
}
|
|
49124
48992
|
function decodeJwtClaims(jwt2) {
|
|
49125
48993
|
try {
|
|
@@ -49142,36 +49010,57 @@ function isJwtExpired(jwt2) {
|
|
|
49142
49010
|
return true;
|
|
49143
49011
|
}
|
|
49144
49012
|
}
|
|
49145
|
-
async function
|
|
49146
|
-
|
|
49147
|
-
|
|
49148
|
-
|
|
49013
|
+
async function refreshSupabaseJwtRaw(supabaseRefreshToken) {
|
|
49014
|
+
const inflight = refreshRawMutex2.get(supabaseRefreshToken);
|
|
49015
|
+
if (inflight) {
|
|
49016
|
+
console.error(`[JWT_REFRESH] DEDUP: reusing in-flight raw refresh`);
|
|
49017
|
+
return inflight;
|
|
49149
49018
|
}
|
|
49019
|
+
const promise3 = _doRefreshRaw(supabaseRefreshToken).finally(() => {
|
|
49020
|
+
refreshRawMutex2.delete(supabaseRefreshToken);
|
|
49021
|
+
});
|
|
49022
|
+
refreshRawMutex2.set(supabaseRefreshToken, promise3);
|
|
49023
|
+
return promise3;
|
|
49024
|
+
}
|
|
49025
|
+
async function _doRefreshRaw(supabaseRefreshToken) {
|
|
49150
49026
|
const supabaseUrl = process.env.SUPABASE_URL;
|
|
49151
49027
|
if (!supabaseUrl) {
|
|
49152
49028
|
console.error("[JWT_REFRESH] SUPABASE_URL not set, cannot refresh");
|
|
49029
|
+
return null;
|
|
49030
|
+
}
|
|
49031
|
+
const res = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=refresh_token`, {
|
|
49032
|
+
method: "POST",
|
|
49033
|
+
headers: {
|
|
49034
|
+
"Content-Type": "application/json",
|
|
49035
|
+
apikey: process.env.SUPABASE_ANON_KEY
|
|
49036
|
+
},
|
|
49037
|
+
body: JSON.stringify({ refresh_token: supabaseRefreshToken })
|
|
49038
|
+
});
|
|
49039
|
+
if (res.ok) {
|
|
49040
|
+
const data = await res.json();
|
|
49041
|
+
return { jwt: data.access_token, refreshToken: data.refresh_token };
|
|
49042
|
+
}
|
|
49043
|
+
const body = await res.text().catch(() => "");
|
|
49044
|
+
console.error(`[JWT_REFRESH] FAIL: Supabase returned ${res.status} (refreshToken=${supabaseRefreshToken.slice(0, 12)}...): ${body}`);
|
|
49045
|
+
if (body.includes("session_expired") || body.includes("refresh_token_not_found") || body.includes("refresh_token_already_used")) {
|
|
49046
|
+
throw new SessionExpiredError("Your Kadoa session has expired due to inactivity. Please reconnect to re-authenticate.");
|
|
49047
|
+
}
|
|
49048
|
+
return null;
|
|
49049
|
+
}
|
|
49050
|
+
async function refreshSupabaseJwt(ctx) {
|
|
49051
|
+
if (!ctx.supabaseRefreshToken) {
|
|
49052
|
+
console.error("[JWT_REFRESH] No refresh token available, cannot refresh");
|
|
49153
49053
|
return;
|
|
49154
49054
|
}
|
|
49155
49055
|
try {
|
|
49156
49056
|
const refreshToken = ctx.supabaseRefreshToken;
|
|
49157
49057
|
console.error(`[JWT_REFRESH] Refreshing Supabase JWT (refreshToken=${refreshToken.slice(0, 12)}..., team=${ctx.teamId ?? "unknown"})`);
|
|
49158
|
-
const
|
|
49159
|
-
|
|
49160
|
-
headers: {
|
|
49161
|
-
"Content-Type": "application/json",
|
|
49162
|
-
apikey: process.env.SUPABASE_ANON_KEY
|
|
49163
|
-
},
|
|
49164
|
-
body: JSON.stringify({ refresh_token: refreshToken })
|
|
49165
|
-
});
|
|
49166
|
-
if (!res.ok) {
|
|
49167
|
-
const body = await res.text().catch(() => "");
|
|
49168
|
-
console.error(`[JWT_REFRESH] FAIL: Supabase returned ${res.status} (refreshToken=${refreshToken.slice(0, 12)}...): ${body}`);
|
|
49058
|
+
const result = await refreshSupabaseJwtRaw(refreshToken);
|
|
49059
|
+
if (!result)
|
|
49169
49060
|
return;
|
|
49170
|
-
|
|
49171
|
-
|
|
49172
|
-
ctx.
|
|
49173
|
-
ctx.supabaseRefreshToken = data.refresh_token;
|
|
49174
|
-
ctx.client.setBearerToken(data.access_token);
|
|
49061
|
+
ctx.supabaseJwt = result.jwt;
|
|
49062
|
+
ctx.supabaseRefreshToken = result.refreshToken;
|
|
49063
|
+
ctx.client.setBearerToken(result.jwt);
|
|
49175
49064
|
try {
|
|
49176
49065
|
await ctx.persist?.({
|
|
49177
49066
|
supabaseJwt: ctx.supabaseJwt,
|
|
@@ -49181,9 +49070,11 @@ async function refreshSupabaseJwt(ctx) {
|
|
|
49181
49070
|
} catch (e) {
|
|
49182
49071
|
console.error("[JWT_REFRESH] WARN: persist failed, tokens updated in-memory only:", e);
|
|
49183
49072
|
}
|
|
49184
|
-
console.error(`[JWT_REFRESH] OK: token refreshed (team=${ctx.teamId ?? "unknown"}, newRefreshToken=${
|
|
49185
|
-
return
|
|
49073
|
+
console.error(`[JWT_REFRESH] OK: token refreshed (team=${ctx.teamId ?? "unknown"}, newRefreshToken=${result.refreshToken.slice(0, 12)}...)`);
|
|
49074
|
+
return result.jwt;
|
|
49186
49075
|
} catch (error48) {
|
|
49076
|
+
if (error48 instanceof SessionExpiredError)
|
|
49077
|
+
throw error48;
|
|
49187
49078
|
console.error("[JWT_REFRESH] FAIL: threw", error48);
|
|
49188
49079
|
return;
|
|
49189
49080
|
}
|
|
@@ -49204,9 +49095,16 @@ async function getValidJwt(ctx) {
|
|
|
49204
49095
|
ctxRefreshMutex2.set(ctx, promise3);
|
|
49205
49096
|
return promise3;
|
|
49206
49097
|
}
|
|
49207
|
-
var ctxRefreshMutex2;
|
|
49098
|
+
var SessionExpiredError, refreshRawMutex2, ctxRefreshMutex2;
|
|
49208
49099
|
var init_client2 = __esm(() => {
|
|
49209
49100
|
init_dist2();
|
|
49101
|
+
SessionExpiredError = class SessionExpiredError extends Error {
|
|
49102
|
+
constructor(message) {
|
|
49103
|
+
super(message ?? "Supabase session expired. Please re-authenticate.");
|
|
49104
|
+
this.name = "SessionExpiredError";
|
|
49105
|
+
}
|
|
49106
|
+
};
|
|
49107
|
+
refreshRawMutex2 = new Map;
|
|
49210
49108
|
ctxRefreshMutex2 = new WeakMap;
|
|
49211
49109
|
});
|
|
49212
49110
|
|
|
@@ -49265,7 +49163,7 @@ function classifyError(error48) {
|
|
|
49265
49163
|
if (httpError.httpStatus === 403) {
|
|
49266
49164
|
return `Access denied${status}. Your current team role may not have permission for this action. Use the whoami tool to check your role, or contact your team admin to request elevated access.`;
|
|
49267
49165
|
}
|
|
49268
|
-
return `Authentication failed${status}.
|
|
49166
|
+
return `Authentication failed${status}. Please re-authenticate via OAuth.`;
|
|
49269
49167
|
case "NOT_FOUND":
|
|
49270
49168
|
return `Not found${status}. The workflow may have been deleted or the ID is incorrect.`;
|
|
49271
49169
|
case "RATE_LIMITED":
|
|
@@ -49283,7 +49181,7 @@ function classifyError(error48) {
|
|
|
49283
49181
|
}
|
|
49284
49182
|
switch (code) {
|
|
49285
49183
|
case "AUTH_ERROR":
|
|
49286
|
-
return "Authentication failed.
|
|
49184
|
+
return "Authentication failed. Please re-authenticate via OAuth.";
|
|
49287
49185
|
case "NOT_FOUND":
|
|
49288
49186
|
return "Not found. The workflow may have been deleted or the ID is incorrect.";
|
|
49289
49187
|
case "RATE_LIMITED":
|
|
@@ -49324,13 +49222,16 @@ function registerTools(server, ctx) {
|
|
|
49324
49222
|
}
|
|
49325
49223
|
return await handler(...args);
|
|
49326
49224
|
} catch (error48) {
|
|
49225
|
+
if (error48 instanceof SessionExpiredError) {
|
|
49226
|
+
console.error(`[Tool Error] ${name}: session expired, user must re-authenticate`);
|
|
49227
|
+
return errorResult("Your session has expired. Please reconnect the MCP server to re-authenticate.");
|
|
49228
|
+
}
|
|
49327
49229
|
let message = classifyError(error48);
|
|
49328
49230
|
if (KadoaHttpException.isInstance(error48) && error48.httpStatus === 403) {
|
|
49329
49231
|
try {
|
|
49330
49232
|
const jwt2 = ctx.supabaseJwt;
|
|
49331
49233
|
const teams = await ctx.client.listTeams(jwt2 ? { bearerToken: jwt2 } : undefined);
|
|
49332
|
-
const
|
|
49333
|
-
const activeTeamId = ctx.teamId ?? config2.teamId ?? teams[0]?.id;
|
|
49234
|
+
const activeTeamId = ctx.teamId ?? teams[0]?.id;
|
|
49334
49235
|
const activeTeam = teams.find((t) => t.id === activeTeamId);
|
|
49335
49236
|
if (activeTeam?.adminEmail) {
|
|
49336
49237
|
message += ` Your team admin is ${activeTeam.adminEmail}.`;
|
|
@@ -49349,13 +49250,11 @@ function registerTools(server, ctx) {
|
|
|
49349
49250
|
}, withErrorHandling("whoami", async () => {
|
|
49350
49251
|
const jwt2 = await getValidJwt(ctx);
|
|
49351
49252
|
const user = await ctx.client.user.getCurrentUser();
|
|
49352
|
-
const authMethod = jwt2 ? "OAuth (JWT)" : "API Key";
|
|
49353
49253
|
const teams = await ctx.client.listTeams(jwt2 ? { bearerToken: jwt2 } : undefined);
|
|
49354
|
-
const
|
|
49355
|
-
const activeTeamId = ctx.teamId ?? config2.teamId ?? teams[0]?.id;
|
|
49254
|
+
const activeTeamId = ctx.teamId ?? teams[0]?.id;
|
|
49356
49255
|
return jsonResult({
|
|
49357
49256
|
email: user.email,
|
|
49358
|
-
authMethod,
|
|
49257
|
+
authMethod: "OAuth",
|
|
49359
49258
|
teams: teams.map((t) => ({
|
|
49360
49259
|
name: t.name,
|
|
49361
49260
|
memberRole: t.memberRole,
|
|
@@ -49999,8 +49898,7 @@ function registerTools(server, ctx) {
|
|
|
49999
49898
|
}, withErrorHandling("team_list", async () => {
|
|
50000
49899
|
const jwt2 = await getValidJwt(ctx);
|
|
50001
49900
|
const teams = await ctx.client.listTeams(jwt2 ? { bearerToken: jwt2 } : undefined);
|
|
50002
|
-
const
|
|
50003
|
-
const activeTeamId = ctx.teamId ?? config2.teamId ?? teams[0]?.id;
|
|
49901
|
+
const activeTeamId = ctx.teamId ?? teams[0]?.id;
|
|
50004
49902
|
return jsonResult({
|
|
50005
49903
|
teams: teams.map((t) => ({
|
|
50006
49904
|
id: t.id,
|
|
@@ -50020,9 +49918,6 @@ function registerTools(server, ctx) {
|
|
|
50020
49918
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true }
|
|
50021
49919
|
}, withErrorHandling("team_switch", async (args) => {
|
|
50022
49920
|
const jwt2 = await getValidJwt(ctx);
|
|
50023
|
-
if (!jwt2) {
|
|
50024
|
-
return errorResult("Team switching requires OAuth authentication (HTTP mode). " + "In stdio mode, re-run with a different KADOA_API_KEY or use 'kadoa login' to authenticate via the CLI.");
|
|
50025
|
-
}
|
|
50026
49921
|
const teams = await ctx.client.listTeams({ bearerToken: jwt2 });
|
|
50027
49922
|
const identifier = args.teamIdentifier;
|
|
50028
49923
|
const match = teams.find((t) => t.id === identifier || t.name.toLowerCase() === identifier.toLowerCase());
|
|
@@ -50036,10 +49931,6 @@ function registerTools(server, ctx) {
|
|
|
50036
49931
|
} catch (e) {
|
|
50037
49932
|
console.error("[TEAM_SWITCH] WARN: persist failed:", e);
|
|
50038
49933
|
}
|
|
50039
|
-
const config2 = loadConfig2();
|
|
50040
|
-
config2.teamId = match.id;
|
|
50041
|
-
config2.teamName = match.name;
|
|
50042
|
-
saveConfig(config2);
|
|
50043
49934
|
return jsonResult({
|
|
50044
49935
|
success: true,
|
|
50045
49936
|
teamId: match.id,
|
|
@@ -54059,45 +53950,6 @@ function generatePKCE() {
|
|
|
54059
53950
|
const challenge = createHash2("sha256").update(verifier).digest("base64url");
|
|
54060
53951
|
return { verifier, challenge };
|
|
54061
53952
|
}
|
|
54062
|
-
async function refreshSupabaseToken(supabaseRefreshToken, context) {
|
|
54063
|
-
const inflight = supabaseRefreshMutex.get(supabaseRefreshToken);
|
|
54064
|
-
if (inflight) {
|
|
54065
|
-
console.error(`[AUTH] REFRESH_DEDUP: reusing in-flight refresh (${context})`);
|
|
54066
|
-
return inflight;
|
|
54067
|
-
}
|
|
54068
|
-
const promise3 = (async () => {
|
|
54069
|
-
const supabaseUrl = process.env.SUPABASE_URL;
|
|
54070
|
-
if (!supabaseUrl || !supabaseRefreshToken)
|
|
54071
|
-
return null;
|
|
54072
|
-
try {
|
|
54073
|
-
const res = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=refresh_token`, {
|
|
54074
|
-
method: "POST",
|
|
54075
|
-
headers: {
|
|
54076
|
-
"Content-Type": "application/json",
|
|
54077
|
-
apikey: process.env.SUPABASE_ANON_KEY
|
|
54078
|
-
},
|
|
54079
|
-
body: JSON.stringify({ refresh_token: supabaseRefreshToken })
|
|
54080
|
-
});
|
|
54081
|
-
if (res.ok) {
|
|
54082
|
-
const data = await res.json();
|
|
54083
|
-
const newClaims = jwtClaims(data.access_token);
|
|
54084
|
-
console.log(`[AUTH] REFRESH_OK: Supabase JWT refreshed (${context}, newEmail=${newClaims.email})`);
|
|
54085
|
-
return { jwt: data.access_token, refreshToken: data.refresh_token };
|
|
54086
|
-
}
|
|
54087
|
-
const body = await res.text().catch(() => "");
|
|
54088
|
-
console.error(`[AUTH] REFRESH_FAIL: Supabase returned ${res.status} (${context}): ${body.slice(0, 200)}`);
|
|
54089
|
-
return null;
|
|
54090
|
-
} catch (err) {
|
|
54091
|
-
console.error(`[AUTH] REFRESH_FAIL: Supabase refresh threw (${context}):`, err);
|
|
54092
|
-
return null;
|
|
54093
|
-
}
|
|
54094
|
-
})();
|
|
54095
|
-
supabaseRefreshMutex.set(supabaseRefreshToken, promise3);
|
|
54096
|
-
promise3.finally(() => {
|
|
54097
|
-
supabaseRefreshMutex.delete(supabaseRefreshToken);
|
|
54098
|
-
});
|
|
54099
|
-
return promise3;
|
|
54100
|
-
}
|
|
54101
53953
|
function jwtClaims(jwt2) {
|
|
54102
53954
|
try {
|
|
54103
53955
|
const payload = JSON.parse(Buffer.from(jwt2.split(".")[1], "base64url").toString());
|
|
@@ -54405,12 +54257,22 @@ class KadoaOAuthProvider {
|
|
|
54405
54257
|
let { supabaseJwt, supabaseRefreshToken } = entry;
|
|
54406
54258
|
const claims = jwtClaims(entry.supabaseJwt);
|
|
54407
54259
|
const context = `email=${claims.email}, team=${entry.teamId}`;
|
|
54408
|
-
|
|
54409
|
-
|
|
54410
|
-
|
|
54411
|
-
|
|
54412
|
-
|
|
54413
|
-
|
|
54260
|
+
try {
|
|
54261
|
+
const { refreshSupabaseJwtRaw: refreshSupabaseJwtRaw2, SessionExpiredError: SessionExpiredError2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
|
|
54262
|
+
const refreshed = await refreshSupabaseJwtRaw2(supabaseRefreshToken);
|
|
54263
|
+
if (refreshed) {
|
|
54264
|
+
supabaseJwt = refreshed.jwt;
|
|
54265
|
+
supabaseRefreshToken = refreshed.refreshToken;
|
|
54266
|
+
console.error(`[AUTH] REFRESH_OK: Supabase JWT refreshed (${context})`);
|
|
54267
|
+
} else {
|
|
54268
|
+
console.error(`[AUTH] REFRESH_WARN: using stale Supabase JWT as fallback (${context})`);
|
|
54269
|
+
}
|
|
54270
|
+
} catch (error48) {
|
|
54271
|
+
if (error48 instanceof Error && error48.name === "SessionExpiredError") {
|
|
54272
|
+
console.error(`[AUTH] REFRESH_DEAD: session permanently expired (${context}): ${error48.message}`);
|
|
54273
|
+
throw new InvalidTokenError("Supabase session expired. Please re-authenticate.");
|
|
54274
|
+
}
|
|
54275
|
+
console.error(`[AUTH] REFRESH_WARN: unexpected error, using stale JWT (${context}):`, error48);
|
|
54414
54276
|
}
|
|
54415
54277
|
const freshClaims = jwtClaims(supabaseJwt);
|
|
54416
54278
|
const teamId = freshClaims.activeTeamId ?? entry.teamId;
|
|
@@ -54438,15 +54300,6 @@ class KadoaOAuthProvider {
|
|
|
54438
54300
|
};
|
|
54439
54301
|
}
|
|
54440
54302
|
async verifyAccessToken(token) {
|
|
54441
|
-
if (token.startsWith("tk-")) {
|
|
54442
|
-
return {
|
|
54443
|
-
token,
|
|
54444
|
-
clientId: "direct-api-key",
|
|
54445
|
-
scopes: [],
|
|
54446
|
-
expiresAt: Math.floor(Date.now() / 1000) + 3600,
|
|
54447
|
-
extra: { apiKey: token }
|
|
54448
|
-
};
|
|
54449
|
-
}
|
|
54450
54303
|
const entry = await this.store.get("access_tokens", token);
|
|
54451
54304
|
if (!entry) {
|
|
54452
54305
|
const sessionCount = await this.store.size("access_tokens");
|
|
@@ -54546,7 +54399,7 @@ class KadoaOAuthProvider {
|
|
|
54546
54399
|
codeChallenge: pending.params.codeChallenge,
|
|
54547
54400
|
clientId: pending.client.client_id,
|
|
54548
54401
|
redirectUri: pending.params.redirectUri,
|
|
54549
|
-
expiresAt: Date.now() +
|
|
54402
|
+
expiresAt: Date.now() + 600000
|
|
54550
54403
|
}, 600);
|
|
54551
54404
|
const redirectUrl = new URL(pending.params.redirectUri);
|
|
54552
54405
|
redirectUrl.searchParams.set("code", mcpCode);
|
|
@@ -54975,12 +54828,11 @@ function renderLoginPage(state, error48) {
|
|
|
54975
54828
|
function escapeHtml(str) {
|
|
54976
54829
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
54977
54830
|
}
|
|
54978
|
-
var TEAM_SELECTION_TTL, ACCESS_TOKEN_TTL
|
|
54831
|
+
var TEAM_SELECTION_TTL, ACCESS_TOKEN_TTL;
|
|
54979
54832
|
var init_auth2 = __esm(() => {
|
|
54980
54833
|
init_errors4();
|
|
54981
54834
|
TEAM_SELECTION_TTL = 10 * 60 * 1000;
|
|
54982
54835
|
ACCESS_TOKEN_TTL = 7 * 24 * 3600;
|
|
54983
|
-
supabaseRefreshMutex = new Map;
|
|
54984
54836
|
});
|
|
54985
54837
|
|
|
54986
54838
|
// src/redis-store.ts
|
|
@@ -55098,9 +54950,6 @@ function resolveAuth(req) {
|
|
|
55098
54950
|
console.error("[AUTH_RESOLVE] FAIL: req.auth.extra is missing");
|
|
55099
54951
|
return;
|
|
55100
54952
|
}
|
|
55101
|
-
if (typeof extra.apiKey === "string" && extra.apiKey.startsWith("tk-")) {
|
|
55102
|
-
return { kind: "apiKey", apiKey: extra.apiKey };
|
|
55103
|
-
}
|
|
55104
54953
|
if (typeof extra.supabaseJwt === "string") {
|
|
55105
54954
|
const claims = jwtClaims2(extra.supabaseJwt);
|
|
55106
54955
|
const userId = claims.sub;
|
|
@@ -55118,7 +54967,6 @@ function resolveAuth(req) {
|
|
|
55118
54967
|
}
|
|
55119
54968
|
}
|
|
55120
54969
|
return {
|
|
55121
|
-
kind: "jwt",
|
|
55122
54970
|
jwt: extra.supabaseJwt,
|
|
55123
54971
|
refreshToken: extra.supabaseRefreshToken ?? "",
|
|
55124
54972
|
teamId: extra.teamId ?? "",
|
|
@@ -55126,7 +54974,7 @@ function resolveAuth(req) {
|
|
|
55126
54974
|
mcpToken: req.auth.token
|
|
55127
54975
|
};
|
|
55128
54976
|
}
|
|
55129
|
-
console.error(`[AUTH_RESOLVE] FAIL: no
|
|
54977
|
+
console.error(`[AUTH_RESOLVE] FAIL: no supabaseJwt in extra (keys: ${Object.keys(extra).join(", ")})`);
|
|
55130
54978
|
return;
|
|
55131
54979
|
}
|
|
55132
54980
|
async function startHttpServer(options) {
|
|
@@ -55176,13 +55024,46 @@ async function startHttpServer(options) {
|
|
|
55176
55024
|
});
|
|
55177
55025
|
return;
|
|
55178
55026
|
}
|
|
55179
|
-
const identity =
|
|
55027
|
+
const identity = `jwt:${auth.userId.slice(0, 8)}...:team=${auth.teamId.slice(0, 8)}...`;
|
|
55028
|
+
if (isJwtExpired(auth.jwt)) {
|
|
55029
|
+
try {
|
|
55030
|
+
const refreshed = await refreshSupabaseJwtRaw(auth.refreshToken);
|
|
55031
|
+
if (refreshed) {
|
|
55032
|
+
auth.jwt = refreshed.jwt;
|
|
55033
|
+
auth.refreshToken = refreshed.refreshToken;
|
|
55034
|
+
const entry = await store.get("access_tokens", auth.mcpToken);
|
|
55035
|
+
if (entry) {
|
|
55036
|
+
const remainingMs = entry.expiresAt - Date.now();
|
|
55037
|
+
if (remainingMs > 0) {
|
|
55038
|
+
await store.set("access_tokens", auth.mcpToken, {
|
|
55039
|
+
...entry,
|
|
55040
|
+
supabaseJwt: refreshed.jwt,
|
|
55041
|
+
supabaseRefreshToken: refreshed.refreshToken
|
|
55042
|
+
}, Math.ceil(remainingMs / 1000));
|
|
55043
|
+
console.error(`[PROACTIVE_REFRESH] OK: JWT refreshed on ${method} (${identity})`);
|
|
55044
|
+
}
|
|
55045
|
+
}
|
|
55046
|
+
}
|
|
55047
|
+
} catch (error48) {
|
|
55048
|
+
if (error48 instanceof SessionExpiredError) {
|
|
55049
|
+
console.error(`[PROACTIVE_REFRESH] Session dead on ${method} (${identity}): ${error48.message}`);
|
|
55050
|
+
await store.del("access_tokens", auth.mcpToken);
|
|
55051
|
+
res.status(401).json({
|
|
55052
|
+
jsonrpc: "2.0",
|
|
55053
|
+
error: { code: -32001, message: error48.message },
|
|
55054
|
+
id: req.body?.id ?? null
|
|
55055
|
+
});
|
|
55056
|
+
return;
|
|
55057
|
+
}
|
|
55058
|
+
console.error(`[PROACTIVE_REFRESH] WARN: refresh failed on ${method}, continuing with stale JWT`, error48);
|
|
55059
|
+
}
|
|
55060
|
+
}
|
|
55180
55061
|
try {
|
|
55181
55062
|
console.error(`[MCP] POST method=${method} auth=${identity}`);
|
|
55182
55063
|
const transport = new StreamableHTTPServerTransport({
|
|
55183
55064
|
sessionIdGenerator: undefined
|
|
55184
55065
|
});
|
|
55185
|
-
const server =
|
|
55066
|
+
const server = createServer({
|
|
55186
55067
|
jwt: auth.jwt,
|
|
55187
55068
|
refreshToken: auth.refreshToken,
|
|
55188
55069
|
teamId: auth.teamId,
|
|
@@ -55206,7 +55087,7 @@ async function startHttpServer(options) {
|
|
|
55206
55087
|
}, ttlSeconds);
|
|
55207
55088
|
console.error(`[PERSIST] OK: updated access token in store (token=${auth.mcpToken.slice(0, 12)}..., team=${state.teamId ?? "unchanged"}, ttl=${ttlSeconds}s)`);
|
|
55208
55089
|
}
|
|
55209
|
-
})
|
|
55090
|
+
});
|
|
55210
55091
|
await server.connect(transport);
|
|
55211
55092
|
await transport.handleRequest(req, res, req.body);
|
|
55212
55093
|
} catch (error48) {
|
|
@@ -55254,66 +55135,31 @@ var init_http2 = __esm(async () => {
|
|
|
55254
55135
|
init_bearerAuth();
|
|
55255
55136
|
init_auth2();
|
|
55256
55137
|
init_redis_store();
|
|
55138
|
+
init_client2();
|
|
55257
55139
|
await init_src();
|
|
55258
55140
|
});
|
|
55259
55141
|
|
|
55260
55142
|
// src/index.ts
|
|
55261
55143
|
function createServer(auth) {
|
|
55262
|
-
|
|
55263
|
-
|
|
55264
|
-
|
|
55265
|
-
|
|
55266
|
-
|
|
55267
|
-
|
|
55268
|
-
|
|
55269
|
-
persist: auth.persist
|
|
55270
|
-
};
|
|
55271
|
-
} else if (typeof auth === "object" && auth !== null && "apiKey" in auth) {
|
|
55272
|
-
ctx = {
|
|
55273
|
-
client: createKadoaClient({ apiKey: auth.apiKey })
|
|
55274
|
-
};
|
|
55275
|
-
} else {
|
|
55276
|
-
ctx = {
|
|
55277
|
-
client: createKadoaClient(auth)
|
|
55278
|
-
};
|
|
55279
|
-
}
|
|
55144
|
+
const ctx = {
|
|
55145
|
+
client: createKadoaClient({ jwt: auth.jwt, teamId: auth.teamId }),
|
|
55146
|
+
supabaseJwt: auth.jwt,
|
|
55147
|
+
supabaseRefreshToken: auth.refreshToken,
|
|
55148
|
+
teamId: auth.teamId,
|
|
55149
|
+
persist: auth.persist
|
|
55150
|
+
};
|
|
55280
55151
|
const server = new McpServer({ name: "kadoa", version: "0.3.2" });
|
|
55281
55152
|
registerTools(server, ctx);
|
|
55282
55153
|
server.server.onerror = (error48) => console.error("[MCP Error]", error48);
|
|
55283
55154
|
return server;
|
|
55284
55155
|
}
|
|
55285
|
-
async function validateApiKey() {
|
|
55286
|
-
const client = createKadoaClient();
|
|
55287
|
-
try {
|
|
55288
|
-
await client.workflow.list({ limit: 1 });
|
|
55289
|
-
} catch (error48) {
|
|
55290
|
-
if (KadoaSdkException.isInstance(error48) && error48.code === "AUTH_ERROR") {
|
|
55291
|
-
console.error("Kadoa MCP: Invalid API key. Check KADOA_API_KEY or run 'kadoa login'.");
|
|
55292
|
-
process.exit(1);
|
|
55293
|
-
}
|
|
55294
|
-
}
|
|
55295
|
-
}
|
|
55296
55156
|
var init_src = __esm(async () => {
|
|
55297
55157
|
init_mcp();
|
|
55298
|
-
init_stdio2();
|
|
55299
55158
|
init_client();
|
|
55300
55159
|
init_tools();
|
|
55301
55160
|
if (!process.env.VITEST && !process.env.BUN_TEST) {
|
|
55302
|
-
const
|
|
55303
|
-
|
|
55304
|
-
const { startHttpServer: startHttpServer2 } = await init_http2().then(() => exports_http);
|
|
55305
|
-
await startHttpServer2();
|
|
55306
|
-
} else {
|
|
55307
|
-
await validateApiKey();
|
|
55308
|
-
const server = createServer();
|
|
55309
|
-
const transport = new StdioServerTransport;
|
|
55310
|
-
await server.connect(transport);
|
|
55311
|
-
console.error("Kadoa MCP Server started");
|
|
55312
|
-
process.on("SIGINT", async () => {
|
|
55313
|
-
await server.close();
|
|
55314
|
-
process.exit(0);
|
|
55315
|
-
});
|
|
55316
|
-
}
|
|
55161
|
+
const { startHttpServer: startHttpServer2 } = await init_http2().then(() => exports_http);
|
|
55162
|
+
await startHttpServer2();
|
|
55317
55163
|
}
|
|
55318
55164
|
});
|
|
55319
55165
|
await init_src();
|
package/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kadoa/mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9-rc.1",
|
|
4
4
|
"description": "Kadoa MCP Server — manage workflows from Claude Desktop, Cursor, and other MCP clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"kadoa-mcp": "dist/index.js"
|
|
9
|
-
},
|
|
10
7
|
"publishConfig": {
|
|
11
8
|
"access": "public"
|
|
12
9
|
},
|
|
@@ -18,8 +15,7 @@
|
|
|
18
15
|
"lint": "bunx biome check",
|
|
19
16
|
"lint:fix": "bunx biome check --write",
|
|
20
17
|
"dev": "bun src/index.ts",
|
|
21
|
-
"
|
|
22
|
-
"build": "bun build src/index.ts --outdir=dist --target=node --external express --external ioredis && node -e \"const f='dist/index.js';require('fs').writeFileSync(f,require('fs').readFileSync(f,'utf8').replace('#!/usr/bin/env bun','#!/usr/bin/env node'))\"",
|
|
18
|
+
"build": "bun build src/index.ts --outdir=dist --target=node --external express --external ioredis",
|
|
23
19
|
"check-types": "tsc --noEmit",
|
|
24
20
|
"test": "BUN_TEST=1 bun test",
|
|
25
21
|
"test:unit": "BUN_TEST=1 bun test tests/unit --timeout=120000",
|