@unclick/mcp-server 0.2.4 → 0.2.5
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/dist/algolia-tool.d.ts +5 -0
- package/dist/algolia-tool.d.ts.map +1 -0
- package/dist/algolia-tool.js +121 -0
- package/dist/algolia-tool.js.map +1 -0
- package/dist/assemblyai-tool.d.ts +7 -0
- package/dist/assemblyai-tool.d.ts.map +1 -0
- package/dist/assemblyai-tool.js +127 -0
- package/dist/assemblyai-tool.js.map +1 -0
- package/dist/circleci-tool.d.ts +7 -0
- package/dist/circleci-tool.d.ts.map +1 -0
- package/dist/circleci-tool.js +133 -0
- package/dist/circleci-tool.js.map +1 -0
- package/dist/cohere-tool.d.ts +7 -0
- package/dist/cohere-tool.d.ts.map +1 -0
- package/dist/cohere-tool.js +225 -0
- package/dist/cohere-tool.js.map +1 -0
- package/dist/convertkit-tool.d.ts +7 -0
- package/dist/convertkit-tool.d.ts.map +1 -0
- package/dist/convertkit-tool.js +213 -0
- package/dist/convertkit-tool.js.map +1 -0
- package/dist/datadog-tool.d.ts +7 -0
- package/dist/datadog-tool.d.ts.map +1 -0
- package/dist/datadog-tool.js +121 -0
- package/dist/datadog-tool.js.map +1 -0
- package/dist/deepl-tool.d.ts +5 -0
- package/dist/deepl-tool.d.ts.map +1 -0
- package/dist/deepl-tool.js +137 -0
- package/dist/deepl-tool.js.map +1 -0
- package/dist/flyio-tool.d.ts +6 -0
- package/dist/flyio-tool.d.ts.map +1 -0
- package/dist/flyio-tool.js +158 -0
- package/dist/flyio-tool.js.map +1 -0
- package/dist/groq-tool.d.ts +3 -0
- package/dist/groq-tool.d.ts.map +1 -0
- package/dist/groq-tool.js +109 -0
- package/dist/groq-tool.js.map +1 -0
- package/dist/gumroad-tool.d.ts +6 -0
- package/dist/gumroad-tool.d.ts.map +1 -0
- package/dist/gumroad-tool.js +90 -0
- package/dist/gumroad-tool.js.map +1 -0
- package/dist/heygen-tool.d.ts +5 -0
- package/dist/heygen-tool.d.ts.map +1 -0
- package/dist/heygen-tool.js +134 -0
- package/dist/heygen-tool.js.map +1 -0
- package/dist/higgsfield-tool.d.ts +5 -0
- package/dist/higgsfield-tool.d.ts.map +1 -0
- package/dist/higgsfield-tool.js +120 -0
- package/dist/higgsfield-tool.js.map +1 -0
- package/dist/keychain-crypto.d.ts +24 -0
- package/dist/keychain-crypto.d.ts.map +1 -0
- package/dist/keychain-crypto.js +60 -0
- package/dist/keychain-crypto.js.map +1 -0
- package/dist/keychain-secure-input.d.ts +17 -0
- package/dist/keychain-secure-input.d.ts.map +1 -0
- package/dist/keychain-secure-input.js +229 -0
- package/dist/keychain-secure-input.js.map +1 -0
- package/dist/keychain-tool.d.ts +3 -0
- package/dist/keychain-tool.d.ts.map +1 -0
- package/dist/keychain-tool.js +516 -0
- package/dist/keychain-tool.js.map +1 -0
- package/dist/kling-tool.d.ts +3 -0
- package/dist/kling-tool.d.ts.map +1 -0
- package/dist/kling-tool.js +102 -0
- package/dist/kling-tool.js.map +1 -0
- package/dist/lemonsqueezy-tool.d.ts +7 -0
- package/dist/lemonsqueezy-tool.d.ts.map +1 -0
- package/dist/lemonsqueezy-tool.js +220 -0
- package/dist/lemonsqueezy-tool.js.map +1 -0
- package/dist/local-catalog-handlers.d.ts +3 -0
- package/dist/local-catalog-handlers.d.ts.map +1 -0
- package/dist/local-catalog-handlers.js +1254 -0
- package/dist/local-catalog-handlers.js.map +1 -0
- package/dist/mailchimp-tool.d.ts +8 -0
- package/dist/mailchimp-tool.d.ts.map +1 -0
- package/dist/mailchimp-tool.js +138 -0
- package/dist/mailchimp-tool.js.map +1 -0
- package/dist/mapbox-tool.d.ts +6 -0
- package/dist/mapbox-tool.d.ts.map +1 -0
- package/dist/mapbox-tool.js +106 -0
- package/dist/mapbox-tool.js.map +1 -0
- package/dist/mistral-tool.d.ts +4 -0
- package/dist/mistral-tool.d.ts.map +1 -0
- package/dist/mistral-tool.js +145 -0
- package/dist/mistral-tool.js.map +1 -0
- package/dist/mixpanel-tool.d.ts +6 -0
- package/dist/mixpanel-tool.d.ts.map +1 -0
- package/dist/mixpanel-tool.js +162 -0
- package/dist/mixpanel-tool.js.map +1 -0
- package/dist/neon-tool.d.ts +7 -0
- package/dist/neon-tool.d.ts.map +1 -0
- package/dist/neon-tool.js +156 -0
- package/dist/neon-tool.js.map +1 -0
- package/dist/pagerduty-tool.d.ts +8 -0
- package/dist/pagerduty-tool.d.ts.map +1 -0
- package/dist/pagerduty-tool.js +185 -0
- package/dist/pagerduty-tool.js.map +1 -0
- package/dist/perplexity-tool.d.ts +2 -0
- package/dist/perplexity-tool.d.ts.map +1 -0
- package/dist/perplexity-tool.js +93 -0
- package/dist/perplexity-tool.js.map +1 -0
- package/dist/pika-tool.d.ts +4 -0
- package/dist/pika-tool.d.ts.map +1 -0
- package/dist/pika-tool.js +102 -0
- package/dist/pika-tool.js.map +1 -0
- package/dist/pinecone-tool.d.ts +6 -0
- package/dist/pinecone-tool.d.ts.map +1 -0
- package/dist/pinecone-tool.js +148 -0
- package/dist/pinecone-tool.js.map +1 -0
- package/dist/postmark-tool.d.ts +7 -0
- package/dist/postmark-tool.d.ts.map +1 -0
- package/dist/postmark-tool.js +148 -0
- package/dist/postmark-tool.js.map +1 -0
- package/dist/qc-tool.d.ts +4 -0
- package/dist/qc-tool.d.ts.map +1 -0
- package/dist/qc-tool.js +415 -0
- package/dist/qc-tool.js.map +1 -0
- package/dist/render-tool.d.ts +7 -0
- package/dist/render-tool.d.ts.map +1 -0
- package/dist/render-tool.js +158 -0
- package/dist/render-tool.js.map +1 -0
- package/dist/runway-tool.d.ts +4 -0
- package/dist/runway-tool.d.ts.map +1 -0
- package/dist/runway-tool.js +110 -0
- package/dist/runway-tool.js.map +1 -0
- package/dist/segment-tool.d.ts +6 -0
- package/dist/segment-tool.d.ts.map +1 -0
- package/dist/segment-tool.js +129 -0
- package/dist/segment-tool.js.map +1 -0
- package/dist/sendgrid-tool.d.ts +7 -0
- package/dist/sendgrid-tool.d.ts.map +1 -0
- package/dist/sendgrid-tool.js +124 -0
- package/dist/sendgrid-tool.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +10 -0
- package/dist/server.js.map +1 -1
- package/dist/togetherai-tool.d.ts +5 -0
- package/dist/togetherai-tool.d.ts.map +1 -0
- package/dist/togetherai-tool.js +129 -0
- package/dist/togetherai-tool.js.map +1 -0
- package/dist/tool-wiring.d.ts +4608 -692
- package/dist/tool-wiring.d.ts.map +1 -1
- package/dist/tool-wiring.js +2946 -463
- package/dist/tool-wiring.js.map +1 -1
- package/dist/turso-tool.d.ts +6 -0
- package/dist/turso-tool.d.ts.map +1 -0
- package/dist/turso-tool.js +158 -0
- package/dist/turso-tool.js.map +1 -0
- package/dist/upstash-tool.d.ts +8 -0
- package/dist/upstash-tool.d.ts.map +1 -0
- package/dist/upstash-tool.js +191 -0
- package/dist/upstash-tool.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain-tool.d.ts","sourceRoot":"","sources":["../src/keychain-tool.ts"],"names":[],"mappings":"AA0kBA,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAY,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqBvG;AA4BD,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,OAAO,CAAC,CAgBlB"}
|
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
// ─── UnClick Keychain ─────────────────────────────────────────────────────────
|
|
2
|
+
// Encrypted credential vault for platform connections.
|
|
3
|
+
// Tenant-isolated by the caller's UNCLICK_API_KEY (SHA-256 hashed for lookups).
|
|
4
|
+
// All credential values are AES-256-GCM encrypted at rest.
|
|
5
|
+
//
|
|
6
|
+
// Required env vars:
|
|
7
|
+
// UNCLICK_API_KEY - caller's UnClick API key (never stored)
|
|
8
|
+
// SUPABASE_URL - Supabase project URL
|
|
9
|
+
// SUPABASE_SERVICE_ROLE_KEY - service role key (bypasses RLS)
|
|
10
|
+
import { encrypt, decrypt, hashKeyFull } from "./keychain-crypto.js";
|
|
11
|
+
import { resolveCredential } from "./keychain-secure-input.js";
|
|
12
|
+
// ─── Supabase helpers ─────────────────────────────────────────────────────────
|
|
13
|
+
function sbHeaders(serviceKey) {
|
|
14
|
+
return {
|
|
15
|
+
apikey: serviceKey,
|
|
16
|
+
Authorization: `Bearer ${serviceKey}`,
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
Prefer: "return=representation",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async function sbFetch(url, method, headers, body) {
|
|
22
|
+
const res = await fetch(url, {
|
|
23
|
+
method,
|
|
24
|
+
headers,
|
|
25
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
26
|
+
});
|
|
27
|
+
let data;
|
|
28
|
+
try {
|
|
29
|
+
data = await res.json();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
data = null;
|
|
33
|
+
}
|
|
34
|
+
return { ok: res.ok, status: res.status, data };
|
|
35
|
+
}
|
|
36
|
+
// ─── Metering ─────────────────────────────────────────────────────────────────
|
|
37
|
+
async function logMeter(supabaseUrl, serviceKey, keyHash, platform, operation, success, responseMs) {
|
|
38
|
+
try {
|
|
39
|
+
await sbFetch(`${supabaseUrl}/rest/v1/metering_events`, "POST", { ...sbHeaders(serviceKey), Prefer: "return=minimal" }, {
|
|
40
|
+
key_hash: keyHash,
|
|
41
|
+
platform,
|
|
42
|
+
operation,
|
|
43
|
+
success,
|
|
44
|
+
response_ms: responseMs,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// metering failure must never block the caller
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// ─── Connection test logging ──────────────────────────────────────────────────
|
|
52
|
+
async function logConnectionTest(supabaseUrl, serviceKey, platform, keyHash, result) {
|
|
53
|
+
try {
|
|
54
|
+
await sbFetch(`${supabaseUrl}/rest/v1/connection_tests`, "POST", { ...sbHeaders(serviceKey), Prefer: "return=minimal" }, {
|
|
55
|
+
key_hash: keyHash,
|
|
56
|
+
platform,
|
|
57
|
+
success: result.success,
|
|
58
|
+
status_code: result.status_code ?? null,
|
|
59
|
+
error_message: result.error_message ?? null,
|
|
60
|
+
response_ms: result.response_ms,
|
|
61
|
+
auth_method: result.auth_method,
|
|
62
|
+
auto_bug_filed: result.auto_bug_filed,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// logging must never block the main operation
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ─── Auto bug report on connection failure ────────────────────────────────────
|
|
70
|
+
async function autoBugReport(supabaseUrl, serviceKey, platform, errorMessage, statusCode) {
|
|
71
|
+
try {
|
|
72
|
+
// Dedup: skip if a bug for this platform was filed in the last 24 hours
|
|
73
|
+
const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
|
74
|
+
const checkUrl = `${supabaseUrl}/rest/v1/bug_reports?tool_name=eq.${encodeURIComponent(platform)}&created_at=gte.${encodeURIComponent(cutoff)}&select=id&limit=1`;
|
|
75
|
+
const { ok: checkOk, data: checkData } = await sbFetch(checkUrl, "GET", sbHeaders(serviceKey));
|
|
76
|
+
if (checkOk) {
|
|
77
|
+
const existing = checkData;
|
|
78
|
+
if (existing && existing.length > 0)
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
// Severity: high for auth failures, medium for timeouts, low for other
|
|
82
|
+
let severity = "low";
|
|
83
|
+
const msg = errorMessage.toLowerCase();
|
|
84
|
+
if (statusCode === 401 || statusCode === 403 || msg.includes("unauthorized") || msg.includes("forbidden")) {
|
|
85
|
+
severity = "high";
|
|
86
|
+
}
|
|
87
|
+
else if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("econnreset") || msg.includes("network")) {
|
|
88
|
+
severity = "medium";
|
|
89
|
+
}
|
|
90
|
+
const { ok } = await sbFetch(`${supabaseUrl}/rest/v1/bug_reports`, "POST", { ...sbHeaders(serviceKey), Prefer: "return=minimal" }, {
|
|
91
|
+
tool_name: platform,
|
|
92
|
+
error_message: errorMessage,
|
|
93
|
+
agent_context: "Auto-filed by Keychain connection test",
|
|
94
|
+
severity,
|
|
95
|
+
status: "open",
|
|
96
|
+
});
|
|
97
|
+
return ok;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const PLATFORM_TEST_CONFIG = {
|
|
104
|
+
// Stripe: Basic auth with key as username, empty password
|
|
105
|
+
stripe: {
|
|
106
|
+
auth_method: "basic",
|
|
107
|
+
buildHeaders: (cred) => ({
|
|
108
|
+
Authorization: `Basic ${Buffer.from(`${cred}:`).toString("base64")}`,
|
|
109
|
+
}),
|
|
110
|
+
},
|
|
111
|
+
// Twilio: Basic auth with AccountSID:AuthToken as a single credential string
|
|
112
|
+
twilio: {
|
|
113
|
+
auth_method: "basic",
|
|
114
|
+
buildHeaders: (cred) => ({
|
|
115
|
+
Authorization: `Basic ${Buffer.from(cred).toString("base64")}`,
|
|
116
|
+
}),
|
|
117
|
+
},
|
|
118
|
+
// Anthropic: x-api-key header + version header, POST with minimal body
|
|
119
|
+
anthropic: {
|
|
120
|
+
method: "POST",
|
|
121
|
+
auth_method: "x-api-key",
|
|
122
|
+
buildHeaders: (cred) => ({
|
|
123
|
+
"x-api-key": cred,
|
|
124
|
+
"anthropic-version": "2023-06-01",
|
|
125
|
+
"Content-Type": "application/json",
|
|
126
|
+
}),
|
|
127
|
+
body: {
|
|
128
|
+
model: "claude-haiku-4-5-20251001",
|
|
129
|
+
max_tokens: 1,
|
|
130
|
+
messages: [{ role: "user", content: "hi" }],
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
// Notion: Bearer + required Notion-Version header
|
|
134
|
+
notion: {
|
|
135
|
+
auth_method: "bearer",
|
|
136
|
+
buildHeaders: (cred) => ({
|
|
137
|
+
Authorization: `Bearer ${cred}`,
|
|
138
|
+
"Notion-Version": "2022-06-28",
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
// Linear: Bearer + POST GraphQL
|
|
142
|
+
linear: {
|
|
143
|
+
method: "POST",
|
|
144
|
+
auth_method: "bearer",
|
|
145
|
+
buildHeaders: (cred) => ({
|
|
146
|
+
Authorization: `Bearer ${cred}`,
|
|
147
|
+
"Content-Type": "application/json",
|
|
148
|
+
}),
|
|
149
|
+
body: { query: "{ viewer { id } }" },
|
|
150
|
+
},
|
|
151
|
+
// Shopify: custom header - but test URL has {store} placeholder so test is skipped
|
|
152
|
+
shopify: {
|
|
153
|
+
skip: true,
|
|
154
|
+
auth_method: "custom-header",
|
|
155
|
+
buildHeaders: (cred) => ({ "X-Shopify-Access-Token": cred }),
|
|
156
|
+
},
|
|
157
|
+
// Xero: OAuth2 - cannot test with a bare API key
|
|
158
|
+
xero: {
|
|
159
|
+
skip: true,
|
|
160
|
+
auth_method: "oauth2",
|
|
161
|
+
buildHeaders: () => ({}),
|
|
162
|
+
},
|
|
163
|
+
// Railway: Bearer + POST GraphQL
|
|
164
|
+
railway: {
|
|
165
|
+
method: "POST",
|
|
166
|
+
auth_method: "bearer",
|
|
167
|
+
buildHeaders: (cred) => ({
|
|
168
|
+
Authorization: `Bearer ${cred}`,
|
|
169
|
+
"Content-Type": "application/json",
|
|
170
|
+
}),
|
|
171
|
+
body: { query: "{ me { id } }" },
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
function defaultBuildHeaders(cred) {
|
|
175
|
+
return { Authorization: `Bearer ${cred}` };
|
|
176
|
+
}
|
|
177
|
+
async function testCredential(platform, credential, testEndpoint) {
|
|
178
|
+
const config = PLATFORM_TEST_CONFIG[platform];
|
|
179
|
+
const auth_method = config?.auth_method ?? "bearer";
|
|
180
|
+
if (!testEndpoint) {
|
|
181
|
+
return { passed: false, skipped: true, message: "No test endpoint configured.", response_ms: 0, auth_method };
|
|
182
|
+
}
|
|
183
|
+
// Skip endpoints with dynamic placeholders (e.g. {project_ref}, {store})
|
|
184
|
+
if (/\{[^}]+\}/.test(testEndpoint)) {
|
|
185
|
+
return {
|
|
186
|
+
passed: true,
|
|
187
|
+
skipped: true,
|
|
188
|
+
message: `${platform} credential accepted without live test (dynamic endpoint).`,
|
|
189
|
+
response_ms: 0,
|
|
190
|
+
auth_method,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// Skip OAuth or explicitly skipped platforms
|
|
194
|
+
if (config?.skip) {
|
|
195
|
+
return {
|
|
196
|
+
passed: true,
|
|
197
|
+
skipped: true,
|
|
198
|
+
message: `${platform} credential stored (live test not available for this platform type).`,
|
|
199
|
+
response_ms: 0,
|
|
200
|
+
auth_method,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const start = Date.now();
|
|
204
|
+
const buildHeaders = config?.buildHeaders ?? defaultBuildHeaders;
|
|
205
|
+
const method = config?.method ?? "GET";
|
|
206
|
+
const body = config?.body;
|
|
207
|
+
try {
|
|
208
|
+
const fetchOptions = { method, headers: buildHeaders(credential) };
|
|
209
|
+
if (body !== undefined) {
|
|
210
|
+
fetchOptions.body = JSON.stringify(body);
|
|
211
|
+
}
|
|
212
|
+
const res = await fetch(testEndpoint, fetchOptions);
|
|
213
|
+
const ms = Date.now() - start;
|
|
214
|
+
if (res.ok || res.status === 200) {
|
|
215
|
+
return {
|
|
216
|
+
passed: true,
|
|
217
|
+
skipped: false,
|
|
218
|
+
message: `Credential verified in ${ms}ms.`,
|
|
219
|
+
status_code: res.status,
|
|
220
|
+
response_ms: ms,
|
|
221
|
+
auth_method,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (res.status === 401 || res.status === 403) {
|
|
225
|
+
const errMsg = `Credential rejected by ${platform} (HTTP ${res.status}). Check your token.`;
|
|
226
|
+
return {
|
|
227
|
+
passed: false,
|
|
228
|
+
skipped: false,
|
|
229
|
+
message: errMsg,
|
|
230
|
+
status_code: res.status,
|
|
231
|
+
response_ms: ms,
|
|
232
|
+
error_message: errMsg,
|
|
233
|
+
auth_method,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
// Other non-200s (rate limits, partial responses) - treat as passing
|
|
237
|
+
return {
|
|
238
|
+
passed: true,
|
|
239
|
+
skipped: false,
|
|
240
|
+
message: `${platform} responded with HTTP ${res.status} - credential appears valid.`,
|
|
241
|
+
status_code: res.status,
|
|
242
|
+
response_ms: ms,
|
|
243
|
+
auth_method,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
const ms = Date.now() - start;
|
|
248
|
+
const errMsg = `Could not reach ${platform} test endpoint: ${err instanceof Error ? err.message : String(err)}`;
|
|
249
|
+
return {
|
|
250
|
+
passed: false,
|
|
251
|
+
skipped: false,
|
|
252
|
+
message: errMsg,
|
|
253
|
+
response_ms: ms,
|
|
254
|
+
error_message: errMsg,
|
|
255
|
+
auth_method,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// ─── Actions ──────────────────────────────────────────────────────────────────
|
|
260
|
+
async function keychainConnect(args) {
|
|
261
|
+
const apiKey = String(process.env.UNCLICK_API_KEY ?? "").trim();
|
|
262
|
+
const supaUrl = String(process.env.SUPABASE_URL ?? "").trim();
|
|
263
|
+
const serviceKey = String(process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
264
|
+
if (!apiKey)
|
|
265
|
+
return { error: "UNCLICK_API_KEY env var is not set." };
|
|
266
|
+
if (!supaUrl)
|
|
267
|
+
return { error: "SUPABASE_URL env var is not set." };
|
|
268
|
+
if (!serviceKey)
|
|
269
|
+
return { error: "SUPABASE_SERVICE_ROLE_KEY env var is not set." };
|
|
270
|
+
const platform = String(args.platform ?? "").trim().toLowerCase();
|
|
271
|
+
const credential = String(args.credential ?? "").trim();
|
|
272
|
+
const label = String(args.label ?? "default").trim() || "default";
|
|
273
|
+
if (!platform)
|
|
274
|
+
return { error: "platform is required." };
|
|
275
|
+
if (!credential)
|
|
276
|
+
return { error: "credential is required." };
|
|
277
|
+
const start = Date.now();
|
|
278
|
+
const keyHash = hashKeyFull(apiKey);
|
|
279
|
+
// Look up the platform connector
|
|
280
|
+
const connectorUrl = `${supaUrl}/rest/v1/platform_connectors?id=eq.${encodeURIComponent(platform)}&select=id,name,test_endpoint`;
|
|
281
|
+
const { ok: cOk, data: cData } = await sbFetch(connectorUrl, "GET", sbHeaders(serviceKey));
|
|
282
|
+
if (!cOk) {
|
|
283
|
+
return { error: "Failed to look up platform connector." };
|
|
284
|
+
}
|
|
285
|
+
const connectors = cData;
|
|
286
|
+
if (!connectors || connectors.length === 0) {
|
|
287
|
+
return { error: `Unknown platform "${platform}". Use keychain_list_platforms to see available options.` };
|
|
288
|
+
}
|
|
289
|
+
const connector = connectors[0];
|
|
290
|
+
const testEndpoint = connector.test_endpoint ? String(connector.test_endpoint) : null;
|
|
291
|
+
// Test the credential before storing
|
|
292
|
+
const test = await testCredential(platform, credential, testEndpoint);
|
|
293
|
+
const autoBugFiled = !test.passed && !test.skipped
|
|
294
|
+
? await autoBugReport(supaUrl, serviceKey, platform, test.error_message ?? test.message, test.status_code)
|
|
295
|
+
: false;
|
|
296
|
+
await logConnectionTest(supaUrl, serviceKey, platform, keyHash, {
|
|
297
|
+
success: test.passed,
|
|
298
|
+
status_code: test.status_code,
|
|
299
|
+
error_message: test.error_message,
|
|
300
|
+
response_ms: test.response_ms,
|
|
301
|
+
auth_method: test.auth_method,
|
|
302
|
+
auto_bug_filed: autoBugFiled,
|
|
303
|
+
});
|
|
304
|
+
if (!test.passed) {
|
|
305
|
+
await logMeter(supaUrl, serviceKey, keyHash, platform, "connect", false, Date.now() - start);
|
|
306
|
+
return {
|
|
307
|
+
error: `Credential validation failed for ${platform}.`,
|
|
308
|
+
message: test.message,
|
|
309
|
+
platform,
|
|
310
|
+
label,
|
|
311
|
+
status: "rejected",
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
// Encrypt and store
|
|
315
|
+
const { encrypted_value, iv, auth_tag } = encrypt(credential, apiKey);
|
|
316
|
+
const now = new Date().toISOString();
|
|
317
|
+
const row = {
|
|
318
|
+
key_hash: keyHash,
|
|
319
|
+
platform,
|
|
320
|
+
label,
|
|
321
|
+
encrypted_value,
|
|
322
|
+
iv,
|
|
323
|
+
auth_tag,
|
|
324
|
+
is_valid: true,
|
|
325
|
+
last_tested_at: now,
|
|
326
|
+
created_at: now,
|
|
327
|
+
};
|
|
328
|
+
const upsertUrl = `${supaUrl}/rest/v1/platform_credentials`;
|
|
329
|
+
const { ok, status } = await sbFetch(upsertUrl, "POST", { ...sbHeaders(serviceKey), Prefer: "resolution=merge-duplicates,return=minimal" }, row);
|
|
330
|
+
const ms = Date.now() - start;
|
|
331
|
+
await logMeter(supaUrl, serviceKey, keyHash, platform, "connect", ok, ms);
|
|
332
|
+
if (!ok) {
|
|
333
|
+
return { error: `Failed to store credential (HTTP ${status}).` };
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
platform,
|
|
337
|
+
label,
|
|
338
|
+
status: "connected",
|
|
339
|
+
tested: !test.skipped,
|
|
340
|
+
tested_at: now,
|
|
341
|
+
message: test.message,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
async function keychainStatus(args) {
|
|
345
|
+
const apiKey = String(process.env.UNCLICK_API_KEY ?? "").trim();
|
|
346
|
+
const supaUrl = String(process.env.SUPABASE_URL ?? "").trim();
|
|
347
|
+
const serviceKey = String(process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
348
|
+
if (!apiKey)
|
|
349
|
+
return { error: "UNCLICK_API_KEY env var is not set." };
|
|
350
|
+
if (!supaUrl)
|
|
351
|
+
return { error: "SUPABASE_URL env var is not set." };
|
|
352
|
+
if (!serviceKey)
|
|
353
|
+
return { error: "SUPABASE_SERVICE_ROLE_KEY env var is not set." };
|
|
354
|
+
const start = Date.now();
|
|
355
|
+
const keyHash = hashKeyFull(apiKey);
|
|
356
|
+
const platform = args.platform ? String(args.platform).trim().toLowerCase() : null;
|
|
357
|
+
let queryUrl = `${supaUrl}/rest/v1/platform_credentials?key_hash=eq.${encodeURIComponent(keyHash)}&select=platform,label,is_valid,last_tested_at,created_at`;
|
|
358
|
+
if (platform) {
|
|
359
|
+
queryUrl += `&platform=eq.${encodeURIComponent(platform)}`;
|
|
360
|
+
}
|
|
361
|
+
const { ok, data } = await sbFetch(queryUrl, "GET", sbHeaders(serviceKey));
|
|
362
|
+
const ms = Date.now() - start;
|
|
363
|
+
await logMeter(supaUrl, serviceKey, keyHash, platform ?? "all", "status", ok, ms);
|
|
364
|
+
if (!ok)
|
|
365
|
+
return { error: "Failed to query credentials." };
|
|
366
|
+
const rows = data;
|
|
367
|
+
if (!rows || rows.length === 0) {
|
|
368
|
+
if (platform) {
|
|
369
|
+
return { platform, connected: false, message: `No credential stored for "${platform}".` };
|
|
370
|
+
}
|
|
371
|
+
return { connected_platforms: [], count: 0 };
|
|
372
|
+
}
|
|
373
|
+
const result = rows.map((r) => ({
|
|
374
|
+
platform: r.platform,
|
|
375
|
+
label: r.label,
|
|
376
|
+
is_valid: r.is_valid,
|
|
377
|
+
last_tested_at: r.last_tested_at,
|
|
378
|
+
created_at: r.created_at,
|
|
379
|
+
}));
|
|
380
|
+
if (platform) {
|
|
381
|
+
return { ...result[0], connected: true };
|
|
382
|
+
}
|
|
383
|
+
return { connected_platforms: result, count: result.length };
|
|
384
|
+
}
|
|
385
|
+
async function keychainDisconnect(args) {
|
|
386
|
+
const apiKey = String(process.env.UNCLICK_API_KEY ?? "").trim();
|
|
387
|
+
const supaUrl = String(process.env.SUPABASE_URL ?? "").trim();
|
|
388
|
+
const serviceKey = String(process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
389
|
+
if (!apiKey)
|
|
390
|
+
return { error: "UNCLICK_API_KEY env var is not set." };
|
|
391
|
+
if (!supaUrl)
|
|
392
|
+
return { error: "SUPABASE_URL env var is not set." };
|
|
393
|
+
if (!serviceKey)
|
|
394
|
+
return { error: "SUPABASE_SERVICE_ROLE_KEY env var is not set." };
|
|
395
|
+
const platform = String(args.platform ?? "").trim().toLowerCase();
|
|
396
|
+
const label = args.label ? String(args.label).trim() : null;
|
|
397
|
+
if (!platform)
|
|
398
|
+
return { error: "platform is required." };
|
|
399
|
+
const start = Date.now();
|
|
400
|
+
const keyHash = hashKeyFull(apiKey);
|
|
401
|
+
let deleteUrl = `${supaUrl}/rest/v1/platform_credentials?key_hash=eq.${encodeURIComponent(keyHash)}&platform=eq.${encodeURIComponent(platform)}`;
|
|
402
|
+
if (label) {
|
|
403
|
+
deleteUrl += `&label=eq.${encodeURIComponent(label)}`;
|
|
404
|
+
}
|
|
405
|
+
const { ok, status } = await sbFetch(deleteUrl, "DELETE", sbHeaders(serviceKey));
|
|
406
|
+
const ms = Date.now() - start;
|
|
407
|
+
await logMeter(supaUrl, serviceKey, keyHash, platform, "disconnect", ok, ms);
|
|
408
|
+
if (!ok) {
|
|
409
|
+
return { error: `Failed to remove credential (HTTP ${status}).` };
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
platform,
|
|
413
|
+
label: label ?? "all",
|
|
414
|
+
status: "disconnected",
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
async function keychainListPlatforms(args) {
|
|
418
|
+
const apiKey = String(process.env.UNCLICK_API_KEY ?? "").trim();
|
|
419
|
+
const supaUrl = String(process.env.SUPABASE_URL ?? "").trim();
|
|
420
|
+
const serviceKey = String(process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
421
|
+
if (!supaUrl)
|
|
422
|
+
return { error: "SUPABASE_URL env var is not set." };
|
|
423
|
+
if (!serviceKey)
|
|
424
|
+
return { error: "SUPABASE_SERVICE_ROLE_KEY env var is not set." };
|
|
425
|
+
const category = args.category ? String(args.category).trim() : null;
|
|
426
|
+
const start = Date.now();
|
|
427
|
+
let connectorUrl = `${supaUrl}/rest/v1/platform_connectors?select=id,name,category,auth_type,description,setup_url,sort_order&order=sort_order.asc`;
|
|
428
|
+
if (category) {
|
|
429
|
+
connectorUrl += `&category=eq.${encodeURIComponent(category)}`;
|
|
430
|
+
}
|
|
431
|
+
const { ok, data } = await sbFetch(connectorUrl, "GET", sbHeaders(serviceKey));
|
|
432
|
+
if (!ok)
|
|
433
|
+
return { error: "Failed to query platform connectors." };
|
|
434
|
+
const platforms = data;
|
|
435
|
+
// If the caller has an API key, enrich with connection status
|
|
436
|
+
if (apiKey) {
|
|
437
|
+
const keyHash = hashKeyFull(apiKey);
|
|
438
|
+
const statusUrl = `${supaUrl}/rest/v1/platform_credentials?key_hash=eq.${encodeURIComponent(keyHash)}&select=platform,label,is_valid`;
|
|
439
|
+
const { ok: sOk, data: sData } = await sbFetch(statusUrl, "GET", sbHeaders(serviceKey));
|
|
440
|
+
const ms = Date.now() - start;
|
|
441
|
+
await logMeter(supaUrl, serviceKey, keyHash, "all", "list_platforms", sOk, ms);
|
|
442
|
+
if (sOk) {
|
|
443
|
+
const connected = new Set(sData.map((r) => String(r.platform)));
|
|
444
|
+
return {
|
|
445
|
+
platforms: platforms.map((p) => ({
|
|
446
|
+
...p,
|
|
447
|
+
connected: connected.has(String(p.id)),
|
|
448
|
+
})),
|
|
449
|
+
count: platforms.length,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return { platforms, count: platforms.length };
|
|
454
|
+
}
|
|
455
|
+
// ─── Decrypt helper for internal use ─────────────────────────────────────────
|
|
456
|
+
// Called by other tools that need to retrieve a stored credential.
|
|
457
|
+
export async function keychainGetCredential(platform, label = "default") {
|
|
458
|
+
const apiKey = String(process.env.UNCLICK_API_KEY ?? "").trim();
|
|
459
|
+
const supaUrl = String(process.env.SUPABASE_URL ?? "").trim();
|
|
460
|
+
const serviceKey = String(process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
461
|
+
if (!apiKey || !supaUrl || !serviceKey)
|
|
462
|
+
return null;
|
|
463
|
+
const keyHash = hashKeyFull(apiKey);
|
|
464
|
+
const url = `${supaUrl}/rest/v1/platform_credentials?key_hash=eq.${encodeURIComponent(keyHash)}&platform=eq.${encodeURIComponent(platform)}&label=eq.${encodeURIComponent(label)}&select=encrypted_value,iv,auth_tag`;
|
|
465
|
+
const { ok, data } = await sbFetch(url, "GET", sbHeaders(serviceKey));
|
|
466
|
+
if (!ok)
|
|
467
|
+
return null;
|
|
468
|
+
const rows = data;
|
|
469
|
+
if (!rows || rows.length === 0)
|
|
470
|
+
return null;
|
|
471
|
+
try {
|
|
472
|
+
return decrypt(rows[0].encrypted_value, rows[0].iv, rows[0].auth_tag, apiKey);
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// ─── Secure connect (env detection + localhost input page) ────────────────────
|
|
479
|
+
async function keychainSecureConnect(args) {
|
|
480
|
+
const platform = String(args.platform ?? "").trim().toLowerCase();
|
|
481
|
+
const label = String(args.label ?? "default").trim() || "default";
|
|
482
|
+
if (!platform)
|
|
483
|
+
return { error: "platform is required." };
|
|
484
|
+
const state = resolveCredential(platform, args.setup_url ? String(args.setup_url) : undefined);
|
|
485
|
+
if (state.status === "awaiting_input") {
|
|
486
|
+
return {
|
|
487
|
+
status: "awaiting_input",
|
|
488
|
+
url: state.url,
|
|
489
|
+
message: state.message,
|
|
490
|
+
next_step: `Open the URL in a browser, paste your key, then call keychain_secure_connect again with the same platform to complete the connection.`,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
// Credential resolved - proceed with the same flow as keychain_connect
|
|
494
|
+
const credential = state.value;
|
|
495
|
+
return keychainConnect({ ...args, platform, credential, label });
|
|
496
|
+
}
|
|
497
|
+
// ─── Public dispatcher ────────────────────────────────────────────────────────
|
|
498
|
+
export async function keychainAction(action, args) {
|
|
499
|
+
try {
|
|
500
|
+
switch (action) {
|
|
501
|
+
case "keychain_connect": return keychainConnect(args);
|
|
502
|
+
case "keychain_status": return keychainStatus(args);
|
|
503
|
+
case "keychain_disconnect": return keychainDisconnect(args);
|
|
504
|
+
case "keychain_list_platforms": return keychainListPlatforms(args);
|
|
505
|
+
case "keychain_secure_connect": return keychainSecureConnect(args);
|
|
506
|
+
default:
|
|
507
|
+
return {
|
|
508
|
+
error: `Unknown keychain action: "${action}". Valid actions: keychain_connect, keychain_status, keychain_disconnect, keychain_list_platforms, keychain_secure_connect.`,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
catch (err) {
|
|
513
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
//# sourceMappingURL=keychain-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain-tool.js","sourceRoot":"","sources":["../src/keychain-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kling-tool.d.ts","sourceRoot":"","sources":["../src/kling-tool.ts"],"names":[],"mappings":"AAoDA,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAoC1F;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAwBpF"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Kling AI API integration for the UnClick MCP server.
|
|
2
|
+
// Uses the Kling AI REST API via fetch - no external dependencies.
|
|
3
|
+
// Users must supply an API key from klingai.com (access_key format or pre-generated JWT).
|
|
4
|
+
const KLING_API_BASE = "https://api.klingai.com/v1";
|
|
5
|
+
// ─── Auth validation ──────────────────────────────────────────────────────────
|
|
6
|
+
function requireKey(args) {
|
|
7
|
+
const key = String(args.api_key ?? "").trim();
|
|
8
|
+
if (!key)
|
|
9
|
+
throw new Error("api_key is required. Get one at klingai.com.");
|
|
10
|
+
return key;
|
|
11
|
+
}
|
|
12
|
+
// ─── API helpers ──────────────────────────────────────────────────────────────
|
|
13
|
+
async function klingGet(apiKey, path) {
|
|
14
|
+
const res = await fetch(`${KLING_API_BASE}${path}`, {
|
|
15
|
+
headers: {
|
|
16
|
+
Authorization: `Bearer ${apiKey}`,
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
const data = await res.json();
|
|
21
|
+
if (!res.ok) {
|
|
22
|
+
const msg = data.message ?? data.error ?? `HTTP ${res.status}`;
|
|
23
|
+
throw new Error(`Kling AI error (${res.status}): ${msg}`);
|
|
24
|
+
}
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
async function klingPost(apiKey, path, body) {
|
|
28
|
+
const res = await fetch(`${KLING_API_BASE}${path}`, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: {
|
|
31
|
+
Authorization: `Bearer ${apiKey}`,
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify(body),
|
|
35
|
+
});
|
|
36
|
+
const data = await res.json();
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const msg = data.message ?? data.error ?? `HTTP ${res.status}`;
|
|
39
|
+
throw new Error(`Kling AI error (${res.status}): ${msg}`);
|
|
40
|
+
}
|
|
41
|
+
return data;
|
|
42
|
+
}
|
|
43
|
+
// ─── Operations ───────────────────────────────────────────────────────────────
|
|
44
|
+
export async function kling_generate_video(args) {
|
|
45
|
+
const apiKey = requireKey(args);
|
|
46
|
+
const prompt = String(args.prompt ?? "").trim();
|
|
47
|
+
if (!prompt)
|
|
48
|
+
throw new Error("prompt is required.");
|
|
49
|
+
const model = String(args.model ?? "kling-v1");
|
|
50
|
+
const mode = String(args.mode ?? "std");
|
|
51
|
+
const duration = String(args.duration ?? "5");
|
|
52
|
+
const body = {
|
|
53
|
+
model_name: model,
|
|
54
|
+
prompt,
|
|
55
|
+
mode,
|
|
56
|
+
duration,
|
|
57
|
+
};
|
|
58
|
+
if (args.image_url)
|
|
59
|
+
body.image = String(args.image_url);
|
|
60
|
+
if (args.negative_prompt)
|
|
61
|
+
body.negative_prompt = String(args.negative_prompt);
|
|
62
|
+
if (args.cfg_scale !== undefined)
|
|
63
|
+
body.cfg_scale = Number(args.cfg_scale);
|
|
64
|
+
if (args.aspect_ratio)
|
|
65
|
+
body.aspect_ratio = String(args.aspect_ratio);
|
|
66
|
+
if (args.camera_control)
|
|
67
|
+
body.camera_control = args.camera_control;
|
|
68
|
+
const result = await klingPost(apiKey, "/videos/text2video", body);
|
|
69
|
+
const taskData = result.data;
|
|
70
|
+
const taskId = taskData?.task_id ?? result.task_id ?? null;
|
|
71
|
+
return {
|
|
72
|
+
task_id: taskId,
|
|
73
|
+
status: taskData?.task_status ?? result.status ?? "submitted",
|
|
74
|
+
model,
|
|
75
|
+
mode,
|
|
76
|
+
duration,
|
|
77
|
+
note: "Use kling_get_task with the task_id to poll for completion. Status: submitted -> processing -> succeed/failed.",
|
|
78
|
+
raw: result,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export async function kling_get_task(args) {
|
|
82
|
+
const apiKey = requireKey(args);
|
|
83
|
+
const taskId = String(args.task_id ?? "").trim();
|
|
84
|
+
if (!taskId)
|
|
85
|
+
throw new Error("task_id is required.");
|
|
86
|
+
const result = await klingGet(apiKey, `/videos/text2video/${encodeURIComponent(taskId)}`);
|
|
87
|
+
const taskData = result.data;
|
|
88
|
+
const info = taskData ?? result;
|
|
89
|
+
const videos = info.task_result;
|
|
90
|
+
return {
|
|
91
|
+
task_id: taskId,
|
|
92
|
+
status: info.task_status ?? null,
|
|
93
|
+
progress: info.task_progress ?? null,
|
|
94
|
+
video_url: videos?.videos?.[0]?.url ?? null,
|
|
95
|
+
videos: videos?.videos ?? [],
|
|
96
|
+
created_at: info.created_at ?? null,
|
|
97
|
+
updated_at: info.updated_at ?? null,
|
|
98
|
+
error: info.task_status_msg ?? null,
|
|
99
|
+
raw: result,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=kling-tool.js.map
|