@commandable/mcp 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/{Sdkz9rYy.js → BD6mASiY.js} +1 -1
- package/.output/public/_nuxt/{Ctwv5nxD.js → BUmYUDQu.js} +3 -3
- package/.output/public/_nuxt/CjAs3eBq.js +1 -0
- package/.output/public/_nuxt/{CBR-0oRi.js → D9wFDhac.js} +1 -1
- package/.output/public/_nuxt/{KqToXREt.js → DRfk9W3W.js} +1 -1
- package/.output/public/_nuxt/DSWYWRXT.js +59 -0
- package/.output/public/_nuxt/{DOIzs5t4.js → VvnbcAzZ.js} +1 -1
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/9441a86b-16e9-4000-bffc-3b2e78e57710.json +1 -0
- package/.output/server/chunks/build/{_id_-Co8jGxsD.mjs → _id_-DA3Q8jun.mjs} +603 -24
- package/.output/server/chunks/build/_id_-DA3Q8jun.mjs.map +1 -0
- package/.output/server/chunks/build/client.precomputed.mjs +1 -1
- package/.output/server/chunks/build/error-404-D1k2kWid.mjs +3 -5
- package/.output/server/chunks/build/error-500-D2K2rAfl.mjs +3 -5
- package/.output/server/chunks/build/fetch-aDh21opM.mjs +1 -1
- package/.output/server/chunks/build/{index-BxsJPthj.mjs → index-F5lAFSQk.mjs} +7 -7
- package/.output/server/chunks/build/index-F5lAFSQk.mjs.map +1 -0
- package/.output/server/chunks/build/index-ycGPozML.mjs +3 -5
- package/.output/server/chunks/build/server.mjs +6 -8
- package/.output/server/chunks/nitro/nitro.mjs +2456 -625
- package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
- package/.output/server/chunks/routes/api/_commandable/status.get.mjs +3 -5
- package/.output/server/chunks/routes/api/_commandable/status.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/catalog/_type/tools.get.mjs +3 -5
- package/.output/server/chunks/routes/api/catalog/_type/tools.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/catalog/_type/toolsets.get.mjs +3 -5
- package/.output/server/chunks/routes/api/catalog/_type/toolsets.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/catalog.get.mjs +3 -5
- package/.output/server/chunks/routes/api/catalog.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get.mjs +3 -5
- package/.output/server/chunks/routes/api/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.post.mjs +5 -5
- package/.output/server/chunks/routes/api/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/credentials-config.get.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/credentials-config.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/credentials-status.get.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/credentials-status.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/credentials.delete.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/credentials.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/credentials.post.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/credentials.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/permissions.post.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/permissions.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/tools.delete.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/tools.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/tools.get.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/tools.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/toolsets.get.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/toolsets.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/toolsets.post.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id/toolsets.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/integrations/_id/variant-options.post.mjs +72 -0
- package/.output/server/chunks/routes/api/integrations/_id/variant-options.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/integrations/_id_.delete.mjs +3 -5
- package/.output/server/chunks/routes/api/integrations/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/health.get.mjs +3 -5
- package/.output/server/chunks/routes/health.get.mjs.map +1 -1
- package/.output/server/chunks/routes/mcp/create.mjs +4 -6
- package/.output/server/chunks/routes/mcp/create.mjs.map +1 -1
- package/.output/server/chunks/routes/mcp/static.mjs +4 -6
- package/.output/server/chunks/routes/mcp/static.mjs.map +1 -1
- package/.output/server/chunks/routes/mcp.mjs +4 -6
- package/.output/server/chunks/routes/mcp.mjs.map +1 -1
- package/.output/server/chunks/routes/renderer.mjs +1 -1
- package/.output/server/index.mjs +4 -6
- package/.output/server/index.mjs.map +1 -1
- package/.output/server/package.json +1 -1
- package/package.json +2 -2
- package/.output/public/_nuxt/CYsCQznM.js +0 -59
- package/.output/public/_nuxt/DKO0MviJ.js +0 -1
- package/.output/public/_nuxt/builds/meta/3380bacd-d6f5-40cf-8376-35445d2f246f.json +0 -1
- package/.output/server/chunks/build/_id_-Co8jGxsD.mjs.map +0 -1
- package/.output/server/chunks/build/index-BxsJPthj.mjs.map +0 -1
|
@@ -3,8 +3,6 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
3
3
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
4
4
|
import { ListToolsRequestSchema, CallToolRequestSchema, isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
import { distance } from 'fastest-levenshtein';
|
|
6
|
-
import { URLSearchParams as URLSearchParams$1, URL as URL$1, fileURLToPath } from 'node:url';
|
|
7
|
-
import vm from 'node:vm';
|
|
8
6
|
import TurndownService from 'turndown';
|
|
9
7
|
import { marked } from 'marked';
|
|
10
8
|
import { promisify } from 'node:util';
|
|
@@ -12,19 +10,19 @@ import { execFile as execFile$2 } from 'node:child_process';
|
|
|
12
10
|
import { mkdtemp, writeFile as writeFile$1, readFile as readFile$1, rm } from 'node:fs/promises';
|
|
13
11
|
import { resolve as resolve$1, dirname as dirname$1, join, basename as basename$1 } from 'node:path';
|
|
14
12
|
import { tmpdir, homedir } from 'node:os';
|
|
15
|
-
import { promises, existsSync, mkdirSync, readFileSync, statSync, writeFileSync, chmodSync } from 'node:fs';
|
|
16
13
|
import { and, eq } from 'drizzle-orm';
|
|
14
|
+
import { URLSearchParams as URLSearchParams$1, URL as URL$1, fileURLToPath } from 'node:url';
|
|
15
|
+
import vm from 'node:vm';
|
|
17
16
|
import { Buffer as Buffer$1 } from 'node:buffer';
|
|
18
17
|
import { JWT } from 'google-auth-library';
|
|
19
18
|
import http, { Server as Server$2 } from 'node:http';
|
|
20
19
|
import https, { Server as Server$1 } from 'node:https';
|
|
21
20
|
import { EventEmitter } from 'node:events';
|
|
21
|
+
import { promises, existsSync, writeFileSync, mkdirSync, statSync, readFileSync, chmodSync } from 'node:fs';
|
|
22
22
|
import Database from 'better-sqlite3';
|
|
23
23
|
import { drizzle as drizzle$1 } from 'drizzle-orm/better-sqlite3';
|
|
24
24
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
25
25
|
import { Pool } from 'pg';
|
|
26
|
-
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
|
|
27
|
-
import { migrate as migrate$1 } from 'drizzle-orm/node-postgres/migrator';
|
|
28
26
|
import { sqliteTable, integer, text, primaryKey } from 'drizzle-orm/sqlite-core';
|
|
29
27
|
import { pgTable, timestamp, jsonb, text as text$1, primaryKey as primaryKey$1, integer as integer$1 } from 'drizzle-orm/pg-core';
|
|
30
28
|
import { cwd as cwd$1 } from 'node:process';
|
|
@@ -4433,7 +4431,7 @@ function _expandFromEnv(value) {
|
|
|
4433
4431
|
const _inlineRuntimeConfig = {
|
|
4434
4432
|
"app": {
|
|
4435
4433
|
"baseURL": "/",
|
|
4436
|
-
"buildId": "
|
|
4434
|
+
"buildId": "9441a86b-16e9-4000-bffc-3b2e78e57710",
|
|
4437
4435
|
"buildAssetsDir": "/_nuxt/",
|
|
4438
4436
|
"cdnURL": ""
|
|
4439
4437
|
},
|
|
@@ -5392,7 +5390,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
5392
5390
|
"handlerCode": "async (input) => {\n const path = `/${input.baseId}/${input.tableId}`\n const params = new URLSearchParams()\n params.set('records[]', input.recordId)\n const res = await integration.fetch(`${path}?${params.toString()}`, { method: 'DELETE' })\n return await res.json()\n}",
|
|
5393
5391
|
"scope": "write"
|
|
5394
5392
|
}
|
|
5395
|
-
]
|
|
5393
|
+
],
|
|
5394
|
+
"variantOwnerType": null
|
|
5396
5395
|
},
|
|
5397
5396
|
"confluence": {
|
|
5398
5397
|
"manifest": {
|
|
@@ -5963,7 +5962,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
5963
5962
|
],
|
|
5964
5963
|
"scope": "write"
|
|
5965
5964
|
}
|
|
5966
|
-
]
|
|
5965
|
+
],
|
|
5966
|
+
"variantOwnerType": null
|
|
5967
5967
|
},
|
|
5968
5968
|
"github": {
|
|
5969
5969
|
"manifest": {
|
|
@@ -8279,7 +8279,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
8279
8279
|
"scope": "write",
|
|
8280
8280
|
"toolset": "releases"
|
|
8281
8281
|
}
|
|
8282
|
-
]
|
|
8282
|
+
],
|
|
8283
|
+
"variantOwnerType": null
|
|
8283
8284
|
},
|
|
8284
8285
|
"google-calendar": {
|
|
8285
8286
|
"manifest": {
|
|
@@ -9020,7 +9021,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
9020
9021
|
"scope": "admin",
|
|
9021
9022
|
"toolset": "sharing"
|
|
9022
9023
|
}
|
|
9023
|
-
]
|
|
9024
|
+
],
|
|
9025
|
+
"variantOwnerType": null
|
|
9024
9026
|
},
|
|
9025
9027
|
"google-gmail": {
|
|
9026
9028
|
"manifest": {
|
|
@@ -10225,7 +10227,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
10225
10227
|
"scope": "admin",
|
|
10226
10228
|
"toolset": "organize"
|
|
10227
10229
|
}
|
|
10228
|
-
]
|
|
10230
|
+
],
|
|
10231
|
+
"variantOwnerType": null
|
|
10229
10232
|
},
|
|
10230
10233
|
"google-workspace": {
|
|
10231
10234
|
"manifest": {
|
|
@@ -12292,7 +12295,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
12292
12295
|
"scope": "write",
|
|
12293
12296
|
"toolset": "slides"
|
|
12294
12297
|
}
|
|
12295
|
-
]
|
|
12298
|
+
],
|
|
12299
|
+
"variantOwnerType": null
|
|
12296
12300
|
},
|
|
12297
12301
|
"hubspot": {
|
|
12298
12302
|
"manifest": {
|
|
@@ -13889,7 +13893,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
13889
13893
|
"handlerCode": "async (input) => {\n const props = { ...(input.properties || {}) }\n\n if (input.subject !== undefined) props.hs_task_subject = input.subject\n if (input.body !== undefined) props.hs_task_body = input.body\n if (input.status !== undefined) props.hs_task_status = input.status\n if (input.priority !== undefined) props.hs_task_priority = input.priority\n if (input.dueTimestamp !== undefined) props.hs_timestamp = String(input.dueTimestamp)\n if (input.hubspot_owner_id !== undefined) props.hubspot_owner_id = String(input.hubspot_owner_id)\n\n const res = await integration.fetch(`/crm/v3/objects/tasks/${encodeURIComponent(input.id)}`, {\n method: 'PATCH',\n body: { properties: props },\n })\n return await res.json()\n}",
|
|
13890
13894
|
"scope": "write"
|
|
13891
13895
|
}
|
|
13892
|
-
]
|
|
13896
|
+
],
|
|
13897
|
+
"variantOwnerType": null
|
|
13893
13898
|
},
|
|
13894
13899
|
"jira": {
|
|
13895
13900
|
"manifest": {
|
|
@@ -15010,7 +15015,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
15010
15015
|
"scope": "write",
|
|
15011
15016
|
"toolset": "boards"
|
|
15012
15017
|
}
|
|
15013
|
-
]
|
|
15018
|
+
],
|
|
15019
|
+
"variantOwnerType": null
|
|
15014
15020
|
},
|
|
15015
15021
|
"notion": {
|
|
15016
15022
|
"manifest": {
|
|
@@ -15835,331 +15841,1741 @@ const GENERATED_INTEGRATIONS = {
|
|
|
15835
15841
|
"scope": "write",
|
|
15836
15842
|
"toolset": "databases"
|
|
15837
15843
|
}
|
|
15838
|
-
]
|
|
15844
|
+
],
|
|
15845
|
+
"variantOwnerType": null
|
|
15839
15846
|
},
|
|
15840
|
-
"
|
|
15847
|
+
"sharepoint": {
|
|
15841
15848
|
"manifest": {
|
|
15842
|
-
"name": "
|
|
15849
|
+
"name": "sharepoint",
|
|
15843
15850
|
"version": "0.1.0",
|
|
15844
|
-
"baseUrl": "https://
|
|
15851
|
+
"baseUrl": "https://graph.microsoft.com/v1.0",
|
|
15845
15852
|
"tools": [
|
|
15846
15853
|
{
|
|
15847
|
-
"name": "
|
|
15848
|
-
"description": "
|
|
15849
|
-
"inputSchema": "schemas/
|
|
15850
|
-
"handler": "handlers/
|
|
15851
|
-
"scope": "read"
|
|
15852
|
-
},
|
|
15853
|
-
{
|
|
15854
|
-
"name": "get_member_boards",
|
|
15855
|
-
"description": "List boards for the current member.",
|
|
15856
|
-
"inputSchema": "schemas/empty.json",
|
|
15857
|
-
"handler": "handlers/get_member_boards.js",
|
|
15858
|
-
"scope": "read"
|
|
15859
|
-
},
|
|
15860
|
-
{
|
|
15861
|
-
"name": "get_member_organizations",
|
|
15862
|
-
"description": "List organizations (workspaces) for the current member.",
|
|
15863
|
-
"inputSchema": "schemas/empty.json",
|
|
15864
|
-
"handler": "handlers/get_member_organizations.js",
|
|
15865
|
-
"scope": "read"
|
|
15866
|
-
},
|
|
15867
|
-
{
|
|
15868
|
-
"name": "get_board",
|
|
15869
|
-
"description": "Fetch a board by id.",
|
|
15870
|
-
"inputSchema": "schemas/id_board.json",
|
|
15871
|
-
"handler": "handlers/get_board.js",
|
|
15872
|
-
"scope": "read"
|
|
15873
|
-
},
|
|
15874
|
-
{
|
|
15875
|
-
"name": "get_board_lists",
|
|
15876
|
-
"description": "List lists on a board.",
|
|
15877
|
-
"inputSchema": "schemas/id_board.json",
|
|
15878
|
-
"handler": "handlers/get_board_lists.js",
|
|
15879
|
-
"scope": "read"
|
|
15880
|
-
},
|
|
15881
|
-
{
|
|
15882
|
-
"name": "get_board_cards",
|
|
15883
|
-
"description": "List cards on a board.",
|
|
15884
|
-
"inputSchema": "schemas/id_board.json",
|
|
15885
|
-
"handler": "handlers/get_board_cards.js",
|
|
15886
|
-
"scope": "read"
|
|
15887
|
-
},
|
|
15888
|
-
{
|
|
15889
|
-
"name": "get_board_members",
|
|
15890
|
-
"description": "List members on a board.",
|
|
15891
|
-
"inputSchema": "schemas/id_board.json",
|
|
15892
|
-
"handler": "handlers/get_board_members.js",
|
|
15893
|
-
"scope": "read"
|
|
15894
|
-
},
|
|
15895
|
-
{
|
|
15896
|
-
"name": "get_board_labels",
|
|
15897
|
-
"description": "List labels on a board.",
|
|
15898
|
-
"inputSchema": "schemas/id_board.json",
|
|
15899
|
-
"handler": "handlers/get_board_labels.js",
|
|
15900
|
-
"scope": "read"
|
|
15901
|
-
},
|
|
15902
|
-
{
|
|
15903
|
-
"name": "get_board_custom_fields",
|
|
15904
|
-
"description": "List custom fields on a board.",
|
|
15905
|
-
"inputSchema": "schemas/id_board.json",
|
|
15906
|
-
"handler": "handlers/get_board_custom_fields.js",
|
|
15907
|
-
"scope": "read"
|
|
15908
|
-
},
|
|
15909
|
-
{
|
|
15910
|
-
"name": "get_board_memberships",
|
|
15911
|
-
"description": "List memberships for a board.",
|
|
15912
|
-
"inputSchema": "schemas/id_board.json",
|
|
15913
|
-
"handler": "handlers/get_board_memberships.js",
|
|
15914
|
-
"scope": "read"
|
|
15915
|
-
},
|
|
15916
|
-
{
|
|
15917
|
-
"name": "get_list",
|
|
15918
|
-
"description": "Fetch a list by id.",
|
|
15919
|
-
"inputSchema": "schemas/id_list.json",
|
|
15920
|
-
"handler": "handlers/get_list.js",
|
|
15921
|
-
"scope": "read"
|
|
15922
|
-
},
|
|
15923
|
-
{
|
|
15924
|
-
"name": "get_list_cards",
|
|
15925
|
-
"description": "List cards in a list.",
|
|
15926
|
-
"inputSchema": "schemas/id_list.json",
|
|
15927
|
-
"handler": "handlers/get_list_cards.js",
|
|
15928
|
-
"scope": "read"
|
|
15929
|
-
},
|
|
15930
|
-
{
|
|
15931
|
-
"name": "get_card",
|
|
15932
|
-
"description": "Fetch a card by id.",
|
|
15933
|
-
"inputSchema": "schemas/id_card.json",
|
|
15934
|
-
"handler": "handlers/get_card.js",
|
|
15935
|
-
"scope": "read"
|
|
15936
|
-
},
|
|
15937
|
-
{
|
|
15938
|
-
"name": "get_card_members",
|
|
15939
|
-
"description": "List members assigned to a card.",
|
|
15940
|
-
"inputSchema": "schemas/id_card.json",
|
|
15941
|
-
"handler": "handlers/get_card_members.js",
|
|
15854
|
+
"name": "search_sites",
|
|
15855
|
+
"description": "Search SharePoint sites by keyword across the tenant. Returns compact site summaries with IDs and web URLs. Use this when you know the site name or topic but not the site ID. If you already know the hostname and path, use get_site_by_path instead.",
|
|
15856
|
+
"inputSchema": "schemas/search_sites.json",
|
|
15857
|
+
"handler": "handlers/search_sites.js",
|
|
15942
15858
|
"scope": "read"
|
|
15943
15859
|
},
|
|
15944
15860
|
{
|
|
15945
|
-
"name": "
|
|
15946
|
-
"description": "
|
|
15947
|
-
"inputSchema": "schemas/
|
|
15948
|
-
"handler": "handlers/
|
|
15861
|
+
"name": "get_site_by_path",
|
|
15862
|
+
"description": "Resolve a SharePoint site from its hostname and server-relative path, such as hostname='contoso.sharepoint.com' and relativePath='//Marketing'. Use this when you know the SharePoint URL structure and need the stable site ID for later calls.",
|
|
15863
|
+
"inputSchema": "schemas/get_site_by_path.json",
|
|
15864
|
+
"handler": "handlers/get_site_by_path.js",
|
|
15949
15865
|
"scope": "read"
|
|
15950
15866
|
},
|
|
15951
15867
|
{
|
|
15952
|
-
"name": "
|
|
15953
|
-
"description": "
|
|
15954
|
-
"inputSchema": "schemas/
|
|
15955
|
-
"handler": "handlers/
|
|
15868
|
+
"name": "get_site",
|
|
15869
|
+
"description": "Get metadata for a SharePoint site by site ID. Returns the site name, description, web URL, and timestamps. Use search_sites or get_site_by_path first if you do not already know the site ID.",
|
|
15870
|
+
"inputSchema": "schemas/get_site.json",
|
|
15871
|
+
"handler": "handlers/get_site.js",
|
|
15956
15872
|
"scope": "read"
|
|
15957
15873
|
},
|
|
15958
15874
|
{
|
|
15959
|
-
"name": "
|
|
15960
|
-
"description": "List
|
|
15961
|
-
"inputSchema": "schemas/
|
|
15962
|
-
"handler": "handlers/
|
|
15875
|
+
"name": "list_site_drives",
|
|
15876
|
+
"description": "List document libraries (drives) for a SharePoint site. Returns compact drive summaries including IDs, names, web URLs, and drive type. Use this after resolving a site to discover the right document library before browsing folders or reading files.",
|
|
15877
|
+
"inputSchema": "schemas/list_site_drives.json",
|
|
15878
|
+
"handler": "handlers/list_site_drives.js",
|
|
15963
15879
|
"scope": "read"
|
|
15964
15880
|
},
|
|
15965
15881
|
{
|
|
15966
|
-
"name": "
|
|
15967
|
-
"description": "
|
|
15968
|
-
"inputSchema": "schemas/
|
|
15969
|
-
"handler": "handlers/
|
|
15882
|
+
"name": "list_drive_children",
|
|
15883
|
+
"description": "List the files and folders inside a SharePoint document library folder. By default this lists the root of the drive. Provide itemId to browse a specific folder. Returns compact entries with file-or-folder flags, MIME type when available, and parent references. Use get_drive_item_meta when you need one specific item.",
|
|
15884
|
+
"inputSchema": "schemas/list_drive_children.json",
|
|
15885
|
+
"handler": "handlers/list_drive_children.js",
|
|
15970
15886
|
"scope": "read"
|
|
15971
15887
|
},
|
|
15972
15888
|
{
|
|
15973
|
-
"name": "
|
|
15974
|
-
"description": "
|
|
15975
|
-
"inputSchema": "schemas/
|
|
15976
|
-
"handler": "handlers/
|
|
15889
|
+
"name": "get_drive_item_meta",
|
|
15890
|
+
"description": "Get metadata for a single SharePoint file or folder by drive ID and item ID. Returns a compact item summary including IDs, name, type flags, web URL, size, timestamps, and parent reference. Use read_file_content to read the actual file contents.",
|
|
15891
|
+
"inputSchema": "schemas/get_drive_item.json",
|
|
15892
|
+
"handler": "handlers/get_drive_item.js",
|
|
15977
15893
|
"scope": "read"
|
|
15978
15894
|
},
|
|
15979
15895
|
{
|
|
15980
|
-
"name": "
|
|
15981
|
-
"description": "
|
|
15982
|
-
"inputSchema": "schemas/
|
|
15983
|
-
"handler": "handlers/
|
|
15896
|
+
"name": "search_files",
|
|
15897
|
+
"description": "Search SharePoint and OneDrive content through Microsoft Graph search and return flattened file hits. Provide a query string; Graph KQL syntax is supported. Optional siteId and driveId filters narrow the flattened results after search. Use this for broad file discovery when folder-by-folder browsing is too narrow.",
|
|
15898
|
+
"inputSchema": "schemas/search_files.json",
|
|
15899
|
+
"handler": "handlers/search_files.js",
|
|
15984
15900
|
"scope": "read"
|
|
15985
15901
|
},
|
|
15986
15902
|
{
|
|
15987
|
-
"name": "
|
|
15988
|
-
"description": "
|
|
15989
|
-
"inputSchema": "schemas/
|
|
15990
|
-
"handler": "handlers/
|
|
15903
|
+
"name": "read_file_content",
|
|
15904
|
+
"description": "Read a SharePoint file into agent-friendly text using the shared file extraction pipeline. This is the standard way to consume document contents such as PDF, DOCX, XLSX, PPTX, and text-like files stored in SharePoint document libraries. Provide driveId and itemId. Folders are rejected; use list_drive_children to browse them.",
|
|
15905
|
+
"inputSchema": "schemas/read_file_content.json",
|
|
15906
|
+
"handler": "handlers/read_file_content.js",
|
|
15991
15907
|
"scope": "read"
|
|
15992
15908
|
},
|
|
15993
15909
|
{
|
|
15994
|
-
"name": "
|
|
15995
|
-
"description": "Create a new
|
|
15996
|
-
"inputSchema": "schemas/
|
|
15997
|
-
"handler": "handlers/
|
|
15998
|
-
"scope": "write"
|
|
15999
|
-
},
|
|
16000
|
-
{
|
|
16001
|
-
"name": "close_board",
|
|
16002
|
-
"description": "Close a board (set closed=true).",
|
|
16003
|
-
"inputSchema": "schemas/close_board.json",
|
|
16004
|
-
"handler": "handlers/close_board.js",
|
|
16005
|
-
"scope": "write"
|
|
16006
|
-
},
|
|
16007
|
-
{
|
|
16008
|
-
"name": "delete_board",
|
|
16009
|
-
"description": "Permanently delete a closed board.",
|
|
16010
|
-
"inputSchema": "schemas/delete_board.json",
|
|
16011
|
-
"handler": "handlers/delete_board.js",
|
|
16012
|
-
"scope": "write"
|
|
16013
|
-
},
|
|
16014
|
-
{
|
|
16015
|
-
"name": "create_card",
|
|
16016
|
-
"description": "Create a new card in a list.",
|
|
16017
|
-
"inputSchema": "schemas/create_card.json",
|
|
16018
|
-
"handler": "handlers/create_card.js",
|
|
16019
|
-
"scope": "write"
|
|
16020
|
-
},
|
|
16021
|
-
{
|
|
16022
|
-
"name": "update_card",
|
|
16023
|
-
"description": "Update a card's fields (name, desc, due, list, etc).",
|
|
16024
|
-
"inputSchema": "schemas/update_card.json",
|
|
16025
|
-
"handler": "handlers/update_card.js",
|
|
16026
|
-
"scope": "write"
|
|
16027
|
-
},
|
|
16028
|
-
{
|
|
16029
|
-
"name": "delete_card",
|
|
16030
|
-
"description": "Delete a card.",
|
|
16031
|
-
"inputSchema": "schemas/delete_card.json",
|
|
16032
|
-
"handler": "handlers/delete_card.js",
|
|
16033
|
-
"scope": "write"
|
|
16034
|
-
},
|
|
16035
|
-
{
|
|
16036
|
-
"name": "move_card_to_list",
|
|
16037
|
-
"description": "Move a card to another list.",
|
|
16038
|
-
"inputSchema": "schemas/move_card_to_list.json",
|
|
16039
|
-
"handler": "handlers/move_card_to_list.js",
|
|
16040
|
-
"scope": "write"
|
|
16041
|
-
},
|
|
16042
|
-
{
|
|
16043
|
-
"name": "add_member_to_card",
|
|
16044
|
-
"description": "Add a member to a card.",
|
|
16045
|
-
"inputSchema": "schemas/add_member_to_card.json",
|
|
16046
|
-
"handler": "handlers/add_member_to_card.js",
|
|
16047
|
-
"scope": "write"
|
|
16048
|
-
},
|
|
16049
|
-
{
|
|
16050
|
-
"name": "remove_member_from_card",
|
|
16051
|
-
"description": "Remove a member from a card.",
|
|
16052
|
-
"inputSchema": "schemas/remove_member_from_card.json",
|
|
16053
|
-
"handler": "handlers/remove_member_from_card.js",
|
|
16054
|
-
"scope": "write"
|
|
16055
|
-
},
|
|
16056
|
-
{
|
|
16057
|
-
"name": "add_checklist_to_card",
|
|
16058
|
-
"description": "Create a checklist on a card.",
|
|
16059
|
-
"inputSchema": "schemas/add_checklist_to_card.json",
|
|
16060
|
-
"handler": "handlers/add_checklist_to_card.js",
|
|
16061
|
-
"scope": "write"
|
|
16062
|
-
},
|
|
16063
|
-
{
|
|
16064
|
-
"name": "create_list",
|
|
16065
|
-
"description": "Create a new list on a board.",
|
|
16066
|
-
"inputSchema": "schemas/create_list.json",
|
|
16067
|
-
"handler": "handlers/create_list.js",
|
|
15910
|
+
"name": "create_folder",
|
|
15911
|
+
"description": "Create a new folder in a SharePoint document library. By default the folder is created in the drive root. Provide parentItemId to create it inside an existing folder. Returns the created folder metadata including its item ID for later browsing or moves.",
|
|
15912
|
+
"inputSchema": "schemas/create_folder.json",
|
|
15913
|
+
"handler": "handlers/create_folder.js",
|
|
16068
15914
|
"scope": "write"
|
|
16069
15915
|
},
|
|
16070
15916
|
{
|
|
16071
|
-
"name": "
|
|
16072
|
-
"description": "
|
|
16073
|
-
"inputSchema": "schemas/
|
|
16074
|
-
"handler": "handlers/
|
|
15917
|
+
"name": "move_drive_item",
|
|
15918
|
+
"description": "Move a SharePoint file or folder to a different parent folder in the same drive. Provide destinationParentId and optionally a newName to rename during the move. Use get_drive_item_meta or list_drive_children first to discover the current item and destination IDs.",
|
|
15919
|
+
"inputSchema": "schemas/move_drive_item.json",
|
|
15920
|
+
"handler": "handlers/move_drive_item.js",
|
|
16075
15921
|
"scope": "write"
|
|
16076
15922
|
},
|
|
16077
15923
|
{
|
|
16078
|
-
"name": "
|
|
16079
|
-
"description": "
|
|
16080
|
-
"inputSchema": "schemas/
|
|
16081
|
-
"handler": "handlers/
|
|
15924
|
+
"name": "delete_drive_item",
|
|
15925
|
+
"description": "Delete a SharePoint file or folder by drive ID and item ID. This is a destructive operation. Use get_drive_item_meta or list_drive_children first to confirm you have the correct item before deleting it.",
|
|
15926
|
+
"inputSchema": "schemas/delete_drive_item.json",
|
|
15927
|
+
"handler": "handlers/delete_drive_item.js",
|
|
16082
15928
|
"scope": "write"
|
|
16083
15929
|
}
|
|
16084
15930
|
]
|
|
16085
15931
|
},
|
|
16086
|
-
"prompt":
|
|
15932
|
+
"prompt": "Use this integration for SharePoint document libraries and files.\n\nRecommended workflow:\n\n1. If you know the SharePoint hostname and path, start with `get_site_by_path`.\n2. Otherwise use `search_sites` to discover the correct site.\n3. Use `list_site_drives` to find the relevant document library for that site.\n4. Use `list_drive_children` for deterministic folder browsing or `search_files` for broader file discovery.\n5. Use `get_drive_item_meta` when you need compact metadata for a specific file or folder.\n6. Use `read_file_content` to consume the actual contents of a file in agent-friendly text.\n\nNotes:\n\n- `search_files` uses Microsoft Graph search. The `query` field accepts normal keywords and Graph KQL syntax.\n- `siteId` and `driveId` filters on `search_files` are applied to the flattened search results after Graph returns them.\n- `read_file_content` is for files only. Folders do not have readable file content.\n- This v1 integration is intentionally focused on SharePoint sites, document libraries, folders, and files. It does not include classic SharePoint list/list-item tools or file upload.\n",
|
|
16087
15933
|
"variants": {
|
|
16088
15934
|
"variants": {
|
|
16089
|
-
"
|
|
16090
|
-
"label": "
|
|
15935
|
+
"app_credentials": {
|
|
15936
|
+
"label": "Microsoft Graph App Credentials",
|
|
16091
15937
|
"schema": {
|
|
16092
15938
|
"type": "object",
|
|
16093
15939
|
"properties": {
|
|
16094
|
-
"
|
|
15940
|
+
"tenantId": {
|
|
16095
15941
|
"type": "string",
|
|
16096
|
-
"title": "
|
|
16097
|
-
"description": "
|
|
15942
|
+
"title": "Tenant ID",
|
|
15943
|
+
"description": "Microsoft Entra tenant ID (GUID) that owns the SharePoint tenant."
|
|
16098
15944
|
},
|
|
16099
|
-
"
|
|
15945
|
+
"clientId": {
|
|
16100
15946
|
"type": "string",
|
|
16101
|
-
"title": "
|
|
16102
|
-
"description":
|
|
15947
|
+
"title": "Client ID",
|
|
15948
|
+
"description": "Application (client) ID of the Microsoft Entra app registration."
|
|
15949
|
+
},
|
|
15950
|
+
"clientSecret": {
|
|
15951
|
+
"type": "string",
|
|
15952
|
+
"title": "Client Secret",
|
|
15953
|
+
"description": "Client secret value for the Microsoft Entra app registration.",
|
|
15954
|
+
"format": "password"
|
|
16103
15955
|
}
|
|
16104
15956
|
},
|
|
16105
15957
|
"required": [
|
|
16106
|
-
"
|
|
16107
|
-
"
|
|
15958
|
+
"tenantId",
|
|
15959
|
+
"clientId",
|
|
15960
|
+
"clientSecret"
|
|
16108
15961
|
],
|
|
16109
15962
|
"additionalProperties": false
|
|
16110
15963
|
},
|
|
15964
|
+
"preprocess": {
|
|
15965
|
+
"type": "handler",
|
|
15966
|
+
"handlerCode": "async (creds, utils) => {\n const tenantId = String(creds?.tenantId || '').trim()\n const clientId = String(creds?.clientId || '').trim()\n const clientSecret = String(creds?.clientSecret || '').trim()\n\n if (!tenantId)\n throw new Error('Missing tenantId')\n if (!clientId)\n throw new Error('Missing clientId')\n if (!clientSecret)\n throw new Error('Missing clientSecret')\n\n const response = await utils.tokenFetch(\n `https://login.microsoftonline.com/${encodeURIComponent(tenantId)}/oauth2/v2.0/token`,\n {\n method: 'POST',\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: clientId,\n client_secret: clientSecret,\n scope: 'https://graph.microsoft.com/.default',\n }),\n },\n )\n\n const data = await response.json()\n if (!response.ok) {\n const message = typeof data?.error_description === 'string'\n ? data.error_description\n : (typeof data?.error === 'string' ? data.error : `Token request failed with status ${response.status}`)\n throw new Error(message)\n }\n\n const token = typeof data?.access_token === 'string' ? data.access_token : ''\n if (!token)\n throw new Error('Microsoft token response did not include access_token')\n\n return {\n token,\n expiresIn: data?.expires_in,\n }\n}",
|
|
15967
|
+
"allowedOrigins": [
|
|
15968
|
+
"https://login.microsoftonline.com"
|
|
15969
|
+
]
|
|
15970
|
+
},
|
|
16111
15971
|
"injection": {
|
|
16112
|
-
"
|
|
16113
|
-
"
|
|
16114
|
-
"token": "{{apiToken}}"
|
|
15972
|
+
"headers": {
|
|
15973
|
+
"Authorization": "Bearer {{token}}"
|
|
16115
15974
|
}
|
|
16116
15975
|
},
|
|
16117
15976
|
"healthCheck": {
|
|
16118
|
-
"
|
|
15977
|
+
"notViable": true
|
|
16119
15978
|
}
|
|
16120
15979
|
}
|
|
16121
15980
|
},
|
|
16122
|
-
"default": "
|
|
15981
|
+
"default": "app_credentials"
|
|
16123
15982
|
},
|
|
16124
|
-
"hint": "1.
|
|
15983
|
+
"hint": "1. Create or use a Microsoft Entra app registration for Microsoft Graph at https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade\n2. Create a client secret for that app and copy the **tenant ID**, **client ID**, and **client secret value**.\n3. In Microsoft Graph **Application permissions**, grant at least `Sites.Read.All` and `Files.Read.All`.\n4. If you intend to use write actions such as folder creation, moves, and deletes, also grant `Sites.ReadWrite.All` and `Files.ReadWrite.All`.\n5. Grant admin consent for those application permissions in the tenant.\n6. Paste the tenant ID, client ID, and client secret into this integration. The integration exchanges them for short-lived Microsoft Graph access tokens automatically.",
|
|
16125
15984
|
"hintsByVariant": {},
|
|
16126
15985
|
"tools": [
|
|
16127
15986
|
{
|
|
16128
|
-
"name": "
|
|
16129
|
-
"description": "
|
|
15987
|
+
"name": "search_sites",
|
|
15988
|
+
"description": "Search SharePoint sites by keyword across the tenant. Returns compact site summaries with IDs and web URLs. Use this when you know the site name or topic but not the site ID. If you already know the hostname and path, use get_site_by_path instead.",
|
|
16130
15989
|
"inputSchema": {
|
|
15990
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16131
15991
|
"type": "object",
|
|
16132
|
-
"
|
|
15992
|
+
"required": [
|
|
15993
|
+
"query"
|
|
15994
|
+
],
|
|
15995
|
+
"properties": {
|
|
15996
|
+
"query": {
|
|
15997
|
+
"type": "string",
|
|
15998
|
+
"description": "Keyword search for SharePoint sites, such as a team name or department."
|
|
15999
|
+
}
|
|
16000
|
+
},
|
|
16001
|
+
"additionalProperties": false
|
|
16002
|
+
},
|
|
16003
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams()\n params.set('search', input.query)\n const res = await integration.fetch(`/sites?${params.toString()}`)\n const data = await res.json()\n const sites = Array.isArray(data?.value)\n ? data.value.map(site => ({\n id: site.id,\n name: site.displayName || site.name || null,\n displayName: site.displayName || site.name || null,\n description: site.description || '',\n webUrl: site.webUrl || null,\n createdDateTime: site.createdDateTime || null,\n lastModifiedDateTime: site.lastModifiedDateTime || null,\n }))\n : []\n return { query: input.query, sites }\n}",
|
|
16004
|
+
"scope": "read"
|
|
16005
|
+
},
|
|
16006
|
+
{
|
|
16007
|
+
"name": "get_site_by_path",
|
|
16008
|
+
"description": "Resolve a SharePoint site from its hostname and server-relative path, such as hostname='contoso.sharepoint.com' and relativePath='//Marketing'. Use this when you know the SharePoint URL structure and need the stable site ID for later calls.",
|
|
16009
|
+
"inputSchema": {
|
|
16010
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16011
|
+
"type": "object",
|
|
16012
|
+
"required": [
|
|
16013
|
+
"hostname",
|
|
16014
|
+
"relativePath"
|
|
16015
|
+
],
|
|
16016
|
+
"properties": {
|
|
16017
|
+
"hostname": {
|
|
16018
|
+
"type": "string",
|
|
16019
|
+
"description": "SharePoint hostname, such as contoso.sharepoint.com."
|
|
16020
|
+
},
|
|
16021
|
+
"relativePath": {
|
|
16022
|
+
"type": "string",
|
|
16023
|
+
"description": "Server-relative site path, such as /sites/Marketing."
|
|
16024
|
+
}
|
|
16025
|
+
},
|
|
16026
|
+
"additionalProperties": false
|
|
16027
|
+
},
|
|
16028
|
+
"handlerCode": "async (input) => {\n const hostname = String(input.hostname || '').trim()\n const rawPath = String(input.relativePath || '').trim()\n const normalizedPath = `/${rawPath.replace(/^\\/+/, '')}`\n const encodedPath = normalizedPath\n .split('/')\n .map((segment, index) => index === 0 ? '' : encodeURIComponent(segment))\n .join('/')\n const res = await integration.fetch(`/sites/${hostname}:${encodedPath}`)\n const site = await res.json()\n return {\n id: site.id,\n name: site.displayName || site.name || null,\n displayName: site.displayName || site.name || null,\n description: site.description || '',\n webUrl: site.webUrl || null,\n createdDateTime: site.createdDateTime || null,\n lastModifiedDateTime: site.lastModifiedDateTime || null,\n }\n}",
|
|
16029
|
+
"scope": "read"
|
|
16030
|
+
},
|
|
16031
|
+
{
|
|
16032
|
+
"name": "get_site",
|
|
16033
|
+
"description": "Get metadata for a SharePoint site by site ID. Returns the site name, description, web URL, and timestamps. Use search_sites or get_site_by_path first if you do not already know the site ID.",
|
|
16034
|
+
"inputSchema": {
|
|
16035
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16036
|
+
"type": "object",
|
|
16037
|
+
"required": [
|
|
16038
|
+
"siteId"
|
|
16039
|
+
],
|
|
16040
|
+
"properties": {
|
|
16041
|
+
"siteId": {
|
|
16042
|
+
"type": "string",
|
|
16043
|
+
"description": "Microsoft Graph SharePoint site ID."
|
|
16044
|
+
}
|
|
16045
|
+
},
|
|
16046
|
+
"additionalProperties": false
|
|
16047
|
+
},
|
|
16048
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/sites/${encodeURIComponent(input.siteId)}`)\n const site = await res.json()\n return {\n id: site.id,\n name: site.displayName || site.name || null,\n displayName: site.displayName || site.name || null,\n description: site.description || '',\n webUrl: site.webUrl || null,\n createdDateTime: site.createdDateTime || null,\n lastModifiedDateTime: site.lastModifiedDateTime || null,\n }\n}",
|
|
16049
|
+
"scope": "read"
|
|
16050
|
+
},
|
|
16051
|
+
{
|
|
16052
|
+
"name": "list_site_drives",
|
|
16053
|
+
"description": "List document libraries (drives) for a SharePoint site. Returns compact drive summaries including IDs, names, web URLs, and drive type. Use this after resolving a site to discover the right document library before browsing folders or reading files.",
|
|
16054
|
+
"inputSchema": {
|
|
16055
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16056
|
+
"type": "object",
|
|
16057
|
+
"required": [
|
|
16058
|
+
"siteId"
|
|
16059
|
+
],
|
|
16060
|
+
"properties": {
|
|
16061
|
+
"siteId": {
|
|
16062
|
+
"type": "string",
|
|
16063
|
+
"description": "Microsoft Graph SharePoint site ID."
|
|
16064
|
+
},
|
|
16065
|
+
"top": {
|
|
16066
|
+
"type": "integer",
|
|
16067
|
+
"minimum": 1,
|
|
16068
|
+
"maximum": 200,
|
|
16069
|
+
"description": "Maximum number of drives to return."
|
|
16070
|
+
},
|
|
16071
|
+
"includeSystem": {
|
|
16072
|
+
"type": "boolean",
|
|
16073
|
+
"description": "Set true to include hidden/system drives."
|
|
16074
|
+
}
|
|
16075
|
+
},
|
|
16076
|
+
"additionalProperties": false
|
|
16077
|
+
},
|
|
16078
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams()\n params.set('$select', input.includeSystem\n ? 'id,name,webUrl,driveType,createdDateTime,lastModifiedDateTime,system'\n : 'id,name,webUrl,driveType,createdDateTime,lastModifiedDateTime')\n if (input.top)\n params.set('$top', String(input.top))\n\n const res = await integration.fetch(`/sites/${encodeURIComponent(input.siteId)}/drives?${params.toString()}`)\n const data = await res.json()\n const drives = Array.isArray(data?.value)\n ? data.value.map(drive => ({\n id: drive.id,\n name: drive.name || null,\n webUrl: drive.webUrl || null,\n driveType: drive.driveType || null,\n createdDateTime: drive.createdDateTime || null,\n lastModifiedDateTime: drive.lastModifiedDateTime || null,\n isSystem: Boolean(drive.system),\n }))\n : []\n\n return {\n siteId: input.siteId,\n drives,\n nextLink: data?.['@odata.nextLink'] || null,\n }\n}",
|
|
16079
|
+
"scope": "read"
|
|
16080
|
+
},
|
|
16081
|
+
{
|
|
16082
|
+
"name": "list_drive_children",
|
|
16083
|
+
"description": "List the files and folders inside a SharePoint document library folder. By default this lists the root of the drive. Provide itemId to browse a specific folder. Returns compact entries with file-or-folder flags, MIME type when available, and parent references. Use get_drive_item_meta when you need one specific item.",
|
|
16084
|
+
"inputSchema": {
|
|
16085
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16086
|
+
"type": "object",
|
|
16087
|
+
"required": [
|
|
16088
|
+
"driveId"
|
|
16089
|
+
],
|
|
16090
|
+
"properties": {
|
|
16091
|
+
"driveId": {
|
|
16092
|
+
"type": "string",
|
|
16093
|
+
"description": "Document library drive ID."
|
|
16094
|
+
},
|
|
16095
|
+
"itemId": {
|
|
16096
|
+
"type": "string",
|
|
16097
|
+
"description": "Optional folder item ID. Omit to list the drive root."
|
|
16098
|
+
},
|
|
16099
|
+
"top": {
|
|
16100
|
+
"type": "integer",
|
|
16101
|
+
"minimum": 1,
|
|
16102
|
+
"maximum": 200,
|
|
16103
|
+
"description": "Maximum number of children to return."
|
|
16104
|
+
},
|
|
16105
|
+
"orderBy": {
|
|
16106
|
+
"type": "string",
|
|
16107
|
+
"description": "Optional Microsoft Graph orderBy expression, such as name or lastModifiedDateTime desc."
|
|
16108
|
+
}
|
|
16109
|
+
},
|
|
16110
|
+
"additionalProperties": false
|
|
16111
|
+
},
|
|
16112
|
+
"handlerCode": "async (input) => {\n const flattenItem = item => ({\n id: item.id,\n name: item.name || null,\n webUrl: item.webUrl || null,\n size: item.size ?? null,\n createdDateTime: item.createdDateTime || null,\n lastModifiedDateTime: item.lastModifiedDateTime || null,\n eTag: item.eTag || null,\n cTag: item.cTag || null,\n mimeType: item.file?.mimeType || null,\n isFolder: Boolean(item.folder || item.package),\n isFile: Boolean(item.file),\n childCount: item.folder?.childCount ?? null,\n parentReference: item.parentReference || null,\n })\n\n const params = new URLSearchParams()\n params.set(\n '$select',\n 'id,name,webUrl,size,createdDateTime,lastModifiedDateTime,eTag,cTag,parentReference,file,folder,package',\n )\n if (input.top)\n params.set('$top', String(input.top))\n if (input.orderBy)\n params.set('$orderby', input.orderBy)\n\n const basePath = input.itemId\n ? `/drives/${encodeURIComponent(input.driveId)}/items/${encodeURIComponent(input.itemId)}/children`\n : `/drives/${encodeURIComponent(input.driveId)}/root/children`\n\n const res = await integration.fetch(`${basePath}?${params.toString()}`)\n const data = await res.json()\n\n return {\n driveId: input.driveId,\n itemId: input.itemId || null,\n children: Array.isArray(data?.value) ? data.value.map(flattenItem) : [],\n nextLink: data?.['@odata.nextLink'] || null,\n }\n}",
|
|
16113
|
+
"scope": "read"
|
|
16114
|
+
},
|
|
16115
|
+
{
|
|
16116
|
+
"name": "get_drive_item_meta",
|
|
16117
|
+
"description": "Get metadata for a single SharePoint file or folder by drive ID and item ID. Returns a compact item summary including IDs, name, type flags, web URL, size, timestamps, and parent reference. Use read_file_content to read the actual file contents.",
|
|
16118
|
+
"inputSchema": {
|
|
16119
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16120
|
+
"type": "object",
|
|
16121
|
+
"required": [
|
|
16122
|
+
"driveId",
|
|
16123
|
+
"itemId"
|
|
16124
|
+
],
|
|
16125
|
+
"properties": {
|
|
16126
|
+
"driveId": {
|
|
16127
|
+
"type": "string",
|
|
16128
|
+
"description": "Document library drive ID."
|
|
16129
|
+
},
|
|
16130
|
+
"itemId": {
|
|
16131
|
+
"type": "string",
|
|
16132
|
+
"description": "Drive item ID for the file or folder."
|
|
16133
|
+
}
|
|
16134
|
+
},
|
|
16135
|
+
"additionalProperties": false
|
|
16136
|
+
},
|
|
16137
|
+
"handlerCode": "async (input) => {\n const flattenItem = item => ({\n id: item.id,\n name: item.name || null,\n webUrl: item.webUrl || null,\n size: item.size ?? null,\n createdDateTime: item.createdDateTime || null,\n lastModifiedDateTime: item.lastModifiedDateTime || null,\n eTag: item.eTag || null,\n cTag: item.cTag || null,\n mimeType: item.file?.mimeType || null,\n isFolder: Boolean(item.folder || item.package),\n isFile: Boolean(item.file),\n childCount: item.folder?.childCount ?? null,\n parentReference: item.parentReference || null,\n })\n\n const params = new URLSearchParams()\n params.set(\n '$select',\n 'id,name,webUrl,size,createdDateTime,lastModifiedDateTime,eTag,cTag,parentReference,file,folder,package',\n )\n const res = await integration.fetch(`/drives/${encodeURIComponent(input.driveId)}/items/${encodeURIComponent(input.itemId)}?${params.toString()}`)\n return flattenItem(await res.json())\n}",
|
|
16138
|
+
"scope": "read"
|
|
16139
|
+
},
|
|
16140
|
+
{
|
|
16141
|
+
"name": "search_files",
|
|
16142
|
+
"description": "Search SharePoint and OneDrive content through Microsoft Graph search and return flattened file hits. Provide a query string; Graph KQL syntax is supported. Optional siteId and driveId filters narrow the flattened results after search. Use this for broad file discovery when folder-by-folder browsing is too narrow.",
|
|
16143
|
+
"inputSchema": {
|
|
16144
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16145
|
+
"type": "object",
|
|
16146
|
+
"required": [
|
|
16147
|
+
"query"
|
|
16148
|
+
],
|
|
16149
|
+
"properties": {
|
|
16150
|
+
"query": {
|
|
16151
|
+
"type": "string",
|
|
16152
|
+
"description": "Search query string. Microsoft Graph KQL syntax is supported."
|
|
16153
|
+
},
|
|
16154
|
+
"siteId": {
|
|
16155
|
+
"type": "string",
|
|
16156
|
+
"description": "Optional site ID to keep only hits from a specific SharePoint site."
|
|
16157
|
+
},
|
|
16158
|
+
"driveId": {
|
|
16159
|
+
"type": "string",
|
|
16160
|
+
"description": "Optional drive ID to keep only hits from a specific document library."
|
|
16161
|
+
},
|
|
16162
|
+
"from": {
|
|
16163
|
+
"type": "integer",
|
|
16164
|
+
"minimum": 0,
|
|
16165
|
+
"description": "Offset into the Graph search results."
|
|
16166
|
+
},
|
|
16167
|
+
"size": {
|
|
16168
|
+
"type": "integer",
|
|
16169
|
+
"minimum": 1,
|
|
16170
|
+
"maximum": 50,
|
|
16171
|
+
"description": "Maximum number of hits to request from Graph."
|
|
16172
|
+
}
|
|
16173
|
+
},
|
|
16174
|
+
"additionalProperties": false
|
|
16175
|
+
},
|
|
16176
|
+
"handlerCode": "async (input) => {\n const extractFallbackRegion = (error) => {\n const texts = [error?.data?.body, error?.message].filter(s => typeof s === 'string')\n for (const text of texts) {\n const match = text.match(/Only valid regions are ([A-Z,\\s]+)/i)\n const region = match?.[1]?.split(',').map(r => r.trim().toUpperCase()).filter(Boolean)[0]\n if (region)\n return region\n }\n return null\n }\n\n const runSearch = async (region) => {\n const res = await integration.fetch('/search/query', {\n method: 'POST',\n body: {\n requests: [{\n entityTypes: ['driveItem'],\n query: { queryString: input.query },\n from: typeof input.from === 'number' ? input.from : 0,\n size: typeof input.size === 'number' ? input.size : 25,\n region,\n }],\n },\n })\n return res.json()\n }\n\n const flattenHit = (hit) => {\n const resource = hit?.resource || {}\n const parentReference = resource.parentReference || {}\n return {\n id: resource.id || hit?.hitId || null,\n name: resource.name || null,\n webUrl: resource.webUrl || null,\n summary: hit?.summary || '',\n rank: hit?.rank ?? null,\n createdDateTime: resource.createdDateTime || null,\n lastModifiedDateTime: resource.lastModifiedDateTime || null,\n mimeType: resource.file?.mimeType || null,\n size: resource.size ?? null,\n isFolder: Boolean(resource.folder || resource.package),\n isFile: Boolean(resource.file),\n driveId: parentReference.driveId || null,\n siteId: parentReference.siteId || null,\n parentReference,\n }\n }\n\n let data\n try {\n data = await runSearch('NAM')\n }\n catch (error) {\n const fallback = extractFallbackRegion(error)\n if (!fallback)\n throw error\n data = await runSearch(fallback)\n }\n\n const container = data?.value?.[0]?.hitsContainers?.[0]\n const allHits = Array.isArray(container?.hits) ? container.hits.map(flattenHit) : []\n const hits = allHits.filter((hit) => {\n if (input.siteId && hit.siteId !== input.siteId)\n return false\n if (input.driveId && hit.driveId !== input.driveId)\n return false\n return true\n })\n\n return {\n query: input.query,\n hits,\n total: container?.total ?? hits.length,\n moreResultsAvailable: Boolean(container?.moreResultsAvailable),\n }\n}",
|
|
16177
|
+
"scope": "read"
|
|
16178
|
+
},
|
|
16179
|
+
{
|
|
16180
|
+
"name": "read_file_content",
|
|
16181
|
+
"description": "Read a SharePoint file into agent-friendly text using the shared file extraction pipeline. This is the standard way to consume document contents such as PDF, DOCX, XLSX, PPTX, and text-like files stored in SharePoint document libraries. Provide driveId and itemId. Folders are rejected; use list_drive_children to browse them.",
|
|
16182
|
+
"inputSchema": {
|
|
16183
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16184
|
+
"type": "object",
|
|
16185
|
+
"required": [
|
|
16186
|
+
"driveId",
|
|
16187
|
+
"itemId"
|
|
16188
|
+
],
|
|
16189
|
+
"properties": {
|
|
16190
|
+
"driveId": {
|
|
16191
|
+
"type": "string",
|
|
16192
|
+
"description": "Document library drive ID."
|
|
16193
|
+
},
|
|
16194
|
+
"itemId": {
|
|
16195
|
+
"type": "string",
|
|
16196
|
+
"description": "Drive item ID for the file."
|
|
16197
|
+
},
|
|
16198
|
+
"mimeType": {
|
|
16199
|
+
"type": "string",
|
|
16200
|
+
"description": "Optional MIME type from get_drive_item_meta or search_files."
|
|
16201
|
+
}
|
|
16202
|
+
},
|
|
16203
|
+
"additionalProperties": false
|
|
16204
|
+
},
|
|
16205
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams()\n params.set(\n '$select',\n 'id,name,webUrl,size,createdDateTime,lastModifiedDateTime,parentReference,file,folder,package',\n )\n const res = await integration.fetch(`/drives/${encodeURIComponent(input.driveId)}/items/${encodeURIComponent(input.itemId)}?${params.toString()}`)\n const item = await res.json()\n const mimeType = input.mimeType || item?.file?.mimeType || null\n\n if (item?.folder || item?.package) {\n return {\n driveId: input.driveId,\n itemId: input.itemId,\n name: item?.name || null,\n mimeType,\n content: null,\n message: 'Folders do not have readable file content.',\n }\n }\n\n const extracted = await utils.extractFileContent({\n auth: true,\n source: `/drives/${encodeURIComponent(input.driveId)}/items/${encodeURIComponent(input.itemId)}/content`,\n })\n\n return {\n driveId: input.driveId,\n itemId: input.itemId,\n name: item?.name || null,\n webUrl: item?.webUrl || null,\n mimeType,\n ...extracted,\n }\n}",
|
|
16206
|
+
"scope": "read"
|
|
16207
|
+
},
|
|
16208
|
+
{
|
|
16209
|
+
"name": "create_folder",
|
|
16210
|
+
"description": "Create a new folder in a SharePoint document library. By default the folder is created in the drive root. Provide parentItemId to create it inside an existing folder. Returns the created folder metadata including its item ID for later browsing or moves.",
|
|
16211
|
+
"inputSchema": {
|
|
16212
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16213
|
+
"type": "object",
|
|
16214
|
+
"required": [
|
|
16215
|
+
"driveId",
|
|
16216
|
+
"name"
|
|
16217
|
+
],
|
|
16218
|
+
"properties": {
|
|
16219
|
+
"driveId": {
|
|
16220
|
+
"type": "string",
|
|
16221
|
+
"description": "Document library drive ID."
|
|
16222
|
+
},
|
|
16223
|
+
"name": {
|
|
16224
|
+
"type": "string",
|
|
16225
|
+
"description": "Folder name to create."
|
|
16226
|
+
},
|
|
16227
|
+
"parentItemId": {
|
|
16228
|
+
"type": "string",
|
|
16229
|
+
"description": "Optional parent folder item ID. Omit to create in the drive root."
|
|
16230
|
+
},
|
|
16231
|
+
"conflictBehavior": {
|
|
16232
|
+
"type": "string",
|
|
16233
|
+
"enum": [
|
|
16234
|
+
"rename",
|
|
16235
|
+
"replace",
|
|
16236
|
+
"fail"
|
|
16237
|
+
],
|
|
16238
|
+
"description": "How Graph should handle name conflicts. Defaults to rename."
|
|
16239
|
+
}
|
|
16240
|
+
},
|
|
16241
|
+
"additionalProperties": false
|
|
16242
|
+
},
|
|
16243
|
+
"handlerCode": "async (input) => {\n const path = input.parentItemId\n ? `/drives/${encodeURIComponent(input.driveId)}/items/${encodeURIComponent(input.parentItemId)}/children`\n : `/drives/${encodeURIComponent(input.driveId)}/root/children`\n\n const res = await integration.fetch(path, {\n method: 'POST',\n body: {\n name: input.name,\n folder: {},\n '@microsoft.graph.conflictBehavior': input.conflictBehavior || 'rename',\n },\n })\n const item = await res.json()\n return {\n id: item.id,\n name: item.name || null,\n webUrl: item.webUrl || null,\n size: item.size ?? null,\n createdDateTime: item.createdDateTime || null,\n lastModifiedDateTime: item.lastModifiedDateTime || null,\n mimeType: item.file?.mimeType || null,\n isFolder: Boolean(item.folder || item.package),\n isFile: Boolean(item.file),\n childCount: item.folder?.childCount ?? null,\n parentReference: item.parentReference || null,\n }\n}",
|
|
16244
|
+
"scope": "write"
|
|
16245
|
+
},
|
|
16246
|
+
{
|
|
16247
|
+
"name": "move_drive_item",
|
|
16248
|
+
"description": "Move a SharePoint file or folder to a different parent folder in the same drive. Provide destinationParentId and optionally a newName to rename during the move. Use get_drive_item_meta or list_drive_children first to discover the current item and destination IDs.",
|
|
16249
|
+
"inputSchema": {
|
|
16250
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16251
|
+
"type": "object",
|
|
16252
|
+
"required": [
|
|
16253
|
+
"driveId",
|
|
16254
|
+
"itemId",
|
|
16255
|
+
"destinationParentId"
|
|
16256
|
+
],
|
|
16257
|
+
"properties": {
|
|
16258
|
+
"driveId": {
|
|
16259
|
+
"type": "string",
|
|
16260
|
+
"description": "Document library drive ID."
|
|
16261
|
+
},
|
|
16262
|
+
"itemId": {
|
|
16263
|
+
"type": "string",
|
|
16264
|
+
"description": "Drive item ID for the file or folder to move."
|
|
16265
|
+
},
|
|
16266
|
+
"destinationParentId": {
|
|
16267
|
+
"type": "string",
|
|
16268
|
+
"description": "Destination folder item ID."
|
|
16269
|
+
},
|
|
16270
|
+
"newName": {
|
|
16271
|
+
"type": "string",
|
|
16272
|
+
"description": "Optional new item name to apply during the move."
|
|
16273
|
+
}
|
|
16274
|
+
},
|
|
16275
|
+
"additionalProperties": false
|
|
16276
|
+
},
|
|
16277
|
+
"handlerCode": "async (input) => {\n const body = {\n parentReference: {\n id: input.destinationParentId,\n },\n }\n if (input.newName)\n body.name = input.newName\n\n const res = await integration.fetch(`/drives/${encodeURIComponent(input.driveId)}/items/${encodeURIComponent(input.itemId)}`, {\n method: 'PATCH',\n body,\n })\n const item = await res.json()\n return {\n id: item.id,\n name: item.name || null,\n webUrl: item.webUrl || null,\n size: item.size ?? null,\n createdDateTime: item.createdDateTime || null,\n lastModifiedDateTime: item.lastModifiedDateTime || null,\n mimeType: item.file?.mimeType || null,\n isFolder: Boolean(item.folder || item.package),\n isFile: Boolean(item.file),\n childCount: item.folder?.childCount ?? null,\n parentReference: item.parentReference || null,\n }\n}",
|
|
16278
|
+
"scope": "write"
|
|
16279
|
+
},
|
|
16280
|
+
{
|
|
16281
|
+
"name": "delete_drive_item",
|
|
16282
|
+
"description": "Delete a SharePoint file or folder by drive ID and item ID. This is a destructive operation. Use get_drive_item_meta or list_drive_children first to confirm you have the correct item before deleting it.",
|
|
16283
|
+
"inputSchema": {
|
|
16284
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16285
|
+
"type": "object",
|
|
16286
|
+
"required": [
|
|
16287
|
+
"driveId",
|
|
16288
|
+
"itemId"
|
|
16289
|
+
],
|
|
16290
|
+
"properties": {
|
|
16291
|
+
"driveId": {
|
|
16292
|
+
"type": "string",
|
|
16293
|
+
"description": "Document library drive ID."
|
|
16294
|
+
},
|
|
16295
|
+
"itemId": {
|
|
16296
|
+
"type": "string",
|
|
16297
|
+
"description": "Drive item ID for the file or folder to delete."
|
|
16298
|
+
}
|
|
16299
|
+
},
|
|
16133
16300
|
"additionalProperties": false
|
|
16134
16301
|
},
|
|
16135
|
-
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/
|
|
16136
|
-
"scope": "
|
|
16137
|
-
}
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16302
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/drives/${encodeURIComponent(input.driveId)}/items/${encodeURIComponent(input.itemId)}`, {\n method: 'DELETE',\n })\n if (res.status === 204)\n return { success: true, status: 204 }\n try {\n return await res.json()\n }\n catch {\n return { success: res.ok, status: res.status }\n }\n}",
|
|
16303
|
+
"scope": "write"
|
|
16304
|
+
}
|
|
16305
|
+
],
|
|
16306
|
+
"variantOwnerType": null
|
|
16307
|
+
},
|
|
16308
|
+
"trello": {
|
|
16309
|
+
"manifest": {
|
|
16310
|
+
"name": "Trello",
|
|
16311
|
+
"version": "0.1.0",
|
|
16312
|
+
"baseUrl": "https://api.trello.com/1",
|
|
16313
|
+
"tools": [
|
|
16314
|
+
{
|
|
16315
|
+
"name": "get_member",
|
|
16316
|
+
"description": "Fetch the current member profile.",
|
|
16317
|
+
"inputSchema": "schemas/get_member.json",
|
|
16318
|
+
"handler": "handlers/get_member.js",
|
|
16319
|
+
"scope": "read"
|
|
16320
|
+
},
|
|
16321
|
+
{
|
|
16322
|
+
"name": "get_member_boards",
|
|
16323
|
+
"description": "List boards for the current member.",
|
|
16324
|
+
"inputSchema": "schemas/empty.json",
|
|
16325
|
+
"handler": "handlers/get_member_boards.js",
|
|
16326
|
+
"scope": "read"
|
|
16327
|
+
},
|
|
16328
|
+
{
|
|
16329
|
+
"name": "get_member_organizations",
|
|
16330
|
+
"description": "List organizations (workspaces) for the current member.",
|
|
16331
|
+
"inputSchema": "schemas/empty.json",
|
|
16332
|
+
"handler": "handlers/get_member_organizations.js",
|
|
16333
|
+
"scope": "read"
|
|
16334
|
+
},
|
|
16335
|
+
{
|
|
16336
|
+
"name": "get_board",
|
|
16337
|
+
"description": "Fetch a board by id.",
|
|
16338
|
+
"inputSchema": "schemas/id_board.json",
|
|
16339
|
+
"handler": "handlers/get_board.js",
|
|
16340
|
+
"scope": "read"
|
|
16341
|
+
},
|
|
16342
|
+
{
|
|
16343
|
+
"name": "get_board_lists",
|
|
16344
|
+
"description": "List lists on a board.",
|
|
16345
|
+
"inputSchema": "schemas/id_board.json",
|
|
16346
|
+
"handler": "handlers/get_board_lists.js",
|
|
16347
|
+
"scope": "read"
|
|
16348
|
+
},
|
|
16349
|
+
{
|
|
16350
|
+
"name": "get_board_cards",
|
|
16351
|
+
"description": "List cards on a board.",
|
|
16352
|
+
"inputSchema": "schemas/id_board.json",
|
|
16353
|
+
"handler": "handlers/get_board_cards.js",
|
|
16354
|
+
"scope": "read"
|
|
16355
|
+
},
|
|
16356
|
+
{
|
|
16357
|
+
"name": "get_board_members",
|
|
16358
|
+
"description": "List members on a board.",
|
|
16359
|
+
"inputSchema": "schemas/id_board.json",
|
|
16360
|
+
"handler": "handlers/get_board_members.js",
|
|
16361
|
+
"scope": "read"
|
|
16362
|
+
},
|
|
16363
|
+
{
|
|
16364
|
+
"name": "get_board_labels",
|
|
16365
|
+
"description": "List labels on a board.",
|
|
16366
|
+
"inputSchema": "schemas/id_board.json",
|
|
16367
|
+
"handler": "handlers/get_board_labels.js",
|
|
16368
|
+
"scope": "read"
|
|
16369
|
+
},
|
|
16370
|
+
{
|
|
16371
|
+
"name": "get_board_custom_fields",
|
|
16372
|
+
"description": "List custom fields on a board.",
|
|
16373
|
+
"inputSchema": "schemas/id_board.json",
|
|
16374
|
+
"handler": "handlers/get_board_custom_fields.js",
|
|
16375
|
+
"scope": "read"
|
|
16376
|
+
},
|
|
16377
|
+
{
|
|
16378
|
+
"name": "get_board_memberships",
|
|
16379
|
+
"description": "List memberships for a board.",
|
|
16380
|
+
"inputSchema": "schemas/id_board.json",
|
|
16381
|
+
"handler": "handlers/get_board_memberships.js",
|
|
16382
|
+
"scope": "read"
|
|
16383
|
+
},
|
|
16384
|
+
{
|
|
16385
|
+
"name": "get_list",
|
|
16386
|
+
"description": "Fetch a list by id.",
|
|
16387
|
+
"inputSchema": "schemas/id_list.json",
|
|
16388
|
+
"handler": "handlers/get_list.js",
|
|
16389
|
+
"scope": "read"
|
|
16390
|
+
},
|
|
16391
|
+
{
|
|
16392
|
+
"name": "get_list_cards",
|
|
16393
|
+
"description": "List cards in a list.",
|
|
16394
|
+
"inputSchema": "schemas/id_list.json",
|
|
16395
|
+
"handler": "handlers/get_list_cards.js",
|
|
16396
|
+
"scope": "read"
|
|
16397
|
+
},
|
|
16398
|
+
{
|
|
16399
|
+
"name": "get_card",
|
|
16400
|
+
"description": "Fetch a card by id.",
|
|
16401
|
+
"inputSchema": "schemas/id_card.json",
|
|
16402
|
+
"handler": "handlers/get_card.js",
|
|
16403
|
+
"scope": "read"
|
|
16404
|
+
},
|
|
16405
|
+
{
|
|
16406
|
+
"name": "get_card_members",
|
|
16407
|
+
"description": "List members assigned to a card.",
|
|
16408
|
+
"inputSchema": "schemas/id_card.json",
|
|
16409
|
+
"handler": "handlers/get_card_members.js",
|
|
16410
|
+
"scope": "read"
|
|
16411
|
+
},
|
|
16412
|
+
{
|
|
16413
|
+
"name": "get_card_attachments",
|
|
16414
|
+
"description": "List attachments on a card.",
|
|
16415
|
+
"inputSchema": "schemas/id_card.json",
|
|
16416
|
+
"handler": "handlers/get_card_attachments.js",
|
|
16417
|
+
"scope": "read"
|
|
16418
|
+
},
|
|
16419
|
+
{
|
|
16420
|
+
"name": "get_card_actions",
|
|
16421
|
+
"description": "List actions (activity) on a card.",
|
|
16422
|
+
"inputSchema": "schemas/id_card.json",
|
|
16423
|
+
"handler": "handlers/get_card_actions.js",
|
|
16424
|
+
"scope": "read"
|
|
16425
|
+
},
|
|
16426
|
+
{
|
|
16427
|
+
"name": "get_card_checklists",
|
|
16428
|
+
"description": "List checklists on a card.",
|
|
16429
|
+
"inputSchema": "schemas/id_card.json",
|
|
16430
|
+
"handler": "handlers/get_card_checklists.js",
|
|
16431
|
+
"scope": "read"
|
|
16432
|
+
},
|
|
16433
|
+
{
|
|
16434
|
+
"name": "get_card_custom_field_items",
|
|
16435
|
+
"description": "Get custom field items on a card.",
|
|
16436
|
+
"inputSchema": "schemas/id_card.json",
|
|
16437
|
+
"handler": "handlers/get_card_custom_field_items.js",
|
|
16438
|
+
"scope": "read"
|
|
16439
|
+
},
|
|
16440
|
+
{
|
|
16441
|
+
"name": "get_organization",
|
|
16442
|
+
"description": "Fetch an organization (workspace) by id.",
|
|
16443
|
+
"inputSchema": "schemas/id_org.json",
|
|
16444
|
+
"handler": "handlers/get_organization.js",
|
|
16445
|
+
"scope": "read"
|
|
16446
|
+
},
|
|
16447
|
+
{
|
|
16448
|
+
"name": "get_organization_boards",
|
|
16449
|
+
"description": "List boards in an organization (workspace).",
|
|
16450
|
+
"inputSchema": "schemas/id_org.json",
|
|
16451
|
+
"handler": "handlers/get_organization_boards.js",
|
|
16452
|
+
"scope": "read"
|
|
16453
|
+
},
|
|
16454
|
+
{
|
|
16455
|
+
"name": "search",
|
|
16456
|
+
"description": "Search across boards, cards, and members.",
|
|
16457
|
+
"inputSchema": "schemas/search.json",
|
|
16458
|
+
"handler": "handlers/search.js",
|
|
16459
|
+
"scope": "read"
|
|
16460
|
+
},
|
|
16461
|
+
{
|
|
16462
|
+
"name": "create_board",
|
|
16463
|
+
"description": "Create a new board.",
|
|
16464
|
+
"inputSchema": "schemas/create_board.json",
|
|
16465
|
+
"handler": "handlers/create_board.js",
|
|
16466
|
+
"scope": "write"
|
|
16467
|
+
},
|
|
16468
|
+
{
|
|
16469
|
+
"name": "close_board",
|
|
16470
|
+
"description": "Close a board (set closed=true).",
|
|
16471
|
+
"inputSchema": "schemas/close_board.json",
|
|
16472
|
+
"handler": "handlers/close_board.js",
|
|
16473
|
+
"scope": "write"
|
|
16474
|
+
},
|
|
16475
|
+
{
|
|
16476
|
+
"name": "delete_board",
|
|
16477
|
+
"description": "Permanently delete a closed board.",
|
|
16478
|
+
"inputSchema": "schemas/delete_board.json",
|
|
16479
|
+
"handler": "handlers/delete_board.js",
|
|
16480
|
+
"scope": "write"
|
|
16481
|
+
},
|
|
16482
|
+
{
|
|
16483
|
+
"name": "create_card",
|
|
16484
|
+
"description": "Create a new card in a list.",
|
|
16485
|
+
"inputSchema": "schemas/create_card.json",
|
|
16486
|
+
"handler": "handlers/create_card.js",
|
|
16487
|
+
"scope": "write"
|
|
16488
|
+
},
|
|
16489
|
+
{
|
|
16490
|
+
"name": "update_card",
|
|
16491
|
+
"description": "Update a card's fields (name, desc, due, list, etc).",
|
|
16492
|
+
"inputSchema": "schemas/update_card.json",
|
|
16493
|
+
"handler": "handlers/update_card.js",
|
|
16494
|
+
"scope": "write"
|
|
16495
|
+
},
|
|
16496
|
+
{
|
|
16497
|
+
"name": "delete_card",
|
|
16498
|
+
"description": "Delete a card.",
|
|
16499
|
+
"inputSchema": "schemas/delete_card.json",
|
|
16500
|
+
"handler": "handlers/delete_card.js",
|
|
16501
|
+
"scope": "write"
|
|
16502
|
+
},
|
|
16503
|
+
{
|
|
16504
|
+
"name": "move_card_to_list",
|
|
16505
|
+
"description": "Move a card to another list.",
|
|
16506
|
+
"inputSchema": "schemas/move_card_to_list.json",
|
|
16507
|
+
"handler": "handlers/move_card_to_list.js",
|
|
16508
|
+
"scope": "write"
|
|
16509
|
+
},
|
|
16510
|
+
{
|
|
16511
|
+
"name": "add_member_to_card",
|
|
16512
|
+
"description": "Add a member to a card.",
|
|
16513
|
+
"inputSchema": "schemas/add_member_to_card.json",
|
|
16514
|
+
"handler": "handlers/add_member_to_card.js",
|
|
16515
|
+
"scope": "write"
|
|
16516
|
+
},
|
|
16517
|
+
{
|
|
16518
|
+
"name": "remove_member_from_card",
|
|
16519
|
+
"description": "Remove a member from a card.",
|
|
16520
|
+
"inputSchema": "schemas/remove_member_from_card.json",
|
|
16521
|
+
"handler": "handlers/remove_member_from_card.js",
|
|
16522
|
+
"scope": "write"
|
|
16523
|
+
},
|
|
16524
|
+
{
|
|
16525
|
+
"name": "add_checklist_to_card",
|
|
16526
|
+
"description": "Create a checklist on a card.",
|
|
16527
|
+
"inputSchema": "schemas/add_checklist_to_card.json",
|
|
16528
|
+
"handler": "handlers/add_checklist_to_card.js",
|
|
16529
|
+
"scope": "write"
|
|
16530
|
+
},
|
|
16531
|
+
{
|
|
16532
|
+
"name": "create_list",
|
|
16533
|
+
"description": "Create a new list on a board.",
|
|
16534
|
+
"inputSchema": "schemas/create_list.json",
|
|
16535
|
+
"handler": "handlers/create_list.js",
|
|
16536
|
+
"scope": "write"
|
|
16537
|
+
},
|
|
16538
|
+
{
|
|
16539
|
+
"name": "update_list",
|
|
16540
|
+
"description": "Update a list (name, pos, closed).",
|
|
16541
|
+
"inputSchema": "schemas/update_list.json",
|
|
16542
|
+
"handler": "handlers/update_list.js",
|
|
16543
|
+
"scope": "write"
|
|
16544
|
+
},
|
|
16545
|
+
{
|
|
16546
|
+
"name": "archive_list",
|
|
16547
|
+
"description": "Archive a list (set closed=true).",
|
|
16548
|
+
"inputSchema": "schemas/archive_list.json",
|
|
16549
|
+
"handler": "handlers/archive_list.js",
|
|
16550
|
+
"scope": "write"
|
|
16551
|
+
}
|
|
16552
|
+
]
|
|
16553
|
+
},
|
|
16554
|
+
"prompt": null,
|
|
16555
|
+
"variants": {
|
|
16556
|
+
"variants": {
|
|
16557
|
+
"api_key_token": {
|
|
16558
|
+
"label": "API Key + Token",
|
|
16559
|
+
"schema": {
|
|
16560
|
+
"type": "object",
|
|
16561
|
+
"properties": {
|
|
16562
|
+
"apiKey": {
|
|
16563
|
+
"type": "string",
|
|
16564
|
+
"title": "API Key",
|
|
16565
|
+
"description": "Your Trello API key from https://trello.com/power-ups/admin"
|
|
16566
|
+
},
|
|
16567
|
+
"apiToken": {
|
|
16568
|
+
"type": "string",
|
|
16569
|
+
"title": "API Token",
|
|
16570
|
+
"description": `Your Trello API token ("token" param). Generate one via Trello's authorize flow.`
|
|
16571
|
+
}
|
|
16572
|
+
},
|
|
16573
|
+
"required": [
|
|
16574
|
+
"apiKey",
|
|
16575
|
+
"apiToken"
|
|
16576
|
+
],
|
|
16577
|
+
"additionalProperties": false
|
|
16578
|
+
},
|
|
16579
|
+
"injection": {
|
|
16580
|
+
"query": {
|
|
16581
|
+
"key": "{{apiKey}}",
|
|
16582
|
+
"token": "{{apiToken}}"
|
|
16583
|
+
}
|
|
16584
|
+
},
|
|
16585
|
+
"healthCheck": {
|
|
16586
|
+
"path": "/members/me"
|
|
16587
|
+
}
|
|
16588
|
+
}
|
|
16589
|
+
},
|
|
16590
|
+
"default": "api_key_token"
|
|
16591
|
+
},
|
|
16592
|
+
"hint": "1. Go to `https://trello.com/power-ups/admin`\n2. Create a new app\n3. Navigate to **API Key** and copy your API key\n4. Click **Generate a Token** and copy the token value",
|
|
16593
|
+
"hintsByVariant": {},
|
|
16594
|
+
"tools": [
|
|
16595
|
+
{
|
|
16596
|
+
"name": "get_member",
|
|
16597
|
+
"description": "Fetch the current member profile.",
|
|
16598
|
+
"inputSchema": {
|
|
16599
|
+
"type": "object",
|
|
16600
|
+
"properties": {},
|
|
16601
|
+
"additionalProperties": false
|
|
16602
|
+
},
|
|
16603
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/members/me`)\n return await res.json()\n}",
|
|
16604
|
+
"scope": "read"
|
|
16605
|
+
},
|
|
16606
|
+
{
|
|
16607
|
+
"name": "get_member_boards",
|
|
16608
|
+
"description": "List boards for the current member.",
|
|
16609
|
+
"inputSchema": {
|
|
16610
|
+
"type": "object",
|
|
16611
|
+
"properties": {},
|
|
16612
|
+
"additionalProperties": false
|
|
16613
|
+
},
|
|
16614
|
+
"handlerCode": "async (input) => {\n const truncateDesc = (desc) => {\n if (typeof desc !== 'string' || !desc.trim())\n return null\n const oneLine = desc.replace(/\\s+/g, ' ').trim()\n const max = 200\n return oneLine.length <= max ? oneLine : `${oneLine.slice(0, max - 1)}\u2026`\n }\n\n const fields = [\n 'id',\n 'name',\n 'desc',\n 'url',\n 'shortUrl',\n 'shortLink',\n 'dateLastActivity',\n 'idOrganization',\n 'closed',\n 'starred',\n ].join(',')\n const res = await integration.fetch(`/members/me/boards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n if (!Array.isArray(raw))\n return { count: 0, boards: [], note: 'Unexpected response from Trello; expected a list of boards.' }\n\n const boards = raw.map((b) => ({\n id: b.id,\n name: b.name,\n url: b.url || b.shortUrl || (b.shortLink ? `https://trello.com/b/${b.shortLink}` : undefined),\n shortLink: b.shortLink,\n closed: !!b.closed,\n starred: !!b.starred,\n workspaceId: b.idOrganization || null,\n lastActivity: b.dateLastActivity || null,\n descriptionPreview: truncateDesc(b.desc),\n }))\n\n boards.sort((a, b) => {\n if (a.closed !== b.closed)\n return a.closed ? 1 : -1\n if (a.starred !== b.starred)\n return a.starred ? -1 : 1\n return String(a.name || '').localeCompare(String(b.name || ''), undefined, { sensitivity: 'base' })\n })\n\n const open = boards.filter((x) => !x.closed).length\n return {\n count: boards.length,\n openCount: open,\n closedCount: boards.length - open,\n note:\n 'Use `id` as `boardId` in other Trello tools (lists, cards, labels). `url` is the human-facing board link. Closed boards are archived.',\n boards,\n }\n}",
|
|
16615
|
+
"scope": "read"
|
|
16616
|
+
},
|
|
16617
|
+
{
|
|
16618
|
+
"name": "get_member_organizations",
|
|
16619
|
+
"description": "List organizations (workspaces) for the current member.",
|
|
16620
|
+
"inputSchema": {
|
|
16621
|
+
"type": "object",
|
|
16622
|
+
"properties": {},
|
|
16623
|
+
"additionalProperties": false
|
|
16624
|
+
},
|
|
16625
|
+
"handlerCode": "async (input) => {\n const fields = ['id', 'name', 'displayName', 'desc', 'url'].join(',')\n const res = await integration.fetch(`/members/me/organizations?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const organizations = Array.isArray(raw)\n ? raw.map(org => ({\n id: org.id,\n name: org.name || null,\n displayName: org.displayName || null,\n url: org.url || null,\n descriptionPreview: typeof org.desc === 'string' && org.desc.trim()\n ? (org.desc.trim().length <= 200 ? org.desc.trim() : `${org.desc.trim().slice(0, 199)}...`)\n : null,\n }))\n : []\n return {\n count: organizations.length,\n note: 'Use org id with get_organization for full organization details.',\n organizations,\n }\n}",
|
|
16626
|
+
"scope": "read"
|
|
16627
|
+
},
|
|
16628
|
+
{
|
|
16629
|
+
"name": "get_board",
|
|
16630
|
+
"description": "Fetch a board by id.",
|
|
16631
|
+
"inputSchema": {
|
|
16632
|
+
"type": "object",
|
|
16633
|
+
"properties": {
|
|
16634
|
+
"boardId": {
|
|
16635
|
+
"type": "string"
|
|
16636
|
+
}
|
|
16637
|
+
},
|
|
16638
|
+
"required": [
|
|
16639
|
+
"boardId"
|
|
16640
|
+
],
|
|
16641
|
+
"additionalProperties": false
|
|
16642
|
+
},
|
|
16643
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}`)\n return await res.json()\n}",
|
|
16644
|
+
"scope": "read"
|
|
16645
|
+
},
|
|
16646
|
+
{
|
|
16647
|
+
"name": "get_board_lists",
|
|
16648
|
+
"description": "List lists on a board.",
|
|
16649
|
+
"inputSchema": {
|
|
16650
|
+
"type": "object",
|
|
16651
|
+
"properties": {
|
|
16652
|
+
"boardId": {
|
|
16653
|
+
"type": "string"
|
|
16654
|
+
}
|
|
16655
|
+
},
|
|
16656
|
+
"required": [
|
|
16657
|
+
"boardId"
|
|
16658
|
+
],
|
|
16659
|
+
"additionalProperties": false
|
|
16660
|
+
},
|
|
16661
|
+
"handlerCode": "async (input) => {\n const fields = ['id', 'name', 'idBoard', 'closed', 'pos', 'softLimit'].join(',')\n const res = await integration.fetch(`/boards/${input.boardId}/lists?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const lists = Array.isArray(raw)\n ? raw.map(list => ({\n id: list.id,\n name: list.name,\n idBoard: list.idBoard || null,\n closed: !!list.closed,\n position: list.pos ?? null,\n softLimit: typeof list.softLimit === 'number' ? list.softLimit : null,\n }))\n : []\n return {\n boardId: input.boardId,\n count: lists.length,\n note: 'Use list id with get_list for full list details.',\n lists,\n }\n}",
|
|
16662
|
+
"scope": "read"
|
|
16663
|
+
},
|
|
16664
|
+
{
|
|
16665
|
+
"name": "get_board_cards",
|
|
16666
|
+
"description": "List cards on a board.",
|
|
16667
|
+
"inputSchema": {
|
|
16668
|
+
"type": "object",
|
|
16669
|
+
"properties": {
|
|
16670
|
+
"boardId": {
|
|
16671
|
+
"type": "string"
|
|
16672
|
+
}
|
|
16673
|
+
},
|
|
16674
|
+
"required": [
|
|
16675
|
+
"boardId"
|
|
16676
|
+
],
|
|
16677
|
+
"additionalProperties": false
|
|
16678
|
+
},
|
|
16679
|
+
"handlerCode": "async (input) => {\n const fields = [\n 'id',\n 'name',\n 'desc',\n 'idBoard',\n 'idList',\n 'shortLink',\n 'shortUrl',\n 'url',\n 'closed',\n 'due',\n 'dateLastActivity',\n 'labels',\n 'pos',\n ].join(',')\n const res = await integration.fetch(`/boards/${input.boardId}/cards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const cards = Array.isArray(raw)\n ? raw.map(card => ({\n id: card.id,\n name: card.name,\n idBoard: card.idBoard || null,\n idList: card.idList || null,\n url: card.url || card.shortUrl || (card.shortLink ? `https://trello.com/c/${card.shortLink}` : null),\n shortLink: card.shortLink || null,\n closed: !!card.closed,\n due: card.due || null,\n lastActivity: card.dateLastActivity || null,\n position: card.pos ?? null,\n labels: Array.isArray(card.labels)\n ? card.labels.map(label => ({ id: label.id, name: label.name || null, color: label.color || null }))\n : [],\n descriptionPreview: typeof card.desc === 'string' && card.desc.trim()\n ? (card.desc.trim().length <= 200 ? card.desc.trim() : `${card.desc.trim().slice(0, 199)}...`)\n : null,\n }))\n : []\n return {\n boardId: input.boardId,\n count: cards.length,\n note: 'Use card id with get_card for full card details.',\n cards,\n }\n}",
|
|
16680
|
+
"scope": "read"
|
|
16681
|
+
},
|
|
16682
|
+
{
|
|
16683
|
+
"name": "get_board_members",
|
|
16684
|
+
"description": "List members on a board.",
|
|
16685
|
+
"inputSchema": {
|
|
16686
|
+
"type": "object",
|
|
16687
|
+
"properties": {
|
|
16688
|
+
"boardId": {
|
|
16689
|
+
"type": "string"
|
|
16690
|
+
}
|
|
16691
|
+
},
|
|
16692
|
+
"required": [
|
|
16693
|
+
"boardId"
|
|
16694
|
+
],
|
|
16695
|
+
"additionalProperties": false
|
|
16696
|
+
},
|
|
16697
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/members`)\n return await res.json()\n}",
|
|
16698
|
+
"scope": "read"
|
|
16699
|
+
},
|
|
16700
|
+
{
|
|
16701
|
+
"name": "get_board_labels",
|
|
16702
|
+
"description": "List labels on a board.",
|
|
16703
|
+
"inputSchema": {
|
|
16704
|
+
"type": "object",
|
|
16705
|
+
"properties": {
|
|
16706
|
+
"boardId": {
|
|
16707
|
+
"type": "string"
|
|
16708
|
+
}
|
|
16709
|
+
},
|
|
16710
|
+
"required": [
|
|
16711
|
+
"boardId"
|
|
16712
|
+
],
|
|
16713
|
+
"additionalProperties": false
|
|
16714
|
+
},
|
|
16715
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/labels`)\n return await res.json()\n}",
|
|
16716
|
+
"scope": "read"
|
|
16717
|
+
},
|
|
16718
|
+
{
|
|
16719
|
+
"name": "get_board_custom_fields",
|
|
16720
|
+
"description": "List custom fields on a board.",
|
|
16721
|
+
"inputSchema": {
|
|
16722
|
+
"type": "object",
|
|
16723
|
+
"properties": {
|
|
16724
|
+
"boardId": {
|
|
16725
|
+
"type": "string"
|
|
16726
|
+
}
|
|
16727
|
+
},
|
|
16728
|
+
"required": [
|
|
16729
|
+
"boardId"
|
|
16730
|
+
],
|
|
16731
|
+
"additionalProperties": false
|
|
16732
|
+
},
|
|
16733
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/customFields`)\n return await res.json()\n}",
|
|
16734
|
+
"scope": "read"
|
|
16735
|
+
},
|
|
16736
|
+
{
|
|
16737
|
+
"name": "get_board_memberships",
|
|
16738
|
+
"description": "List memberships for a board.",
|
|
16739
|
+
"inputSchema": {
|
|
16740
|
+
"type": "object",
|
|
16741
|
+
"properties": {
|
|
16742
|
+
"boardId": {
|
|
16743
|
+
"type": "string"
|
|
16744
|
+
}
|
|
16745
|
+
},
|
|
16746
|
+
"required": [
|
|
16747
|
+
"boardId"
|
|
16748
|
+
],
|
|
16749
|
+
"additionalProperties": false
|
|
16750
|
+
},
|
|
16751
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/memberships`)\n return await res.json()\n}",
|
|
16752
|
+
"scope": "read"
|
|
16753
|
+
},
|
|
16754
|
+
{
|
|
16755
|
+
"name": "get_list",
|
|
16756
|
+
"description": "Fetch a list by id.",
|
|
16757
|
+
"inputSchema": {
|
|
16758
|
+
"type": "object",
|
|
16759
|
+
"properties": {
|
|
16760
|
+
"listId": {
|
|
16761
|
+
"type": "string"
|
|
16762
|
+
}
|
|
16763
|
+
},
|
|
16764
|
+
"required": [
|
|
16765
|
+
"listId"
|
|
16766
|
+
],
|
|
16767
|
+
"additionalProperties": false
|
|
16768
|
+
},
|
|
16769
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/lists/${input.listId}`)\n return await res.json()\n}",
|
|
16770
|
+
"scope": "read"
|
|
16771
|
+
},
|
|
16772
|
+
{
|
|
16773
|
+
"name": "get_list_cards",
|
|
16774
|
+
"description": "List cards in a list.",
|
|
16775
|
+
"inputSchema": {
|
|
16776
|
+
"type": "object",
|
|
16777
|
+
"properties": {
|
|
16778
|
+
"listId": {
|
|
16779
|
+
"type": "string"
|
|
16780
|
+
}
|
|
16781
|
+
},
|
|
16782
|
+
"required": [
|
|
16783
|
+
"listId"
|
|
16784
|
+
],
|
|
16785
|
+
"additionalProperties": false
|
|
16786
|
+
},
|
|
16787
|
+
"handlerCode": "async (input) => {\n const fields = [\n 'id',\n 'name',\n 'desc',\n 'idBoard',\n 'idList',\n 'shortLink',\n 'shortUrl',\n 'url',\n 'closed',\n 'due',\n 'dateLastActivity',\n 'labels',\n 'pos',\n ].join(',')\n const res = await integration.fetch(`/lists/${input.listId}/cards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const cards = Array.isArray(raw)\n ? raw.map(card => ({\n id: card.id,\n name: card.name,\n idBoard: card.idBoard || null,\n idList: card.idList || null,\n url: card.url || card.shortUrl || (card.shortLink ? `https://trello.com/c/${card.shortLink}` : null),\n shortLink: card.shortLink || null,\n closed: !!card.closed,\n due: card.due || null,\n lastActivity: card.dateLastActivity || null,\n position: card.pos ?? null,\n labels: Array.isArray(card.labels)\n ? card.labels.map(label => ({ id: label.id, name: label.name || null, color: label.color || null }))\n : [],\n descriptionPreview: typeof card.desc === 'string' && card.desc.trim()\n ? (card.desc.trim().length <= 200 ? card.desc.trim() : `${card.desc.trim().slice(0, 199)}...`)\n : null,\n }))\n : []\n return {\n listId: input.listId,\n count: cards.length,\n note: 'Use card id with get_card for full card details.',\n cards,\n }\n}",
|
|
16788
|
+
"scope": "read"
|
|
16789
|
+
},
|
|
16790
|
+
{
|
|
16791
|
+
"name": "get_card",
|
|
16792
|
+
"description": "Fetch a card by id.",
|
|
16793
|
+
"inputSchema": {
|
|
16794
|
+
"type": "object",
|
|
16795
|
+
"properties": {
|
|
16796
|
+
"cardId": {
|
|
16797
|
+
"type": "string"
|
|
16798
|
+
}
|
|
16799
|
+
},
|
|
16800
|
+
"required": [
|
|
16801
|
+
"cardId"
|
|
16802
|
+
],
|
|
16803
|
+
"additionalProperties": false
|
|
16804
|
+
},
|
|
16805
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}`)\n return await res.json()\n}",
|
|
16806
|
+
"scope": "read"
|
|
16807
|
+
},
|
|
16808
|
+
{
|
|
16809
|
+
"name": "get_card_members",
|
|
16810
|
+
"description": "List members assigned to a card.",
|
|
16811
|
+
"inputSchema": {
|
|
16812
|
+
"type": "object",
|
|
16813
|
+
"properties": {
|
|
16814
|
+
"cardId": {
|
|
16815
|
+
"type": "string"
|
|
16816
|
+
}
|
|
16817
|
+
},
|
|
16818
|
+
"required": [
|
|
16819
|
+
"cardId"
|
|
16820
|
+
],
|
|
16821
|
+
"additionalProperties": false
|
|
16822
|
+
},
|
|
16823
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/members`)\n return await res.json()\n}",
|
|
16824
|
+
"scope": "read"
|
|
16825
|
+
},
|
|
16826
|
+
{
|
|
16827
|
+
"name": "get_card_attachments",
|
|
16828
|
+
"description": "List attachments on a card.",
|
|
16829
|
+
"inputSchema": {
|
|
16830
|
+
"type": "object",
|
|
16831
|
+
"properties": {
|
|
16832
|
+
"cardId": {
|
|
16833
|
+
"type": "string"
|
|
16834
|
+
}
|
|
16835
|
+
},
|
|
16836
|
+
"required": [
|
|
16837
|
+
"cardId"
|
|
16838
|
+
],
|
|
16839
|
+
"additionalProperties": false
|
|
16840
|
+
},
|
|
16841
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/attachments`)\n return await res.json()\n}",
|
|
16842
|
+
"scope": "read"
|
|
16843
|
+
},
|
|
16844
|
+
{
|
|
16845
|
+
"name": "get_card_actions",
|
|
16846
|
+
"description": "List actions (activity) on a card.",
|
|
16847
|
+
"inputSchema": {
|
|
16848
|
+
"type": "object",
|
|
16849
|
+
"properties": {
|
|
16850
|
+
"cardId": {
|
|
16851
|
+
"type": "string"
|
|
16852
|
+
}
|
|
16853
|
+
},
|
|
16854
|
+
"required": [
|
|
16855
|
+
"cardId"
|
|
16856
|
+
],
|
|
16857
|
+
"additionalProperties": false
|
|
16858
|
+
},
|
|
16859
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/actions`)\n return await res.json()\n}",
|
|
16860
|
+
"scope": "read"
|
|
16861
|
+
},
|
|
16862
|
+
{
|
|
16863
|
+
"name": "get_card_checklists",
|
|
16864
|
+
"description": "List checklists on a card.",
|
|
16865
|
+
"inputSchema": {
|
|
16866
|
+
"type": "object",
|
|
16867
|
+
"properties": {
|
|
16868
|
+
"cardId": {
|
|
16869
|
+
"type": "string"
|
|
16870
|
+
}
|
|
16871
|
+
},
|
|
16872
|
+
"required": [
|
|
16873
|
+
"cardId"
|
|
16874
|
+
],
|
|
16875
|
+
"additionalProperties": false
|
|
16876
|
+
},
|
|
16877
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/checklists`)\n return await res.json()\n}",
|
|
16878
|
+
"scope": "read"
|
|
16879
|
+
},
|
|
16880
|
+
{
|
|
16881
|
+
"name": "get_card_custom_field_items",
|
|
16882
|
+
"description": "Get custom field items on a card.",
|
|
16883
|
+
"inputSchema": {
|
|
16884
|
+
"type": "object",
|
|
16885
|
+
"properties": {
|
|
16886
|
+
"cardId": {
|
|
16887
|
+
"type": "string"
|
|
16888
|
+
}
|
|
16889
|
+
},
|
|
16890
|
+
"required": [
|
|
16891
|
+
"cardId"
|
|
16892
|
+
],
|
|
16893
|
+
"additionalProperties": false
|
|
16894
|
+
},
|
|
16895
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/customFieldItems`)\n return await res.json()\n}",
|
|
16896
|
+
"scope": "read"
|
|
16897
|
+
},
|
|
16898
|
+
{
|
|
16899
|
+
"name": "get_organization",
|
|
16900
|
+
"description": "Fetch an organization (workspace) by id.",
|
|
16901
|
+
"inputSchema": {
|
|
16902
|
+
"type": "object",
|
|
16903
|
+
"properties": {
|
|
16904
|
+
"orgId": {
|
|
16905
|
+
"type": "string"
|
|
16906
|
+
}
|
|
16907
|
+
},
|
|
16908
|
+
"required": [
|
|
16909
|
+
"orgId"
|
|
16910
|
+
],
|
|
16911
|
+
"additionalProperties": false
|
|
16912
|
+
},
|
|
16913
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/organizations/${input.orgId}`)\n return await res.json()\n}",
|
|
16914
|
+
"scope": "read"
|
|
16915
|
+
},
|
|
16916
|
+
{
|
|
16917
|
+
"name": "get_organization_boards",
|
|
16918
|
+
"description": "List boards in an organization (workspace).",
|
|
16919
|
+
"inputSchema": {
|
|
16920
|
+
"type": "object",
|
|
16921
|
+
"properties": {
|
|
16922
|
+
"orgId": {
|
|
16923
|
+
"type": "string"
|
|
16924
|
+
}
|
|
16925
|
+
},
|
|
16926
|
+
"required": [
|
|
16927
|
+
"orgId"
|
|
16928
|
+
],
|
|
16929
|
+
"additionalProperties": false
|
|
16930
|
+
},
|
|
16931
|
+
"handlerCode": "async (input) => {\n const fields = [\n 'id',\n 'name',\n 'desc',\n 'url',\n 'shortUrl',\n 'shortLink',\n 'dateLastActivity',\n 'idOrganization',\n 'closed',\n 'starred',\n ].join(',')\n const res = await integration.fetch(`/organizations/${input.orgId}/boards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const boards = Array.isArray(raw)\n ? raw.map(b => ({\n id: b.id,\n name: b.name,\n url: b.url || b.shortUrl || (b.shortLink ? `https://trello.com/b/${b.shortLink}` : null),\n shortLink: b.shortLink || null,\n closed: !!b.closed,\n starred: !!b.starred,\n workspaceId: b.idOrganization || null,\n lastActivity: b.dateLastActivity || null,\n descriptionPreview: typeof b.desc === 'string' && b.desc.trim()\n ? (b.desc.trim().length <= 200 ? b.desc.trim() : `${b.desc.trim().slice(0, 199)}...`)\n : null,\n }))\n : []\n return {\n orgId: input.orgId,\n count: boards.length,\n note: 'Use board id with get_board for full board details.',\n boards,\n }\n}",
|
|
16932
|
+
"scope": "read"
|
|
16933
|
+
},
|
|
16934
|
+
{
|
|
16935
|
+
"name": "search",
|
|
16936
|
+
"description": "Search across boards, cards, and members.",
|
|
16937
|
+
"inputSchema": {
|
|
16938
|
+
"type": "object",
|
|
16939
|
+
"properties": {
|
|
16940
|
+
"query": {
|
|
16941
|
+
"type": "string"
|
|
16942
|
+
}
|
|
16943
|
+
},
|
|
16944
|
+
"required": [
|
|
16945
|
+
"query"
|
|
16946
|
+
],
|
|
16947
|
+
"additionalProperties": false
|
|
16948
|
+
},
|
|
16949
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ query: input.query })\n const res = await integration.fetch(`/search?${params.toString()}`)\n const data = await res.json()\n\n const boards = Array.isArray(data?.boards)\n ? data.boards.map(board => ({\n id: board.id,\n name: board.name,\n shortLink: board.shortLink || null,\n url: board.url || (board.shortLink ? `https://trello.com/b/${board.shortLink}` : null),\n closed: !!board.closed,\n }))\n : []\n\n const cards = Array.isArray(data?.cards)\n ? data.cards.map(card => ({\n id: card.id,\n name: card.name,\n idBoard: card.idBoard || null,\n idList: card.idList || null,\n shortLink: card.shortLink || null,\n url: card.url || card.shortUrl || (card.shortLink ? `https://trello.com/c/${card.shortLink}` : null),\n closed: !!card.closed,\n }))\n : []\n\n return {\n query: input.query,\n count: boards.length + cards.length,\n boardCount: boards.length,\n cardCount: cards.length,\n note: 'Use get_board with board id or get_card with card id for full details.',\n boards,\n cards,\n }\n}",
|
|
16950
|
+
"scope": "read"
|
|
16951
|
+
},
|
|
16952
|
+
{
|
|
16953
|
+
"name": "create_board",
|
|
16954
|
+
"description": "Create a new board.",
|
|
16955
|
+
"inputSchema": {
|
|
16956
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16957
|
+
"type": "object",
|
|
16958
|
+
"required": [
|
|
16959
|
+
"name"
|
|
16960
|
+
],
|
|
16961
|
+
"additionalProperties": false,
|
|
16962
|
+
"properties": {
|
|
16963
|
+
"name": {
|
|
16964
|
+
"type": "string"
|
|
16965
|
+
},
|
|
16966
|
+
"defaultLists": {
|
|
16967
|
+
"type": "boolean",
|
|
16968
|
+
"description": "Create the default lists on the board (default: true)"
|
|
16969
|
+
},
|
|
16970
|
+
"desc": {
|
|
16971
|
+
"type": "string"
|
|
16972
|
+
}
|
|
16973
|
+
}
|
|
16974
|
+
},
|
|
16975
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams()\n params.set('name', input.name)\n if (input.defaultLists !== undefined && input.defaultLists !== null)\n params.set('defaultLists', String(Boolean(input.defaultLists)))\n if (input.desc !== undefined && input.desc !== null)\n params.set('desc', String(input.desc))\n const res = await integration.fetch(`/boards?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
|
|
16976
|
+
"scope": "write"
|
|
16977
|
+
},
|
|
16978
|
+
{
|
|
16979
|
+
"name": "close_board",
|
|
16980
|
+
"description": "Close a board (set closed=true).",
|
|
16981
|
+
"inputSchema": {
|
|
16982
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16983
|
+
"type": "object",
|
|
16984
|
+
"required": [
|
|
16985
|
+
"boardId"
|
|
16986
|
+
],
|
|
16987
|
+
"additionalProperties": false,
|
|
16988
|
+
"properties": {
|
|
16989
|
+
"boardId": {
|
|
16990
|
+
"type": "string"
|
|
16991
|
+
}
|
|
16992
|
+
}
|
|
16993
|
+
},
|
|
16994
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ closed: 'true' })\n const res = await integration.fetch(`/boards/${encodeURIComponent(input.boardId)}?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
|
|
16995
|
+
"scope": "write"
|
|
16996
|
+
},
|
|
16997
|
+
{
|
|
16998
|
+
"name": "delete_board",
|
|
16999
|
+
"description": "Permanently delete a closed board.",
|
|
17000
|
+
"inputSchema": {
|
|
17001
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17002
|
+
"type": "object",
|
|
17003
|
+
"required": [
|
|
17004
|
+
"boardId"
|
|
17005
|
+
],
|
|
17006
|
+
"additionalProperties": false,
|
|
17007
|
+
"properties": {
|
|
17008
|
+
"boardId": {
|
|
17009
|
+
"type": "string"
|
|
17010
|
+
}
|
|
17011
|
+
}
|
|
17012
|
+
},
|
|
17013
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${encodeURIComponent(input.boardId)}`, { method: 'DELETE' })\n if (res.status === 204)\n return { success: true, status: 204 }\n // Trello sometimes returns JSON on delete failures.\n try {\n return await res.json()\n }\n catch {\n return { success: res.ok, status: res.status }\n }\n}",
|
|
17014
|
+
"scope": "write"
|
|
17015
|
+
},
|
|
17016
|
+
{
|
|
17017
|
+
"name": "create_card",
|
|
17018
|
+
"description": "Create a new card in a list.",
|
|
17019
|
+
"inputSchema": {
|
|
17020
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17021
|
+
"type": "object",
|
|
17022
|
+
"required": [
|
|
17023
|
+
"idList",
|
|
17024
|
+
"name"
|
|
17025
|
+
],
|
|
17026
|
+
"additionalProperties": false,
|
|
17027
|
+
"properties": {
|
|
17028
|
+
"idList": {
|
|
17029
|
+
"type": "string"
|
|
17030
|
+
},
|
|
17031
|
+
"name": {
|
|
17032
|
+
"type": "string"
|
|
17033
|
+
},
|
|
17034
|
+
"desc": {
|
|
17035
|
+
"type": "string"
|
|
17036
|
+
},
|
|
17037
|
+
"due": {
|
|
17038
|
+
"type": [
|
|
17039
|
+
"string",
|
|
17040
|
+
"null"
|
|
17041
|
+
],
|
|
17042
|
+
"description": "ISO 8601 due date"
|
|
17043
|
+
},
|
|
17044
|
+
"pos": {
|
|
17045
|
+
"type": [
|
|
17046
|
+
"string",
|
|
17047
|
+
"number"
|
|
17048
|
+
],
|
|
17049
|
+
"description": "Position (top,bottom or float)"
|
|
17050
|
+
}
|
|
17051
|
+
}
|
|
17052
|
+
},
|
|
17053
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams()\n params.set('idList', input.idList)\n params.set('name', input.name)\n if (input.desc !== undefined)\n params.set('desc', input.desc)\n if (input.due !== undefined && input.due !== null)\n params.set('due', input.due)\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/cards?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
|
|
17054
|
+
"scope": "write"
|
|
17055
|
+
},
|
|
17056
|
+
{
|
|
17057
|
+
"name": "update_card",
|
|
17058
|
+
"description": "Update a card's fields (name, desc, due, list, etc).",
|
|
17059
|
+
"inputSchema": {
|
|
17060
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17061
|
+
"type": "object",
|
|
17062
|
+
"required": [
|
|
17063
|
+
"cardId"
|
|
17064
|
+
],
|
|
17065
|
+
"additionalProperties": false,
|
|
17066
|
+
"properties": {
|
|
17067
|
+
"cardId": {
|
|
17068
|
+
"type": "string"
|
|
17069
|
+
},
|
|
17070
|
+
"name": {
|
|
17071
|
+
"type": [
|
|
17072
|
+
"string",
|
|
17073
|
+
"null"
|
|
17074
|
+
]
|
|
17075
|
+
},
|
|
17076
|
+
"desc": {
|
|
17077
|
+
"type": [
|
|
17078
|
+
"string",
|
|
17079
|
+
"null"
|
|
17080
|
+
]
|
|
17081
|
+
},
|
|
17082
|
+
"due": {
|
|
17083
|
+
"type": [
|
|
17084
|
+
"string",
|
|
17085
|
+
"null"
|
|
17086
|
+
]
|
|
17087
|
+
},
|
|
17088
|
+
"dueComplete": {
|
|
17089
|
+
"type": [
|
|
17090
|
+
"boolean",
|
|
17091
|
+
"null"
|
|
17092
|
+
]
|
|
17093
|
+
},
|
|
17094
|
+
"closed": {
|
|
17095
|
+
"type": [
|
|
17096
|
+
"boolean",
|
|
17097
|
+
"null"
|
|
17098
|
+
]
|
|
17099
|
+
},
|
|
17100
|
+
"idList": {
|
|
17101
|
+
"type": [
|
|
17102
|
+
"string",
|
|
17103
|
+
"null"
|
|
17104
|
+
]
|
|
17105
|
+
},
|
|
17106
|
+
"pos": {
|
|
17107
|
+
"type": [
|
|
17108
|
+
"string",
|
|
17109
|
+
"number",
|
|
17110
|
+
"null"
|
|
17111
|
+
]
|
|
17112
|
+
}
|
|
17113
|
+
}
|
|
17114
|
+
},
|
|
17115
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams()\n if (input.name !== undefined && input.name !== null)\n params.set('name', input.name)\n if (input.desc !== undefined && input.desc !== null)\n params.set('desc', input.desc)\n if (input.due !== undefined)\n params.set('due', input.due === null ? '' : input.due)\n if (input.dueComplete !== undefined && input.dueComplete !== null)\n params.set('dueComplete', String(input.dueComplete))\n if (input.closed !== undefined && input.closed !== null)\n params.set('closed', String(input.closed))\n if (input.idList !== undefined && input.idList !== null)\n params.set('idList', input.idList)\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
|
|
17116
|
+
"scope": "write"
|
|
17117
|
+
},
|
|
17118
|
+
{
|
|
17119
|
+
"name": "delete_card",
|
|
17120
|
+
"description": "Delete a card.",
|
|
17121
|
+
"inputSchema": {
|
|
17122
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17123
|
+
"type": "object",
|
|
17124
|
+
"required": [
|
|
17125
|
+
"cardId"
|
|
17126
|
+
],
|
|
17127
|
+
"additionalProperties": false,
|
|
17128
|
+
"properties": {
|
|
17129
|
+
"cardId": {
|
|
17130
|
+
"type": "string"
|
|
17131
|
+
}
|
|
17132
|
+
}
|
|
17133
|
+
},
|
|
17134
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}`, { method: 'DELETE' })\n try {\n return await res.json()\n }\n catch {\n return ''\n }\n}",
|
|
17135
|
+
"scope": "write"
|
|
17136
|
+
},
|
|
17137
|
+
{
|
|
17138
|
+
"name": "move_card_to_list",
|
|
17139
|
+
"description": "Move a card to another list.",
|
|
17140
|
+
"inputSchema": {
|
|
17141
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17142
|
+
"type": "object",
|
|
17143
|
+
"required": [
|
|
17144
|
+
"cardId",
|
|
17145
|
+
"listId"
|
|
17146
|
+
],
|
|
17147
|
+
"additionalProperties": false,
|
|
17148
|
+
"properties": {
|
|
17149
|
+
"cardId": {
|
|
17150
|
+
"type": "string"
|
|
17151
|
+
},
|
|
17152
|
+
"listId": {
|
|
17153
|
+
"type": "string"
|
|
17154
|
+
}
|
|
17155
|
+
}
|
|
17156
|
+
},
|
|
17157
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ value: input.listId })\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}/idList?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
|
|
17158
|
+
"scope": "write"
|
|
17159
|
+
},
|
|
17160
|
+
{
|
|
17161
|
+
"name": "add_member_to_card",
|
|
17162
|
+
"description": "Add a member to a card.",
|
|
17163
|
+
"inputSchema": {
|
|
17164
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17165
|
+
"type": "object",
|
|
17166
|
+
"required": [
|
|
17167
|
+
"cardId",
|
|
17168
|
+
"memberId"
|
|
17169
|
+
],
|
|
17170
|
+
"additionalProperties": false,
|
|
17171
|
+
"properties": {
|
|
17172
|
+
"cardId": {
|
|
17173
|
+
"type": "string"
|
|
17174
|
+
},
|
|
17175
|
+
"memberId": {
|
|
17176
|
+
"type": "string"
|
|
17177
|
+
}
|
|
17178
|
+
}
|
|
17179
|
+
},
|
|
17180
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ value: input.memberId })\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}/idMembers?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
|
|
17181
|
+
"scope": "write"
|
|
17182
|
+
},
|
|
17183
|
+
{
|
|
17184
|
+
"name": "remove_member_from_card",
|
|
17185
|
+
"description": "Remove a member from a card.",
|
|
17186
|
+
"inputSchema": {
|
|
17187
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17188
|
+
"type": "object",
|
|
17189
|
+
"required": [
|
|
17190
|
+
"cardId",
|
|
17191
|
+
"memberId"
|
|
17192
|
+
],
|
|
17193
|
+
"additionalProperties": false,
|
|
17194
|
+
"properties": {
|
|
17195
|
+
"cardId": {
|
|
17196
|
+
"type": "string"
|
|
17197
|
+
},
|
|
17198
|
+
"memberId": {
|
|
17199
|
+
"type": "string"
|
|
17200
|
+
}
|
|
17201
|
+
}
|
|
17202
|
+
},
|
|
17203
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}/idMembers/${encodeURIComponent(input.memberId)}`, { method: 'DELETE' })\n try {\n return await res.json()\n }\n catch {\n return ''\n }\n}",
|
|
17204
|
+
"scope": "write"
|
|
17205
|
+
},
|
|
17206
|
+
{
|
|
17207
|
+
"name": "add_checklist_to_card",
|
|
17208
|
+
"description": "Create a checklist on a card.",
|
|
17209
|
+
"inputSchema": {
|
|
17210
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17211
|
+
"type": "object",
|
|
17212
|
+
"required": [
|
|
17213
|
+
"cardId",
|
|
17214
|
+
"name"
|
|
17215
|
+
],
|
|
17216
|
+
"additionalProperties": false,
|
|
17217
|
+
"properties": {
|
|
17218
|
+
"cardId": {
|
|
17219
|
+
"type": "string"
|
|
17220
|
+
},
|
|
17221
|
+
"name": {
|
|
17222
|
+
"type": "string"
|
|
17223
|
+
}
|
|
17224
|
+
}
|
|
17225
|
+
},
|
|
17226
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ idCard: input.cardId, name: input.name })\n const res = await integration.fetch(`/checklists?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
|
|
17227
|
+
"scope": "write"
|
|
17228
|
+
},
|
|
17229
|
+
{
|
|
17230
|
+
"name": "create_list",
|
|
17231
|
+
"description": "Create a new list on a board.",
|
|
17232
|
+
"inputSchema": {
|
|
17233
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17234
|
+
"type": "object",
|
|
17235
|
+
"required": [
|
|
17236
|
+
"idBoard",
|
|
17237
|
+
"name"
|
|
17238
|
+
],
|
|
17239
|
+
"additionalProperties": false,
|
|
17240
|
+
"properties": {
|
|
17241
|
+
"idBoard": {
|
|
17242
|
+
"type": "string"
|
|
17243
|
+
},
|
|
17244
|
+
"name": {
|
|
17245
|
+
"type": "string"
|
|
17246
|
+
},
|
|
17247
|
+
"pos": {
|
|
17248
|
+
"type": [
|
|
17249
|
+
"string",
|
|
17250
|
+
"number"
|
|
17251
|
+
],
|
|
17252
|
+
"description": "Position (top,bottom or float)"
|
|
17253
|
+
}
|
|
17254
|
+
}
|
|
17255
|
+
},
|
|
17256
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ idBoard: input.idBoard, name: input.name })\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/lists?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
|
|
17257
|
+
"scope": "write"
|
|
17258
|
+
},
|
|
17259
|
+
{
|
|
17260
|
+
"name": "update_list",
|
|
17261
|
+
"description": "Update a list (name, pos, closed).",
|
|
17262
|
+
"inputSchema": {
|
|
17263
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17264
|
+
"type": "object",
|
|
17265
|
+
"required": [
|
|
17266
|
+
"listId"
|
|
17267
|
+
],
|
|
17268
|
+
"additionalProperties": false,
|
|
17269
|
+
"properties": {
|
|
17270
|
+
"listId": {
|
|
17271
|
+
"type": "string"
|
|
17272
|
+
},
|
|
17273
|
+
"name": {
|
|
17274
|
+
"type": [
|
|
17275
|
+
"string",
|
|
17276
|
+
"null"
|
|
17277
|
+
]
|
|
17278
|
+
},
|
|
17279
|
+
"closed": {
|
|
17280
|
+
"type": [
|
|
17281
|
+
"boolean",
|
|
17282
|
+
"null"
|
|
17283
|
+
]
|
|
17284
|
+
},
|
|
17285
|
+
"pos": {
|
|
17286
|
+
"type": [
|
|
17287
|
+
"string",
|
|
17288
|
+
"number",
|
|
17289
|
+
"null"
|
|
17290
|
+
]
|
|
17291
|
+
}
|
|
17292
|
+
}
|
|
17293
|
+
},
|
|
17294
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams()\n if (input.name !== undefined && input.name !== null)\n params.set('name', input.name)\n if (input.closed !== undefined && input.closed !== null)\n params.set('closed', String(input.closed))\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/lists/${encodeURIComponent(input.listId)}?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
|
|
17295
|
+
"scope": "write"
|
|
17296
|
+
},
|
|
17297
|
+
{
|
|
17298
|
+
"name": "archive_list",
|
|
17299
|
+
"description": "Archive a list (set closed=true).",
|
|
17300
|
+
"inputSchema": {
|
|
17301
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
17302
|
+
"type": "object",
|
|
17303
|
+
"required": [
|
|
17304
|
+
"listId"
|
|
17305
|
+
],
|
|
17306
|
+
"additionalProperties": false,
|
|
17307
|
+
"properties": {
|
|
17308
|
+
"listId": {
|
|
17309
|
+
"type": "string"
|
|
17310
|
+
}
|
|
17311
|
+
}
|
|
17312
|
+
},
|
|
17313
|
+
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ value: 'true' })\n const res = await integration.fetch(`/lists/${encodeURIComponent(input.listId)}/closed?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
|
|
17314
|
+
"scope": "write"
|
|
17315
|
+
}
|
|
17316
|
+
],
|
|
17317
|
+
"variantOwnerType": null
|
|
17318
|
+
},
|
|
17319
|
+
"trello-board": {
|
|
17320
|
+
"manifest": {
|
|
17321
|
+
"name": "Trello",
|
|
17322
|
+
"version": "0.1.0",
|
|
17323
|
+
"baseUrl": "https://api.trello.com/1",
|
|
17324
|
+
"variantLabel": "Single board",
|
|
17325
|
+
"variantConfig": [
|
|
17326
|
+
{
|
|
17327
|
+
"key": "board",
|
|
17328
|
+
"label": "Board",
|
|
17329
|
+
"selectionMode": "single",
|
|
17330
|
+
"listHandler": "async (config) => {\n const fields = ['id', 'name', 'closed', 'starred'].join(',')\n const res = await integration.fetch(`/members/me/boards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n if (!Array.isArray(raw))\n return []\n\n return raw\n .map(board => ({\n id: String(board.id ?? ''),\n name: String(board.name ?? ''),\n closed: !!board.closed,\n starred: !!board.starred,\n }))\n .filter(board => board.id && board.name)\n .sort((a, b) => {\n if (a.closed !== b.closed)\n return a.closed ? 1 : -1\n if (a.starred !== b.starred)\n return a.starred ? -1 : 1\n return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })\n })\n .map(({ id, name }) => ({ id, name }))\n}"
|
|
17331
|
+
}
|
|
17332
|
+
],
|
|
17333
|
+
"tools": [
|
|
17334
|
+
{
|
|
17335
|
+
"name": "get_board",
|
|
17336
|
+
"description": "Fetch the connected board.",
|
|
17337
|
+
"inputSchema": "../../schemas/id_board.json",
|
|
17338
|
+
"handler": "../../handlers/get_board.js",
|
|
17339
|
+
"scope": "read",
|
|
17340
|
+
"injectFromConfig": {
|
|
17341
|
+
"boardId": "boardId"
|
|
17342
|
+
}
|
|
17343
|
+
},
|
|
17344
|
+
{
|
|
17345
|
+
"name": "get_lists",
|
|
17346
|
+
"description": "List lists on the connected board.",
|
|
17347
|
+
"inputSchema": "../../schemas/id_board.json",
|
|
17348
|
+
"handler": "../../handlers/get_board_lists.js",
|
|
17349
|
+
"scope": "read",
|
|
17350
|
+
"injectFromConfig": {
|
|
17351
|
+
"boardId": "boardId"
|
|
17352
|
+
}
|
|
17353
|
+
},
|
|
17354
|
+
{
|
|
17355
|
+
"name": "get_cards",
|
|
17356
|
+
"description": "List cards on the connected board.",
|
|
17357
|
+
"inputSchema": "../../schemas/id_board.json",
|
|
17358
|
+
"handler": "../../handlers/get_board_cards.js",
|
|
17359
|
+
"scope": "read",
|
|
17360
|
+
"injectFromConfig": {
|
|
17361
|
+
"boardId": "boardId"
|
|
17362
|
+
}
|
|
17363
|
+
},
|
|
17364
|
+
{
|
|
17365
|
+
"name": "get_members",
|
|
17366
|
+
"description": "List members on the connected board.",
|
|
17367
|
+
"inputSchema": "../../schemas/id_board.json",
|
|
17368
|
+
"handler": "../../handlers/get_board_members.js",
|
|
17369
|
+
"scope": "read",
|
|
17370
|
+
"injectFromConfig": {
|
|
17371
|
+
"boardId": "boardId"
|
|
17372
|
+
}
|
|
17373
|
+
},
|
|
17374
|
+
{
|
|
17375
|
+
"name": "get_labels",
|
|
17376
|
+
"description": "List labels on the connected board.",
|
|
17377
|
+
"inputSchema": "../../schemas/id_board.json",
|
|
17378
|
+
"handler": "../../handlers/get_board_labels.js",
|
|
17379
|
+
"scope": "read",
|
|
17380
|
+
"injectFromConfig": {
|
|
17381
|
+
"boardId": "boardId"
|
|
17382
|
+
}
|
|
17383
|
+
},
|
|
17384
|
+
{
|
|
17385
|
+
"name": "get_custom_fields",
|
|
17386
|
+
"description": "List custom fields on the connected board.",
|
|
17387
|
+
"inputSchema": "../../schemas/id_board.json",
|
|
17388
|
+
"handler": "../../handlers/get_board_custom_fields.js",
|
|
17389
|
+
"scope": "read",
|
|
17390
|
+
"injectFromConfig": {
|
|
17391
|
+
"boardId": "boardId"
|
|
17392
|
+
}
|
|
17393
|
+
},
|
|
17394
|
+
{
|
|
17395
|
+
"name": "get_memberships",
|
|
17396
|
+
"description": "List memberships for the connected board.",
|
|
17397
|
+
"inputSchema": "../../schemas/id_board.json",
|
|
17398
|
+
"handler": "../../handlers/get_board_memberships.js",
|
|
17399
|
+
"scope": "read",
|
|
17400
|
+
"injectFromConfig": {
|
|
17401
|
+
"boardId": "boardId"
|
|
17402
|
+
}
|
|
17403
|
+
},
|
|
17404
|
+
{
|
|
17405
|
+
"name": "get_list",
|
|
17406
|
+
"description": "Fetch a list by id.",
|
|
17407
|
+
"inputSchema": "../../schemas/id_list.json",
|
|
17408
|
+
"handler": "../../handlers/get_list.js",
|
|
17409
|
+
"scope": "read"
|
|
17410
|
+
},
|
|
17411
|
+
{
|
|
17412
|
+
"name": "get_list_cards",
|
|
17413
|
+
"description": "List cards in a list.",
|
|
17414
|
+
"inputSchema": "../../schemas/id_list.json",
|
|
17415
|
+
"handler": "../../handlers/get_list_cards.js",
|
|
17416
|
+
"scope": "read"
|
|
17417
|
+
},
|
|
17418
|
+
{
|
|
17419
|
+
"name": "get_card",
|
|
17420
|
+
"description": "Fetch a card by id.",
|
|
17421
|
+
"inputSchema": "../../schemas/id_card.json",
|
|
17422
|
+
"handler": "../../handlers/get_card.js",
|
|
17423
|
+
"scope": "read"
|
|
17424
|
+
},
|
|
17425
|
+
{
|
|
17426
|
+
"name": "get_card_members",
|
|
17427
|
+
"description": "List members assigned to a card.",
|
|
17428
|
+
"inputSchema": "../../schemas/id_card.json",
|
|
17429
|
+
"handler": "../../handlers/get_card_members.js",
|
|
17430
|
+
"scope": "read"
|
|
17431
|
+
},
|
|
17432
|
+
{
|
|
17433
|
+
"name": "get_card_attachments",
|
|
17434
|
+
"description": "List attachments on a card.",
|
|
17435
|
+
"inputSchema": "../../schemas/id_card.json",
|
|
17436
|
+
"handler": "../../handlers/get_card_attachments.js",
|
|
17437
|
+
"scope": "read"
|
|
17438
|
+
},
|
|
17439
|
+
{
|
|
17440
|
+
"name": "get_card_actions",
|
|
17441
|
+
"description": "List actions (activity) on a card.",
|
|
17442
|
+
"inputSchema": "../../schemas/id_card.json",
|
|
17443
|
+
"handler": "../../handlers/get_card_actions.js",
|
|
17444
|
+
"scope": "read"
|
|
17445
|
+
},
|
|
17446
|
+
{
|
|
17447
|
+
"name": "get_card_checklists",
|
|
17448
|
+
"description": "List checklists on a card.",
|
|
17449
|
+
"inputSchema": "../../schemas/id_card.json",
|
|
17450
|
+
"handler": "../../handlers/get_card_checklists.js",
|
|
17451
|
+
"scope": "read"
|
|
17452
|
+
},
|
|
17453
|
+
{
|
|
17454
|
+
"name": "get_card_custom_field_items",
|
|
17455
|
+
"description": "Get custom field items on a card.",
|
|
17456
|
+
"inputSchema": "../../schemas/id_card.json",
|
|
17457
|
+
"handler": "../../handlers/get_card_custom_field_items.js",
|
|
17458
|
+
"scope": "read"
|
|
17459
|
+
},
|
|
17460
|
+
{
|
|
17461
|
+
"name": "create_card",
|
|
17462
|
+
"description": "Create a new card in a list.",
|
|
17463
|
+
"inputSchema": "../../schemas/create_card.json",
|
|
17464
|
+
"handler": "../../handlers/create_card.js",
|
|
17465
|
+
"scope": "write"
|
|
17466
|
+
},
|
|
17467
|
+
{
|
|
17468
|
+
"name": "update_card",
|
|
17469
|
+
"description": "Update a card's fields (name, desc, due, list, etc).",
|
|
17470
|
+
"inputSchema": "../../schemas/update_card.json",
|
|
17471
|
+
"handler": "../../handlers/update_card.js",
|
|
17472
|
+
"scope": "write"
|
|
17473
|
+
},
|
|
17474
|
+
{
|
|
17475
|
+
"name": "delete_card",
|
|
17476
|
+
"description": "Delete a card.",
|
|
17477
|
+
"inputSchema": "../../schemas/delete_card.json",
|
|
17478
|
+
"handler": "../../handlers/delete_card.js",
|
|
17479
|
+
"scope": "write"
|
|
17480
|
+
},
|
|
17481
|
+
{
|
|
17482
|
+
"name": "move_card_to_list",
|
|
17483
|
+
"description": "Move a card to another list.",
|
|
17484
|
+
"inputSchema": "../../schemas/move_card_to_list.json",
|
|
17485
|
+
"handler": "../../handlers/move_card_to_list.js",
|
|
17486
|
+
"scope": "write"
|
|
16145
17487
|
},
|
|
16146
|
-
|
|
16147
|
-
|
|
16148
|
-
|
|
16149
|
-
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
"inputSchema": {
|
|
16153
|
-
"type": "object",
|
|
16154
|
-
"properties": {},
|
|
16155
|
-
"additionalProperties": false
|
|
17488
|
+
{
|
|
17489
|
+
"name": "add_member_to_card",
|
|
17490
|
+
"description": "Add a member to a card.",
|
|
17491
|
+
"inputSchema": "../../schemas/add_member_to_card.json",
|
|
17492
|
+
"handler": "../../handlers/add_member_to_card.js",
|
|
17493
|
+
"scope": "write"
|
|
16156
17494
|
},
|
|
16157
|
-
|
|
16158
|
-
|
|
17495
|
+
{
|
|
17496
|
+
"name": "remove_member_from_card",
|
|
17497
|
+
"description": "Remove a member from a card.",
|
|
17498
|
+
"inputSchema": "../../schemas/remove_member_from_card.json",
|
|
17499
|
+
"handler": "../../handlers/remove_member_from_card.js",
|
|
17500
|
+
"scope": "write"
|
|
17501
|
+
},
|
|
17502
|
+
{
|
|
17503
|
+
"name": "add_checklist_to_card",
|
|
17504
|
+
"description": "Create a checklist on a card.",
|
|
17505
|
+
"inputSchema": "../../schemas/add_checklist_to_card.json",
|
|
17506
|
+
"handler": "../../handlers/add_checklist_to_card.js",
|
|
17507
|
+
"scope": "write"
|
|
17508
|
+
},
|
|
17509
|
+
{
|
|
17510
|
+
"name": "create_list",
|
|
17511
|
+
"description": "Create a new list on the connected board.",
|
|
17512
|
+
"inputSchema": "../../schemas/create_list.json",
|
|
17513
|
+
"handler": "../../handlers/create_list.js",
|
|
17514
|
+
"scope": "write",
|
|
17515
|
+
"injectFromConfig": {
|
|
17516
|
+
"idBoard": "boardId"
|
|
17517
|
+
}
|
|
17518
|
+
},
|
|
17519
|
+
{
|
|
17520
|
+
"name": "update_list",
|
|
17521
|
+
"description": "Update a list (name, pos, closed).",
|
|
17522
|
+
"inputSchema": "../../schemas/update_list.json",
|
|
17523
|
+
"handler": "../../handlers/update_list.js",
|
|
17524
|
+
"scope": "write"
|
|
17525
|
+
},
|
|
17526
|
+
{
|
|
17527
|
+
"name": "archive_list",
|
|
17528
|
+
"description": "Archive a list (set closed=true).",
|
|
17529
|
+
"inputSchema": "../../schemas/archive_list.json",
|
|
17530
|
+
"handler": "../../handlers/archive_list.js",
|
|
17531
|
+
"scope": "write"
|
|
17532
|
+
}
|
|
17533
|
+
]
|
|
17534
|
+
},
|
|
17535
|
+
"prompt": null,
|
|
17536
|
+
"variants": {
|
|
17537
|
+
"variants": {
|
|
17538
|
+
"api_key_token": {
|
|
17539
|
+
"label": "API Key + Token",
|
|
17540
|
+
"schema": {
|
|
17541
|
+
"type": "object",
|
|
17542
|
+
"properties": {
|
|
17543
|
+
"apiKey": {
|
|
17544
|
+
"type": "string",
|
|
17545
|
+
"title": "API Key",
|
|
17546
|
+
"description": "Your Trello API key from https://trello.com/power-ups/admin"
|
|
17547
|
+
},
|
|
17548
|
+
"apiToken": {
|
|
17549
|
+
"type": "string",
|
|
17550
|
+
"title": "API Token",
|
|
17551
|
+
"description": `Your Trello API token ("token" param). Generate one via Trello's authorize flow.`
|
|
17552
|
+
}
|
|
17553
|
+
},
|
|
17554
|
+
"required": [
|
|
17555
|
+
"apiKey",
|
|
17556
|
+
"apiToken"
|
|
17557
|
+
],
|
|
17558
|
+
"additionalProperties": false
|
|
17559
|
+
},
|
|
17560
|
+
"injection": {
|
|
17561
|
+
"query": {
|
|
17562
|
+
"key": "{{apiKey}}",
|
|
17563
|
+
"token": "{{apiToken}}"
|
|
17564
|
+
}
|
|
17565
|
+
},
|
|
17566
|
+
"healthCheck": {
|
|
17567
|
+
"path": "/members/me"
|
|
17568
|
+
}
|
|
17569
|
+
}
|
|
16159
17570
|
},
|
|
17571
|
+
"default": "api_key_token"
|
|
17572
|
+
},
|
|
17573
|
+
"hint": "1. Go to `https://trello.com/power-ups/admin`\n2. Create a new app\n3. Navigate to **API Key** and copy your API key\n4. Click **Generate a Token** and copy the token value",
|
|
17574
|
+
"hintsByVariant": {},
|
|
17575
|
+
"tools": [
|
|
16160
17576
|
{
|
|
16161
17577
|
"name": "get_board",
|
|
16162
|
-
"description": "Fetch
|
|
17578
|
+
"description": "Fetch the connected board.",
|
|
16163
17579
|
"inputSchema": {
|
|
16164
17580
|
"type": "object",
|
|
16165
17581
|
"properties": {
|
|
@@ -16173,11 +17589,14 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16173
17589
|
"additionalProperties": false
|
|
16174
17590
|
},
|
|
16175
17591
|
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}`)\n return await res.json()\n}",
|
|
16176
|
-
"scope": "read"
|
|
17592
|
+
"scope": "read",
|
|
17593
|
+
"injectFromConfig": {
|
|
17594
|
+
"boardId": "boardId"
|
|
17595
|
+
}
|
|
16177
17596
|
},
|
|
16178
17597
|
{
|
|
16179
|
-
"name": "
|
|
16180
|
-
"description": "List lists on
|
|
17598
|
+
"name": "get_lists",
|
|
17599
|
+
"description": "List lists on the connected board.",
|
|
16181
17600
|
"inputSchema": {
|
|
16182
17601
|
"type": "object",
|
|
16183
17602
|
"properties": {
|
|
@@ -16191,11 +17610,14 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16191
17610
|
"additionalProperties": false
|
|
16192
17611
|
},
|
|
16193
17612
|
"handlerCode": "async (input) => {\n const fields = ['id', 'name', 'idBoard', 'closed', 'pos', 'softLimit'].join(',')\n const res = await integration.fetch(`/boards/${input.boardId}/lists?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const lists = Array.isArray(raw)\n ? raw.map(list => ({\n id: list.id,\n name: list.name,\n idBoard: list.idBoard || null,\n closed: !!list.closed,\n position: list.pos ?? null,\n softLimit: typeof list.softLimit === 'number' ? list.softLimit : null,\n }))\n : []\n return {\n boardId: input.boardId,\n count: lists.length,\n note: 'Use list id with get_list for full list details.',\n lists,\n }\n}",
|
|
16194
|
-
"scope": "read"
|
|
17613
|
+
"scope": "read",
|
|
17614
|
+
"injectFromConfig": {
|
|
17615
|
+
"boardId": "boardId"
|
|
17616
|
+
}
|
|
16195
17617
|
},
|
|
16196
17618
|
{
|
|
16197
|
-
"name": "
|
|
16198
|
-
"description": "List cards on
|
|
17619
|
+
"name": "get_cards",
|
|
17620
|
+
"description": "List cards on the connected board.",
|
|
16199
17621
|
"inputSchema": {
|
|
16200
17622
|
"type": "object",
|
|
16201
17623
|
"properties": {
|
|
@@ -16209,11 +17631,14 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16209
17631
|
"additionalProperties": false
|
|
16210
17632
|
},
|
|
16211
17633
|
"handlerCode": "async (input) => {\n const fields = [\n 'id',\n 'name',\n 'desc',\n 'idBoard',\n 'idList',\n 'shortLink',\n 'shortUrl',\n 'url',\n 'closed',\n 'due',\n 'dateLastActivity',\n 'labels',\n 'pos',\n ].join(',')\n const res = await integration.fetch(`/boards/${input.boardId}/cards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const cards = Array.isArray(raw)\n ? raw.map(card => ({\n id: card.id,\n name: card.name,\n idBoard: card.idBoard || null,\n idList: card.idList || null,\n url: card.url || card.shortUrl || (card.shortLink ? `https://trello.com/c/${card.shortLink}` : null),\n shortLink: card.shortLink || null,\n closed: !!card.closed,\n due: card.due || null,\n lastActivity: card.dateLastActivity || null,\n position: card.pos ?? null,\n labels: Array.isArray(card.labels)\n ? card.labels.map(label => ({ id: label.id, name: label.name || null, color: label.color || null }))\n : [],\n descriptionPreview: typeof card.desc === 'string' && card.desc.trim()\n ? (card.desc.trim().length <= 200 ? card.desc.trim() : `${card.desc.trim().slice(0, 199)}...`)\n : null,\n }))\n : []\n return {\n boardId: input.boardId,\n count: cards.length,\n note: 'Use card id with get_card for full card details.',\n cards,\n }\n}",
|
|
16212
|
-
"scope": "read"
|
|
17634
|
+
"scope": "read",
|
|
17635
|
+
"injectFromConfig": {
|
|
17636
|
+
"boardId": "boardId"
|
|
17637
|
+
}
|
|
16213
17638
|
},
|
|
16214
17639
|
{
|
|
16215
|
-
"name": "
|
|
16216
|
-
"description": "List members on
|
|
17640
|
+
"name": "get_members",
|
|
17641
|
+
"description": "List members on the connected board.",
|
|
16217
17642
|
"inputSchema": {
|
|
16218
17643
|
"type": "object",
|
|
16219
17644
|
"properties": {
|
|
@@ -16227,11 +17652,14 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16227
17652
|
"additionalProperties": false
|
|
16228
17653
|
},
|
|
16229
17654
|
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/members`)\n return await res.json()\n}",
|
|
16230
|
-
"scope": "read"
|
|
17655
|
+
"scope": "read",
|
|
17656
|
+
"injectFromConfig": {
|
|
17657
|
+
"boardId": "boardId"
|
|
17658
|
+
}
|
|
16231
17659
|
},
|
|
16232
17660
|
{
|
|
16233
|
-
"name": "
|
|
16234
|
-
"description": "List labels on
|
|
17661
|
+
"name": "get_labels",
|
|
17662
|
+
"description": "List labels on the connected board.",
|
|
16235
17663
|
"inputSchema": {
|
|
16236
17664
|
"type": "object",
|
|
16237
17665
|
"properties": {
|
|
@@ -16245,11 +17673,14 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16245
17673
|
"additionalProperties": false
|
|
16246
17674
|
},
|
|
16247
17675
|
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/labels`)\n return await res.json()\n}",
|
|
16248
|
-
"scope": "read"
|
|
17676
|
+
"scope": "read",
|
|
17677
|
+
"injectFromConfig": {
|
|
17678
|
+
"boardId": "boardId"
|
|
17679
|
+
}
|
|
16249
17680
|
},
|
|
16250
17681
|
{
|
|
16251
|
-
"name": "
|
|
16252
|
-
"description": "List custom fields on
|
|
17682
|
+
"name": "get_custom_fields",
|
|
17683
|
+
"description": "List custom fields on the connected board.",
|
|
16253
17684
|
"inputSchema": {
|
|
16254
17685
|
"type": "object",
|
|
16255
17686
|
"properties": {
|
|
@@ -16263,11 +17694,14 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16263
17694
|
"additionalProperties": false
|
|
16264
17695
|
},
|
|
16265
17696
|
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/customFields`)\n return await res.json()\n}",
|
|
16266
|
-
"scope": "read"
|
|
17697
|
+
"scope": "read",
|
|
17698
|
+
"injectFromConfig": {
|
|
17699
|
+
"boardId": "boardId"
|
|
17700
|
+
}
|
|
16267
17701
|
},
|
|
16268
17702
|
{
|
|
16269
|
-
"name": "
|
|
16270
|
-
"description": "List memberships for
|
|
17703
|
+
"name": "get_memberships",
|
|
17704
|
+
"description": "List memberships for the connected board.",
|
|
16271
17705
|
"inputSchema": {
|
|
16272
17706
|
"type": "object",
|
|
16273
17707
|
"properties": {
|
|
@@ -16281,7 +17715,10 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16281
17715
|
"additionalProperties": false
|
|
16282
17716
|
},
|
|
16283
17717
|
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/memberships`)\n return await res.json()\n}",
|
|
16284
|
-
"scope": "read"
|
|
17718
|
+
"scope": "read",
|
|
17719
|
+
"injectFromConfig": {
|
|
17720
|
+
"boardId": "boardId"
|
|
17721
|
+
}
|
|
16285
17722
|
},
|
|
16286
17723
|
{
|
|
16287
17724
|
"name": "get_list",
|
|
@@ -16415,135 +17852,17 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16415
17852
|
"inputSchema": {
|
|
16416
17853
|
"type": "object",
|
|
16417
17854
|
"properties": {
|
|
16418
|
-
"cardId": {
|
|
16419
|
-
"type": "string"
|
|
16420
|
-
}
|
|
16421
|
-
},
|
|
16422
|
-
"required": [
|
|
16423
|
-
"cardId"
|
|
16424
|
-
],
|
|
16425
|
-
"additionalProperties": false
|
|
16426
|
-
},
|
|
16427
|
-
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/customFieldItems`)\n return await res.json()\n}",
|
|
16428
|
-
"scope": "read"
|
|
16429
|
-
},
|
|
16430
|
-
{
|
|
16431
|
-
"name": "get_organization",
|
|
16432
|
-
"description": "Fetch an organization (workspace) by id.",
|
|
16433
|
-
"inputSchema": {
|
|
16434
|
-
"type": "object",
|
|
16435
|
-
"properties": {
|
|
16436
|
-
"orgId": {
|
|
16437
|
-
"type": "string"
|
|
16438
|
-
}
|
|
16439
|
-
},
|
|
16440
|
-
"required": [
|
|
16441
|
-
"orgId"
|
|
16442
|
-
],
|
|
16443
|
-
"additionalProperties": false
|
|
16444
|
-
},
|
|
16445
|
-
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/organizations/${input.orgId}`)\n return await res.json()\n}",
|
|
16446
|
-
"scope": "read"
|
|
16447
|
-
},
|
|
16448
|
-
{
|
|
16449
|
-
"name": "get_organization_boards",
|
|
16450
|
-
"description": "List boards in an organization (workspace).",
|
|
16451
|
-
"inputSchema": {
|
|
16452
|
-
"type": "object",
|
|
16453
|
-
"properties": {
|
|
16454
|
-
"orgId": {
|
|
16455
|
-
"type": "string"
|
|
16456
|
-
}
|
|
16457
|
-
},
|
|
16458
|
-
"required": [
|
|
16459
|
-
"orgId"
|
|
16460
|
-
],
|
|
16461
|
-
"additionalProperties": false
|
|
16462
|
-
},
|
|
16463
|
-
"handlerCode": "async (input) => {\n const fields = [\n 'id',\n 'name',\n 'desc',\n 'url',\n 'shortUrl',\n 'shortLink',\n 'dateLastActivity',\n 'idOrganization',\n 'closed',\n 'starred',\n ].join(',')\n const res = await integration.fetch(`/organizations/${input.orgId}/boards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const boards = Array.isArray(raw)\n ? raw.map(b => ({\n id: b.id,\n name: b.name,\n url: b.url || b.shortUrl || (b.shortLink ? `https://trello.com/b/${b.shortLink}` : null),\n shortLink: b.shortLink || null,\n closed: !!b.closed,\n starred: !!b.starred,\n workspaceId: b.idOrganization || null,\n lastActivity: b.dateLastActivity || null,\n descriptionPreview: typeof b.desc === 'string' && b.desc.trim()\n ? (b.desc.trim().length <= 200 ? b.desc.trim() : `${b.desc.trim().slice(0, 199)}...`)\n : null,\n }))\n : []\n return {\n orgId: input.orgId,\n count: boards.length,\n note: 'Use board id with get_board for full board details.',\n boards,\n }\n}",
|
|
16464
|
-
"scope": "read"
|
|
16465
|
-
},
|
|
16466
|
-
{
|
|
16467
|
-
"name": "search",
|
|
16468
|
-
"description": "Search across boards, cards, and members.",
|
|
16469
|
-
"inputSchema": {
|
|
16470
|
-
"type": "object",
|
|
16471
|
-
"properties": {
|
|
16472
|
-
"query": {
|
|
16473
|
-
"type": "string"
|
|
16474
|
-
}
|
|
16475
|
-
},
|
|
16476
|
-
"required": [
|
|
16477
|
-
"query"
|
|
16478
|
-
],
|
|
16479
|
-
"additionalProperties": false
|
|
16480
|
-
},
|
|
16481
|
-
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ query: input.query })\n const res = await integration.fetch(`/search?${params.toString()}`)\n const data = await res.json()\n\n const boards = Array.isArray(data?.boards)\n ? data.boards.map(board => ({\n id: board.id,\n name: board.name,\n shortLink: board.shortLink || null,\n url: board.url || (board.shortLink ? `https://trello.com/b/${board.shortLink}` : null),\n closed: !!board.closed,\n }))\n : []\n\n const cards = Array.isArray(data?.cards)\n ? data.cards.map(card => ({\n id: card.id,\n name: card.name,\n idBoard: card.idBoard || null,\n idList: card.idList || null,\n shortLink: card.shortLink || null,\n url: card.url || card.shortUrl || (card.shortLink ? `https://trello.com/c/${card.shortLink}` : null),\n closed: !!card.closed,\n }))\n : []\n\n return {\n query: input.query,\n count: boards.length + cards.length,\n boardCount: boards.length,\n cardCount: cards.length,\n note: 'Use get_board with board id or get_card with card id for full details.',\n boards,\n cards,\n }\n}",
|
|
16482
|
-
"scope": "read"
|
|
16483
|
-
},
|
|
16484
|
-
{
|
|
16485
|
-
"name": "create_board",
|
|
16486
|
-
"description": "Create a new board.",
|
|
16487
|
-
"inputSchema": {
|
|
16488
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16489
|
-
"type": "object",
|
|
16490
|
-
"required": [
|
|
16491
|
-
"name"
|
|
16492
|
-
],
|
|
16493
|
-
"additionalProperties": false,
|
|
16494
|
-
"properties": {
|
|
16495
|
-
"name": {
|
|
16496
|
-
"type": "string"
|
|
16497
|
-
},
|
|
16498
|
-
"defaultLists": {
|
|
16499
|
-
"type": "boolean",
|
|
16500
|
-
"description": "Create the default lists on the board (default: true)"
|
|
16501
|
-
},
|
|
16502
|
-
"desc": {
|
|
16503
|
-
"type": "string"
|
|
16504
|
-
}
|
|
16505
|
-
}
|
|
16506
|
-
},
|
|
16507
|
-
"handlerCode": "async (input) => {\n const params = new URLSearchParams()\n params.set('name', input.name)\n if (input.defaultLists !== undefined && input.defaultLists !== null)\n params.set('defaultLists', String(Boolean(input.defaultLists)))\n if (input.desc !== undefined && input.desc !== null)\n params.set('desc', String(input.desc))\n const res = await integration.fetch(`/boards?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
|
|
16508
|
-
"scope": "write"
|
|
16509
|
-
},
|
|
16510
|
-
{
|
|
16511
|
-
"name": "close_board",
|
|
16512
|
-
"description": "Close a board (set closed=true).",
|
|
16513
|
-
"inputSchema": {
|
|
16514
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16515
|
-
"type": "object",
|
|
16516
|
-
"required": [
|
|
16517
|
-
"boardId"
|
|
16518
|
-
],
|
|
16519
|
-
"additionalProperties": false,
|
|
16520
|
-
"properties": {
|
|
16521
|
-
"boardId": {
|
|
16522
|
-
"type": "string"
|
|
16523
|
-
}
|
|
16524
|
-
}
|
|
16525
|
-
},
|
|
16526
|
-
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ closed: 'true' })\n const res = await integration.fetch(`/boards/${encodeURIComponent(input.boardId)}?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
|
|
16527
|
-
"scope": "write"
|
|
16528
|
-
},
|
|
16529
|
-
{
|
|
16530
|
-
"name": "delete_board",
|
|
16531
|
-
"description": "Permanently delete a closed board.",
|
|
16532
|
-
"inputSchema": {
|
|
16533
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16534
|
-
"type": "object",
|
|
16535
|
-
"required": [
|
|
16536
|
-
"boardId"
|
|
16537
|
-
],
|
|
16538
|
-
"additionalProperties": false,
|
|
16539
|
-
"properties": {
|
|
16540
|
-
"boardId": {
|
|
17855
|
+
"cardId": {
|
|
16541
17856
|
"type": "string"
|
|
16542
17857
|
}
|
|
16543
|
-
}
|
|
17858
|
+
},
|
|
17859
|
+
"required": [
|
|
17860
|
+
"cardId"
|
|
17861
|
+
],
|
|
17862
|
+
"additionalProperties": false
|
|
16544
17863
|
},
|
|
16545
|
-
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/
|
|
16546
|
-
"scope": "
|
|
17864
|
+
"handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/customFieldItems`)\n return await res.json()\n}",
|
|
17865
|
+
"scope": "read"
|
|
16547
17866
|
},
|
|
16548
17867
|
{
|
|
16549
17868
|
"name": "create_card",
|
|
@@ -16760,7 +18079,7 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16760
18079
|
},
|
|
16761
18080
|
{
|
|
16762
18081
|
"name": "create_list",
|
|
16763
|
-
"description": "Create a new list on
|
|
18082
|
+
"description": "Create a new list on the connected board.",
|
|
16764
18083
|
"inputSchema": {
|
|
16765
18084
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
16766
18085
|
"type": "object",
|
|
@@ -16786,7 +18105,10 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16786
18105
|
}
|
|
16787
18106
|
},
|
|
16788
18107
|
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ idBoard: input.idBoard, name: input.name })\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/lists?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
|
|
16789
|
-
"scope": "write"
|
|
18108
|
+
"scope": "write",
|
|
18109
|
+
"injectFromConfig": {
|
|
18110
|
+
"idBoard": "boardId"
|
|
18111
|
+
}
|
|
16790
18112
|
},
|
|
16791
18113
|
{
|
|
16792
18114
|
"name": "update_list",
|
|
@@ -16845,7 +18167,8 @@ const GENERATED_INTEGRATIONS = {
|
|
|
16845
18167
|
"handlerCode": "async (input) => {\n const params = new URLSearchParams({ value: 'true' })\n const res = await integration.fetch(`/lists/${encodeURIComponent(input.listId)}/closed?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
|
|
16846
18168
|
"scope": "write"
|
|
16847
18169
|
}
|
|
16848
|
-
]
|
|
18170
|
+
],
|
|
18171
|
+
"variantOwnerType": "trello"
|
|
16849
18172
|
}
|
|
16850
18173
|
};
|
|
16851
18174
|
|
|
@@ -16859,8 +18182,12 @@ function getIntegration(type) {
|
|
|
16859
18182
|
function cloneManifest(manifest) {
|
|
16860
18183
|
return {
|
|
16861
18184
|
...manifest,
|
|
18185
|
+
variantConfig: manifest.variantConfig ? JSON.parse(JSON.stringify(manifest.variantConfig)) : void 0,
|
|
16862
18186
|
toolsets: manifest.toolsets ? { ...manifest.toolsets } : void 0,
|
|
16863
|
-
tools: manifest.tools.map((tool) => ({
|
|
18187
|
+
tools: manifest.tools.map((tool) => ({
|
|
18188
|
+
...tool,
|
|
18189
|
+
injectFromConfig: tool.injectFromConfig ? { ...tool.injectFromConfig } : void 0
|
|
18190
|
+
}))
|
|
16864
18191
|
};
|
|
16865
18192
|
}
|
|
16866
18193
|
function cloneCredentialVariant(variant) {
|
|
@@ -16871,6 +18198,10 @@ function cloneCredentialVariant(variant) {
|
|
|
16871
18198
|
headers: ((_a = variant.injection) == null ? void 0 : _a.headers) ? { ...variant.injection.headers } : void 0,
|
|
16872
18199
|
query: ((_b = variant.injection) == null ? void 0 : _b.query) ? { ...variant.injection.query } : void 0
|
|
16873
18200
|
},
|
|
18201
|
+
preprocess: typeof variant.preprocess === "object" && variant.preprocess !== null ? {
|
|
18202
|
+
...variant.preprocess,
|
|
18203
|
+
allowedOrigins: Array.isArray(variant.preprocess.allowedOrigins) ? [...variant.preprocess.allowedOrigins] : void 0
|
|
18204
|
+
} : variant.preprocess,
|
|
16874
18205
|
healthCheck: "path" in variant.healthCheck ? { ...variant.healthCheck } : { notViable: true }
|
|
16875
18206
|
};
|
|
16876
18207
|
}
|
|
@@ -16896,6 +18227,25 @@ function cloneCredentialVariantsFile(type, variants) {
|
|
|
16896
18227
|
variants: Object.fromEntries(Object.entries(validated.variants).map(([key, value]) => [key, cloneCredentialVariant(value)]))
|
|
16897
18228
|
};
|
|
16898
18229
|
}
|
|
18230
|
+
function stripInjectedFieldsFromSchema(inputSchema, injectFromConfig) {
|
|
18231
|
+
const injectedKeys = Object.keys(injectFromConfig != null ? injectFromConfig : {});
|
|
18232
|
+
if (!injectedKeys.length || !inputSchema || typeof inputSchema !== "object" || Array.isArray(inputSchema))
|
|
18233
|
+
return inputSchema;
|
|
18234
|
+
const schema = JSON.parse(JSON.stringify(inputSchema));
|
|
18235
|
+
const properties = schema.properties;
|
|
18236
|
+
if (properties && typeof properties === "object" && !Array.isArray(properties)) {
|
|
18237
|
+
for (const key of injectedKeys)
|
|
18238
|
+
delete properties[key];
|
|
18239
|
+
}
|
|
18240
|
+
if (Array.isArray(schema.required)) {
|
|
18241
|
+
const required = schema.required.filter((key) => !injectedKeys.includes(String(key)));
|
|
18242
|
+
if (required.length)
|
|
18243
|
+
schema.required = required;
|
|
18244
|
+
else
|
|
18245
|
+
delete schema.required;
|
|
18246
|
+
}
|
|
18247
|
+
return schema;
|
|
18248
|
+
}
|
|
16899
18249
|
function loadIntegrationManifest(type) {
|
|
16900
18250
|
const entry = getIntegration(type);
|
|
16901
18251
|
return entry ? cloneManifest(entry.manifest) : null;
|
|
@@ -16936,9 +18286,10 @@ function loadIntegrationTools(type, opts) {
|
|
|
16936
18286
|
name: tool.name,
|
|
16937
18287
|
displayName: tool.displayName,
|
|
16938
18288
|
description: tool.description,
|
|
16939
|
-
inputSchema: tool.inputSchema,
|
|
18289
|
+
inputSchema: stripInjectedFieldsFromSchema(tool.inputSchema, tool.injectFromConfig),
|
|
16940
18290
|
handlerCode: tool.handlerCode,
|
|
16941
|
-
utils: tool.utils
|
|
18291
|
+
utils: tool.utils,
|
|
18292
|
+
injectFromConfig: tool.injectFromConfig ? { ...tool.injectFromConfig } : void 0
|
|
16942
18293
|
};
|
|
16943
18294
|
if (scope === "write")
|
|
16944
18295
|
write.push(nextTool);
|
|
@@ -16984,8 +18335,9 @@ function loadIntegrationVariants(type) {
|
|
|
16984
18335
|
return variants ? cloneCredentialVariantsFile(type, variants) : null;
|
|
16985
18336
|
}
|
|
16986
18337
|
function loadIntegrationCredentialConfig(type, variantKey) {
|
|
16987
|
-
var _a, _b;
|
|
16988
|
-
const
|
|
18338
|
+
var _a, _b, _c, _d;
|
|
18339
|
+
const ownerType = (_b = (_a = getIntegration(type)) == null ? void 0 : _a.variantOwnerType) != null ? _b : type;
|
|
18340
|
+
const file = loadIntegrationVariants(ownerType);
|
|
16989
18341
|
if (!file)
|
|
16990
18342
|
return null;
|
|
16991
18343
|
const key = file.default;
|
|
@@ -16998,29 +18350,43 @@ function loadIntegrationCredentialConfig(type, variantKey) {
|
|
|
16998
18350
|
schema: variant.schema,
|
|
16999
18351
|
baseUrlTemplate: typeof variant.baseUrlTemplate === "string" ? variant.baseUrlTemplate : void 0,
|
|
17000
18352
|
injection: {
|
|
17001
|
-
headers: ((
|
|
17002
|
-
query: ((
|
|
18353
|
+
headers: ((_c = variant.injection) == null ? void 0 : _c.headers) || void 0,
|
|
18354
|
+
query: ((_d = variant.injection) == null ? void 0 : _d.query) || void 0
|
|
17003
18355
|
},
|
|
17004
18356
|
preprocess: variant.preprocess,
|
|
17005
18357
|
healthCheck: cloneCredentialVariant(variant).healthCheck
|
|
17006
18358
|
};
|
|
17007
18359
|
}
|
|
17008
18360
|
function loadIntegrationHint(type, variantKey) {
|
|
17009
|
-
var _a;
|
|
17010
|
-
const
|
|
18361
|
+
var _a, _b, _c;
|
|
18362
|
+
const ownerType = (_b = (_a = getIntegration(type)) == null ? void 0 : _a.variantOwnerType) != null ? _b : type;
|
|
18363
|
+
const entry = getIntegration(ownerType);
|
|
17011
18364
|
if (!entry)
|
|
17012
18365
|
return null;
|
|
17013
18366
|
if (variantKey && entry.hintsByVariant[variantKey])
|
|
17014
18367
|
return entry.hintsByVariant[variantKey];
|
|
17015
|
-
return (
|
|
18368
|
+
return (_c = entry.hint) != null ? _c : null;
|
|
17016
18369
|
}
|
|
17017
18370
|
function listIntegrationTypes() {
|
|
17018
18371
|
return Object.keys(GENERATED_INTEGRATIONS);
|
|
17019
18372
|
}
|
|
17020
18373
|
function listIntegrationCatalog() {
|
|
17021
|
-
return listIntegrationTypes().map((type) => ({
|
|
18374
|
+
return listIntegrationTypes().filter((type) => !GENERATED_INTEGRATIONS[type].variantOwnerType).map((type) => ({
|
|
17022
18375
|
type,
|
|
17023
|
-
name: GENERATED_INTEGRATIONS[type].manifest.name || type
|
|
18376
|
+
name: GENERATED_INTEGRATIONS[type].manifest.name || type,
|
|
18377
|
+
variants: listIntegrationTypes().filter((candidate) => GENERATED_INTEGRATIONS[candidate].variantOwnerType === type).map((candidate) => {
|
|
18378
|
+
var _a, _b;
|
|
18379
|
+
return {
|
|
18380
|
+
type: candidate,
|
|
18381
|
+
label: GENERATED_INTEGRATIONS[candidate].manifest.variantLabel || candidate,
|
|
18382
|
+
variantConfig: (_b = (_a = GENERATED_INTEGRATIONS[candidate].manifest.variantConfig) == null ? void 0 : _a.map((item) => ({
|
|
18383
|
+
key: item.key,
|
|
18384
|
+
label: item.label,
|
|
18385
|
+
selectionMode: item.selectionMode,
|
|
18386
|
+
hasListHandler: Boolean(item.listHandler)
|
|
18387
|
+
}))) != null ? _b : null
|
|
18388
|
+
};
|
|
18389
|
+
})
|
|
17024
18390
|
}));
|
|
17025
18391
|
}
|
|
17026
18392
|
|
|
@@ -17706,29 +19072,228 @@ function createGetIntegration(integrations, proxy) {
|
|
|
17706
19072
|
};
|
|
17707
19073
|
}
|
|
17708
19074
|
|
|
19075
|
+
const EXTRACT_FILE_PY = `#!/usr/bin/env python3
|
|
19076
|
+
import argparse
|
|
19077
|
+
import csv
|
|
19078
|
+
import html
|
|
19079
|
+
import json
|
|
19080
|
+
import mimetypes
|
|
19081
|
+
import re
|
|
19082
|
+
import zipfile
|
|
19083
|
+
from pathlib import Path
|
|
19084
|
+
|
|
19085
|
+
from markitdown import MarkItDown
|
|
19086
|
+
|
|
19087
|
+
|
|
19088
|
+
def collapse_whitespace(value: str) -> str:
|
|
19089
|
+
return re.sub(r"\\s+", " ", value or "").strip()
|
|
19090
|
+
|
|
19091
|
+
|
|
19092
|
+
def join_blocks(blocks):
|
|
19093
|
+
cleaned = [str(block).strip() for block in blocks if str(block or "").strip()]
|
|
19094
|
+
return "\\n\\n".join(cleaned).strip()
|
|
19095
|
+
|
|
19096
|
+
|
|
19097
|
+
MARKITDOWN_EXTENSIONS = {
|
|
19098
|
+
".pdf",
|
|
19099
|
+
".doc",
|
|
19100
|
+
".docx",
|
|
19101
|
+
".ppt",
|
|
19102
|
+
".pptx",
|
|
19103
|
+
".xls",
|
|
19104
|
+
".xlsx",
|
|
19105
|
+
}
|
|
19106
|
+
|
|
19107
|
+
|
|
19108
|
+
DIRECT_TEXT_EXTENSIONS = {
|
|
19109
|
+
".txt",
|
|
19110
|
+
".md",
|
|
19111
|
+
".mdx",
|
|
19112
|
+
".rtf",
|
|
19113
|
+
".log",
|
|
19114
|
+
".json",
|
|
19115
|
+
".xml",
|
|
19116
|
+
".csv",
|
|
19117
|
+
".yaml",
|
|
19118
|
+
".yml",
|
|
19119
|
+
".ini",
|
|
19120
|
+
".cfg",
|
|
19121
|
+
".properties",
|
|
19122
|
+
".html",
|
|
19123
|
+
".htm",
|
|
19124
|
+
}
|
|
19125
|
+
|
|
19126
|
+
|
|
19127
|
+
def sniff_kind(path: Path) -> str:
|
|
19128
|
+
suffix = path.suffix.lower()
|
|
19129
|
+
if suffix in DIRECT_TEXT_EXTENSIONS | MARKITDOWN_EXTENSIONS:
|
|
19130
|
+
return suffix.lstrip(".")
|
|
19131
|
+
|
|
19132
|
+
mime_guess, _ = mimetypes.guess_type(path.name)
|
|
19133
|
+
if mime_guess == "application/pdf":
|
|
19134
|
+
return "pdf"
|
|
19135
|
+
|
|
19136
|
+
with path.open("rb") as handle:
|
|
19137
|
+
prefix = handle.read(16)
|
|
19138
|
+
if prefix.startswith(b"%PDF"):
|
|
19139
|
+
return "pdf"
|
|
19140
|
+
|
|
19141
|
+
if zipfile.is_zipfile(path):
|
|
19142
|
+
with zipfile.ZipFile(path, "r") as archive:
|
|
19143
|
+
names = set(archive.namelist())
|
|
19144
|
+
if "word/document.xml" in names:
|
|
19145
|
+
return "docx"
|
|
19146
|
+
if "xl/workbook.xml" in names:
|
|
19147
|
+
return "xlsx"
|
|
19148
|
+
if "ppt/presentation.xml" in names:
|
|
19149
|
+
return "pptx"
|
|
19150
|
+
|
|
19151
|
+
return "unknown"
|
|
19152
|
+
|
|
19153
|
+
|
|
19154
|
+
def read_text(path: Path) -> dict:
|
|
19155
|
+
content = path.read_text(encoding="utf-8", errors="replace").strip()
|
|
19156
|
+
return {"kind": "text", "content": content, "metadata": {"filename": path.name}}
|
|
19157
|
+
|
|
19158
|
+
|
|
19159
|
+
def read_markdown(path: Path) -> dict:
|
|
19160
|
+
content = path.read_text(encoding="utf-8", errors="replace").strip()
|
|
19161
|
+
return {"kind": "markdown", "content": content, "metadata": {"filename": path.name}}
|
|
19162
|
+
|
|
19163
|
+
|
|
19164
|
+
def read_json(path: Path) -> dict:
|
|
19165
|
+
raw = path.read_text(encoding="utf-8", errors="replace")
|
|
19166
|
+
try:
|
|
19167
|
+
data = json.loads(raw)
|
|
19168
|
+
content = json.dumps(data, indent=2, ensure_ascii=False)
|
|
19169
|
+
except Exception:
|
|
19170
|
+
content = raw
|
|
19171
|
+
return {"kind": "json", "content": content.strip(), "metadata": {"filename": path.name}}
|
|
19172
|
+
|
|
19173
|
+
|
|
19174
|
+
def read_html(path: Path) -> dict:
|
|
19175
|
+
raw = path.read_text(encoding="utf-8", errors="replace")
|
|
19176
|
+
text = re.sub(r"<script[\\s\\S]*?<\/script>", " ", raw, flags=re.IGNORECASE)
|
|
19177
|
+
text = re.sub(r"<style[\\s\\S]*?</style>", " ", text, flags=re.IGNORECASE)
|
|
19178
|
+
text = re.sub(r"<br\\s*/?>", "\\n", text, flags=re.IGNORECASE)
|
|
19179
|
+
text = re.sub(r"</(p|div|section|article|li|tr|h[1-6])>", "\\n", text, flags=re.IGNORECASE)
|
|
19180
|
+
text = re.sub(r"<[^>]+>", " ", text)
|
|
19181
|
+
text = html.unescape(text)
|
|
19182
|
+
text = re.sub(r"[ \\t]+\\n", "\\n", text)
|
|
19183
|
+
text = re.sub(r"\\n{3,}", "\\n\\n", text).strip()
|
|
19184
|
+
return {"kind": "html", "content": text, "metadata": {"filename": path.name}}
|
|
19185
|
+
|
|
19186
|
+
|
|
19187
|
+
def read_csv_file(path: Path) -> dict:
|
|
19188
|
+
with path.open("r", encoding="utf-8", errors="replace", newline="") as handle:
|
|
19189
|
+
reader = csv.reader(handle)
|
|
19190
|
+
rows = list(reader)
|
|
19191
|
+
|
|
19192
|
+
if not rows:
|
|
19193
|
+
return {"kind": "csv", "content": "", "metadata": {"filename": path.name, "rowCount": 0}}
|
|
19194
|
+
|
|
19195
|
+
header_width = max(len(row) for row in rows)
|
|
19196
|
+
normalized = [row + [""] * (header_width - len(row)) for row in rows]
|
|
19197
|
+
headers = normalized[0]
|
|
19198
|
+
body = normalized[1:]
|
|
19199
|
+
|
|
19200
|
+
md_rows = [
|
|
19201
|
+
f"| {' | '.join(headers)} |",
|
|
19202
|
+
f"| {' | '.join(['---'] * header_width)} |",
|
|
19203
|
+
]
|
|
19204
|
+
md_rows.extend(f"| {' | '.join(row)} |" for row in body[:200])
|
|
19205
|
+
warnings = []
|
|
19206
|
+
if len(body) > 200:
|
|
19207
|
+
warnings.append("CSV output truncated to first 200 data rows.")
|
|
19208
|
+
|
|
19209
|
+
return {
|
|
19210
|
+
"kind": "csv",
|
|
19211
|
+
"content": "\\n".join(md_rows).strip(),
|
|
19212
|
+
"warnings": warnings or None,
|
|
19213
|
+
"metadata": {"filename": path.name, "rowCount": len(body), "columnCount": header_width},
|
|
19214
|
+
}
|
|
19215
|
+
|
|
19216
|
+
|
|
19217
|
+
def read_with_markitdown(path: Path, kind: str) -> dict:
|
|
19218
|
+
try:
|
|
19219
|
+
result = MarkItDown().convert(str(path))
|
|
19220
|
+
except Exception as exc:
|
|
19221
|
+
raise RuntimeError(f"MarkItDown extraction failed for {path.name}: {exc}") from exc
|
|
19222
|
+
|
|
19223
|
+
content = (getattr(result, "text_content", "") or "").strip()
|
|
19224
|
+
return {
|
|
19225
|
+
"kind": kind,
|
|
19226
|
+
"content": content,
|
|
19227
|
+
"metadata": {"filename": path.name, "parser": "markitdown"},
|
|
19228
|
+
}
|
|
19229
|
+
|
|
19230
|
+
|
|
19231
|
+
def extract(path: Path) -> dict:
|
|
19232
|
+
kind = sniff_kind(path)
|
|
19233
|
+
if kind == "txt":
|
|
19234
|
+
return read_text(path)
|
|
19235
|
+
if kind == "md":
|
|
19236
|
+
return read_markdown(path)
|
|
19237
|
+
if kind == "json":
|
|
19238
|
+
return read_json(path)
|
|
19239
|
+
if kind in {"html", "htm"}:
|
|
19240
|
+
return read_html(path)
|
|
19241
|
+
if kind == "csv":
|
|
19242
|
+
return read_csv_file(path)
|
|
19243
|
+
if path.suffix.lower() in MARKITDOWN_EXTENSIONS or kind in {"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx"}:
|
|
19244
|
+
return read_with_markitdown(path, kind)
|
|
19245
|
+
|
|
19246
|
+
raw = path.read_text(encoding="utf-8", errors="replace")
|
|
19247
|
+
return {
|
|
19248
|
+
"kind": "unknown",
|
|
19249
|
+
"content": raw.strip(),
|
|
19250
|
+
"warnings": ["Unknown file type; returned best-effort UTF-8 text decode."],
|
|
19251
|
+
"metadata": {"filename": path.name},
|
|
19252
|
+
}
|
|
19253
|
+
|
|
19254
|
+
|
|
19255
|
+
def main() -> int:
|
|
19256
|
+
parser = argparse.ArgumentParser()
|
|
19257
|
+
parser.add_argument("--input", required=True)
|
|
19258
|
+
parser.add_argument("--output", required=True)
|
|
19259
|
+
args = parser.parse_args()
|
|
19260
|
+
|
|
19261
|
+
input_path = Path(args.input)
|
|
19262
|
+
output_path = Path(args.output)
|
|
19263
|
+
|
|
19264
|
+
result = extract(input_path)
|
|
19265
|
+
output_path.write_text(json.dumps(result, ensure_ascii=False), encoding="utf-8")
|
|
19266
|
+
return 0
|
|
19267
|
+
|
|
19268
|
+
|
|
19269
|
+
if __name__ == "__main__":
|
|
19270
|
+
raise SystemExit(main())
|
|
19271
|
+
`;
|
|
19272
|
+
const EXTRACT_FILE_PY_HASH = "632e2322c14941f8c30b5f60b4c5bb1d773e0d2953fde39a7a16eaf1dbfc21c2";
|
|
19273
|
+
|
|
17709
19274
|
const execFile$1 = promisify(execFile$2);
|
|
17710
|
-
const INSTALL_COMMAND = "pip3 install
|
|
19275
|
+
const INSTALL_COMMAND = "pip3 install markitdown[all]";
|
|
17711
19276
|
const DOCKER_HINT = "Run Commandable with Docker to use the preinstalled extraction runtime.";
|
|
19277
|
+
let cachedScriptPath = null;
|
|
19278
|
+
function ensureExtractorScript() {
|
|
19279
|
+
if (cachedScriptPath)
|
|
19280
|
+
return cachedScriptPath;
|
|
19281
|
+
const path = join(tmpdir(), `commandable-extractor-${EXTRACT_FILE_PY_HASH.slice(0, 16)}.py`);
|
|
19282
|
+
if (!existsSync(path))
|
|
19283
|
+
writeFileSync(path, EXTRACT_FILE_PY, "utf8");
|
|
19284
|
+
cachedScriptPath = path;
|
|
19285
|
+
return path;
|
|
19286
|
+
}
|
|
17712
19287
|
const FILE_PROCESSING_DISABLED_TOOLS = {
|
|
17713
|
-
"google-workspace": ["read_file_content"]
|
|
19288
|
+
"google-workspace": ["read_file_content"],
|
|
19289
|
+
sharepoint: ["read_file_content"]
|
|
17714
19290
|
};
|
|
17715
19291
|
let capabilityPromise = null;
|
|
17716
19292
|
function pythonExecutable() {
|
|
17717
19293
|
return process.env.COMMANDABLE_PYTHON || "python3";
|
|
17718
19294
|
}
|
|
17719
|
-
function extractorScriptCandidates() {
|
|
17720
|
-
const cwd = process.cwd();
|
|
17721
|
-
return [
|
|
17722
|
-
fileURLToPath(new URL("../file-extractor/extract_file.py", globalThis._importMeta_.url)),
|
|
17723
|
-
resolve$1(cwd, "packages/core/src/file-extractor/extract_file.py"),
|
|
17724
|
-
resolve$1(cwd, "packages/core/dist/file-extractor/extract_file.py"),
|
|
17725
|
-
resolve$1(cwd, "node_modules/@commandable/mcp-core/dist/file-extractor/extract_file.py"),
|
|
17726
|
-
resolve$1(cwd, "app/.output/server/node_modules/@commandable/mcp-core/dist/file-extractor/extract_file.py")
|
|
17727
|
-
];
|
|
17728
|
-
}
|
|
17729
19295
|
function extractorScriptPath() {
|
|
17730
|
-
|
|
17731
|
-
return candidates.find((path) => existsSync(path)) || candidates[0];
|
|
19296
|
+
return ensureExtractorScript();
|
|
17732
19297
|
}
|
|
17733
19298
|
function getFileProcessingMode() {
|
|
17734
19299
|
const raw = String(process.env.COMMANDABLE_FILE_PROCESSING || "").trim().toLowerCase();
|
|
@@ -17766,10 +19331,7 @@ async function probeFileProcessing() {
|
|
|
17766
19331
|
if (mode === "off") {
|
|
17767
19332
|
return buildDisabledCapability("disabled_by_env", "File processing is disabled by COMMANDABLE_FILE_PROCESSING=off.");
|
|
17768
19333
|
}
|
|
17769
|
-
|
|
17770
|
-
if (!existsSync(scriptPath)) {
|
|
17771
|
-
return buildDisabledCapability("extractor_script_missing", `File processing is unavailable because the extractor script was not found at ${scriptPath}.`);
|
|
17772
|
-
}
|
|
19334
|
+
ensureExtractorScript();
|
|
17773
19335
|
try {
|
|
17774
19336
|
await execFile$1(pythonExecutable(), ["-c", "import markitdown"]);
|
|
17775
19337
|
return buildEnabledCapability();
|
|
@@ -17967,6 +19529,25 @@ function filterBuiltInToolsForOverrides(builtInTools, definitions) {
|
|
|
17967
19529
|
const overridingNames = new Set(definitions.map((definition) => definition.name));
|
|
17968
19530
|
return builtInTools.filter((tool) => !overridingNames.has(tool.name));
|
|
17969
19531
|
}
|
|
19532
|
+
function buildHandlerWrapper(integrationId, handlerCode, integrationConfig, injectFromConfig) {
|
|
19533
|
+
const serializedConfig = JSON.stringify(integrationConfig != null ? integrationConfig : {});
|
|
19534
|
+
const serializedMapping = JSON.stringify(injectFromConfig != null ? injectFromConfig : {});
|
|
19535
|
+
return `async (input) => {
|
|
19536
|
+
const integration = getIntegration('${integrationId}');
|
|
19537
|
+
const __inner = ${handlerCode};
|
|
19538
|
+
const __config = ${serializedConfig};
|
|
19539
|
+
const __mapping = ${serializedMapping};
|
|
19540
|
+
const __baseInput = (input && typeof input === 'object' && !Array.isArray(input)) ? input : {};
|
|
19541
|
+
const __injected = {};
|
|
19542
|
+
for (const [targetKey, configKey] of Object.entries(__mapping)) {
|
|
19543
|
+
const value = __config?.[configKey];
|
|
19544
|
+
if (value === undefined || value === null)
|
|
19545
|
+
throw new Error(\`Missing integration config value '\${configKey}' required for tool input '\${targetKey}'.\`);
|
|
19546
|
+
__injected[targetKey] = value;
|
|
19547
|
+
}
|
|
19548
|
+
return await __inner({ ...__baseInput, ...__injected });
|
|
19549
|
+
}`;
|
|
19550
|
+
}
|
|
17970
19551
|
function buildToolsByIntegration(spaceId, integrations, proxy, opts = {}) {
|
|
17971
19552
|
var _a, _b, _c, _d;
|
|
17972
19553
|
const { requireWriteConfirmation = false, integrationsRef, toolDefinitions, utils: injectUtils } = opts;
|
|
@@ -17998,11 +19579,7 @@ function buildToolsByIntegration(spaceId, integrations, proxy, opts = {}) {
|
|
|
17998
19579
|
const toolName = makeIntegrationToolName(integ.type, t.name, integ.id);
|
|
17999
19580
|
const description = `[${integ.label} | ${integ.type}] ${t.description}`;
|
|
18000
19581
|
const extractFileContent = createExtractFileContent(getIntegration, integ.id);
|
|
18001
|
-
const wrapper =
|
|
18002
|
-
const integration = getIntegration('${integ.id}');
|
|
18003
|
-
const __inner = ${t.handlerCode};
|
|
18004
|
-
return await __inner(input);
|
|
18005
|
-
}`;
|
|
19582
|
+
const wrapper = buildHandlerWrapper(integ.id, t.handlerCode, integ.config, t.injectFromConfig);
|
|
18006
19583
|
const utils = injectUtils != null ? injectUtils : buildSandboxUtils(Array.isArray(t.utils) ? t.utils : void 0, { extractFileContent });
|
|
18007
19584
|
const safeHandler = createSafeHandlerFromString(wrapper, getIntegration, utils);
|
|
18008
19585
|
return {
|
|
@@ -18046,6 +19623,9 @@ function buildToolsByIntegration(spaceId, integrations, proxy, opts = {}) {
|
|
|
18046
19623
|
return toolsByIntegration;
|
|
18047
19624
|
}
|
|
18048
19625
|
|
|
19626
|
+
function isHandlerPreprocess(preprocess) {
|
|
19627
|
+
return typeof preprocess === "object" && preprocess !== null && preprocess.type === "handler" && typeof preprocess.handlerCode === "string";
|
|
19628
|
+
}
|
|
18049
19629
|
function getBuiltInIntegrationTypeConfig(typeSlug) {
|
|
18050
19630
|
var _a, _b, _c, _d;
|
|
18051
19631
|
const variantsFile = loadIntegrationVariants(typeSlug);
|
|
@@ -18057,8 +19637,9 @@ function getBuiltInIntegrationTypeConfig(typeSlug) {
|
|
|
18057
19637
|
const variants = {};
|
|
18058
19638
|
for (const [key, variant] of Object.entries(variantsFile.variants)) {
|
|
18059
19639
|
const preprocess = (_c = variant.preprocess) != null ? _c : null;
|
|
18060
|
-
|
|
18061
|
-
|
|
19640
|
+
const isSupportedHandler = isHandlerPreprocess(preprocess);
|
|
19641
|
+
if (preprocess !== null && preprocess !== "google_service_account" && !isSupportedHandler) {
|
|
19642
|
+
throw new Error(`Unsupported preprocess for built-in integration '${typeSlug}/${key}'.`);
|
|
18062
19643
|
}
|
|
18063
19644
|
variants[key] = {
|
|
18064
19645
|
label: variant.label,
|
|
@@ -18069,7 +19650,11 @@ function getBuiltInIntegrationTypeConfig(typeSlug) {
|
|
|
18069
19650
|
allowedOrigins: manifestAllowedOrigins,
|
|
18070
19651
|
healthCheck: (_d = variant.healthCheck) != null ? _d : null,
|
|
18071
19652
|
hintMarkdown: loadIntegrationHint(typeSlug, key),
|
|
18072
|
-
preprocess
|
|
19653
|
+
preprocess: isSupportedHandler ? {
|
|
19654
|
+
type: "handler",
|
|
19655
|
+
handlerCode: preprocess.handlerCode,
|
|
19656
|
+
allowedOrigins: Array.isArray(preprocess.allowedOrigins) ? [...preprocess.allowedOrigins] : null
|
|
19657
|
+
} : preprocess
|
|
18073
19658
|
};
|
|
18074
19659
|
}
|
|
18075
19660
|
return {
|
|
@@ -18172,6 +19757,28 @@ function buildCredentialUrl(integrationId) {
|
|
|
18172
19757
|
const port = portRaw && /^\d+$/.test(portRaw) ? Number(portRaw) : 23432;
|
|
18173
19758
|
return `http://127.0.0.1:${port}/integrations/${encodeURIComponent(integrationId)}`;
|
|
18174
19759
|
}
|
|
19760
|
+
function decodeJwtPayloadForDebug(token) {
|
|
19761
|
+
try {
|
|
19762
|
+
const parts = token.split(".");
|
|
19763
|
+
if (parts.length < 2 || !parts[1])
|
|
19764
|
+
return null;
|
|
19765
|
+
let b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
19766
|
+
const pad = b64.length % 4 === 0 ? "" : "=".repeat(4 - b64.length % 4);
|
|
19767
|
+
b64 = b64 + pad;
|
|
19768
|
+
const json = Buffer$1.from(b64, "base64").toString("utf8");
|
|
19769
|
+
const payload = JSON.parse(json);
|
|
19770
|
+
return {
|
|
19771
|
+
aud: payload.aud,
|
|
19772
|
+
tid: payload.tid,
|
|
19773
|
+
appid: payload.appid,
|
|
19774
|
+
roles: payload.roles,
|
|
19775
|
+
scp: payload.scp,
|
|
19776
|
+
idtyp: payload.idtyp
|
|
19777
|
+
};
|
|
19778
|
+
} catch {
|
|
19779
|
+
return null;
|
|
19780
|
+
}
|
|
19781
|
+
}
|
|
18175
19782
|
function isAbsoluteHttpUrl(value) {
|
|
18176
19783
|
try {
|
|
18177
19784
|
const url = new URL(value);
|
|
@@ -18232,71 +19839,163 @@ function resolveRelativeBaseUrl(provider, baseUrl, rawPath) {
|
|
|
18232
19839
|
return "https://slides.googleapis.com/v1";
|
|
18233
19840
|
return baseUrl;
|
|
18234
19841
|
}
|
|
19842
|
+
function joinWithoutDuplicateSegments(baseUrl, rawPath) {
|
|
19843
|
+
let pathOnly = rawPath || "";
|
|
19844
|
+
let queryPart = "";
|
|
19845
|
+
const qIndex = pathOnly.indexOf("?");
|
|
19846
|
+
if (qIndex >= 0) {
|
|
19847
|
+
queryPart = pathOnly.slice(qIndex + 1);
|
|
19848
|
+
pathOnly = pathOnly.slice(0, qIndex);
|
|
19849
|
+
}
|
|
19850
|
+
try {
|
|
19851
|
+
const base = new URL(baseUrl);
|
|
19852
|
+
const baseSegs = base.pathname.split("/").filter(Boolean);
|
|
19853
|
+
const pathSegs = (pathOnly || "/").split("/").filter(Boolean);
|
|
19854
|
+
let overlap = 0;
|
|
19855
|
+
const maxK = Math.min(baseSegs.length, pathSegs.length);
|
|
19856
|
+
for (let k = maxK; k >= 1; k--) {
|
|
19857
|
+
let ok = true;
|
|
19858
|
+
for (let i = 0; i < k; i++) {
|
|
19859
|
+
if (baseSegs[baseSegs.length - k + i] !== pathSegs[i]) {
|
|
19860
|
+
ok = false;
|
|
19861
|
+
break;
|
|
19862
|
+
}
|
|
19863
|
+
}
|
|
19864
|
+
if (ok) {
|
|
19865
|
+
overlap = k;
|
|
19866
|
+
break;
|
|
19867
|
+
}
|
|
19868
|
+
}
|
|
19869
|
+
const normalizedPath = `/${[...baseSegs, ...pathSegs.slice(overlap)].join("/")}`;
|
|
19870
|
+
const baseOrigin = base.origin;
|
|
19871
|
+
const urlNoQuery = `${baseOrigin}${normalizedPath}`;
|
|
19872
|
+
return queryPart ? `${urlNoQuery}?${queryPart}` : urlNoQuery;
|
|
19873
|
+
} catch {
|
|
19874
|
+
const cleanedBase = baseUrl.replace(/\/+$/, "");
|
|
19875
|
+
const cleanedPath = `/${(pathOnly || "").replace(/^\/+/, "")}`;
|
|
19876
|
+
const baseParts = cleanedBase.split("/").filter(Boolean);
|
|
19877
|
+
const pathParts = cleanedPath.split("/").filter(Boolean);
|
|
19878
|
+
let overlap = 0;
|
|
19879
|
+
const maxK = Math.min(baseParts.length, pathParts.length);
|
|
19880
|
+
for (let k = maxK; k >= 1; k--) {
|
|
19881
|
+
let ok = true;
|
|
19882
|
+
for (let i = 0; i < k; i++) {
|
|
19883
|
+
if (baseParts[baseParts.length - k + i] !== pathParts[i]) {
|
|
19884
|
+
ok = false;
|
|
19885
|
+
break;
|
|
19886
|
+
}
|
|
19887
|
+
}
|
|
19888
|
+
if (ok) {
|
|
19889
|
+
overlap = k;
|
|
19890
|
+
break;
|
|
19891
|
+
}
|
|
19892
|
+
}
|
|
19893
|
+
const joined = `/${[...baseParts, ...pathParts.slice(overlap)].join("/")}`;
|
|
19894
|
+
return queryPart ? `${joined}?${queryPart}` : joined;
|
|
19895
|
+
}
|
|
19896
|
+
}
|
|
19897
|
+
function stableStringify(value) {
|
|
19898
|
+
if (value === null || typeof value !== "object")
|
|
19899
|
+
return JSON.stringify(value);
|
|
19900
|
+
if (Array.isArray(value))
|
|
19901
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
19902
|
+
const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, innerValue]) => `${JSON.stringify(key)}:${stableStringify(innerValue)}`);
|
|
19903
|
+
return `{${entries.join(",")}}`;
|
|
19904
|
+
}
|
|
19905
|
+
const preprocessResultCache = /* @__PURE__ */ new Map();
|
|
19906
|
+
function isHandlerCredentialPreprocess(preprocess) {
|
|
19907
|
+
return typeof preprocess === "object" && preprocess !== null && preprocess.type === "handler" && typeof preprocess.handlerCode === "string";
|
|
19908
|
+
}
|
|
19909
|
+
function getPreprocessCacheKey(provider, variantKey, creds) {
|
|
19910
|
+
return createHash("sha256").update(`${provider}:${variantKey}:${stableStringify(creds)}`).digest("hex");
|
|
19911
|
+
}
|
|
19912
|
+
function getExpiresAtMs(result, now) {
|
|
19913
|
+
var _a;
|
|
19914
|
+
const rawExpiresIn = (_a = result.expiresIn) != null ? _a : result.expires_in;
|
|
19915
|
+
const expiresIn = typeof rawExpiresIn === "number" ? rawExpiresIn : typeof rawExpiresIn === "string" && rawExpiresIn.trim() ? Number(rawExpiresIn) : NaN;
|
|
19916
|
+
if (Number.isFinite(expiresIn) && expiresIn > 0)
|
|
19917
|
+
return now + expiresIn * 1e3;
|
|
19918
|
+
return now + 55 * 6e4;
|
|
19919
|
+
}
|
|
19920
|
+
function normalizeRequestInit(init = {}) {
|
|
19921
|
+
const preparedInit = { ...init };
|
|
19922
|
+
if (preparedInit.body !== void 0 && typeof preparedInit.body !== "string" && !(preparedInit.body instanceof URLSearchParams) && !(preparedInit.body instanceof FormData) && !(preparedInit.body instanceof Blob) && !(preparedInit.body instanceof ArrayBuffer)) {
|
|
19923
|
+
preparedInit.body = JSON.stringify(preparedInit.body);
|
|
19924
|
+
preparedInit.headers = {
|
|
19925
|
+
"Content-Type": "application/json",
|
|
19926
|
+
...preparedInit.headers
|
|
19927
|
+
};
|
|
19928
|
+
} else if (preparedInit.body instanceof URLSearchParams) {
|
|
19929
|
+
preparedInit.body = preparedInit.body.toString();
|
|
19930
|
+
preparedInit.headers = {
|
|
19931
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
19932
|
+
...preparedInit.headers
|
|
19933
|
+
};
|
|
19934
|
+
}
|
|
19935
|
+
return preparedInit;
|
|
19936
|
+
}
|
|
19937
|
+
async function runSandboxCredentialPreprocess(params) {
|
|
19938
|
+
var _a, _b;
|
|
19939
|
+
const { provider, variantKey, preprocess, creds, baseUrl, allowedOrigins } = params;
|
|
19940
|
+
const cacheKey = getPreprocessCacheKey(provider, variantKey, creds);
|
|
19941
|
+
const existing = preprocessResultCache.get(cacheKey);
|
|
19942
|
+
const now = Date.now();
|
|
19943
|
+
if (existing && existing.expiresAtMs - now > 6e4) {
|
|
19944
|
+
Object.assign(creds, existing.data);
|
|
19945
|
+
return;
|
|
19946
|
+
}
|
|
19947
|
+
const tokenFetch = async (path, init = {}) => {
|
|
19948
|
+
let finalUrl;
|
|
19949
|
+
if (isAbsoluteHttpUrl(path)) {
|
|
19950
|
+
assertAbsoluteUrlIsAllowed(path, baseUrl, allowedOrigins);
|
|
19951
|
+
finalUrl = path;
|
|
19952
|
+
} else {
|
|
19953
|
+
finalUrl = joinWithoutDuplicateSegments(baseUrl, path);
|
|
19954
|
+
}
|
|
19955
|
+
const preparedInit = normalizeRequestInit(init);
|
|
19956
|
+
return await fetch(finalUrl, {
|
|
19957
|
+
...preparedInit,
|
|
19958
|
+
method: preparedInit.method || "GET"
|
|
19959
|
+
});
|
|
19960
|
+
};
|
|
19961
|
+
const wrapper = `async (input) => {
|
|
19962
|
+
const __inner = ${preprocess.handlerCode};
|
|
19963
|
+
return await __inner(input, utils)
|
|
19964
|
+
}`;
|
|
19965
|
+
const safeHandler = createSafeHandlerFromString(wrapper, () => ({}), { tokenFetch });
|
|
19966
|
+
const res = await safeHandler(creds);
|
|
19967
|
+
if (!res.success)
|
|
19968
|
+
throw new HttpError(400, `Credential preprocess failed for '${provider}': ${String(((_a = res.result) == null ? void 0 : _a.message) || res.result || "Unknown error")}`);
|
|
19969
|
+
const result = res.result;
|
|
19970
|
+
if (!result || typeof result !== "object" || Array.isArray(result))
|
|
19971
|
+
throw new HttpError(400, `Credential preprocess for '${provider}' must return an object.`);
|
|
19972
|
+
if (typeof result.token !== "string" || !result.token.trim())
|
|
19973
|
+
throw new HttpError(400, `Credential preprocess for '${provider}' must return a non-empty 'token' string.`);
|
|
19974
|
+
Object.assign(creds, result);
|
|
19975
|
+
preprocessResultCache.set(cacheKey, {
|
|
19976
|
+
data: { ...result },
|
|
19977
|
+
expiresAtMs: getExpiresAtMs(result, now)
|
|
19978
|
+
});
|
|
19979
|
+
if (provider === "sharepoint") {
|
|
19980
|
+
const t = result == null ? void 0 : result.token;
|
|
19981
|
+
const tokenStr = typeof t === "string" ? t : "";
|
|
19982
|
+
const claims = tokenStr ? decodeJwtPayloadForDebug(tokenStr) : null;
|
|
19983
|
+
const roles = claims == null ? void 0 : claims.roles;
|
|
19984
|
+
const rolesList = Array.isArray(roles) ? roles.map((r) => String(r).slice(0, 80)) : [];
|
|
19985
|
+
fetch("http://127.0.0.1:7886/ingest/d4127044-8bb5-4b15-95f1-be96d51d67ea", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "797117" }, body: JSON.stringify({ sessionId: "797117", location: "proxy.ts:runSandboxCredentialPreprocess", message: "sharepoint preprocess ok", data: { variantKey, tokenLen: typeof t === "string" ? t.length : 0, expiresIn: (_b = result == null ? void 0 : result.expiresIn) != null ? _b : result == null ? void 0 : result.expires_in, tokenAud: claims == null ? void 0 : claims.aud, tokenTid: claims == null ? void 0 : claims.tid, tokenAppId: claims == null ? void 0 : claims.appid, tokenIdtyp: claims == null ? void 0 : claims.idtyp, rolesCount: rolesList.length, rolesSample: rolesList.slice(0, 12), hasScp: typeof (claims == null ? void 0 : claims.scp) === "string" && String(claims.scp).length > 0, jwtDecodeOk: !!claims }, timestamp: Date.now(), hypothesisId: "H6" }) }).catch(() => {
|
|
19986
|
+
});
|
|
19987
|
+
}
|
|
19988
|
+
}
|
|
18235
19989
|
class IntegrationProxy {
|
|
18236
19990
|
constructor(opts = {}) {
|
|
18237
19991
|
__publicField$4(this, "opts");
|
|
18238
19992
|
this.opts = opts;
|
|
18239
19993
|
}
|
|
18240
19994
|
async call(integration, path, init = {}) {
|
|
18241
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
19995
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
18242
19996
|
const { type: provider } = integration;
|
|
18243
19997
|
if (!provider || !path)
|
|
18244
19998
|
throw new HttpError(400, "provider and path are required.");
|
|
18245
|
-
const joinWithoutDuplicateSegments = (baseUrl, rawPath) => {
|
|
18246
|
-
let pathOnly = rawPath || "";
|
|
18247
|
-
let queryPart = "";
|
|
18248
|
-
const qIndex = pathOnly.indexOf("?");
|
|
18249
|
-
if (qIndex >= 0) {
|
|
18250
|
-
queryPart = pathOnly.slice(qIndex + 1);
|
|
18251
|
-
pathOnly = pathOnly.slice(0, qIndex);
|
|
18252
|
-
}
|
|
18253
|
-
try {
|
|
18254
|
-
const base = new URL(baseUrl);
|
|
18255
|
-
const baseSegs = base.pathname.split("/").filter(Boolean);
|
|
18256
|
-
const pathSegs = (pathOnly || "/").split("/").filter(Boolean);
|
|
18257
|
-
let overlap = 0;
|
|
18258
|
-
const maxK = Math.min(baseSegs.length, pathSegs.length);
|
|
18259
|
-
for (let k = maxK; k >= 1; k--) {
|
|
18260
|
-
let ok = true;
|
|
18261
|
-
for (let i = 0; i < k; i++) {
|
|
18262
|
-
if (baseSegs[baseSegs.length - k + i] !== pathSegs[i]) {
|
|
18263
|
-
ok = false;
|
|
18264
|
-
break;
|
|
18265
|
-
}
|
|
18266
|
-
}
|
|
18267
|
-
if (ok) {
|
|
18268
|
-
overlap = k;
|
|
18269
|
-
break;
|
|
18270
|
-
}
|
|
18271
|
-
}
|
|
18272
|
-
const normalizedPath = `/${[...baseSegs, ...pathSegs.slice(overlap)].join("/")}`;
|
|
18273
|
-
const baseOrigin = base.origin;
|
|
18274
|
-
const urlNoQuery = `${baseOrigin}${normalizedPath}`;
|
|
18275
|
-
return queryPart ? `${urlNoQuery}?${queryPart}` : urlNoQuery;
|
|
18276
|
-
} catch {
|
|
18277
|
-
const cleanedBase = baseUrl.replace(/\/+$/, "");
|
|
18278
|
-
const cleanedPath = `/${(pathOnly || "").replace(/^\/+/, "")}`;
|
|
18279
|
-
const baseParts = cleanedBase.split("/").filter(Boolean);
|
|
18280
|
-
const pathParts = cleanedPath.split("/").filter(Boolean);
|
|
18281
|
-
let overlap = 0;
|
|
18282
|
-
const maxK = Math.min(baseParts.length, pathParts.length);
|
|
18283
|
-
for (let k = maxK; k >= 1; k--) {
|
|
18284
|
-
let ok = true;
|
|
18285
|
-
for (let i = 0; i < k; i++) {
|
|
18286
|
-
if (baseParts[baseParts.length - k + i] !== pathParts[i]) {
|
|
18287
|
-
ok = false;
|
|
18288
|
-
break;
|
|
18289
|
-
}
|
|
18290
|
-
}
|
|
18291
|
-
if (ok) {
|
|
18292
|
-
overlap = k;
|
|
18293
|
-
break;
|
|
18294
|
-
}
|
|
18295
|
-
}
|
|
18296
|
-
const joined = `/${[...baseParts, ...pathParts.slice(overlap)].join("/")}`;
|
|
18297
|
-
return queryPart ? `${joined}?${queryPart}` : joined;
|
|
18298
|
-
}
|
|
18299
|
-
};
|
|
18300
19999
|
const usesCredentials = integration.connectionMethod === "credentials";
|
|
18301
20000
|
if (usesCredentials) {
|
|
18302
20001
|
if (!this.opts.credentialStore)
|
|
@@ -18387,6 +20086,18 @@ class IntegrationProxy {
|
|
|
18387
20086
|
throw new HttpError(400, `Missing OAuth scopes for Google integration '${provider}'.`);
|
|
18388
20087
|
const token = await getGoogleAccessToken({ serviceAccountJson, scopes, subject });
|
|
18389
20088
|
creds.token = token;
|
|
20089
|
+
} else if (isHandlerCredentialPreprocess(typeConfig.preprocess)) {
|
|
20090
|
+
await runSandboxCredentialPreprocess({
|
|
20091
|
+
provider,
|
|
20092
|
+
variantKey,
|
|
20093
|
+
preprocess: typeConfig.preprocess,
|
|
20094
|
+
creds,
|
|
20095
|
+
baseUrl,
|
|
20096
|
+
allowedOrigins: [
|
|
20097
|
+
...typeConfig.allowedOrigins,
|
|
20098
|
+
...(_f = typeConfig.preprocess.allowedOrigins) != null ? _f : []
|
|
20099
|
+
]
|
|
20100
|
+
});
|
|
18390
20101
|
}
|
|
18391
20102
|
const resolvedHeaders = {};
|
|
18392
20103
|
const resolvedQuery = new URLSearchParams();
|
|
@@ -18399,9 +20110,9 @@ class IntegrationProxy {
|
|
|
18399
20110
|
const token = Buffer$1.from(`${username}:${password}`).toString("base64");
|
|
18400
20111
|
resolvedHeaders.Authorization = `Basic ${token}`;
|
|
18401
20112
|
} else {
|
|
18402
|
-
for (const [k, v] of Object.entries(((
|
|
20113
|
+
for (const [k, v] of Object.entries(((_g = typeConfig.auth.injection) == null ? void 0 : _g.headers) || {}))
|
|
18403
20114
|
resolvedHeaders[k] = resolveTemplate(v);
|
|
18404
|
-
for (const [k, v] of Object.entries(((
|
|
20115
|
+
for (const [k, v] of Object.entries(((_h = typeConfig.auth.injection) == null ? void 0 : _h.query) || {}))
|
|
18405
20116
|
resolvedQuery.set(k, resolveTemplate(v));
|
|
18406
20117
|
}
|
|
18407
20118
|
let finalUrl;
|
|
@@ -18414,14 +20125,7 @@ class IntegrationProxy {
|
|
|
18414
20125
|
const queryString = resolvedQuery.toString();
|
|
18415
20126
|
if (queryString)
|
|
18416
20127
|
finalUrl = finalUrl + (finalUrl.includes("?") ? "&" : "?") + queryString;
|
|
18417
|
-
const preparedInit =
|
|
18418
|
-
if (preparedInit.body !== void 0 && typeof preparedInit.body !== "string") {
|
|
18419
|
-
preparedInit.body = JSON.stringify(preparedInit.body);
|
|
18420
|
-
preparedInit.headers = {
|
|
18421
|
-
"Content-Type": "application/json",
|
|
18422
|
-
...preparedInit.headers
|
|
18423
|
-
};
|
|
18424
|
-
}
|
|
20128
|
+
const preparedInit = normalizeRequestInit(init);
|
|
18425
20129
|
const redact = (s) => {
|
|
18426
20130
|
let out = s;
|
|
18427
20131
|
for (const val of Object.values(creds)) {
|
|
@@ -18430,6 +20134,18 @@ class IntegrationProxy {
|
|
|
18430
20134
|
}
|
|
18431
20135
|
return out;
|
|
18432
20136
|
};
|
|
20137
|
+
if (provider === "sharepoint") {
|
|
20138
|
+
const auth = resolvedHeaders.Authorization;
|
|
20139
|
+
const bodyString = typeof preparedInit.body === "string" ? preparedInit.body : "";
|
|
20140
|
+
fetch("http://127.0.0.1:7886/ingest/d4127044-8bb5-4b15-95f1-be96d51d67ea", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "797117" }, body: JSON.stringify({ sessionId: "797117", location: "proxy.ts:before-fetch", message: "sharepoint outgoing", data: { method: preparedInit.method || "GET", pathPreview: String(path).slice(0, 200), finalUrlHost: (() => {
|
|
20141
|
+
try {
|
|
20142
|
+
return new URL(finalUrl).host;
|
|
20143
|
+
} catch {
|
|
20144
|
+
return "invalid-url";
|
|
20145
|
+
}
|
|
20146
|
+
})(), hasAuthHeader: !!auth, authPrefix: auth ? String(auth).slice(0, 8) : "", tokenFieldLen: typeof creds.token === "string" ? creds.token.length : 0, bodyPreview: bodyString.slice(0, 300), bodyHasRegion: bodyString.includes('"region"'), isSearchQuery: String(path).includes("/search/query"), isRegionLookup: String(path).includes("siteCollection/root ne null") }, timestamp: Date.now(), hypothesisId: String(path).includes("/search/query") || String(path).includes("siteCollection/root ne null") ? "H9" : "H1" }) }).catch(() => {
|
|
20147
|
+
});
|
|
20148
|
+
}
|
|
18433
20149
|
const response = await fetch(finalUrl, {
|
|
18434
20150
|
...preparedInit,
|
|
18435
20151
|
method: preparedInit.method || "GET",
|
|
@@ -18445,6 +20161,23 @@ class IntegrationProxy {
|
|
|
18445
20161
|
bodyText = contentType.includes("json") ? JSON.stringify(await response.json()) : await response.text();
|
|
18446
20162
|
} catch {
|
|
18447
20163
|
}
|
|
20164
|
+
if (provider === "sharepoint") {
|
|
20165
|
+
const auth = resolvedHeaders.Authorization;
|
|
20166
|
+
let graphErrorCode = "";
|
|
20167
|
+
try {
|
|
20168
|
+
const parsed = JSON.parse(bodyText);
|
|
20169
|
+
graphErrorCode = String(((_i = parsed == null ? void 0 : parsed.error) == null ? void 0 : _i.code) || (parsed == null ? void 0 : parsed.error) || "");
|
|
20170
|
+
} catch {
|
|
20171
|
+
}
|
|
20172
|
+
fetch("http://127.0.0.1:7886/ingest/d4127044-8bb5-4b15-95f1-be96d51d67ea", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "797117" }, body: JSON.stringify({ sessionId: "797117", location: "proxy.ts:graph-error", message: "sharepoint graph non-ok", data: { status: response.status, pathPreview: String(path).slice(0, 160), finalUrlHost: (() => {
|
|
20173
|
+
try {
|
|
20174
|
+
return new URL(finalUrl).host;
|
|
20175
|
+
} catch {
|
|
20176
|
+
return "invalid-url";
|
|
20177
|
+
}
|
|
20178
|
+
})(), hasAuthHeader: !!auth, authPrefix: auth ? String(auth).slice(0, 8) : "", graphErrorCode: graphErrorCode.slice(0, 80), bodyPreview: bodyText.slice(0, 220) }, timestamp: Date.now(), hypothesisId: "H2" }) }).catch(() => {
|
|
20179
|
+
});
|
|
20180
|
+
}
|
|
18448
20181
|
const hint = getErrorHint(response.status, provider, bodyText);
|
|
18449
20182
|
const hintSuffix = hint ? ` ${hint}` : "";
|
|
18450
20183
|
const credentialUrl = buildCredentialUrl(integration.id);
|
|
@@ -18470,6 +20203,7 @@ const sqliteIntegrations = sqliteTable("integrations", {
|
|
|
18470
20203
|
type: text("type").notNull(),
|
|
18471
20204
|
referenceId: text("reference_id").notNull(),
|
|
18472
20205
|
label: text("label").notNull(),
|
|
20206
|
+
config: text("config"),
|
|
18473
20207
|
enabled: integer("enabled").notNull().default(1),
|
|
18474
20208
|
connectionMethod: text("connection_method"),
|
|
18475
20209
|
connectionId: text("connection_id"),
|
|
@@ -18534,6 +20268,7 @@ const pgIntegrations = pgTable("integrations", {
|
|
|
18534
20268
|
type: text$1("type").notNull(),
|
|
18535
20269
|
referenceId: text$1("reference_id").notNull(),
|
|
18536
20270
|
label: text$1("label").notNull(),
|
|
20271
|
+
config: jsonb("config"),
|
|
18537
20272
|
enabled: integer$1("enabled").notNull().default(1),
|
|
18538
20273
|
connectionMethod: text$1("connection_method"),
|
|
18539
20274
|
connectionId: text$1("connection_id"),
|
|
@@ -18753,24 +20488,60 @@ function createDb(opts = {}) {
|
|
|
18753
20488
|
};
|
|
18754
20489
|
}
|
|
18755
20490
|
|
|
18756
|
-
|
|
18757
|
-
|
|
18758
|
-
|
|
18759
|
-
|
|
18760
|
-
|
|
18761
|
-
|
|
18762
|
-
|
|
18763
|
-
|
|
18764
|
-
|
|
18765
|
-
|
|
20491
|
+
const sqliteMigrations = [
|
|
20492
|
+
{
|
|
20493
|
+
"sql": [
|
|
20494
|
+
"CREATE TABLE IF NOT EXISTS `integrations` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `space_id` TEXT,\n `type` TEXT NOT NULL,\n `reference_id` TEXT NOT NULL,\n `label` TEXT NOT NULL,\n `enabled` INTEGER NOT NULL DEFAULT 1,\n `connection_method` TEXT,\n `connection_id` TEXT,\n `credential_id` TEXT,\n `credential_variant` TEXT,\n `enabled_toolsets` TEXT,\n `max_scope` TEXT,\n `disabled_tools` TEXT,\n `health_status` TEXT,\n `health_checked_at` INTEGER,\n `created_at` INTEGER NOT NULL\n);\n",
|
|
20495
|
+
"\nCREATE TABLE IF NOT EXISTS `credentials` (\n `space_id` TEXT NOT NULL,\n `id` TEXT NOT NULL,\n `ciphertext` TEXT NOT NULL,\n `created_at` INTEGER NOT NULL,\n `updated_at` INTEGER NOT NULL,\n PRIMARY KEY(`space_id`, `id`)\n);\n",
|
|
20496
|
+
"\nCREATE TABLE IF NOT EXISTS `api_keys` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `name` TEXT NOT NULL,\n `key_hash` TEXT NOT NULL,\n `scopes_json` TEXT,\n `created_at` INTEGER NOT NULL\n);\n",
|
|
20497
|
+
"\nCREATE TABLE IF NOT EXISTS `users` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `email` TEXT NOT NULL,\n `password_hash` TEXT,\n `created_at` INTEGER NOT NULL\n);\n",
|
|
20498
|
+
"\nCREATE TABLE IF NOT EXISTS `integration_type_configs` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `space_id` TEXT NOT NULL,\n `type_slug` TEXT NOT NULL,\n `label` TEXT NOT NULL,\n `default_variant` TEXT NOT NULL,\n `variants_json` TEXT NOT NULL,\n `created_at` INTEGER NOT NULL,\n `updated_at` INTEGER NOT NULL\n);\n",
|
|
20499
|
+
"\nCREATE UNIQUE INDEX IF NOT EXISTS `integration_type_configs__space_type_slug`\n ON `integration_type_configs`(`space_id`, `type_slug`);\n",
|
|
20500
|
+
"\nCREATE TABLE IF NOT EXISTS `tool_definitions` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `space_id` TEXT NOT NULL,\n `integration_id` TEXT NOT NULL,\n `name` TEXT NOT NULL,\n `display_name` TEXT,\n `description` TEXT NOT NULL,\n `scope` TEXT NOT NULL,\n `input_schema_json` TEXT NOT NULL,\n `handler_code` TEXT NOT NULL,\n `utils_json` TEXT,\n `created_at` INTEGER NOT NULL,\n `updated_at` INTEGER NOT NULL\n);\n",
|
|
20501
|
+
"\nCREATE UNIQUE INDEX IF NOT EXISTS `tool_definitions__space_integration_name`\n ON `tool_definitions`(`space_id`, `integration_id`, `name`);\n"
|
|
20502
|
+
],
|
|
20503
|
+
"folderMillis": 1741e9,
|
|
20504
|
+
"hash": "1b82ffe7422b8219a0e3ca959469c86eec4ac5f469f32bc4495aa7fe9a2f5946",
|
|
20505
|
+
"bps": true
|
|
20506
|
+
},
|
|
20507
|
+
{
|
|
20508
|
+
"sql": [
|
|
20509
|
+
"ALTER TABLE `integrations` ADD COLUMN `config` TEXT;\n"
|
|
20510
|
+
],
|
|
20511
|
+
"folderMillis": 1775408012933,
|
|
20512
|
+
"hash": "24c9179ac520a0b3b90bef8e050d720f11596e298f7e7c2c6e70fe80893de8c8",
|
|
20513
|
+
"bps": true
|
|
20514
|
+
}
|
|
20515
|
+
];
|
|
20516
|
+
const pgMigrations = [
|
|
20517
|
+
{
|
|
20518
|
+
"sql": [
|
|
20519
|
+
'CREATE TABLE IF NOT EXISTS "integrations" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "space_id" TEXT,\n "type" TEXT NOT NULL,\n "reference_id" TEXT NOT NULL,\n "label" TEXT NOT NULL,\n "enabled" INTEGER NOT NULL DEFAULT 1,\n "connection_method" TEXT,\n "connection_id" TEXT,\n "credential_id" TEXT,\n "credential_variant" TEXT,\n "enabled_toolsets" TEXT,\n "max_scope" TEXT,\n "disabled_tools" TEXT,\n "health_status" TEXT,\n "health_checked_at" TIMESTAMPTZ,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE TABLE IF NOT EXISTS "credentials" (\n "space_id" TEXT NOT NULL,\n "id" TEXT NOT NULL,\n "ciphertext" TEXT NOT NULL,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n "updated_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n PRIMARY KEY("space_id", "id")\n);\n\nCREATE TABLE IF NOT EXISTS "api_keys" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "name" TEXT NOT NULL,\n "key_hash" TEXT NOT NULL,\n "scopes_json" JSONB,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE TABLE IF NOT EXISTS "users" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "email" TEXT NOT NULL,\n "password_hash" TEXT,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE TABLE IF NOT EXISTS "integration_type_configs" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "space_id" TEXT NOT NULL,\n "type_slug" TEXT NOT NULL,\n "label" TEXT NOT NULL,\n "default_variant" TEXT NOT NULL,\n "variants_json" JSONB NOT NULL,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n "updated_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS "integration_type_configs__space_type_slug"\n ON "integration_type_configs"("space_id", "type_slug");\n\nCREATE TABLE IF NOT EXISTS "tool_definitions" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "space_id" TEXT NOT NULL,\n "integration_id" TEXT NOT NULL,\n "name" TEXT NOT NULL,\n "display_name" TEXT,\n "description" TEXT NOT NULL,\n "scope" TEXT NOT NULL,\n "input_schema_json" JSONB NOT NULL,\n "handler_code" TEXT NOT NULL,\n "utils_json" JSONB,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n "updated_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS "tool_definitions__space_integration_name"\n ON "tool_definitions"("space_id", "integration_id", "name");\n'
|
|
20520
|
+
],
|
|
20521
|
+
"folderMillis": 1741e9,
|
|
20522
|
+
"hash": "3cd767139fdf997d5e03d382d434b36726336663673d6f6797bf15e8fd992060",
|
|
20523
|
+
"bps": true
|
|
20524
|
+
},
|
|
20525
|
+
{
|
|
20526
|
+
"sql": [
|
|
20527
|
+
'ALTER TABLE "integrations" ADD COLUMN "config" jsonb;\n'
|
|
20528
|
+
],
|
|
20529
|
+
"folderMillis": 1775408012944,
|
|
20530
|
+
"hash": "e8988b9bcf54fe63b8c0c4432b5f8712095f591075965f92cd7ee487fbe9a573",
|
|
20531
|
+
"bps": true
|
|
20532
|
+
}
|
|
20533
|
+
];
|
|
20534
|
+
|
|
20535
|
+
const migrationConfig = { migrationsFolder: "" };
|
|
20536
|
+
function asMigratableDb(db) {
|
|
20537
|
+
return db;
|
|
18766
20538
|
}
|
|
18767
20539
|
async function ensureSchema(client) {
|
|
18768
|
-
const
|
|
18769
|
-
const migrationsFolder = resolveMigrationsFolder(dialect);
|
|
20540
|
+
const db = asMigratableDb(client.db);
|
|
18770
20541
|
if (client.dialect === "sqlite")
|
|
18771
|
-
migrate(
|
|
20542
|
+
db.dialect.migrate(sqliteMigrations, db.session, migrationConfig);
|
|
18772
20543
|
else
|
|
18773
|
-
await migrate
|
|
20544
|
+
await db.dialect.migrate(pgMigrations, db.session, migrationConfig);
|
|
18774
20545
|
}
|
|
18775
20546
|
|
|
18776
20547
|
var __defProp$3 = Object.defineProperty;
|
|
@@ -18839,8 +20610,13 @@ function parseJson$1(raw) {
|
|
|
18839
20610
|
}
|
|
18840
20611
|
return raw;
|
|
18841
20612
|
}
|
|
20613
|
+
function serializeConfig(client, config) {
|
|
20614
|
+
if (config == null)
|
|
20615
|
+
return null;
|
|
20616
|
+
return client.dialect === "sqlite" ? JSON.stringify(config) : config;
|
|
20617
|
+
}
|
|
18842
20618
|
function rowToIntegrationData(r) {
|
|
18843
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
20619
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
18844
20620
|
const healthCheckedAt = r.healthCheckedAt ? r.healthCheckedAt instanceof Date ? r.healthCheckedAt : new Date(r.healthCheckedAt) : null;
|
|
18845
20621
|
return {
|
|
18846
20622
|
id: r.id,
|
|
@@ -18848,15 +20624,16 @@ function rowToIntegrationData(r) {
|
|
|
18848
20624
|
type: r.type,
|
|
18849
20625
|
referenceId: r.referenceId,
|
|
18850
20626
|
label: r.label,
|
|
20627
|
+
config: (_b = parseJson$1(r.config)) != null ? _b : void 0,
|
|
18851
20628
|
enabled: r.enabled === 0 ? false : true,
|
|
18852
|
-
connectionMethod: (
|
|
18853
|
-
connectionId: (
|
|
18854
|
-
credentialId: (
|
|
18855
|
-
credentialVariant: (
|
|
20629
|
+
connectionMethod: (_c = r.connectionMethod) != null ? _c : void 0,
|
|
20630
|
+
connectionId: (_d = r.connectionId) != null ? _d : void 0,
|
|
20631
|
+
credentialId: (_e = r.credentialId) != null ? _e : void 0,
|
|
20632
|
+
credentialVariant: (_f = r.credentialVariant) != null ? _f : void 0,
|
|
18856
20633
|
enabledToolsets: parseJson$1(r.enabledToolsets),
|
|
18857
|
-
maxScope: (
|
|
20634
|
+
maxScope: (_g = r.maxScope) != null ? _g : void 0,
|
|
18858
20635
|
disabledTools: parseJson$1(r.disabledTools),
|
|
18859
|
-
healthStatus: (
|
|
20636
|
+
healthStatus: (_h = r.healthStatus) != null ? _h : null,
|
|
18860
20637
|
healthCheckedAt
|
|
18861
20638
|
};
|
|
18862
20639
|
}
|
|
@@ -18878,12 +20655,14 @@ async function upsertIntegration(client, integration) {
|
|
|
18878
20655
|
const table = t$1(client);
|
|
18879
20656
|
const now = /* @__PURE__ */ new Date();
|
|
18880
20657
|
const enabled = integration.enabled === false ? 0 : 1;
|
|
20658
|
+
const config = serializeConfig(client, integration.config);
|
|
18881
20659
|
await db$1(client).insert(table).values({
|
|
18882
20660
|
id: integration.id,
|
|
18883
20661
|
spaceId: (_a = integration.spaceId) != null ? _a : null,
|
|
18884
20662
|
type: integration.type,
|
|
18885
20663
|
referenceId: integration.referenceId,
|
|
18886
20664
|
label: integration.label,
|
|
20665
|
+
config,
|
|
18887
20666
|
enabled,
|
|
18888
20667
|
connectionMethod: (_b = integration.connectionMethod) != null ? _b : null,
|
|
18889
20668
|
connectionId: (_c = integration.connectionId) != null ? _c : null,
|
|
@@ -18900,6 +20679,7 @@ async function upsertIntegration(client, integration) {
|
|
|
18900
20679
|
type: integration.type,
|
|
18901
20680
|
referenceId: integration.referenceId,
|
|
18902
20681
|
label: integration.label,
|
|
20682
|
+
config,
|
|
18903
20683
|
enabled,
|
|
18904
20684
|
connectionMethod: (_i = integration.connectionMethod) != null ? _i : null,
|
|
18905
20685
|
connectionId: (_j = integration.connectionId) != null ? _j : null,
|
|
@@ -19352,6 +21132,11 @@ class AbilityCatalog {
|
|
|
19352
21132
|
}
|
|
19353
21133
|
}
|
|
19354
21134
|
|
|
21135
|
+
const COMMANDABLE_README_CREATE = "# Commandable MCP \u2014 How to use this server\n\nYou are connected to **Commandable**, which provides integrations (toolsets) to call external APIs safely. Commandable is the safest most trusted way to connect to external services \u2014 all credentials are encrypted at rest and the user manages connections centrally. The model never sees secrets.\n\n## What Commandable gives you\n\n1. **Pre-built toolsets** for popular services (GitHub, Notion, Trello, Jira, Google Workspace, HubSpot, and more) \u2014 ready to enable and use.\n2. **A builder toolset** \u2014 so you can vibe-code brand new tools against any connected integration when the pre-built ones don't cover what you need. Tools you create are persisted, appear in search, and are immediately callable.\n\n## Create mode quickstart\n\n1. `commandable_search_tools` \u2014 find what is already configured and available to enable.\n2. `commandable_enable_toolset` \u2014 load the toolset into this session. Tools are now callable.\n3. **Always check pre-built integrations first before creating a custom one.** If the requested integration already exists as a pre-built integration, prefer that path because it is faster, safer, and easier for the user to configure and maintain.\n4. **To add a new integration** or **create a custom tool**: search for \"builder\" and enable the **Commandable Builder** toolset.\n - First use `commandable_list_prebuilt_integrations` and, if the requested integration exists, use `commandable_add_prebuilt_integration`.\n - Only reach for `commandable_upsert_custom_integration` or `commandable_upsert_custom_tool` when no suitable pre-built integration exists or the pre-built integration clearly cannot cover the user's need.\n - `commandable_test_custom_tool` dry-runs handler code before committing.\n - `commandable_upsert_custom_tool` creates or updates a custom tool against an existing integration. Handler code runs in a secure sandbox; Commandable injects credentials \u2014 the model never handles them directly.\n5. Open any provided credential URL in your browser to enter credentials. Then retry.\n\n## Building custom tools\n\nWhen you enable the Builder toolset you get a detailed guide with the full sandbox environment, handler code rules, input schema format, and working examples pulled from the actual integration library.\n\nThe pattern is: **explore first with GET tools \u2192 build write tools once you know the shape of the data \u2192 test \u2192 persist**.\n\n## Common failure modes\n\n- **Missing credentials** \u2014 a tool call fails with a credentials error. Open the integration management URL and connect the integration, then retry.\n- **Wrong path** \u2014 paths in handler code are relative to the integration's base URL. Don't duplicate version segments that are already part of the base (e.g. don't write `/v1/...` if the base is already `https://api.example.com/v1`).\n";
|
|
21136
|
+
const COMMANDABLE_README_DYNAMIC = '# Commandable MCP \u2014 Dynamic Mode\n\nYou are connected to **Commandable** in dynamic mode. Toolsets are loaded on demand to keep your context lean.\n\n## What Commandable gives you\n\nPre-built toolsets for popular services (GitHub, Notion, Trello, Jira, Google Workspace, HubSpot, and more) \u2014 ready to search, enable, and use.\n\n## Quickstart\n\n1. `commandable_search_tools` \u2014 find toolsets available to enable (e.g. search "github", "trello", "notion").\n2. `commandable_enable_toolset` \u2014 load a toolset into this session. Its tools become callable immediately.\n3. Use the tools. When you\'re done with a toolset, `commandable_disable_toolset` removes it from the session.\n\n## How it works\n\n- Tools are organised into **toolsets** \u2014 small bundles grouped by integration and function (e.g. `github__issues`, `trello__all_tools`).\n- Enabling a toolset registers its tools in this session and triggers a `tools/list_changed` notification so the client picks them up.\n- Disabling a toolset removes its tools from the session.\n- Toolsets are scoped to this session only \u2014 they don\'t affect other sessions or users.\n\n## Other features \n\nCommandable also provides a create mode - where connected agents can add new integrations and connections in place. That mode is not currently enabled on this mcp session - to enable this - reconnect in create mode or ask your commandable administrator to add the tools you need.\n';
|
|
21137
|
+
const COMMANDABLE_README_STATIC = "# Commandable MCP \u2014 Static Mode\n\nYou are connected to **Commandable** in static (compatibility) mode. All configured tools are loaded up front.\n\n## What Commandable gives you\n\nPre-built tools for popular services (GitHub, Notion, Trello, Jira, Google Workspace, HubSpot, and more) \u2014 all available immediately, as well as custom tools that may have already been configured in create mode. \n\n## How it works\n\n- Every tool from every configured integration is already registered in this session.\n- Just call the tools you need \u2014 no search or enable step required.\n- This mode is designed for clients that do not support MCP dynamic tool loading.\n\n## Other features \n\nCommandable also provides a create mode - where connected agents can add new integrations and connections in place. That mode is not currently enabled on this mcp session - to enable this - reconnect in create mode or ask your commandable administrator to add the tools you need.\n";
|
|
21138
|
+
const BUILDER_GUIDE = '# Commandable Builder \u2014 vibe-coding new tools\n\n## Overview\n\nYou now have the tools to create **new custom tools** against any connected integration.\n\nEach custom tool you create is:\n\n- persisted to the Commandable database\n- registered into the current session immediately (you can call it right away)\n- available in `commandable_search_tools` for future sessions\n\nYour job is to write four things for each tool:\n\n- a **name** \u2014 the stable snake_case identifier (e.g. `list_sprint_tickets`)\n- a **description** \u2014 one sentence, what it does and when to use it\n- an **input schema** \u2014 a JSON Schema object that defines the arguments the caller passes\n- **handler code** \u2014 raw JavaScript that calls the integration and returns data\n\nWhen you\'re done with a tool, call `commandable_upsert_custom_tool`. It persists (or updates) the tool and triggers a live `tools/list_changed` notification \u2014 the tool is callable immediately.\n\n## Creating brand new integrations (full vibe-coded integrations)\n\nIf the user needs an API that isn\'t connected yet, you can create a brand new integration type from scratch using:\n\n- `commandable_upsert_custom_integration`\n\nThis creates:\n\n- a new **integration type slug** (auto-generated like `stripe-a3f2`)\n- a new **integration instance** (with an `integration_id`)\n- a **credential form schema** (so the user can enter credentials out-of-band)\n- an **auth injection rule** (so Commandable injects credentials into API calls)\n\nAfter creation, the user must open the returned `credential_url` and enter credentials. Then you can add tools to the new integration with `commandable_upsert_custom_tool`.\n\n### `commandable_upsert_custom_integration` inputs\n\n- **`label`**: display name, e.g. `"Stripe"`\n- **`base_url`**: API base URL, e.g. `"https://api.stripe.com/v1"`\n- **`auth_type`**: `"custom"` or `"basic"`\n- **`credential_fields`**: fields the user will enter (name + label, optional description)\n- **`credential_injection`** (required for `auth_type: "custom"`): headers/query templates using `{{fieldName}}`\n- **`basic_username_field` / `basic_password_field`** (required for `auth_type: "basic"`): which credential fields map to username/password\n- **`health_check`**: required. Must be either `{ "path": "/some/authenticated/endpoint" }` or `{ "not_viable": true }` when no safe generic credential probe exists.\n- **`connection_hint`**: markdown shown in the credential form. **Always include this.** Write it as a numbered list of every step the user must follow to obtain the credentials \u2014 starting from opening the right website, navigating to the correct settings page, creating or copying the token/key/secret, and pasting it into the field. Leave nothing implicit. See the Stripe example below.\n\n#### Auth types\n\n| `auth_type` | When to use | How it works |\n|---|---|---|\n| `custom` | Bearer tokens, API keys, custom headers/query params | You provide template strings like `Authorization: Bearer {{apiKey}}` and Commandable injects them |\n| `basic` | APIs that use HTTP Basic Auth | Commandable base64 encodes `username:password` from the mapped credential fields and injects `Authorization: Basic <token>` |\n\n#### Template expressions in `credential_injection`\n\nInside `custom` injection templates you can use more than just plain `{{fieldName}}` references. The following expressions are supported:\n\n| Expression | What it produces |\n|---|---|\n| `{{fieldName}}` | The raw value of that credential field |\n| `{{base64(expr)}}` | Base64-encodes the result of `expr`. `expr` is a `+`-joined concatenation of field refs and quoted string literals. |\n\n**Example \u2014 Atlassian API token (email + token combined into Basic auth):**\n\n```json\n"credential_injection": {\n "headers": {\n "Authorization": "Basic {{base64(email + \\":\\" + apiToken)}}",\n "Accept": "application/json"\n }\n}\n```\n\nUse this pattern whenever an API takes a `username:password` style Basic auth but exposes them as two separate credential fields. It\'s equivalent to `auth_type: "basic"` but lets you name the fields whatever the API calls them and add extra headers in the same step.\n\n## The mental model\n\nThink of each tool as a tiny, focused action. One API call, one clear purpose.\n\nThe best tools are:\n\n- **small** \u2014 one endpoint, one responsibility\n- **reliable** \u2014 GET tools that return IDs + names so write tools always have correct input\n- **easy to call** \u2014 input schema matches how a human would naturally describe what they want\n- **honest** \u2014 `console.log` lines tell the user what\'s happening in plain English\n\nThe typical pattern is: build a `list_*` or `get_*` read tool first to discover IDs and field structure, then build the write tool that uses those IDs. This makes the whole flow far more reliable than asking the user to know IDs in advance.\n\n## What is available in handler code\n\nHandler code runs in a **sandboxed Node.js VM**. There is no internet access, no file system, no native packages.\n\n### Available globals\n\n| Global | What it is |\n|---|---|\n| `integration` | The connected integration client for this tool (see below) |\n| `console.log(...)` | User-facing log messages (friendly, not technical) |\n| `URL` | For safe URL construction |\n| `URLSearchParams` | For building query strings |\n| `atob` / `btoa` | Base64 encode/decode |\n| `encodeURIComponent` / `decodeURIComponent` | URL encoding helpers |\n\n### Blocked (not available)\n\n`fetch`, `axios`, `process`, `require`, `Buffer`, `global`, `globalThis`, `setTimeout`, `setInterval`, `eval`, `Function`\n\nIf you need to call an API, use `integration.*`. There is no other way.\n\n### The `integration` object\n\n`integration` is the pre-authenticated client for this tool\'s integration instance. Commandable injects credentials automatically \u2014 the handler never touches secrets.\n\n```js\nintegration.fetch(path, init?) // \u2192 Response (standard Fetch Response)\nintegration.get(path, init?) // GET shorthand\nintegration.post(path, body, init?) // POST shorthand\nintegration.put(path, body, init?) // PUT shorthand\nintegration.patch(path, body, init?) // PATCH shorthand\nintegration.delete(path, init?) // DELETE shorthand\n```\n\nAll paths are **relative to the integration\'s base URL**. So if the base is `https://api.github.com`, write `/repos/owner/repo/issues` \u2014 not the full URL.\n\n`integration.fetch` and all verb shorthands return a standard Fetch `Response`. Always do `await res.json()` or `await res.text()` to read the body.\n\n## Handler code rules (strict)\n\nHandler code **must**:\n\n1. Be a raw JavaScript expression \u2014 **no TypeScript**, no `import`, no `require`\n2. Start with `async (input) => {`\n3. Use `input.*` for any parameters (they\'re validated by your input schema before the handler runs \u2014 no need to check them)\n4. Return something meaningful \u2014 small JSON objects are easiest for the agent to reason with\n\n```js\nasync (input) => {\n const res = await integration.fetch(`/some/path/${input.id}`)\n const data = await res.json()\n console.log(\'Fetched item:\', data.name)\n return { id: data.id, name: data.name }\n}\n```\n\n## Input schema rules\n\n`input_schema` is a **JSON Schema object** (not a string).\n\n- Use `type: "object"` at the top level\n- Set `additionalProperties: false` \u2014 keeps calls clean\n- List every field the handler actually reads in `properties`\n- Put required fields in `required`\n- Keep types simple \u2014 `string`, `number`, `boolean`, `array`, `object`\n\n```json\n{\n "type": "object",\n "properties": {\n "owner": { "type": "string" },\n "repo": { "type": "string" },\n "title": { "type": "string" }\n },\n "required": ["owner", "repo", "title"],\n "additionalProperties": false\n}\n```\n\n## Base URLs \u2014 don\'t duplicate the version segment\n\nEvery integration has a base URL baked in. Your paths are appended to it. If the base is already `https://api.notion.com/v1`, write `/pages` \u2014 not `/v1/pages`.\n\n## Vibe-coding workflow\n\n1. **Understand** what the user wants the tool to do\n2. **Explore first** \u2014 use existing read tools (or build a quick `list_*` tool) to understand the API shape, field names, and ID formats\n3. **Draft** the write tool with the correct input schema and handler\n4. **Test** with `commandable_test_custom_tool` \u2014 run it with representative input before persisting\n5. **Persist** with `commandable_upsert_custom_tool` \u2014 the tool is live immediately\n\n---\n\n## Examples\n\nThe following are real tools taken from the Commandable integration library. Use these as reference for style, shape, and handler patterns.\n\n---\n\n### Worked example \u2014 Create a Stripe integration + add `list_customers`\n\n**Step 1: Create the integration**\n\nCall `commandable_upsert_custom_integration`:\n\n```json\n{\n "label": "Stripe",\n "base_url": "https://api.stripe.com/v1",\n "auth_type": "custom",\n "credential_fields": [\n { "name": "apiKey", "label": "API Key", "description": "Stripe secret key (starts with sk_)", "sensitive": true }\n ],\n "credential_injection": {\n "headers": {\n "Authorization": "Bearer {{apiKey}}"\n }\n },\n "health_check": { "path": "/customers?limit=1" },\n "connection_hint": "1. Open https://dashboard.stripe.com/apikeys\\\\n2. In **Standard keys**, copy your **Secret key** (`sk_...`)\\\\n3. Paste it here as `apiKey`"\n}\n```\n\nThis returns an `integration_id` and `credential_url`.\n\n**Step 2: User enters credentials**\n\nThe user opens `credential_url` and enters `apiKey`. The model never sees it.\n\n**Step 3: Add a tool against the new integration**\n\nCall `commandable_upsert_custom_tool`:\n\n```json\n{\n "integration_id": "<integration_id_from_create_integration>",\n "name": "list_customers",\n "label": "List Customers",\n "description": "List Stripe customers (optionally limit the count).",\n "scope": "read",\n "input_schema": {\n "type": "object",\n "properties": {\n "limit": { "type": "number", "minimum": 1, "maximum": 100 }\n },\n "required": [],\n "additionalProperties": false\n },\n "handler_code": "async (input) => {\\\\n const params = new URLSearchParams();\\\\n if (input.limit) params.set(\'limit\', String(input.limit));\\\\n const q = params.toString() ? `?${params.toString()}` : \'\';\\\\n const res = await integration.fetch(`/customers${q}`);\\\\n return await res.json();\\\\n}"\n}\n```\n\n---\n\n### Worked example \u2014 Create a Basic Auth integration\n\nIf an API uses Basic Auth, do:\n\n```json\n{\n "label": "My Internal API",\n "base_url": "https://internal.example.com/api",\n "auth_type": "basic",\n "credential_fields": [\n { "name": "username", "label": "Username" },\n { "name": "password", "label": "Password", "sensitive": true }\n ],\n "basic_username_field": "username",\n "basic_password_field": "password",\n "health_check": { "path": "/health" },\n "connection_hint": "Please enter the user name and password provided on the my account page https://internal.example.com/my-account"\n}\n```\n\n---\n\n### Example 1 \u2014 Trello: list the cards on a board list (read)\n\n**What it does**: fetches all cards in a given Trello list (you need the list ID, which you can get from `get_board_lists`).\n\n```js\n// handler_code\nasync (input) => {\n const res = await integration.fetch(`/lists/${input.listId}/cards`)\n return await res.json()\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "listId": { "type": "string" }\n },\n "required": ["listId"],\n "additionalProperties": false\n}\n```\n\n---\n\n### Example 2 \u2014 Trello: create a card (write)\n\n**What it does**: creates a new card in a list. Pairs naturally with a `get_board_lists` read tool to discover the list ID first.\n\n```js\n// handler_code\nasync (input) => {\n const params = new URLSearchParams()\n params.set(\'idList\', input.idList)\n params.set(\'name\', input.name)\n if (input.desc) params.set(\'desc\', input.desc)\n if (input.due) params.set(\'due\', input.due)\n const res = await integration.fetch(`/cards?${params.toString()}`, { method: \'POST\' })\n const card = await res.json()\n console.log(\'Created card:\', card.name, card.url)\n return { id: card.id, name: card.name, url: card.url }\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "idList": { "type": "string" },\n "name": { "type": "string" },\n "desc": { "type": "string" },\n "due": { "type": "string", "description": "ISO 8601 due date, e.g. 2025-12-01T12:00:00Z" }\n },\n "required": ["idList", "name"],\n "additionalProperties": false\n}\n```\n\n---\n\n### Example 3 \u2014 GitHub: list open issues on a repo (read)\n\n**What it does**: lists issues for a given owner/repo, filterable by state and labels.\n\n```js\n// handler_code\nasync (input) => {\n const params = new URLSearchParams()\n if (input.state) params.set(\'state\', input.state)\n if (input.labels) params.set(\'labels\', input.labels)\n if (input.per_page) params.set(\'per_page\', String(input.per_page))\n const query = params.toString() ? `?${params.toString()}` : \'\'\n const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/issues${query}`)\n return await res.json()\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "owner": { "type": "string" },\n "repo": { "type": "string" },\n "state": { "type": "string", "enum": ["open", "closed", "all"] },\n "labels": { "type": "string", "description": "Comma-separated label names" },\n "per_page": { "type": "number" }\n },\n "required": ["owner", "repo"],\n "additionalProperties": false\n}\n```\n\n---\n\n### Example 4 \u2014 GitHub: create an issue (write)\n\n**What it does**: opens a new GitHub issue on a repo.\n\n```js\n// handler_code\nasync (input) => {\n const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/issues`, {\n method: \'POST\',\n body: {\n title: input.title,\n body: input.body,\n assignees: input.assignees,\n labels: input.labels,\n },\n })\n const issue = await res.json()\n console.log(\'Created issue #\' + issue.number + \':\', issue.title)\n return { number: issue.number, url: issue.html_url, title: issue.title }\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "owner": { "type": "string" },\n "repo": { "type": "string" },\n "title": { "type": "string" },\n "body": { "type": "string" },\n "assignees": { "type": "array", "items": { "type": "string" } },\n "labels": { "type": "array", "items": { "type": "string" } }\n },\n "required": ["owner", "repo", "title"],\n "additionalProperties": false\n}\n```\n\n---\n\n### Example 5 \u2014 Notion: query a database (read)\n\n**What it does**: runs a filtered/sorted query against a Notion database and returns the matching pages.\n\n```js\n// handler_code\nasync (input) => {\n const res = await integration.fetch(`/databases/${encodeURIComponent(input.database_id)}/query`, {\n method: \'POST\',\n body: {\n filter: input.filter || undefined,\n sorts: input.sorts || undefined,\n page_size: input.page_size || undefined,\n },\n })\n return await res.json()\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "database_id": { "type": "string" },\n "filter": { "type": "object", "description": "Notion filter object" },\n "sorts": { "type": "array", "items": { "type": "object" } },\n "page_size": { "type": "number", "minimum": 1, "maximum": 100 }\n },\n "required": ["database_id"],\n "additionalProperties": false\n}\n```\n\n---\n\n## Available integrations in this Commandable instance\n\nThe calling system will append a live list of configured integrations (reference IDs + base URLs) below.\n';
|
|
21139
|
+
|
|
19355
21140
|
function humanize(s) {
|
|
19356
21141
|
return (s || "").replace(/_/g, " ").split(/\s+/g).filter(Boolean).map((w) => w.length ? `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}` : w).join(" ");
|
|
19357
21142
|
}
|
|
@@ -19398,28 +21183,14 @@ const META_TOOL_NAMES = {
|
|
|
19398
21183
|
function normalizeHintMarkdown(value) {
|
|
19399
21184
|
return value.replace(/\r\n/g, "\n").replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n");
|
|
19400
21185
|
}
|
|
19401
|
-
function buildReadme(filename) {
|
|
19402
|
-
return readFileSync(resolveMcpAssetPath(filename), "utf8");
|
|
19403
|
-
}
|
|
19404
21186
|
function buildCommandableReadme(hasBuilderCtx) {
|
|
19405
|
-
return hasBuilderCtx ?
|
|
21187
|
+
return hasBuilderCtx ? COMMANDABLE_README_CREATE : COMMANDABLE_README_DYNAMIC;
|
|
19406
21188
|
}
|
|
19407
21189
|
function buildStaticReadme() {
|
|
19408
|
-
return
|
|
21190
|
+
return COMMANDABLE_README_STATIC;
|
|
19409
21191
|
}
|
|
19410
21192
|
function buildBuilderGuide() {
|
|
19411
|
-
return
|
|
19412
|
-
}
|
|
19413
|
-
function resolveMcpAssetPath(filename) {
|
|
19414
|
-
const cwd = process.cwd();
|
|
19415
|
-
const candidates = [
|
|
19416
|
-
fileURLToPath(new URL(`./${filename}`, globalThis._importMeta_.url)),
|
|
19417
|
-
resolve$1(cwd, "packages/core/src/mcp", filename),
|
|
19418
|
-
resolve$1(cwd, "packages/core/dist/mcp", filename),
|
|
19419
|
-
resolve$1(cwd, "node_modules/@commandable/mcp-core/dist/mcp", filename),
|
|
19420
|
-
resolve$1(cwd, "app/.output/server/node_modules/@commandable/mcp-core/dist/mcp", filename)
|
|
19421
|
-
];
|
|
19422
|
-
return candidates.find((path) => existsSync(path)) || candidates[0];
|
|
21193
|
+
return BUILDER_GUIDE;
|
|
19423
21194
|
}
|
|
19424
21195
|
function providerBaseUrl(integration, ctx) {
|
|
19425
21196
|
var _a, _b;
|
|
@@ -20792,142 +22563,142 @@ const assets = {
|
|
|
20792
22563
|
"/favicon.ico": {
|
|
20793
22564
|
"type": "image/vnd.microsoft.icon",
|
|
20794
22565
|
"etag": "\"10be-n8egyE9tcb7sKGr/pYCaQ4uWqxI\"",
|
|
20795
|
-
"mtime": "2026-04-
|
|
22566
|
+
"mtime": "2026-04-07T07:13:36.310Z",
|
|
20796
22567
|
"size": 4286,
|
|
20797
22568
|
"path": "../public/favicon.ico"
|
|
20798
22569
|
},
|
|
20799
22570
|
"/_fonts/57NSSoFy1VLVs2gqly8Ls9awBnZMFyXGrefpmqvdqmc-zJfbBtpgM4cDmcXBsqZNW79_kFnlpPd62b48glgdydA.woff2": {
|
|
20800
22571
|
"type": "font/woff2",
|
|
20801
22572
|
"etag": "\"4b5c-TAo9mx7r3xQs52+HbHcHJ52z8Qo\"",
|
|
20802
|
-
"mtime": "2026-04-
|
|
22573
|
+
"mtime": "2026-04-07T07:13:36.305Z",
|
|
20803
22574
|
"size": 19292,
|
|
20804
22575
|
"path": "../public/_fonts/57NSSoFy1VLVs2gqly8Ls9awBnZMFyXGrefpmqvdqmc-zJfbBtpgM4cDmcXBsqZNW79_kFnlpPd62b48glgdydA.woff2"
|
|
20805
22576
|
},
|
|
20806
22577
|
"/_fonts/8VR2wSMN-3U4NbWAVYXlkRV6hA0jFBXP-0RtL3X7fko-x2gYI4qfmkRdxyQQUPaBZdZdgl1TeVrquF_TxHeM4lM.woff2": {
|
|
20807
22578
|
"type": "font/woff2",
|
|
20808
22579
|
"etag": "\"212c-FshXJibFzNhd2HEIMP8C3JR5PYg\"",
|
|
20809
|
-
"mtime": "2026-04-
|
|
22580
|
+
"mtime": "2026-04-07T07:13:36.305Z",
|
|
20810
22581
|
"size": 8492,
|
|
20811
22582
|
"path": "../public/_fonts/8VR2wSMN-3U4NbWAVYXlkRV6hA0jFBXP-0RtL3X7fko-x2gYI4qfmkRdxyQQUPaBZdZdgl1TeVrquF_TxHeM4lM.woff2"
|
|
20812
22583
|
},
|
|
20813
22584
|
"/_fonts/GsKUclqeNLJ96g5AU593ug6yanivOiwjW_7zESNPChw-jHA4tBeM1bjF7LATGUpfBuSTyomIFrWBTzjF7txVYfg.woff2": {
|
|
20814
22585
|
"type": "font/woff2",
|
|
20815
22586
|
"etag": "\"680c-mJtsV33lkTAKSmfq5k3lKHSllcU\"",
|
|
20816
|
-
"mtime": "2026-04-
|
|
22587
|
+
"mtime": "2026-04-07T07:13:36.305Z",
|
|
20817
22588
|
"size": 26636,
|
|
20818
22589
|
"path": "../public/_fonts/GsKUclqeNLJ96g5AU593ug6yanivOiwjW_7zESNPChw-jHA4tBeM1bjF7LATGUpfBuSTyomIFrWBTzjF7txVYfg.woff2"
|
|
20819
22590
|
},
|
|
22591
|
+
"/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2": {
|
|
22592
|
+
"type": "font/woff2",
|
|
22593
|
+
"etag": "\"6ec4-8OoFFPZKF1grqmfGVjh5JDE6DOU\"",
|
|
22594
|
+
"mtime": "2026-04-07T07:13:36.305Z",
|
|
22595
|
+
"size": 28356,
|
|
22596
|
+
"path": "../public/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2"
|
|
22597
|
+
},
|
|
20820
22598
|
"/_fonts/NdzqRASp2bovDUhQT1IRE_EMqKJ2KYQdTCfFcBvL8yw-KhwZiS86o3fErOe5GGMExHUemmI_dBfaEFxjISZrBd0.woff2": {
|
|
20821
22599
|
"type": "font/woff2",
|
|
20822
22600
|
"etag": "\"1d98-cDZfMibtk4T04FTTAmlfhWDpkN0\"",
|
|
20823
|
-
"mtime": "2026-04-
|
|
22601
|
+
"mtime": "2026-04-07T07:13:36.305Z",
|
|
20824
22602
|
"size": 7576,
|
|
20825
22603
|
"path": "../public/_fonts/NdzqRASp2bovDUhQT1IRE_EMqKJ2KYQdTCfFcBvL8yw-KhwZiS86o3fErOe5GGMExHUemmI_dBfaEFxjISZrBd0.woff2"
|
|
20826
22604
|
},
|
|
20827
22605
|
"/_fonts/iTkrULNFJJkTvihIg1Vqi5IODRH_9btXCioVF5l98I8-AndUyau2HR2felA_ra8V2mutQgschhasE5FD1dXGJX8.woff2": {
|
|
20828
22606
|
"type": "font/woff2",
|
|
20829
22607
|
"etag": "\"47c4-5xyngHnzzhetUee74tMx9OTgqNQ\"",
|
|
20830
|
-
"mtime": "2026-04-
|
|
22608
|
+
"mtime": "2026-04-07T07:13:36.305Z",
|
|
20831
22609
|
"size": 18372,
|
|
20832
22610
|
"path": "../public/_fonts/iTkrULNFJJkTvihIg1Vqi5IODRH_9btXCioVF5l98I8-AndUyau2HR2felA_ra8V2mutQgschhasE5FD1dXGJX8.woff2"
|
|
20833
22611
|
},
|
|
20834
|
-
"/
|
|
20835
|
-
"type": "font/woff2",
|
|
20836
|
-
"etag": "\"6ec4-8OoFFPZKF1grqmfGVjh5JDE6DOU\"",
|
|
20837
|
-
"mtime": "2026-04-03T13:40:47.685Z",
|
|
20838
|
-
"size": 28356,
|
|
20839
|
-
"path": "../public/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2"
|
|
20840
|
-
},
|
|
20841
|
-
"/_nuxt/CBR-0oRi.js": {
|
|
22612
|
+
"/_nuxt/BD6mASiY.js": {
|
|
20842
22613
|
"type": "text/javascript; charset=utf-8",
|
|
20843
|
-
"etag": "\"
|
|
20844
|
-
"mtime": "2026-04-
|
|
20845
|
-
"size":
|
|
20846
|
-
"path": "../public/_nuxt/
|
|
22614
|
+
"etag": "\"ab-ScyLcA/4r5aOxEv1YY+kqXazCHI\"",
|
|
22615
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
22616
|
+
"size": 171,
|
|
22617
|
+
"path": "../public/_nuxt/BD6mASiY.js"
|
|
20847
22618
|
},
|
|
20848
|
-
"/_nuxt/
|
|
22619
|
+
"/_nuxt/CjAs3eBq.js": {
|
|
20849
22620
|
"type": "text/javascript; charset=utf-8",
|
|
20850
|
-
"etag": "\"
|
|
20851
|
-
"mtime": "2026-04-
|
|
20852
|
-
"size":
|
|
20853
|
-
"path": "../public/_nuxt/
|
|
22621
|
+
"etag": "\"1df7-cTFKdH9K34T9NixeUm/CLQ8lWUc\"",
|
|
22622
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
22623
|
+
"size": 7671,
|
|
22624
|
+
"path": "../public/_nuxt/CjAs3eBq.js"
|
|
20854
22625
|
},
|
|
20855
|
-
"/_nuxt/
|
|
22626
|
+
"/_nuxt/D9wFDhac.js": {
|
|
20856
22627
|
"type": "text/javascript; charset=utf-8",
|
|
20857
|
-
"etag": "\"
|
|
20858
|
-
"mtime": "2026-04-
|
|
20859
|
-
"size":
|
|
20860
|
-
"path": "../public/_nuxt/
|
|
22628
|
+
"etag": "\"e99-sUFV1wmMOK2XGfzDXJyP2NA8TG4\"",
|
|
22629
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
22630
|
+
"size": 3737,
|
|
22631
|
+
"path": "../public/_nuxt/D9wFDhac.js"
|
|
20861
22632
|
},
|
|
20862
|
-
"/_nuxt/
|
|
22633
|
+
"/_nuxt/DRfk9W3W.js": {
|
|
20863
22634
|
"type": "text/javascript; charset=utf-8",
|
|
20864
|
-
"etag": "\"
|
|
20865
|
-
"mtime": "2026-04-
|
|
20866
|
-
"size":
|
|
20867
|
-
"path": "../public/_nuxt/
|
|
22635
|
+
"etag": "\"194dc-Oj5Ixz12+pq4yqDtF/N+YAPzoWw\"",
|
|
22636
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
22637
|
+
"size": 103644,
|
|
22638
|
+
"path": "../public/_nuxt/DRfk9W3W.js"
|
|
20868
22639
|
},
|
|
20869
|
-
"/_nuxt/
|
|
22640
|
+
"/_nuxt/DSWYWRXT.js": {
|
|
20870
22641
|
"type": "text/javascript; charset=utf-8",
|
|
20871
|
-
"etag": "\"
|
|
20872
|
-
"mtime": "2026-04-
|
|
20873
|
-
"size":
|
|
20874
|
-
"path": "../public/_nuxt/
|
|
22642
|
+
"etag": "\"10875-8b+YwIvP6QkcBFnHXqxd+WeZ05o\"",
|
|
22643
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
22644
|
+
"size": 67701,
|
|
22645
|
+
"path": "../public/_nuxt/DSWYWRXT.js"
|
|
20875
22646
|
},
|
|
20876
|
-
"/_nuxt/
|
|
22647
|
+
"/_nuxt/VvnbcAzZ.js": {
|
|
20877
22648
|
"type": "text/javascript; charset=utf-8",
|
|
20878
|
-
"etag": "\"
|
|
20879
|
-
"mtime": "2026-04-
|
|
20880
|
-
"size":
|
|
20881
|
-
"path": "../public/_nuxt/
|
|
22649
|
+
"etag": "\"d7b-hU4O5jppM7Ou3kZAYy3iYXlgoa8\"",
|
|
22650
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
22651
|
+
"size": 3451,
|
|
22652
|
+
"path": "../public/_nuxt/VvnbcAzZ.js"
|
|
20882
22653
|
},
|
|
20883
22654
|
"/_nuxt/_id_.DhlLK-mY.css": {
|
|
20884
22655
|
"type": "text/css; charset=utf-8",
|
|
20885
22656
|
"etag": "\"2f4-xtV37kE566jU74wpZnFHA29RoAY\"",
|
|
20886
|
-
"mtime": "2026-04-
|
|
22657
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
20887
22658
|
"size": 756,
|
|
20888
22659
|
"path": "../public/_nuxt/_id_.DhlLK-mY.css"
|
|
20889
22660
|
},
|
|
20890
|
-
"/_nuxt/
|
|
20891
|
-
"type": "text/
|
|
20892
|
-
"etag": "\"
|
|
20893
|
-
"mtime": "2026-04-
|
|
20894
|
-
"size":
|
|
20895
|
-
"path": "../public/_nuxt/
|
|
22661
|
+
"/_nuxt/BUmYUDQu.js": {
|
|
22662
|
+
"type": "text/javascript; charset=utf-8",
|
|
22663
|
+
"etag": "\"66cba-d/pdEXVc78H3VlgFN3kVzKpvD1Q\"",
|
|
22664
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
22665
|
+
"size": 421050,
|
|
22666
|
+
"path": "../public/_nuxt/BUmYUDQu.js"
|
|
20896
22667
|
},
|
|
20897
22668
|
"/_nuxt/error-404.C7fg894-.css": {
|
|
20898
22669
|
"type": "text/css; charset=utf-8",
|
|
20899
22670
|
"etag": "\"97e-fiQ3o7A11L9BuXRBr0GJldkx0AU\"",
|
|
20900
|
-
"mtime": "2026-04-
|
|
22671
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
20901
22672
|
"size": 2430,
|
|
20902
22673
|
"path": "../public/_nuxt/error-404.C7fg894-.css"
|
|
20903
22674
|
},
|
|
20904
22675
|
"/_nuxt/error-500.DjUK_N2Y.css": {
|
|
20905
22676
|
"type": "text/css; charset=utf-8",
|
|
20906
22677
|
"etag": "\"773-Qf61bSDos4KtmZDaA06FmZyUYNo\"",
|
|
20907
|
-
"mtime": "2026-04-
|
|
22678
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
20908
22679
|
"size": 1907,
|
|
20909
22680
|
"path": "../public/_nuxt/error-500.DjUK_N2Y.css"
|
|
20910
22681
|
},
|
|
20911
|
-
"/_nuxt/Ctwv5nxD.js": {
|
|
20912
|
-
"type": "text/javascript; charset=utf-8",
|
|
20913
|
-
"etag": "\"66cba-QjvxwE3w1y1M86HY4SQQ3d+mH/0\"",
|
|
20914
|
-
"mtime": "2026-04-03T13:40:47.693Z",
|
|
20915
|
-
"size": 421050,
|
|
20916
|
-
"path": "../public/_nuxt/Ctwv5nxD.js"
|
|
20917
|
-
},
|
|
20918
|
-
"/_nuxt/builds/meta/3380bacd-d6f5-40cf-8376-35445d2f246f.json": {
|
|
20919
|
-
"type": "application/json",
|
|
20920
|
-
"etag": "\"58-PvMtM40acZc5iIxMZqVNxK2P/F8\"",
|
|
20921
|
-
"mtime": "2026-04-03T13:40:47.679Z",
|
|
20922
|
-
"size": 88,
|
|
20923
|
-
"path": "../public/_nuxt/builds/meta/3380bacd-d6f5-40cf-8376-35445d2f246f.json"
|
|
20924
|
-
},
|
|
20925
22682
|
"/_nuxt/builds/latest.json": {
|
|
20926
22683
|
"type": "application/json",
|
|
20927
|
-
"etag": "\"47-
|
|
20928
|
-
"mtime": "2026-04-
|
|
22684
|
+
"etag": "\"47-hl0sv2tAIq0lIkhLc1Sve7W2pxs\"",
|
|
22685
|
+
"mtime": "2026-04-07T07:13:36.304Z",
|
|
20929
22686
|
"size": 71,
|
|
20930
22687
|
"path": "../public/_nuxt/builds/latest.json"
|
|
22688
|
+
},
|
|
22689
|
+
"/_nuxt/builds/meta/9441a86b-16e9-4000-bffc-3b2e78e57710.json": {
|
|
22690
|
+
"type": "application/json",
|
|
22691
|
+
"etag": "\"58-cDzg8zvmZMF8VeAEeeEcF3Ng22E\"",
|
|
22692
|
+
"mtime": "2026-04-07T07:13:36.301Z",
|
|
22693
|
+
"size": 88,
|
|
22694
|
+
"path": "../public/_nuxt/builds/meta/9441a86b-16e9-4000-bffc-3b2e78e57710.json"
|
|
22695
|
+
},
|
|
22696
|
+
"/_nuxt/entry.Y3mA4bzA.css": {
|
|
22697
|
+
"type": "text/css; charset=utf-8",
|
|
22698
|
+
"etag": "\"2d46b-zfrD3Ny9WW6qm4fCXAfX5eIAxPA\"",
|
|
22699
|
+
"mtime": "2026-04-07T07:13:36.308Z",
|
|
22700
|
+
"size": 185451,
|
|
22701
|
+
"path": "../public/_nuxt/entry.Y3mA4bzA.css"
|
|
20931
22702
|
}
|
|
20932
22703
|
};
|
|
20933
22704
|
|
|
@@ -21410,6 +23181,64 @@ async function handleMcpHttp(args) {
|
|
|
21410
23181
|
return { kind: "handled" };
|
|
21411
23182
|
}
|
|
21412
23183
|
|
|
23184
|
+
async function runVariantConfigListHandler(params) {
|
|
23185
|
+
var _a, _b, _c, _d, _e;
|
|
23186
|
+
const manifest = loadIntegrationManifest(params.forIntegrationType);
|
|
23187
|
+
if (!manifest)
|
|
23188
|
+
throw createError$1({ statusCode: 404, statusMessage: "Variant integration type not found" });
|
|
23189
|
+
const variantConfig = (_a = manifest.variantConfig) == null ? void 0 : _a.find((item) => item.key === params.key);
|
|
23190
|
+
if (!variantConfig)
|
|
23191
|
+
throw createError$1({ statusCode: 404, statusMessage: `Variant config '${params.key}' not found` });
|
|
23192
|
+
if (!variantConfig.listHandler)
|
|
23193
|
+
throw createError$1({ statusCode: 400, statusMessage: `Variant config '${params.key}' has no list handler` });
|
|
23194
|
+
const db = await getDb();
|
|
23195
|
+
const integration = await getIntegrationById(db, params.integrationId);
|
|
23196
|
+
if (!integration)
|
|
23197
|
+
throw createError$1({ statusCode: 404, statusMessage: "Integration not found" });
|
|
23198
|
+
const spaceId = (_b = integration.spaceId) != null ? _b : "local";
|
|
23199
|
+
const typeConfig = await findIntegrationTypeConfig({
|
|
23200
|
+
db,
|
|
23201
|
+
spaceId,
|
|
23202
|
+
typeSlug: integration.type
|
|
23203
|
+
});
|
|
23204
|
+
const proxy = new IntegrationProxy({
|
|
23205
|
+
credentialStore: new SqlCredentialStore(db, getOrCreateEncryptionSecret()),
|
|
23206
|
+
integrationTypeConfigsRef: typeConfig ? { current: [typeConfig] } : void 0
|
|
23207
|
+
});
|
|
23208
|
+
const getIntegration = createGetIntegration([integration], proxy);
|
|
23209
|
+
const wrappedHandler = `async (config) => {
|
|
23210
|
+
const integration = getIntegration('${integration.id}');
|
|
23211
|
+
const __handler = ${variantConfig.listHandler};
|
|
23212
|
+
const __config = (config && typeof config === 'object' && !Array.isArray(config)) ? config : {};
|
|
23213
|
+
return await __handler(__config);
|
|
23214
|
+
}`;
|
|
23215
|
+
const runner = createSafeHandlerFromString(wrappedHandler, getIntegration);
|
|
23216
|
+
const result = await runner((_c = params.config) != null ? _c : {});
|
|
23217
|
+
if (!result.success) {
|
|
23218
|
+
const innerStatusCode = typeof ((_d = result.result) == null ? void 0 : _d.statusCode) === "number" ? result.result.statusCode : 500;
|
|
23219
|
+
const innerMessage = typeof ((_e = result.result) == null ? void 0 : _e.message) === "string" && result.result.message.trim() ? result.result.message.trim() : "Failed to load variant config options";
|
|
23220
|
+
throw createError$1({ statusCode: innerStatusCode, statusMessage: innerMessage, data: result.logs });
|
|
23221
|
+
}
|
|
23222
|
+
if (!Array.isArray(result.result))
|
|
23223
|
+
throw createError$1({ statusCode: 502, statusMessage: "Variant config list handler must return an array" });
|
|
23224
|
+
const options = result.result.map((item) => {
|
|
23225
|
+
var _a2, _b2;
|
|
23226
|
+
if (!item || typeof item !== "object")
|
|
23227
|
+
return null;
|
|
23228
|
+
const id = "id" in item ? String((_a2 = item.id) != null ? _a2 : "") : "";
|
|
23229
|
+
const name = "name" in item ? String((_b2 = item.name) != null ? _b2 : "") : "";
|
|
23230
|
+
if (!id || !name)
|
|
23231
|
+
return null;
|
|
23232
|
+
return { id, name };
|
|
23233
|
+
}).filter(Boolean);
|
|
23234
|
+
return {
|
|
23235
|
+
label: variantConfig.label,
|
|
23236
|
+
selectionMode: variantConfig.selectionMode,
|
|
23237
|
+
options,
|
|
23238
|
+
logs: result.logs
|
|
23239
|
+
};
|
|
23240
|
+
}
|
|
23241
|
+
|
|
21413
23242
|
const collections = {
|
|
21414
23243
|
'lucide': () => import('../_/icons.mjs').then(m => m.default),
|
|
21415
23244
|
'simple-icons': () => import('../_/icons2.mjs').then(m => m.default),
|
|
@@ -21480,6 +23309,7 @@ const _lazy_tZWrQN = () => import('../routes/api/integrations/_id/tools.delete.m
|
|
|
21480
23309
|
const _lazy_zaazLC = () => import('../routes/api/integrations/_id/tools.get.mjs');
|
|
21481
23310
|
const _lazy_9iz_Is = () => import('../routes/api/integrations/_id/toolsets.get.mjs');
|
|
21482
23311
|
const _lazy_Klwsdp = () => import('../routes/api/integrations/_id/toolsets.post.mjs');
|
|
23312
|
+
const _lazy_Wj3Kn6 = () => import('../routes/api/integrations/_id/variant-options.post.mjs');
|
|
21483
23313
|
const _lazy_FcbHxS = () => import('../routes/api/index.get.mjs');
|
|
21484
23314
|
const _lazy_0b9jj9 = () => import('../routes/api/index.post.mjs');
|
|
21485
23315
|
const _lazy_g_ZIqQ = () => import('../routes/health.get.mjs');
|
|
@@ -21505,6 +23335,7 @@ const handlers = [
|
|
|
21505
23335
|
{ route: '/api/integrations/:id/tools', handler: _lazy_zaazLC, lazy: true, middleware: false, method: "get" },
|
|
21506
23336
|
{ route: '/api/integrations/:id/toolsets', handler: _lazy_9iz_Is, lazy: true, middleware: false, method: "get" },
|
|
21507
23337
|
{ route: '/api/integrations/:id/toolsets', handler: _lazy_Klwsdp, lazy: true, middleware: false, method: "post" },
|
|
23338
|
+
{ route: '/api/integrations/:id/variant-options', handler: _lazy_Wj3Kn6, lazy: true, middleware: false, method: "post" },
|
|
21508
23339
|
{ route: '/api/integrations', handler: _lazy_FcbHxS, lazy: true, middleware: false, method: "get" },
|
|
21509
23340
|
{ route: '/api/integrations', handler: _lazy_0b9jj9, lazy: true, middleware: false, method: "post" },
|
|
21510
23341
|
{ route: '/health', handler: _lazy_g_ZIqQ, lazy: true, middleware: false, method: "get" },
|
|
@@ -21930,5 +23761,5 @@ trapUnhandledNodeErrors();
|
|
|
21930
23761
|
setupGracefulShutdown(listener, nitroApp);
|
|
21931
23762
|
const nodeServer = {};
|
|
21932
23763
|
|
|
21933
|
-
export {
|
|
23764
|
+
export { isEqual as $, handleMcpHttp as A, setResponseStatus as B, buildAssetsURL as C, useRuntimeConfig as D, getResponseStatusText as E, getResponseStatus as F, defineRenderHandler as G, publicAssetsURL as H, IntegrationProxy as I, getQuery as J, destr as K, getRouteRules as L, joinURL as M, useNitroApp as N, serialize$1 as O, klona as P, defu as Q, hasProtocol as R, SqlCredentialStore as S, isScriptProtocol as T, parseQuery as U, defuFn as V, withQuery as W, sanitizeStatusCode as X, parseURL as Y, encodePath as Z, decodePath as _, loadIntegrationCredentialConfig as a, getContext as a0, withTrailingSlash as a1, withoutTrailingSlash as a2, $fetch$1 as a3, baseURL as a4, createHooks as a5, executeAsync as a6, hash$1 as a7, nodeServer as a8, getRouterParam as b, createError$1 as c, defineEventHandler as d, loadIntegrationToolList as e, loadIntegrationToolsets as f, getFileProcessingCapability as g, getDb as h, getIntegrationById as i, deleteToolDefinitionsForIntegration as j, getOrCreateEncryptionSecret as k, listIntegrationCatalog as l, deleteIntegrationById as m, listIntegrations as n, deleteIntegrationTypeConfig as o, findIntegrationTypeConfig as p, updateIntegrationHealth as q, refreshMcpState as r, readBody as s, checkIntegrationHealth as t, updateIntegrationCredentials as u, upsertIntegration as v, deleteToolDefinitionByName as w, applyFileProcessingCapabilityToIntegration as x, listToolDefinitionsForIntegration as y, runVariantConfigListHandler as z };
|
|
21934
23765
|
//# sourceMappingURL=nitro.mjs.map
|