@mediagraph/mcp 1.0.10 → 1.0.13
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/app/index.html +150 -0
- package/dist/index.js +319 -52
- package/package.json +16 -3
package/dist/index.js
CHANGED
|
@@ -12,6 +12,9 @@ import {
|
|
|
12
12
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
13
13
|
import { exec } from "child_process";
|
|
14
14
|
import { platform } from "os";
|
|
15
|
+
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
15
18
|
|
|
16
19
|
// src/auth/oauth.ts
|
|
17
20
|
import { createHash, randomBytes } from "crypto";
|
|
@@ -660,13 +663,32 @@ var MediagraphClient = class {
|
|
|
660
663
|
return this.request("GET", `/api/assets/${id}/face_taggings`);
|
|
661
664
|
}
|
|
662
665
|
async getAssetDownload(id, options) {
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
666
|
+
const prepareResponse = await this.createDownload({
|
|
667
|
+
asset_ids: [typeof id === "string" ? parseInt(id, 10) : id],
|
|
668
|
+
size: options?.size || "original",
|
|
669
|
+
watermarked: options?.watermarked,
|
|
670
|
+
via: options?.via,
|
|
671
|
+
skip_meta: options?.skip_meta
|
|
672
|
+
});
|
|
673
|
+
const downloadUrl = `${this.apiUrl}/api/downloads/${prepareResponse.token}`;
|
|
674
|
+
return {
|
|
675
|
+
url: downloadUrl,
|
|
676
|
+
filename: prepareResponse.filename || `asset-${id}`
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
async getBulkDownload(options) {
|
|
680
|
+
const prepareResponse = await this.createDownload({
|
|
681
|
+
asset_ids: options.asset_ids,
|
|
682
|
+
size: options.size || "original",
|
|
683
|
+
watermarked: options.watermarked,
|
|
684
|
+
via: options.via,
|
|
685
|
+
skip_meta: options.skip_meta
|
|
686
|
+
});
|
|
687
|
+
const downloadUrl = `${this.apiUrl}/api/downloads/${prepareResponse.token}`;
|
|
688
|
+
return {
|
|
689
|
+
url: downloadUrl,
|
|
690
|
+
filename: prepareResponse.filename || `mediagraph-download-${options.asset_ids.length}-assets.zip`
|
|
691
|
+
};
|
|
670
692
|
}
|
|
671
693
|
async addAssetVersion(id, data) {
|
|
672
694
|
return this.request("POST", `/api/assets/${id}/add_version`, { body: data });
|
|
@@ -1218,8 +1240,7 @@ var MediagraphClient = class {
|
|
|
1218
1240
|
return this.request("GET", `/api/comments/${id}`);
|
|
1219
1241
|
}
|
|
1220
1242
|
async createComment(type, id, data) {
|
|
1221
|
-
return this.request("POST",
|
|
1222
|
-
params: { type, id },
|
|
1243
|
+
return this.request("POST", `/api/comments?type=${encodeURIComponent(type)}&id=${id}`, {
|
|
1223
1244
|
body: { comment: data }
|
|
1224
1245
|
});
|
|
1225
1246
|
}
|
|
@@ -1248,7 +1269,20 @@ var MediagraphClient = class {
|
|
|
1248
1269
|
return this.request("GET", `/api/downloads/${token}`);
|
|
1249
1270
|
}
|
|
1250
1271
|
async createDownload(data) {
|
|
1251
|
-
|
|
1272
|
+
const download = {
|
|
1273
|
+
asset_ids: data.asset_ids,
|
|
1274
|
+
size: data.size
|
|
1275
|
+
};
|
|
1276
|
+
if (data.watermarked === true) {
|
|
1277
|
+
download.watermarked = true;
|
|
1278
|
+
}
|
|
1279
|
+
if (data.via) {
|
|
1280
|
+
download.via = data.via;
|
|
1281
|
+
}
|
|
1282
|
+
if (data.skip_meta === true) {
|
|
1283
|
+
download.skip_meta = true;
|
|
1284
|
+
}
|
|
1285
|
+
return this.request("POST", "/api/downloads", { body: { download } });
|
|
1252
1286
|
}
|
|
1253
1287
|
// ============================================================================
|
|
1254
1288
|
// Webhooks
|
|
@@ -1650,6 +1684,29 @@ COMMON SEARCH FIELDS:
|
|
|
1650
1684
|
required: ["id"]
|
|
1651
1685
|
}
|
|
1652
1686
|
},
|
|
1687
|
+
{
|
|
1688
|
+
name: "bulk_download_assets",
|
|
1689
|
+
description: "Get a download URL for multiple assets (returns a ZIP file)",
|
|
1690
|
+
inputSchema: {
|
|
1691
|
+
type: "object",
|
|
1692
|
+
properties: {
|
|
1693
|
+
asset_ids: {
|
|
1694
|
+
type: "array",
|
|
1695
|
+
items: { type: "number" },
|
|
1696
|
+
description: "Array of asset IDs to download"
|
|
1697
|
+
},
|
|
1698
|
+
size: {
|
|
1699
|
+
type: "string",
|
|
1700
|
+
enum: ["small", "permalink", "full", "original"],
|
|
1701
|
+
description: "Maximum size for all assets in the download (default: original)"
|
|
1702
|
+
},
|
|
1703
|
+
watermarked: { type: "boolean", description: "Request watermarked versions" },
|
|
1704
|
+
via: { type: "string", description: "Description of the app or integration making the call" },
|
|
1705
|
+
skip_meta: { type: "boolean", description: "Do not write metadata to files" }
|
|
1706
|
+
},
|
|
1707
|
+
required: ["asset_ids"]
|
|
1708
|
+
}
|
|
1709
|
+
},
|
|
1653
1710
|
{
|
|
1654
1711
|
name: "get_asset_auto_tags",
|
|
1655
1712
|
description: "Get AI-generated auto tags for an asset",
|
|
@@ -1729,6 +1786,15 @@ COMMON SEARCH FIELDS:
|
|
|
1729
1786
|
version_number: args.version_number
|
|
1730
1787
|
}));
|
|
1731
1788
|
},
|
|
1789
|
+
async bulk_download_assets(args, { client: client2 }) {
|
|
1790
|
+
return successResult(await client2.getBulkDownload({
|
|
1791
|
+
asset_ids: args.asset_ids,
|
|
1792
|
+
size: args.size,
|
|
1793
|
+
watermarked: args.watermarked,
|
|
1794
|
+
via: args.via,
|
|
1795
|
+
skip_meta: args.skip_meta
|
|
1796
|
+
}));
|
|
1797
|
+
},
|
|
1732
1798
|
async get_asset_auto_tags(args, { client: client2 }) {
|
|
1733
1799
|
return successResult(await client2.getAssetAutoTags(args.id));
|
|
1734
1800
|
},
|
|
@@ -2648,8 +2714,8 @@ var downloadTools = {
|
|
|
2648
2714
|
asset_ids: { type: "array", items: { type: "number" } },
|
|
2649
2715
|
size: {
|
|
2650
2716
|
type: "string",
|
|
2651
|
-
enum: ["small", "
|
|
2652
|
-
description: "Maximum size requested for assets in the download"
|
|
2717
|
+
enum: ["small", "medium", "full", "original"],
|
|
2718
|
+
description: "Maximum size requested for assets in the download (default: original)"
|
|
2653
2719
|
}
|
|
2654
2720
|
},
|
|
2655
2721
|
required: ["asset_ids"]
|
|
@@ -2663,7 +2729,8 @@ var downloadTools = {
|
|
|
2663
2729
|
],
|
|
2664
2730
|
handlers: {
|
|
2665
2731
|
async create_download(args, { client: client2 }) {
|
|
2666
|
-
|
|
2732
|
+
const { asset_ids, size = "original" } = args;
|
|
2733
|
+
return successResult(await client2.createDownload({ asset_ids, size }));
|
|
2667
2734
|
},
|
|
2668
2735
|
async get_download(args, { client: client2 }) {
|
|
2669
2736
|
return successResult(await client2.getDownload(args.token));
|
|
@@ -3282,6 +3349,100 @@ var adminTools = {
|
|
|
3282
3349
|
}
|
|
3283
3350
|
};
|
|
3284
3351
|
|
|
3352
|
+
// src/tools/app.ts
|
|
3353
|
+
var appTools = {
|
|
3354
|
+
definitions: [
|
|
3355
|
+
{
|
|
3356
|
+
name: "search_assets_visual",
|
|
3357
|
+
description: `Search for assets and display results in an interactive visual gallery.
|
|
3358
|
+
|
|
3359
|
+
This tool provides a rich visual interface for browsing search results with:
|
|
3360
|
+
- Thumbnail grid with hover previews
|
|
3361
|
+
- Click to view full asset details
|
|
3362
|
+
- Inline editing of metadata
|
|
3363
|
+
- Rating, tagging, and download options
|
|
3364
|
+
- Pagination controls
|
|
3365
|
+
|
|
3366
|
+
Use this when the user wants to visually browse or explore assets.`,
|
|
3367
|
+
inputSchema: {
|
|
3368
|
+
type: "object",
|
|
3369
|
+
properties: {
|
|
3370
|
+
q: { type: "string", description: "Search query with optional advanced operators (AND, OR, NOT, field:value, wildcards)" },
|
|
3371
|
+
...paginationParams,
|
|
3372
|
+
ids: { type: "array", items: { type: "number" }, description: "Filter by specific asset IDs" },
|
|
3373
|
+
guids: { type: "array", items: { type: "string" }, description: "Filter by specific asset GUIDs" },
|
|
3374
|
+
tags: { type: "array", items: { type: "string" }, description: "Filter by tags" },
|
|
3375
|
+
collection_id: { type: "number", description: "Filter by collection ID" },
|
|
3376
|
+
storage_folder_id: { type: "number", description: "Filter by storage folder ID" },
|
|
3377
|
+
lightbox_id: { type: "number", description: "Filter by lightbox ID" },
|
|
3378
|
+
exts: { type: "array", items: { type: "string" }, description: "Filter by file extensions" },
|
|
3379
|
+
rating: { type: "array", items: { type: "number" }, description: "Filter by rating range [min, max]" },
|
|
3380
|
+
aspect: { type: "string", enum: ["square", "portrait", "landscape", "panorama"] },
|
|
3381
|
+
has_people: { type: "string", enum: ["yes", "no", "untagged"] },
|
|
3382
|
+
has_alt_text: { type: "string", enum: ["yes", "no"] },
|
|
3383
|
+
gps: { type: "boolean", description: "Filter for assets with GPS data" },
|
|
3384
|
+
captured_at: { type: "array", items: { type: "string" }, description: "Date range [start, end] in ISO 8601" },
|
|
3385
|
+
created_at: { type: "array", items: { type: "string" }, description: "Date range [start, end] in ISO 8601" }
|
|
3386
|
+
},
|
|
3387
|
+
required: []
|
|
3388
|
+
},
|
|
3389
|
+
// MCP Apps metadata - tells the host to display the UI
|
|
3390
|
+
// Include both formats for compatibility with different host versions
|
|
3391
|
+
_meta: {
|
|
3392
|
+
ui: {
|
|
3393
|
+
resourceUri: "ui://mediagraph/gallery"
|
|
3394
|
+
},
|
|
3395
|
+
"ui/resourceUri": "ui://mediagraph/gallery"
|
|
3396
|
+
// Legacy format for older hosts
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
],
|
|
3400
|
+
handlers: {
|
|
3401
|
+
async search_assets_visual(args, { client: client2, organizationSlug }) {
|
|
3402
|
+
const params = {
|
|
3403
|
+
...args,
|
|
3404
|
+
include_renditions: false,
|
|
3405
|
+
// Don't include all renditions to reduce size
|
|
3406
|
+
include_totals: true,
|
|
3407
|
+
per_page: args.per_page || 24
|
|
3408
|
+
// Reasonable default
|
|
3409
|
+
};
|
|
3410
|
+
const response = await client2.searchAssets(params);
|
|
3411
|
+
const lightAssets = response.assets.map((asset) => ({
|
|
3412
|
+
id: asset.id,
|
|
3413
|
+
guid: asset.guid,
|
|
3414
|
+
filename: asset.filename,
|
|
3415
|
+
title: asset.title,
|
|
3416
|
+
description: asset.description,
|
|
3417
|
+
alt_text: asset.alt_text,
|
|
3418
|
+
type: asset.type || asset.file_type,
|
|
3419
|
+
ext: asset.ext,
|
|
3420
|
+
width: asset.width,
|
|
3421
|
+
height: asset.height,
|
|
3422
|
+
duration: asset.duration,
|
|
3423
|
+
rating: asset.rating,
|
|
3424
|
+
// Tags come as objects from API, extract just the names
|
|
3425
|
+
tags: asset.tags?.map((tag) => typeof tag === "string" ? tag : tag.name).filter(Boolean),
|
|
3426
|
+
thumb_url: asset.thumb_url,
|
|
3427
|
+
grid_url: asset.grid_url,
|
|
3428
|
+
small_url: asset.small_url,
|
|
3429
|
+
preview_url: asset.preview_url,
|
|
3430
|
+
created_at: asset.created_at,
|
|
3431
|
+
updated_at: asset.updated_at,
|
|
3432
|
+
captured_at: asset.captured_at
|
|
3433
|
+
}));
|
|
3434
|
+
return successResult({
|
|
3435
|
+
assets: lightAssets,
|
|
3436
|
+
total: response.total,
|
|
3437
|
+
page: response.page,
|
|
3438
|
+
per_page: response.per_page,
|
|
3439
|
+
total_pages: response.total_pages,
|
|
3440
|
+
organization_slug: organizationSlug
|
|
3441
|
+
});
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
};
|
|
3445
|
+
|
|
3285
3446
|
// src/tools/index.ts
|
|
3286
3447
|
var allToolModules = [
|
|
3287
3448
|
userTools,
|
|
@@ -3297,7 +3458,8 @@ var allToolModules = [
|
|
|
3297
3458
|
downloadTools,
|
|
3298
3459
|
uploadTools,
|
|
3299
3460
|
webhookTools,
|
|
3300
|
-
adminTools
|
|
3461
|
+
adminTools,
|
|
3462
|
+
appTools
|
|
3301
3463
|
];
|
|
3302
3464
|
var toolDefinitions = allToolModules.flatMap((m) => m.definitions);
|
|
3303
3465
|
var allHandlers = {};
|
|
@@ -3496,31 +3658,56 @@ function openBrowser(url) {
|
|
|
3496
3658
|
}
|
|
3497
3659
|
async function runAutoAuth() {
|
|
3498
3660
|
if (isAuthInProgress) {
|
|
3499
|
-
|
|
3500
|
-
|
|
3661
|
+
console.error("[MCP] OAuth already in progress, waiting for completion...");
|
|
3662
|
+
const waitStart = Date.now();
|
|
3663
|
+
const maxWait = 12e4;
|
|
3664
|
+
while (isAuthInProgress && Date.now() - waitStart < maxWait) {
|
|
3665
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3666
|
+
}
|
|
3667
|
+
if (isAuthInProgress) {
|
|
3668
|
+
console.error("[MCP] Timed out waiting for existing OAuth flow");
|
|
3669
|
+
return false;
|
|
3501
3670
|
}
|
|
3502
3671
|
return currentTokens !== null;
|
|
3503
3672
|
}
|
|
3504
3673
|
isAuthInProgress = true;
|
|
3674
|
+
console.error("[MCP] Starting OAuth flow...");
|
|
3505
3675
|
try {
|
|
3506
3676
|
const authUrl = oauthHandler.getAuthorizationUrl();
|
|
3507
3677
|
await oauthHandler.startCallbackServer();
|
|
3678
|
+
console.error("[MCP] Callback server ready, opening browser...");
|
|
3508
3679
|
openBrowser(authUrl);
|
|
3680
|
+
console.error("[MCP] Waiting for OAuth callback...");
|
|
3509
3681
|
const { code } = await oauthHandler.waitForCallback();
|
|
3682
|
+
console.error("[MCP] OAuth callback received, exchanging code...");
|
|
3510
3683
|
const tokens = await oauthHandler.exchangeCode(code);
|
|
3511
3684
|
currentTokens = tokens;
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
tokens,
|
|
3515
|
-
organizationId: whoami.organization.id,
|
|
3516
|
-
organizationName: whoami.organization.name,
|
|
3517
|
-
userId: whoami.user.id,
|
|
3518
|
-
userEmail: whoami.user.email
|
|
3519
|
-
};
|
|
3685
|
+
console.error("[MCP] Token exchange successful");
|
|
3686
|
+
let storedData = { tokens };
|
|
3520
3687
|
tokenStore.save(storedData);
|
|
3688
|
+
try {
|
|
3689
|
+
const whoami = await client.whoami();
|
|
3690
|
+
if (whoami?.organization?.id) {
|
|
3691
|
+
const org = whoami.organization;
|
|
3692
|
+
storedData = {
|
|
3693
|
+
tokens,
|
|
3694
|
+
organizationId: org.id,
|
|
3695
|
+
organizationName: org.title || org.name,
|
|
3696
|
+
organizationSlug: org.slug,
|
|
3697
|
+
userId: whoami.user?.id,
|
|
3698
|
+
userEmail: whoami.user?.email
|
|
3699
|
+
};
|
|
3700
|
+
tokenStore.save(storedData);
|
|
3701
|
+
console.error(`[MCP] Authenticated as ${whoami.user?.email} in ${org.title || org.name}`);
|
|
3702
|
+
} else {
|
|
3703
|
+
console.error("[MCP] Authenticated (whoami returned incomplete data)");
|
|
3704
|
+
}
|
|
3705
|
+
} catch (whoamiError) {
|
|
3706
|
+
console.error("[MCP] Authenticated (whoami failed, tokens saved):", whoamiError);
|
|
3707
|
+
}
|
|
3521
3708
|
return true;
|
|
3522
3709
|
} catch (error) {
|
|
3523
|
-
console.error("Auto-auth failed:", error);
|
|
3710
|
+
console.error("[MCP] Auto-auth failed:", error);
|
|
3524
3711
|
oauthHandler.stopCallbackServer();
|
|
3525
3712
|
return false;
|
|
3526
3713
|
} finally {
|
|
@@ -3559,6 +3746,10 @@ var client = new MediagraphClient({
|
|
|
3559
3746
|
});
|
|
3560
3747
|
var toolContext = { client };
|
|
3561
3748
|
var resourceContext = { client };
|
|
3749
|
+
function getOrganizationSlug() {
|
|
3750
|
+
const stored = tokenStore.load();
|
|
3751
|
+
return stored?.organizationSlug;
|
|
3752
|
+
}
|
|
3562
3753
|
var server = new Server(
|
|
3563
3754
|
{
|
|
3564
3755
|
name: "mediagraph-mcp",
|
|
@@ -3580,33 +3771,48 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3580
3771
|
const { name, arguments: args } = request.params;
|
|
3581
3772
|
let token = await getAccessToken();
|
|
3582
3773
|
if (!token) {
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
}
|
|
3774
|
+
if (isAuthInProgress) {
|
|
3775
|
+
console.error("[MCP] OAuth in progress, waiting...");
|
|
3776
|
+
const waitStart = Date.now();
|
|
3777
|
+
const maxWait = 12e4;
|
|
3778
|
+
while (isAuthInProgress && Date.now() - waitStart < maxWait) {
|
|
3779
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3780
|
+
}
|
|
3781
|
+
token = await getAccessToken();
|
|
3782
|
+
if (token) {
|
|
3783
|
+
console.error("[MCP] OAuth completed, proceeding with request");
|
|
3784
|
+
}
|
|
3594
3785
|
}
|
|
3595
|
-
token = await getAccessToken();
|
|
3596
3786
|
if (!token) {
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3787
|
+
const authSuccess = await runAutoAuth();
|
|
3788
|
+
if (!authSuccess) {
|
|
3789
|
+
return {
|
|
3790
|
+
content: [
|
|
3791
|
+
{
|
|
3792
|
+
type: "text",
|
|
3793
|
+
text: "Authorization is in progress. Please complete the login in your browser, then try this request again."
|
|
3794
|
+
}
|
|
3795
|
+
],
|
|
3796
|
+
isError: true
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
3799
|
+
token = await getAccessToken();
|
|
3800
|
+
if (!token) {
|
|
3801
|
+
return {
|
|
3802
|
+
content: [
|
|
3803
|
+
{
|
|
3804
|
+
type: "text",
|
|
3805
|
+
text: "Authentication completed but failed to retrieve access token. Please try again."
|
|
3806
|
+
}
|
|
3807
|
+
],
|
|
3808
|
+
isError: true
|
|
3809
|
+
};
|
|
3810
|
+
}
|
|
3606
3811
|
}
|
|
3607
3812
|
}
|
|
3608
3813
|
console.error(`[MCP] Tool call: ${name}`);
|
|
3609
3814
|
console.error(`[MCP] Arguments: ${JSON.stringify(args, null, 2)}`);
|
|
3815
|
+
toolContext.organizationSlug = getOrganizationSlug();
|
|
3610
3816
|
const result = await handleTool(name, args || {}, toolContext);
|
|
3611
3817
|
if (result.isError) {
|
|
3612
3818
|
console.error(`[MCP] Tool error: ${result.content[0]?.text}`);
|
|
@@ -3633,6 +3839,9 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
|
3633
3839
|
});
|
|
3634
3840
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
3635
3841
|
const { uri } = request.params;
|
|
3842
|
+
if (uri.startsWith("ui://mediagraph/")) {
|
|
3843
|
+
return handleAppResource(uri);
|
|
3844
|
+
}
|
|
3636
3845
|
let token = await getAccessToken();
|
|
3637
3846
|
if (!token) {
|
|
3638
3847
|
const authSuccess = await runAutoAuth();
|
|
@@ -3665,6 +3874,57 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
3665
3874
|
contents: [content]
|
|
3666
3875
|
};
|
|
3667
3876
|
});
|
|
3877
|
+
function handleAppResource(uri) {
|
|
3878
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
3879
|
+
const __dirname = dirname2(__filename);
|
|
3880
|
+
const appPath = join2(__dirname, "app", "index.html");
|
|
3881
|
+
if (!existsSync2(appPath)) {
|
|
3882
|
+
console.error(`[MCP] App resource not found at: ${appPath}`);
|
|
3883
|
+
return {
|
|
3884
|
+
contents: [
|
|
3885
|
+
{
|
|
3886
|
+
uri,
|
|
3887
|
+
mimeType: "text/plain",
|
|
3888
|
+
text: "MCP App UI not found. Please rebuild the project with npm run build."
|
|
3889
|
+
}
|
|
3890
|
+
]
|
|
3891
|
+
};
|
|
3892
|
+
}
|
|
3893
|
+
try {
|
|
3894
|
+
const html = readFileSync2(appPath, "utf-8");
|
|
3895
|
+
return {
|
|
3896
|
+
contents: [
|
|
3897
|
+
{
|
|
3898
|
+
uri,
|
|
3899
|
+
mimeType: "text/html;profile=mcp-app",
|
|
3900
|
+
text: html,
|
|
3901
|
+
// CSP configuration to allow loading images from Mediagraph CDN
|
|
3902
|
+
_meta: {
|
|
3903
|
+
ui: {
|
|
3904
|
+
csp: {
|
|
3905
|
+
// Allow images from CloudFront CDN
|
|
3906
|
+
resourceDomains: ["https://*.cloudfront.net"],
|
|
3907
|
+
// Allow API calls to Mediagraph (for future use)
|
|
3908
|
+
connectDomains: ["https://api.mediagraph.io"]
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
}
|
|
3912
|
+
}
|
|
3913
|
+
]
|
|
3914
|
+
};
|
|
3915
|
+
} catch (error) {
|
|
3916
|
+
console.error("[MCP] Failed to read app resource:", error);
|
|
3917
|
+
return {
|
|
3918
|
+
contents: [
|
|
3919
|
+
{
|
|
3920
|
+
uri,
|
|
3921
|
+
mimeType: "text/plain",
|
|
3922
|
+
text: "Failed to load MCP App UI."
|
|
3923
|
+
}
|
|
3924
|
+
]
|
|
3925
|
+
};
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3668
3928
|
async function runAuthorize() {
|
|
3669
3929
|
if (!config.clientId) {
|
|
3670
3930
|
console.error("Error: MEDIAGRAPH_CLIENT_ID environment variable is required");
|
|
@@ -3691,18 +3951,25 @@ async function runAuthorize() {
|
|
|
3691
3951
|
console.log("Tokens received successfully.");
|
|
3692
3952
|
currentTokens = tokens;
|
|
3693
3953
|
const whoami = await client.whoami();
|
|
3954
|
+
console.log("Whoami response:", JSON.stringify(whoami, null, 2));
|
|
3955
|
+
const org = whoami.organization;
|
|
3694
3956
|
const storedData = {
|
|
3695
3957
|
tokens,
|
|
3696
|
-
organizationId:
|
|
3697
|
-
organizationName:
|
|
3698
|
-
|
|
3699
|
-
|
|
3958
|
+
organizationId: org?.id,
|
|
3959
|
+
organizationName: org?.title || org?.name,
|
|
3960
|
+
organizationSlug: org?.slug,
|
|
3961
|
+
userId: whoami.user?.id,
|
|
3962
|
+
userEmail: whoami.user?.email
|
|
3700
3963
|
};
|
|
3701
3964
|
tokenStore.save(storedData);
|
|
3702
3965
|
console.log("");
|
|
3703
3966
|
console.log("Successfully authorized!");
|
|
3704
|
-
|
|
3705
|
-
|
|
3967
|
+
if (org) {
|
|
3968
|
+
console.log(`Organization: ${org.title || org.name} (${org.slug})`);
|
|
3969
|
+
}
|
|
3970
|
+
if (whoami.user) {
|
|
3971
|
+
console.log(`User: ${whoami.user.full_name || whoami.user.email} (${whoami.user.email})`);
|
|
3972
|
+
}
|
|
3706
3973
|
console.log("");
|
|
3707
3974
|
console.log("You can now use the Mediagraph MCP server.");
|
|
3708
3975
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mediagraph/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "MCP server for Mediagraph - Media Asset Management Platform",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,10 +8,15 @@
|
|
|
8
8
|
"mediagraph-mcp": "./dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
11
|
+
"build": "NODE_ENV=production tsup src/index.ts --format esm --dts --clean && npm run build:app:prod",
|
|
12
|
+
"build:dev": "tsup src/index.ts --format esm --dts --clean && npm run build:app:dev",
|
|
13
|
+
"build:app:prod": "NODE_ENV=production vite build --config vite.config.ts",
|
|
14
|
+
"build:app:dev": "NODE_ENV=development vite build --config vite.config.ts",
|
|
15
|
+
"build:app": "vite build --config vite.config.ts",
|
|
12
16
|
"dev": "tsup src/index.ts --format esm --watch",
|
|
17
|
+
"dev:app": "vite --config vite.config.ts",
|
|
13
18
|
"start": "node dist/index.js",
|
|
14
|
-
"typecheck": "tsc --noEmit",
|
|
19
|
+
"typecheck": "tsc --noEmit && tsc --project tsconfig.app.json --noEmit",
|
|
15
20
|
"lint": "eslint src/**/*.ts",
|
|
16
21
|
"test": "vitest run",
|
|
17
22
|
"test:watch": "vitest",
|
|
@@ -46,13 +51,21 @@
|
|
|
46
51
|
"LICENSE"
|
|
47
52
|
],
|
|
48
53
|
"dependencies": {
|
|
54
|
+
"@modelcontextprotocol/ext-apps": "^1.0.1",
|
|
49
55
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
50
56
|
},
|
|
51
57
|
"devDependencies": {
|
|
52
58
|
"@types/node": "^20.10.0",
|
|
59
|
+
"@types/react": "^18.3.0",
|
|
60
|
+
"@types/react-dom": "^18.3.0",
|
|
61
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
53
62
|
"eslint": "^8.56.0",
|
|
63
|
+
"react": "^18.3.1",
|
|
64
|
+
"react-dom": "^18.3.1",
|
|
54
65
|
"tsup": "^8.0.1",
|
|
55
66
|
"typescript": "^5.3.3",
|
|
67
|
+
"vite": "^5.4.0",
|
|
68
|
+
"vite-plugin-singlefile": "^2.0.0",
|
|
56
69
|
"vitest": "^1.1.0"
|
|
57
70
|
}
|
|
58
71
|
}
|