vibo-mcp 1.3.2 → 1.4.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bundle.js +202 -118
- package/dist/client.js +57 -59
- package/dist/index.js +5 -0
- package/dist/tools/collaboration.js +1 -2
- package/dist/tools/comments.js +1 -2
- package/dist/tools/events.js +1 -2
- package/dist/tools/ideas.js +1 -2
- package/dist/tools/imports.js +1 -2
- package/dist/tools/notifications.js +1 -2
- package/dist/tools/playlists.js +1 -2
- package/dist/tools/profile.js +1 -2
- package/dist/tools/questions.js +54 -18
- package/dist/tools/section-edit.js +1 -2
- package/dist/tools/sections.js +1 -2
- package/dist/tools/session.js +5 -2
- package/dist/tools/shared.js +9 -0
- package/dist/tools/song-management.js +1 -2
- package/dist/tools/songs.js +1 -2
- package/dist/tools/uploads.js +25 -8
- package/dist/upload-source.js +79 -0
- package/dist/version.js +1 -1
- package/dist/vibo-auth.js +34 -0
- package/package.json +14 -5
- package/server.json +2 -2
package/dist/bundle.js
CHANGED
|
@@ -31120,7 +31120,7 @@ function toolAnnotations(opts = {}) {
|
|
|
31120
31120
|
}
|
|
31121
31121
|
|
|
31122
31122
|
// src/version.ts
|
|
31123
|
-
var VERSION = "1.
|
|
31123
|
+
var VERSION = "1.4.1";
|
|
31124
31124
|
|
|
31125
31125
|
// src/client.ts
|
|
31126
31126
|
import { dirname as dirname2, join as join2 } from "path";
|
|
@@ -31299,8 +31299,11 @@ function saveSession(session) {
|
|
|
31299
31299
|
}
|
|
31300
31300
|
|
|
31301
31301
|
// src/client.ts
|
|
31302
|
-
|
|
31303
|
-
|
|
31302
|
+
try {
|
|
31303
|
+
const __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
31304
|
+
await loadDotenvSafely({ path: join2(__dirname, "..", ".env"), override: false });
|
|
31305
|
+
} catch {
|
|
31306
|
+
}
|
|
31304
31307
|
var DEFAULT_API_URL = "https://api.vibodj.com/v2/graphql";
|
|
31305
31308
|
var SERVICE = "Vibo";
|
|
31306
31309
|
var SIGN_IN_HOST = "https://web.vibodj.com";
|
|
@@ -31327,24 +31330,37 @@ var ViboClient = class {
|
|
|
31327
31330
|
email;
|
|
31328
31331
|
password;
|
|
31329
31332
|
// Not readonly: cleared by setTokens() after a browser capture seeds a session.
|
|
31330
|
-
configError;
|
|
31333
|
+
configError = null;
|
|
31331
31334
|
accessToken;
|
|
31332
31335
|
refreshTokenValue;
|
|
31336
|
+
// The constructor is PURE — it does no filesystem / homedir / async-I/O /
|
|
31337
|
+
// random op — so it is safe to run at Worker global scope (where the
|
|
31338
|
+
// module-level `export const client` singleton below is constructed). The
|
|
31339
|
+
// saved-session fallback and the config-error determination both touch
|
|
31340
|
+
// homedir()/the filesystem via loadSession(), so they are deferred to the
|
|
31341
|
+
// first request through `ensureConfigResolved()`. No effect on the stdio path.
|
|
31342
|
+
configResolved = false;
|
|
31333
31343
|
// Single-flight guards so concurrent tool calls never race two logins /
|
|
31334
31344
|
// refreshes against each other (à la mcp-utils' TokenManager).
|
|
31335
31345
|
loginInFlight = null;
|
|
31336
31346
|
reauthInFlight = null;
|
|
31337
|
-
constructor() {
|
|
31338
|
-
this.apiUrl = readEnvVar("VIBO_API_URL") ?? DEFAULT_API_URL;
|
|
31339
|
-
|
|
31340
|
-
|
|
31341
|
-
|
|
31342
|
-
|
|
31343
|
-
|
|
31344
|
-
|
|
31345
|
-
|
|
31346
|
-
|
|
31347
|
-
|
|
31347
|
+
constructor(opts = {}) {
|
|
31348
|
+
this.apiUrl = opts.apiUrl ?? readEnvVar("VIBO_API_URL") ?? DEFAULT_API_URL;
|
|
31349
|
+
this.email = opts.email ?? readEnvVar("VIBO_EMAIL") ?? null;
|
|
31350
|
+
this.password = opts.password ?? readEnvVar("VIBO_PASSWORD") ?? null;
|
|
31351
|
+
this.accessToken = opts.accessToken ?? readEnvVar("VIBO_ACCESS_TOKEN") ?? null;
|
|
31352
|
+
this.refreshTokenValue = opts.refreshToken ?? readEnvVar("VIBO_REFRESH_TOKEN") ?? null;
|
|
31353
|
+
}
|
|
31354
|
+
/**
|
|
31355
|
+
* Resolve the saved-session fallback and the deferred config error on first
|
|
31356
|
+
* use. Kept out of the constructor so construction is pure (Worker-safe):
|
|
31357
|
+
* `loadSession()` reads homedir()/the filesystem, which the Workers runtime
|
|
31358
|
+
* forbids at global scope. Runs its body at most once.
|
|
31359
|
+
*/
|
|
31360
|
+
ensureConfigResolved() {
|
|
31361
|
+
if (this.configResolved) return;
|
|
31362
|
+
this.configResolved = true;
|
|
31363
|
+
const haveLogin = Boolean(this.email && this.password);
|
|
31348
31364
|
if (!this.accessToken && !haveLogin) {
|
|
31349
31365
|
const saved = loadSession();
|
|
31350
31366
|
if (saved) {
|
|
@@ -31360,8 +31376,6 @@ var ViboClient = class {
|
|
|
31360
31376
|
hint: "Set VIBO_EMAIL and VIBO_PASSWORD (recommended); paste a captured VIBO_ACCESS_TOKEN (+ VIBO_REFRESH_TOKEN); or run vibo_capture_session to grab the token from your signed-in web.vibodj.com browser tab (Apple/Google/Facebook accounts)."
|
|
31361
31377
|
}
|
|
31362
31378
|
);
|
|
31363
|
-
} else {
|
|
31364
|
-
this.configError = null;
|
|
31365
31379
|
}
|
|
31366
31380
|
}
|
|
31367
31381
|
/**
|
|
@@ -31382,6 +31396,7 @@ var ViboClient = class {
|
|
|
31382
31396
|
}
|
|
31383
31397
|
/** Run a GraphQL operation, transparently authenticating + retrying once on token expiry. */
|
|
31384
31398
|
async gql(query, variables = {}) {
|
|
31399
|
+
this.ensureConfigResolved();
|
|
31385
31400
|
if (this.configError) throw this.configError;
|
|
31386
31401
|
const token = await this.ensureAccessToken();
|
|
31387
31402
|
let res = await this.post(query, variables, token);
|
|
@@ -31393,44 +31408,38 @@ var ViboClient = class {
|
|
|
31393
31408
|
}
|
|
31394
31409
|
/**
|
|
31395
31410
|
* Run a GraphQL operation that uploads one or more files (the `Upload` scalar),
|
|
31396
|
-
* using the graphql-multipart-request spec. `
|
|
31397
|
-
* path (e.g. "variables.photo" or "variables.payload.answer.images.0") to
|
|
31398
|
-
*
|
|
31399
|
-
*
|
|
31411
|
+
* using the graphql-multipart-request spec. `files` maps a dotted variable
|
|
31412
|
+
* path (e.g. "variables.photo" or "variables.payload.answer.images.0") to an
|
|
31413
|
+
* in-memory {@link UploadFile} (blob + filename); `variables` must carry
|
|
31414
|
+
* `null` at each of those positions. The bytes arrive already resolved (from
|
|
31415
|
+
* a local file on stdio, or inline base64 on the hosted connector — see
|
|
31416
|
+
* src/upload-source.ts), so this method never touches the filesystem and runs
|
|
31417
|
+
* unchanged in the Workers runtime (`FormData`/`Blob`/`fetch` are all
|
|
31418
|
+
* available there). Same auth + single-retry-on-expiry behavior as `gql`.
|
|
31400
31419
|
*/
|
|
31401
|
-
async gqlUpload(query, variables,
|
|
31420
|
+
async gqlUpload(query, variables, files) {
|
|
31421
|
+
this.ensureConfigResolved();
|
|
31402
31422
|
if (this.configError) throw this.configError;
|
|
31403
31423
|
const token = await this.ensureAccessToken();
|
|
31404
|
-
let res = await this.postMultipart(query, variables,
|
|
31424
|
+
let res = await this.postMultipart(query, variables, files, token);
|
|
31405
31425
|
if (this.isAuthError(res.status, res.body.errors)) {
|
|
31406
31426
|
const fresh = await this.reauthenticate();
|
|
31407
|
-
res = await this.postMultipart(query, variables,
|
|
31427
|
+
res = await this.postMultipart(query, variables, files, fresh);
|
|
31408
31428
|
}
|
|
31409
31429
|
return this.unwrap(res.status, res.body);
|
|
31410
31430
|
}
|
|
31411
|
-
async postMultipart(query, variables,
|
|
31412
|
-
const { openAsBlob } = await import("node:fs");
|
|
31413
|
-
const { basename } = await import("node:path");
|
|
31431
|
+
async postMultipart(query, variables, files, token) {
|
|
31414
31432
|
const form = new FormData();
|
|
31415
31433
|
form.append("operations", JSON.stringify({ query, variables }));
|
|
31416
|
-
const paths = Object.keys(
|
|
31434
|
+
const paths = Object.keys(files);
|
|
31417
31435
|
const map2 = {};
|
|
31418
31436
|
paths.forEach((varPath, i) => {
|
|
31419
31437
|
map2[String(i)] = [varPath];
|
|
31420
31438
|
});
|
|
31421
31439
|
form.append("map", JSON.stringify(map2));
|
|
31422
31440
|
for (let i = 0; i < paths.length; i++) {
|
|
31423
|
-
const
|
|
31424
|
-
|
|
31425
|
-
try {
|
|
31426
|
-
blob = await openAsBlob(filePath);
|
|
31427
|
-
} catch (err) {
|
|
31428
|
-
throw new McpToolError(`Could not read file for upload: ${filePath}`, {
|
|
31429
|
-
hint: "Provide an absolute path to a readable local file.",
|
|
31430
|
-
cause: err
|
|
31431
|
-
});
|
|
31432
|
-
}
|
|
31433
|
-
form.append(String(i), blob, basename(filePath));
|
|
31441
|
+
const file2 = files[paths[i]];
|
|
31442
|
+
form.append(String(i), file2.blob, file2.filename);
|
|
31434
31443
|
}
|
|
31435
31444
|
const headers = { "apollo-require-preflight": "true" };
|
|
31436
31445
|
if (token) headers["x-token"] = token;
|
|
@@ -31892,7 +31901,7 @@ var UPLOAD_USER_PHOTO = `
|
|
|
31892
31901
|
`;
|
|
31893
31902
|
|
|
31894
31903
|
// src/tools/profile.ts
|
|
31895
|
-
function registerProfileTools(server) {
|
|
31904
|
+
function registerProfileTools(server, client2) {
|
|
31896
31905
|
server.registerTool(
|
|
31897
31906
|
"vibo_get_me",
|
|
31898
31907
|
{
|
|
@@ -31900,7 +31909,7 @@ function registerProfileTools(server) {
|
|
|
31900
31909
|
annotations: toolAnnotations({ title: "Get my Vibo profile", readOnly: true })
|
|
31901
31910
|
},
|
|
31902
31911
|
async () => {
|
|
31903
|
-
const data = await
|
|
31912
|
+
const data = await client2.gql(GET_ME);
|
|
31904
31913
|
return textResult(data.me);
|
|
31905
31914
|
}
|
|
31906
31915
|
);
|
|
@@ -31911,7 +31920,7 @@ function registerProfileTools(server) {
|
|
|
31911
31920
|
annotations: toolAnnotations({ title: "Vibo healthcheck", readOnly: true })
|
|
31912
31921
|
},
|
|
31913
31922
|
async () => {
|
|
31914
|
-
const data = await
|
|
31923
|
+
const data = await client2.gql(GET_ME);
|
|
31915
31924
|
return textResult({ ok: true, userId: data.me._id, email: data.me.email });
|
|
31916
31925
|
}
|
|
31917
31926
|
);
|
|
@@ -31923,6 +31932,10 @@ var skipSchema = external_exports.number().int().min(0).optional().describe("Num
|
|
|
31923
31932
|
function pagination(limit, skip) {
|
|
31924
31933
|
return { skip: skip ?? 0, limit: limit ?? 20 };
|
|
31925
31934
|
}
|
|
31935
|
+
var inlineFileSchema = external_exports.object({
|
|
31936
|
+
data: external_exports.string().describe("Base64-encoded file bytes (a `data:` URL prefix is allowed)."),
|
|
31937
|
+
filename: external_exports.string().optional().describe("Filename to send with this file.")
|
|
31938
|
+
});
|
|
31926
31939
|
function previewResult(action, willSend) {
|
|
31927
31940
|
return textResult({
|
|
31928
31941
|
preview: true,
|
|
@@ -31933,7 +31946,7 @@ function previewResult(action, willSend) {
|
|
|
31933
31946
|
}
|
|
31934
31947
|
|
|
31935
31948
|
// src/tools/events.ts
|
|
31936
|
-
function registerEventTools(server) {
|
|
31949
|
+
function registerEventTools(server, client2) {
|
|
31937
31950
|
server.registerTool(
|
|
31938
31951
|
"vibo_list_events",
|
|
31939
31952
|
{
|
|
@@ -31952,7 +31965,7 @@ function registerEventTools(server) {
|
|
|
31952
31965
|
...q ? { filter: { q } } : {}
|
|
31953
31966
|
};
|
|
31954
31967
|
const doc = past ? LIST_HISTORY_EVENTS : LIST_UPCOMING_EVENTS;
|
|
31955
|
-
const data = await
|
|
31968
|
+
const data = await client2.gql(doc, variables);
|
|
31956
31969
|
return textResult(past ? data.historyEvents : data.upcomingEvents);
|
|
31957
31970
|
}
|
|
31958
31971
|
);
|
|
@@ -31966,7 +31979,7 @@ function registerEventTools(server) {
|
|
|
31966
31979
|
}
|
|
31967
31980
|
},
|
|
31968
31981
|
async ({ eventId }) => {
|
|
31969
|
-
const data = await
|
|
31982
|
+
const data = await client2.gql(GET_EVENT, { eventId });
|
|
31970
31983
|
return textResult(data.event);
|
|
31971
31984
|
}
|
|
31972
31985
|
);
|
|
@@ -31986,12 +31999,12 @@ function registerEventTools(server) {
|
|
|
31986
31999
|
return previewResult("joinEvent", isUrl ? { deepLink: link } : { hash: link });
|
|
31987
32000
|
}
|
|
31988
32001
|
if (isUrl) {
|
|
31989
|
-
const data2 = await
|
|
32002
|
+
const data2 = await client2.gql(JOIN_EVENT_BY_DEEP_LINK, {
|
|
31990
32003
|
deepLink: link
|
|
31991
32004
|
});
|
|
31992
32005
|
return textResult({ joined: true, eventId: data2.joinEventViaDeepLink._id });
|
|
31993
32006
|
}
|
|
31994
|
-
const data = await
|
|
32007
|
+
const data = await client2.gql(JOIN_EVENT_BY_HASH, { hash: link });
|
|
31995
32008
|
return textResult({ joined: true, eventId: data.joinEventByHash._id });
|
|
31996
32009
|
}
|
|
31997
32010
|
);
|
|
@@ -32007,7 +32020,7 @@ function registerEventTools(server) {
|
|
|
32007
32020
|
},
|
|
32008
32021
|
async ({ eventId, confirm }) => {
|
|
32009
32022
|
if (!confirm) return previewResult("leaveEvent", { eventId });
|
|
32010
|
-
const data = await
|
|
32023
|
+
const data = await client2.gql(LEAVE_EVENT, { eventId });
|
|
32011
32024
|
return textResult({ left: true, eventId, result: data.leaveEvent });
|
|
32012
32025
|
}
|
|
32013
32026
|
);
|
|
@@ -32039,14 +32052,14 @@ function registerEventTools(server) {
|
|
|
32039
32052
|
});
|
|
32040
32053
|
}
|
|
32041
32054
|
if (!confirm) return previewResult("createEventContact", { eventId, payload });
|
|
32042
|
-
const data = await
|
|
32055
|
+
const data = await client2.gql(CREATE_EVENT_CONTACT, { eventId, payload });
|
|
32043
32056
|
return textResult(data.createEventContact);
|
|
32044
32057
|
}
|
|
32045
32058
|
);
|
|
32046
32059
|
}
|
|
32047
32060
|
|
|
32048
32061
|
// src/tools/sections.ts
|
|
32049
|
-
function registerSectionTools(server) {
|
|
32062
|
+
function registerSectionTools(server, client2) {
|
|
32050
32063
|
server.registerTool(
|
|
32051
32064
|
"vibo_list_sections",
|
|
32052
32065
|
{
|
|
@@ -32057,14 +32070,14 @@ function registerSectionTools(server) {
|
|
|
32057
32070
|
}
|
|
32058
32071
|
},
|
|
32059
32072
|
async ({ eventId }) => {
|
|
32060
|
-
const data = await
|
|
32073
|
+
const data = await client2.gql(LIST_SECTIONS, { eventId });
|
|
32061
32074
|
return textResult(data.sections);
|
|
32062
32075
|
}
|
|
32063
32076
|
);
|
|
32064
32077
|
}
|
|
32065
32078
|
|
|
32066
32079
|
// src/tools/songs.ts
|
|
32067
|
-
function registerSongTools(server) {
|
|
32080
|
+
function registerSongTools(server, client2) {
|
|
32068
32081
|
server.registerTool(
|
|
32069
32082
|
"vibo_get_section_songs",
|
|
32070
32083
|
{
|
|
@@ -32094,7 +32107,7 @@ function registerSongTools(server) {
|
|
|
32094
32107
|
...Object.keys(filter).length ? { filter } : {},
|
|
32095
32108
|
...sortField ? { sort: { field: sortField, direction: sortDirection ?? "desc" } } : {}
|
|
32096
32109
|
};
|
|
32097
|
-
const data = await
|
|
32110
|
+
const data = await client2.gql(GET_SECTION_SONGS, variables);
|
|
32098
32111
|
return textResult(data.getSectionSongs);
|
|
32099
32112
|
}
|
|
32100
32113
|
);
|
|
@@ -32112,7 +32125,7 @@ function registerSongTools(server) {
|
|
|
32112
32125
|
}
|
|
32113
32126
|
},
|
|
32114
32127
|
async ({ eventId, sectionId, query, source, limit }) => {
|
|
32115
|
-
const data = await
|
|
32128
|
+
const data = await client2.gql(SEARCH_SONGS, {
|
|
32116
32129
|
eventId,
|
|
32117
32130
|
sectionId,
|
|
32118
32131
|
filter: { q: query, source: source ?? "searchField" },
|
|
@@ -32143,7 +32156,7 @@ function registerSongTools(server) {
|
|
|
32143
32156
|
if (artist !== void 0) song.artist = artist;
|
|
32144
32157
|
const payload = { song };
|
|
32145
32158
|
if (!confirm) return previewResult("addSongToSection", { eventId, sectionId, payload });
|
|
32146
|
-
const data = await
|
|
32159
|
+
const data = await client2.gql(ADD_SONG_TO_SECTION, {
|
|
32147
32160
|
eventId,
|
|
32148
32161
|
sectionId,
|
|
32149
32162
|
payload
|
|
@@ -32166,7 +32179,7 @@ function registerSongTools(server) {
|
|
|
32166
32179
|
},
|
|
32167
32180
|
async ({ eventId, sectionId, songId, liked, confirm }) => {
|
|
32168
32181
|
if (!confirm) return previewResult("toggleLike", { eventId, sectionId, songId, liked });
|
|
32169
|
-
const data = await
|
|
32182
|
+
const data = await client2.gql(TOGGLE_LIKE, {
|
|
32170
32183
|
eventId,
|
|
32171
32184
|
sectionId,
|
|
32172
32185
|
songId,
|
|
@@ -32179,7 +32192,7 @@ function registerSongTools(server) {
|
|
|
32179
32192
|
|
|
32180
32193
|
// src/tools/playlists.ts
|
|
32181
32194
|
var sourceSchema = external_exports.enum(["spotify", "appleMusic"]).describe("Streaming source \u2014 must be connected to your Vibo account.");
|
|
32182
|
-
function registerPlaylistTools(server) {
|
|
32195
|
+
function registerPlaylistTools(server, client2) {
|
|
32183
32196
|
server.registerTool(
|
|
32184
32197
|
"vibo_get_playlists",
|
|
32185
32198
|
{
|
|
@@ -32193,7 +32206,7 @@ function registerPlaylistTools(server) {
|
|
|
32193
32206
|
}
|
|
32194
32207
|
},
|
|
32195
32208
|
async ({ source, q, limit, skip }) => {
|
|
32196
|
-
const data = await
|
|
32209
|
+
const data = await client2.gql(GET_PLAYLISTS, {
|
|
32197
32210
|
source,
|
|
32198
32211
|
pagination: pagination(limit, skip),
|
|
32199
32212
|
...q ? { filter: { q } } : {}
|
|
@@ -32214,7 +32227,7 @@ function registerPlaylistTools(server) {
|
|
|
32214
32227
|
}
|
|
32215
32228
|
},
|
|
32216
32229
|
async ({ playlistId, source, limit, skip }) => {
|
|
32217
|
-
const data = await
|
|
32230
|
+
const data = await client2.gql(GET_PLAYLIST_SONGS, {
|
|
32218
32231
|
playlistId,
|
|
32219
32232
|
source,
|
|
32220
32233
|
pagination: pagination(limit, skip)
|
|
@@ -32240,7 +32253,7 @@ function registerPlaylistTools(server) {
|
|
|
32240
32253
|
if (title !== void 0) variables.title = title;
|
|
32241
32254
|
if (onlyFlagged !== void 0) variables.filter = { isFlagged: onlyFlagged };
|
|
32242
32255
|
if (!confirm) return previewResult("exportEventToSpotify", variables);
|
|
32243
|
-
const data = await
|
|
32256
|
+
const data = await client2.gql(EXPORT_EVENT_TO_SPOTIFY, variables);
|
|
32244
32257
|
return textResult(data.exportEventToSpotify);
|
|
32245
32258
|
}
|
|
32246
32259
|
);
|
|
@@ -32262,14 +32275,14 @@ function registerPlaylistTools(server) {
|
|
|
32262
32275
|
if (title !== void 0) variables.title = title;
|
|
32263
32276
|
if (onlyFlagged !== void 0) variables.filter = { isFlagged: onlyFlagged };
|
|
32264
32277
|
if (!confirm) return previewResult("exportEventToAppleMusic", variables);
|
|
32265
|
-
const data = await
|
|
32278
|
+
const data = await client2.gql(EXPORT_EVENT_TO_APPLE_MUSIC, variables);
|
|
32266
32279
|
return textResult(data.exportEventToAppleMusic);
|
|
32267
32280
|
}
|
|
32268
32281
|
);
|
|
32269
32282
|
}
|
|
32270
32283
|
|
|
32271
32284
|
// src/tools/notifications.ts
|
|
32272
|
-
function registerNotificationTools(server) {
|
|
32285
|
+
function registerNotificationTools(server, client2) {
|
|
32273
32286
|
server.registerTool(
|
|
32274
32287
|
"vibo_list_notifications",
|
|
32275
32288
|
{
|
|
@@ -32281,7 +32294,7 @@ function registerNotificationTools(server) {
|
|
|
32281
32294
|
}
|
|
32282
32295
|
},
|
|
32283
32296
|
async ({ limit, skip }) => {
|
|
32284
|
-
const data = await
|
|
32297
|
+
const data = await client2.gql(GET_NOTIFICATIONS, {
|
|
32285
32298
|
pagination: pagination(limit, skip)
|
|
32286
32299
|
});
|
|
32287
32300
|
return textResult(data.getNotifications);
|
|
@@ -32294,7 +32307,7 @@ function registerNotificationTools(server) {
|
|
|
32294
32307
|
annotations: toolAnnotations({ title: "Unread notification count", readOnly: true })
|
|
32295
32308
|
},
|
|
32296
32309
|
async () => {
|
|
32297
|
-
const data = await
|
|
32310
|
+
const data = await client2.gql(GET_NOTIFICATIONS_COUNT);
|
|
32298
32311
|
return textResult(data.getNotificationsCount);
|
|
32299
32312
|
}
|
|
32300
32313
|
);
|
|
@@ -32319,14 +32332,52 @@ function registerNotificationTools(server) {
|
|
|
32319
32332
|
if (notificationIds?.length) variables.notificationIds = notificationIds;
|
|
32320
32333
|
if (readAll) variables.readAll = true;
|
|
32321
32334
|
if (!confirm) return previewResult("markAsRead", variables);
|
|
32322
|
-
const data = await
|
|
32335
|
+
const data = await client2.gql(MARK_AS_READ, variables);
|
|
32323
32336
|
return textResult({ marked: true, result: data.markAsRead });
|
|
32324
32337
|
}
|
|
32325
32338
|
);
|
|
32326
32339
|
}
|
|
32327
32340
|
|
|
32341
|
+
// src/upload-source.ts
|
|
32342
|
+
var DEFAULT_FILENAME = "upload";
|
|
32343
|
+
function blobFromBase64(data, filename) {
|
|
32344
|
+
const base643 = data.includes(",") && data.startsWith("data:") ? data.slice(data.indexOf(",") + 1) : data;
|
|
32345
|
+
let binary;
|
|
32346
|
+
try {
|
|
32347
|
+
binary = atob(base643.trim());
|
|
32348
|
+
} catch (err) {
|
|
32349
|
+
throw new McpToolError("Could not decode inline file data \u2014 expected base64.", {
|
|
32350
|
+
hint: "Pass the file bytes as a base64 string in `fileData` (a `data:` URL prefix is allowed).",
|
|
32351
|
+
cause: err
|
|
32352
|
+
});
|
|
32353
|
+
}
|
|
32354
|
+
const bytes = new Uint8Array(binary.length);
|
|
32355
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
32356
|
+
return { blob: new Blob([bytes]), filename: filename ?? DEFAULT_FILENAME };
|
|
32357
|
+
}
|
|
32358
|
+
var nodeUploadResolver = async (ref) => {
|
|
32359
|
+
if (ref.path) {
|
|
32360
|
+
const { openAsBlob } = await import("node:fs");
|
|
32361
|
+
const { basename } = await import("node:path");
|
|
32362
|
+
let blob;
|
|
32363
|
+
try {
|
|
32364
|
+
blob = await openAsBlob(ref.path);
|
|
32365
|
+
} catch (err) {
|
|
32366
|
+
throw new McpToolError(`Could not read file for upload: ${ref.path}`, {
|
|
32367
|
+
hint: "Provide an absolute path to a readable local file.",
|
|
32368
|
+
cause: err
|
|
32369
|
+
});
|
|
32370
|
+
}
|
|
32371
|
+
return { blob, filename: ref.filename ?? basename(ref.path) };
|
|
32372
|
+
}
|
|
32373
|
+
if (ref.data) return blobFromBase64(ref.data, ref.filename);
|
|
32374
|
+
throw new McpToolError("No file provided for upload.", {
|
|
32375
|
+
hint: "Pass a local file `path` (or inline base64 `fileData`)."
|
|
32376
|
+
});
|
|
32377
|
+
};
|
|
32378
|
+
|
|
32328
32379
|
// src/tools/questions.ts
|
|
32329
|
-
function registerQuestionTools(server) {
|
|
32380
|
+
function registerQuestionTools(server, client2, resolveUpload = nodeUploadResolver) {
|
|
32330
32381
|
server.registerTool(
|
|
32331
32382
|
"vibo_list_section_questions",
|
|
32332
32383
|
{
|
|
@@ -32338,7 +32389,7 @@ function registerQuestionTools(server) {
|
|
|
32338
32389
|
}
|
|
32339
32390
|
},
|
|
32340
32391
|
async ({ eventId, sectionId }) => {
|
|
32341
|
-
const data = await
|
|
32392
|
+
const data = await client2.gql(LIST_SECTION_QUESTIONS, {
|
|
32342
32393
|
eventId,
|
|
32343
32394
|
sectionId
|
|
32344
32395
|
});
|
|
@@ -32348,7 +32399,7 @@ function registerQuestionTools(server) {
|
|
|
32348
32399
|
server.registerTool(
|
|
32349
32400
|
"vibo_answer_question",
|
|
32350
32401
|
{
|
|
32351
|
-
description: "Answer a section planning question. Provide the field matching the question's type: `text` for a text question, `selectedOptions` (array of option _ids from vibo_list_section_questions) for radio/checkbox/select, or `link` (array of URLs) for a link question. Use `otherOptionTitle` with the question's \"other\" option. For photo/file questions, pass `imagePaths`
|
|
32402
|
+
description: "Answer a section planning question. Provide the field matching the question's type: `text` for a text question, `selectedOptions` (array of option _ids from vibo_list_section_questions) for radio/checkbox/select, or `link` (array of URLs) for a link question. Use `otherOptionTitle` with the question's \"other\" option. For photo/file questions, pass local paths (`imagePaths`/`filePaths`) on the stdio server, or inline base64 bytes (`images`/`files`) on the hosted connector. Confirm-gated.",
|
|
32352
32403
|
annotations: toolAnnotations({ title: "Answer Vibo question", readOnly: false }),
|
|
32353
32404
|
inputSchema: {
|
|
32354
32405
|
eventId: external_exports.string().describe("Event id."),
|
|
@@ -32358,17 +32409,27 @@ function registerQuestionTools(server) {
|
|
|
32358
32409
|
selectedOptions: external_exports.array(external_exports.string()).optional().describe("Option _ids to select, for radio/checkbox/select questions."),
|
|
32359
32410
|
link: external_exports.array(external_exports.string()).optional().describe("URL(s), for a link question."),
|
|
32360
32411
|
otherOptionTitle: external_exports.string().optional().describe(`Free-text value when selecting the question's "other" option.`),
|
|
32361
|
-
imagePaths: external_exports.array(external_exports.string()).optional().describe("Absolute local image file paths, for a photo question."),
|
|
32362
|
-
filePaths: external_exports.array(external_exports.string()).optional().describe("Absolute local file paths, for a file-attachment question."),
|
|
32412
|
+
imagePaths: external_exports.array(external_exports.string()).optional().describe("Absolute local image file paths, for a photo question (local/stdio server only)."),
|
|
32413
|
+
filePaths: external_exports.array(external_exports.string()).optional().describe("Absolute local file paths, for a file-attachment question (local/stdio server only)."),
|
|
32414
|
+
images: external_exports.array(inlineFileSchema).optional().describe("Inline base64 images, for a photo question (used by the hosted connector, which has no filesystem)."),
|
|
32415
|
+
files: external_exports.array(inlineFileSchema).optional().describe("Inline base64 files, for a file-attachment question (used by the hosted connector)."),
|
|
32363
32416
|
confirm: schemaConfirm
|
|
32364
32417
|
}
|
|
32365
32418
|
},
|
|
32366
|
-
async ({ eventId, sectionId, questionId, text, selectedOptions, link, otherOptionTitle, imagePaths, filePaths, confirm }) => {
|
|
32367
|
-
const
|
|
32368
|
-
|
|
32419
|
+
async ({ eventId, sectionId, questionId, text, selectedOptions, link, otherOptionTitle, imagePaths, filePaths, images, files, confirm }) => {
|
|
32420
|
+
const imageRefs = [
|
|
32421
|
+
...(imagePaths ?? []).map((path) => ({ path })),
|
|
32422
|
+
...(images ?? []).map((f) => ({ data: f.data, filename: f.filename }))
|
|
32423
|
+
];
|
|
32424
|
+
const fileRefs = [
|
|
32425
|
+
...(filePaths ?? []).map((path) => ({ path })),
|
|
32426
|
+
...(files ?? []).map((f) => ({ data: f.data, filename: f.filename }))
|
|
32427
|
+
];
|
|
32428
|
+
const hasImages = imageRefs.length > 0;
|
|
32429
|
+
const hasFiles = fileRefs.length > 0;
|
|
32369
32430
|
if (text === void 0 && selectedOptions === void 0 && link === void 0 && !hasImages && !hasFiles) {
|
|
32370
|
-
throw new McpToolError("Provide an answer: text, selectedOptions, link, imagePaths, or filePaths.", {
|
|
32371
|
-
hint: "Match the question's type \u2014 text \u2192 `text`, radio/checkbox/select \u2192 `selectedOptions`, link \u2192 `link`, photo/file \u2192 `imagePaths`/`filePaths
|
|
32431
|
+
throw new McpToolError("Provide an answer: text, selectedOptions, link, imagePaths/images, or filePaths/files.", {
|
|
32432
|
+
hint: "Match the question's type \u2014 text \u2192 `text`, radio/checkbox/select \u2192 `selectedOptions`, link \u2192 `link`, photo/file \u2192 `imagePaths`/`filePaths` (stdio) or `images`/`files` (hosted connector)."
|
|
32372
32433
|
});
|
|
32373
32434
|
}
|
|
32374
32435
|
const answer = {};
|
|
@@ -32377,25 +32438,36 @@ function registerQuestionTools(server) {
|
|
|
32377
32438
|
if (link !== void 0) answer.link = link;
|
|
32378
32439
|
if (otherOptionTitle !== void 0) answer.otherOptionTitle = otherOptionTitle;
|
|
32379
32440
|
if (hasImages || hasFiles) {
|
|
32380
|
-
if (hasImages) answer.images =
|
|
32381
|
-
if (hasFiles) answer.files =
|
|
32441
|
+
if (hasImages) answer.images = imageRefs.map(() => null);
|
|
32442
|
+
if (hasFiles) answer.files = fileRefs.map(() => null);
|
|
32382
32443
|
const payload2 = { answer };
|
|
32383
|
-
const
|
|
32384
|
-
|
|
32385
|
-
|
|
32444
|
+
const previewUploads = {};
|
|
32445
|
+
imageRefs.forEach((ref, i) => {
|
|
32446
|
+
previewUploads[`variables.payload.answer.images.${i}`] = ref.path ?? "(inline bytes)";
|
|
32447
|
+
});
|
|
32448
|
+
fileRefs.forEach((ref, i) => {
|
|
32449
|
+
previewUploads[`variables.payload.answer.files.${i}`] = ref.path ?? "(inline bytes)";
|
|
32450
|
+
});
|
|
32386
32451
|
if (!confirm) {
|
|
32387
|
-
return previewResult("answerEventSectionQuestionV2", { eventId, sectionId, questionId, payload: payload2, uploads:
|
|
32452
|
+
return previewResult("answerEventSectionQuestionV2", { eventId, sectionId, questionId, payload: payload2, uploads: previewUploads });
|
|
32388
32453
|
}
|
|
32389
|
-
const
|
|
32454
|
+
const resolvedFiles = {};
|
|
32455
|
+
for (let i = 0; i < imageRefs.length; i++) {
|
|
32456
|
+
resolvedFiles[`variables.payload.answer.images.${i}`] = await resolveUpload(imageRefs[i]);
|
|
32457
|
+
}
|
|
32458
|
+
for (let i = 0; i < fileRefs.length; i++) {
|
|
32459
|
+
resolvedFiles[`variables.payload.answer.files.${i}`] = await resolveUpload(fileRefs[i]);
|
|
32460
|
+
}
|
|
32461
|
+
const data2 = await client2.gqlUpload(
|
|
32390
32462
|
ANSWER_SECTION_QUESTION,
|
|
32391
32463
|
{ eventId, sectionId, questionId, payload: payload2 },
|
|
32392
|
-
|
|
32464
|
+
resolvedFiles
|
|
32393
32465
|
);
|
|
32394
32466
|
return textResult(data2.answerEventSectionQuestionV2);
|
|
32395
32467
|
}
|
|
32396
32468
|
const payload = { answer };
|
|
32397
32469
|
if (!confirm) return previewResult("answerEventSectionQuestionV2", { eventId, sectionId, questionId, payload });
|
|
32398
|
-
const data = await
|
|
32470
|
+
const data = await client2.gql(ANSWER_SECTION_QUESTION, {
|
|
32399
32471
|
eventId,
|
|
32400
32472
|
sectionId,
|
|
32401
32473
|
questionId,
|
|
@@ -32407,7 +32479,7 @@ function registerQuestionTools(server) {
|
|
|
32407
32479
|
}
|
|
32408
32480
|
|
|
32409
32481
|
// src/tools/song-management.ts
|
|
32410
|
-
function registerSongManagementTools(server) {
|
|
32482
|
+
function registerSongManagementTools(server, client2) {
|
|
32411
32483
|
server.registerTool(
|
|
32412
32484
|
"vibo_remove_song_from_section",
|
|
32413
32485
|
{
|
|
@@ -32423,7 +32495,7 @@ function registerSongManagementTools(server) {
|
|
|
32423
32495
|
async ({ eventId, sectionId, songIds, confirm }) => {
|
|
32424
32496
|
const vars = { eventId, sectionId, songIds };
|
|
32425
32497
|
if (!confirm) return previewResult("removeSectionSongsV2", vars);
|
|
32426
|
-
const data = await
|
|
32498
|
+
const data = await client2.gql(REMOVE_SECTION_SONGS, vars);
|
|
32427
32499
|
return textResult(data.removeSectionSongsV2);
|
|
32428
32500
|
}
|
|
32429
32501
|
);
|
|
@@ -32454,7 +32526,7 @@ function registerSongManagementTools(server) {
|
|
|
32454
32526
|
}
|
|
32455
32527
|
const vars = { eventId, sectionId, songIds, payload };
|
|
32456
32528
|
if (!confirm) return previewResult("updateSectionSongs", vars);
|
|
32457
|
-
const data = await
|
|
32529
|
+
const data = await client2.gql(UPDATE_SECTION_SONGS, vars);
|
|
32458
32530
|
return textResult(data.updateSectionSongs);
|
|
32459
32531
|
}
|
|
32460
32532
|
);
|
|
@@ -32474,7 +32546,7 @@ function registerSongManagementTools(server) {
|
|
|
32474
32546
|
async ({ eventId, sourceSectionId, targetSectionId, songIds, confirm }) => {
|
|
32475
32547
|
const vars = { eventId, sourceSectionId, targetSectionId, songIds };
|
|
32476
32548
|
if (!confirm) return previewResult("moveSectionSongsV2", vars);
|
|
32477
|
-
const data = await
|
|
32549
|
+
const data = await client2.gql(MOVE_SECTION_SONGS, vars);
|
|
32478
32550
|
return textResult(data.moveSectionSongsV2);
|
|
32479
32551
|
}
|
|
32480
32552
|
);
|
|
@@ -32494,14 +32566,14 @@ function registerSongManagementTools(server) {
|
|
|
32494
32566
|
async ({ eventId, sectionId, sourceSongIds, targetSongId, confirm }) => {
|
|
32495
32567
|
const vars = { eventId, sectionId, sourceSongIds, targetSongId: targetSongId ?? null };
|
|
32496
32568
|
if (!confirm) return previewResult("reorderSongsBatch", vars);
|
|
32497
|
-
const data = await
|
|
32569
|
+
const data = await client2.gql(REORDER_SONGS, vars);
|
|
32498
32570
|
return textResult(data.reorderSongsBatch);
|
|
32499
32571
|
}
|
|
32500
32572
|
);
|
|
32501
32573
|
}
|
|
32502
32574
|
|
|
32503
32575
|
// src/tools/comments.ts
|
|
32504
|
-
function registerCommentTools(server) {
|
|
32576
|
+
function registerCommentTools(server, client2) {
|
|
32505
32577
|
server.registerTool(
|
|
32506
32578
|
"vibo_comment_on_song",
|
|
32507
32579
|
{
|
|
@@ -32518,7 +32590,7 @@ function registerCommentTools(server) {
|
|
|
32518
32590
|
async ({ eventId, sectionId, songId, message, confirm }) => {
|
|
32519
32591
|
const vars = { eventId, sectionId, songId, payload: { message } };
|
|
32520
32592
|
if (!confirm) return previewResult("createSongComment", vars);
|
|
32521
|
-
const data = await
|
|
32593
|
+
const data = await client2.gql(CREATE_SONG_COMMENT, vars);
|
|
32522
32594
|
return textResult(data.createSongComment);
|
|
32523
32595
|
}
|
|
32524
32596
|
);
|
|
@@ -32538,7 +32610,7 @@ function registerCommentTools(server) {
|
|
|
32538
32610
|
async ({ eventId, sectionId, songId, commentId, confirm }) => {
|
|
32539
32611
|
const vars = { eventId, sectionId, songId, commentId };
|
|
32540
32612
|
if (!confirm) return previewResult("deleteSongComment", vars);
|
|
32541
|
-
const data = await
|
|
32613
|
+
const data = await client2.gql(DELETE_SONG_COMMENT, vars);
|
|
32542
32614
|
return textResult(data.deleteSongComment);
|
|
32543
32615
|
}
|
|
32544
32616
|
);
|
|
@@ -32557,7 +32629,7 @@ function registerCommentTools(server) {
|
|
|
32557
32629
|
async ({ eventId, sectionId, message, confirm }) => {
|
|
32558
32630
|
const vars = { eventId, sectionId, payload: { message } };
|
|
32559
32631
|
if (!confirm) return previewResult("createSectionComment", vars);
|
|
32560
|
-
const data = await
|
|
32632
|
+
const data = await client2.gql(CREATE_SECTION_COMMENT, vars);
|
|
32561
32633
|
return textResult(data.createSectionComment);
|
|
32562
32634
|
}
|
|
32563
32635
|
);
|
|
@@ -32576,14 +32648,14 @@ function registerCommentTools(server) {
|
|
|
32576
32648
|
async ({ eventId, sectionId, commentId, confirm }) => {
|
|
32577
32649
|
const vars = { eventId, sectionId, commentId };
|
|
32578
32650
|
if (!confirm) return previewResult("deleteSectionComment", vars);
|
|
32579
|
-
const data = await
|
|
32651
|
+
const data = await client2.gql(DELETE_SECTION_COMMENT, vars);
|
|
32580
32652
|
return textResult(data.deleteSectionComment);
|
|
32581
32653
|
}
|
|
32582
32654
|
);
|
|
32583
32655
|
}
|
|
32584
32656
|
|
|
32585
32657
|
// src/tools/ideas.ts
|
|
32586
|
-
function registerIdeasTools(server) {
|
|
32658
|
+
function registerIdeasTools(server, client2) {
|
|
32587
32659
|
server.registerTool(
|
|
32588
32660
|
"vibo_list_section_song_ideas",
|
|
32589
32661
|
{
|
|
@@ -32597,7 +32669,7 @@ function registerIdeasTools(server) {
|
|
|
32597
32669
|
}
|
|
32598
32670
|
},
|
|
32599
32671
|
async ({ eventId, sectionId, limit, skip }) => {
|
|
32600
|
-
const data = await
|
|
32672
|
+
const data = await client2.gql(LIST_SECTION_SONG_IDEAS, {
|
|
32601
32673
|
eventId,
|
|
32602
32674
|
sectionId,
|
|
32603
32675
|
pagination: pagination(limit, skip)
|
|
@@ -32619,7 +32691,7 @@ function registerIdeasTools(server) {
|
|
|
32619
32691
|
}
|
|
32620
32692
|
},
|
|
32621
32693
|
async ({ eventId, sectionId, songIdeasId, limit, skip }) => {
|
|
32622
|
-
const data = await
|
|
32694
|
+
const data = await client2.gql(LIST_SONG_IDEAS_SONGS, {
|
|
32623
32695
|
eventId,
|
|
32624
32696
|
sectionId,
|
|
32625
32697
|
songIdeasId,
|
|
@@ -32631,7 +32703,7 @@ function registerIdeasTools(server) {
|
|
|
32631
32703
|
}
|
|
32632
32704
|
|
|
32633
32705
|
// src/tools/imports.ts
|
|
32634
|
-
function registerImportTools(server) {
|
|
32706
|
+
function registerImportTools(server, client2) {
|
|
32635
32707
|
server.registerTool(
|
|
32636
32708
|
"vibo_import_playlist_to_section",
|
|
32637
32709
|
{
|
|
@@ -32657,7 +32729,7 @@ function registerImportTools(server) {
|
|
|
32657
32729
|
tracksToIgnore: tracksToIgnore ?? []
|
|
32658
32730
|
};
|
|
32659
32731
|
if (!confirm) return previewResult("importPlaylistToSectionWeb", vars);
|
|
32660
|
-
const data = await
|
|
32732
|
+
const data = await client2.gql(
|
|
32661
32733
|
IMPORT_PLAYLIST_TO_SECTION,
|
|
32662
32734
|
vars
|
|
32663
32735
|
);
|
|
@@ -32667,7 +32739,7 @@ function registerImportTools(server) {
|
|
|
32667
32739
|
}
|
|
32668
32740
|
|
|
32669
32741
|
// src/tools/collaboration.ts
|
|
32670
|
-
function registerCollaborationTools(server) {
|
|
32742
|
+
function registerCollaborationTools(server, client2) {
|
|
32671
32743
|
server.registerTool(
|
|
32672
32744
|
"vibo_list_event_users",
|
|
32673
32745
|
{
|
|
@@ -32683,7 +32755,7 @@ function registerCollaborationTools(server) {
|
|
|
32683
32755
|
async ({ eventId, usersType, limit, skip }) => {
|
|
32684
32756
|
const page = pagination(limit, skip);
|
|
32685
32757
|
if (usersType) {
|
|
32686
|
-
const data = await
|
|
32758
|
+
const data = await client2.gql(LIST_EVENT_USERS, {
|
|
32687
32759
|
eventId,
|
|
32688
32760
|
usersType,
|
|
32689
32761
|
pagination: page
|
|
@@ -32691,8 +32763,8 @@ function registerCollaborationTools(server) {
|
|
|
32691
32763
|
return textResult({ ...data.eventUsers, usersType });
|
|
32692
32764
|
}
|
|
32693
32765
|
const [hosts, guests] = await Promise.all([
|
|
32694
|
-
|
|
32695
|
-
|
|
32766
|
+
client2.gql(LIST_EVENT_USERS, { eventId, usersType: "host", pagination: page }),
|
|
32767
|
+
client2.gql(LIST_EVENT_USERS, { eventId, usersType: "guest", pagination: page })
|
|
32696
32768
|
]);
|
|
32697
32769
|
return textResult({
|
|
32698
32770
|
hosts: hosts.eventUsers.users,
|
|
@@ -32718,7 +32790,7 @@ function registerCollaborationTools(server) {
|
|
|
32718
32790
|
async ({ eventId, type, text, emails, confirm }) => {
|
|
32719
32791
|
const variables = { eventId, type, text, emails };
|
|
32720
32792
|
if (!confirm) return previewResult("inviteUserViaEmail", variables);
|
|
32721
|
-
const data = await
|
|
32793
|
+
const data = await client2.gql(INVITE_USERS, variables);
|
|
32722
32794
|
return textResult(data.inviteUserViaEmail);
|
|
32723
32795
|
}
|
|
32724
32796
|
);
|
|
@@ -32737,7 +32809,7 @@ function registerCollaborationTools(server) {
|
|
|
32737
32809
|
async ({ eventId, userId, type, confirm }) => {
|
|
32738
32810
|
const variables = { eventId, userId, type };
|
|
32739
32811
|
if (!confirm) return previewResult("changeUserTypeInEvent", variables);
|
|
32740
|
-
const data = await
|
|
32812
|
+
const data = await client2.gql(CHANGE_USER_ROLE, variables);
|
|
32741
32813
|
return textResult(data.changeUserTypeInEvent);
|
|
32742
32814
|
}
|
|
32743
32815
|
);
|
|
@@ -32755,14 +32827,14 @@ function registerCollaborationTools(server) {
|
|
|
32755
32827
|
async ({ eventId, userId, confirm }) => {
|
|
32756
32828
|
const variables = { eventId, userId };
|
|
32757
32829
|
if (!confirm) return previewResult("removeUserFromEvent", variables);
|
|
32758
|
-
const data = await
|
|
32830
|
+
const data = await client2.gql(REMOVE_USER, variables);
|
|
32759
32831
|
return textResult(data.removeUserFromEvent);
|
|
32760
32832
|
}
|
|
32761
32833
|
);
|
|
32762
32834
|
}
|
|
32763
32835
|
|
|
32764
32836
|
// src/tools/section-edit.ts
|
|
32765
|
-
function registerSectionEditTools(server) {
|
|
32837
|
+
function registerSectionEditTools(server, client2) {
|
|
32766
32838
|
server.registerTool(
|
|
32767
32839
|
"vibo_update_section",
|
|
32768
32840
|
{
|
|
@@ -32791,30 +32863,38 @@ function registerSectionEditTools(server) {
|
|
|
32791
32863
|
}
|
|
32792
32864
|
const vars = { eventId, sectionId, payload };
|
|
32793
32865
|
if (!confirm) return previewResult("updateSection", vars);
|
|
32794
|
-
const data = await
|
|
32866
|
+
const data = await client2.gql(UPDATE_SECTION, vars);
|
|
32795
32867
|
return textResult(data.updateSection);
|
|
32796
32868
|
}
|
|
32797
32869
|
);
|
|
32798
32870
|
}
|
|
32799
32871
|
|
|
32800
32872
|
// src/tools/uploads.ts
|
|
32801
|
-
function registerUploadTools(server) {
|
|
32873
|
+
function registerUploadTools(server, client2, resolveUpload = nodeUploadResolver) {
|
|
32802
32874
|
server.registerTool(
|
|
32803
32875
|
"vibo_set_profile_photo",
|
|
32804
32876
|
{
|
|
32805
|
-
description: "Set your Vibo profile photo from a local image
|
|
32877
|
+
description: "Set your Vibo profile photo from an image. On the local (stdio) server pass a local file `path`; on the hosted connector pass the image bytes as base64 `fileData`. Returns the uploaded image URL. Confirm-gated.",
|
|
32806
32878
|
annotations: toolAnnotations({ title: "Set Vibo profile photo", readOnly: false }),
|
|
32807
32879
|
inputSchema: {
|
|
32808
|
-
path: external_exports.string().describe("Absolute path to a local image file (jpg/png)."),
|
|
32880
|
+
path: external_exports.string().optional().describe("Absolute path to a local image file (jpg/png). Local/stdio server only."),
|
|
32881
|
+
fileData: external_exports.string().optional().describe("Base64-encoded image bytes (a `data:` URL prefix is allowed). Used by the hosted connector, which has no filesystem."),
|
|
32882
|
+
filename: external_exports.string().optional().describe('Filename for the image when using fileData (default "photo.jpg").'),
|
|
32809
32883
|
confirm: schemaConfirm
|
|
32810
32884
|
}
|
|
32811
32885
|
},
|
|
32812
|
-
async ({ path, confirm }) => {
|
|
32813
|
-
if (!
|
|
32814
|
-
|
|
32886
|
+
async ({ path, fileData, filename, confirm }) => {
|
|
32887
|
+
if (!path && !fileData) {
|
|
32888
|
+
throw new McpToolError("Provide an image: a local file `path` or inline base64 `fileData`.", {
|
|
32889
|
+
hint: "On the local server pass `path`; on the hosted connector pass `fileData` (base64)."
|
|
32890
|
+
});
|
|
32891
|
+
}
|
|
32892
|
+
if (!confirm) return previewResult("uploadUserPhoto", { photo: path ?? "(inline bytes)" });
|
|
32893
|
+
const file2 = await resolveUpload({ path, data: fileData, filename: filename ?? "photo.jpg" });
|
|
32894
|
+
const data = await client2.gqlUpload(
|
|
32815
32895
|
UPLOAD_USER_PHOTO,
|
|
32816
32896
|
{ photo: null },
|
|
32817
|
-
{ "variables.photo":
|
|
32897
|
+
{ "variables.photo": file2 }
|
|
32818
32898
|
);
|
|
32819
32899
|
return textResult(data.uploadUserPhoto);
|
|
32820
32900
|
}
|
|
@@ -32868,7 +32948,7 @@ async function captureViboSession(deps = {}) {
|
|
|
32868
32948
|
}
|
|
32869
32949
|
|
|
32870
32950
|
// src/tools/session.ts
|
|
32871
|
-
function registerSessionTools(server) {
|
|
32951
|
+
function registerSessionTools(server, client2) {
|
|
32872
32952
|
server.registerTool(
|
|
32873
32953
|
"vibo_capture_session",
|
|
32874
32954
|
{
|
|
@@ -32877,8 +32957,8 @@ function registerSessionTools(server) {
|
|
|
32877
32957
|
},
|
|
32878
32958
|
async () => {
|
|
32879
32959
|
const { accessToken, refreshToken } = await captureViboSession();
|
|
32880
|
-
|
|
32881
|
-
const data = await
|
|
32960
|
+
client2.setTokens(accessToken, refreshToken);
|
|
32961
|
+
const data = await client2.gql(GET_ME);
|
|
32882
32962
|
saveSession({ accessToken, refreshToken });
|
|
32883
32963
|
return textResult({
|
|
32884
32964
|
captured: true,
|
|
@@ -32895,6 +32975,10 @@ await runMcp({
|
|
|
32895
32975
|
name: "vibo-mcp",
|
|
32896
32976
|
version: VERSION,
|
|
32897
32977
|
banner: "[vibo-mcp] This project was developed and is maintained by AI (Claude Code). Use at your own discretion.",
|
|
32978
|
+
// runMcp invokes each registrar as `register(server, deps)`, threading this
|
|
32979
|
+
// singleton so the tool modules import only the ViboClient TYPE. Same client
|
|
32980
|
+
// as before — just passed in rather than imported by each module.
|
|
32981
|
+
deps: client,
|
|
32898
32982
|
tools: [
|
|
32899
32983
|
registerProfileTools,
|
|
32900
32984
|
registerEventTools,
|