@ganju/utils 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +9 -0
- package/README.md +23 -0
- package/dist/apiError.d.ts +3 -0
- package/dist/apiError.d.ts.map +1 -0
- package/dist/apiError.js +36 -0
- package/dist/attachment.d.ts +33 -0
- package/dist/attachment.d.ts.map +1 -0
- package/dist/attachment.js +59 -0
- package/dist/base64.d.ts +10 -0
- package/dist/base64.d.ts.map +1 -0
- package/dist/base64.js +50 -0
- package/dist/channelDebounce.d.ts +26 -0
- package/dist/channelDebounce.d.ts.map +1 -0
- package/dist/channelDebounce.js +35 -0
- package/dist/channelNotifier.d.ts +9 -0
- package/dist/channelNotifier.d.ts.map +1 -0
- package/dist/channelNotifier.js +31 -0
- package/dist/chunking.d.ts +28 -0
- package/dist/chunking.d.ts.map +1 -0
- package/dist/chunking.js +97 -0
- package/dist/cliConstants.d.ts +9 -0
- package/dist/cliConstants.d.ts.map +1 -0
- package/dist/cliConstants.js +47 -0
- package/dist/coerce.d.ts +2 -0
- package/dist/coerce.d.ts.map +1 -0
- package/dist/coerce.js +13 -0
- package/dist/constants.d.ts +624 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +2220 -0
- package/dist/crypto.d.ts +14 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +93 -0
- package/dist/customCodeProject.d.ts +91 -0
- package/dist/customCodeProject.d.ts.map +1 -0
- package/dist/customCodeProject.js +154 -0
- package/dist/customCodeToken.d.ts +41 -0
- package/dist/customCodeToken.d.ts.map +1 -0
- package/dist/customCodeToken.js +115 -0
- package/dist/deadline.d.ts +6 -0
- package/dist/deadline.d.ts.map +1 -0
- package/dist/deadline.js +45 -0
- package/dist/discordSend.d.ts +25 -0
- package/dist/discordSend.d.ts.map +1 -0
- package/dist/discordSend.js +8 -0
- package/dist/embeddable.d.ts +2 -0
- package/dist/embeddable.d.ts.map +1 -0
- package/dist/embeddable.js +6 -0
- package/dist/exposedResource.d.ts +6 -0
- package/dist/exposedResource.d.ts.map +1 -0
- package/dist/exposedResource.js +18 -0
- package/dist/extractedDocument.d.ts +70 -0
- package/dist/extractedDocument.d.ts.map +1 -0
- package/dist/extractedDocument.js +2 -0
- package/dist/fetcher.d.ts +8 -0
- package/dist/fetcher.d.ts.map +1 -0
- package/dist/fetcher.js +68 -0
- package/dist/formatFilename.d.ts +2 -0
- package/dist/formatFilename.d.ts.map +1 -0
- package/dist/formatFilename.js +19 -0
- package/dist/formatRelative.d.ts +12 -0
- package/dist/formatRelative.d.ts.map +1 -0
- package/dist/formatRelative.js +28 -0
- package/dist/formatRelativeTime.d.ts +2 -0
- package/dist/formatRelativeTime.d.ts.map +1 -0
- package/dist/formatRelativeTime.js +49 -0
- package/dist/getEnv.d.ts +5 -0
- package/dist/getEnv.d.ts.map +1 -0
- package/dist/getEnv.js +11 -0
- package/dist/gmailSend.d.ts +24 -0
- package/dist/gmailSend.d.ts.map +1 -0
- package/dist/gmailSend.js +9 -0
- package/dist/index.d.ts +2839 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +155 -0
- package/dist/jsonSchemaToZodShape.d.ts +38 -0
- package/dist/jsonSchemaToZodShape.d.ts.map +1 -0
- package/dist/jsonSchemaToZodShape.js +117 -0
- package/dist/l2Normalize.d.ts +2 -0
- package/dist/l2Normalize.d.ts.map +1 -0
- package/dist/l2Normalize.js +25 -0
- package/dist/languageCookieDomain.d.ts +21 -0
- package/dist/languageCookieDomain.d.ts.map +1 -0
- package/dist/languageCookieDomain.js +39 -0
- package/dist/localizeZodIssue.d.ts +43 -0
- package/dist/localizeZodIssue.d.ts.map +1 -0
- package/dist/localizeZodIssue.js +90 -0
- package/dist/mailHeaders.d.ts +4 -0
- package/dist/mailHeaders.d.ts.map +1 -0
- package/dist/mailHeaders.js +11 -0
- package/dist/mcpProxy.d.ts +2 -0
- package/dist/mcpProxy.d.ts.map +1 -0
- package/dist/mcpProxy.js +21 -0
- package/dist/mimeMessage.d.ts +21 -0
- package/dist/mimeMessage.d.ts.map +1 -0
- package/dist/mimeMessage.js +58 -0
- package/dist/oauth.d.ts +21 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +75 -0
- package/dist/oauthProviders.d.ts +12 -0
- package/dist/oauthProviders.d.ts.map +1 -0
- package/dist/oauthProviders.js +99 -0
- package/dist/outlookSend.d.ts +19 -0
- package/dist/outlookSend.d.ts.map +1 -0
- package/dist/outlookSend.js +9 -0
- package/dist/parseHttpError.d.ts +2 -0
- package/dist/parseHttpError.d.ts.map +1 -0
- package/dist/parseHttpError.js +23 -0
- package/dist/planLimitError.d.ts +18 -0
- package/dist/planLimitError.d.ts.map +1 -0
- package/dist/planLimitError.js +35 -0
- package/dist/processQueueBatch.d.ts +17 -0
- package/dist/processQueueBatch.d.ts.map +1 -0
- package/dist/processQueueBatch.js +32 -0
- package/dist/reservedToolName.d.ts +16 -0
- package/dist/reservedToolName.d.ts.map +1 -0
- package/dist/reservedToolName.js +25 -0
- package/dist/resourceUri.d.ts +2 -0
- package/dist/resourceUri.d.ts.map +1 -0
- package/dist/resourceUri.js +19 -0
- package/dist/retry.d.ts +10 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +37 -0
- package/dist/sanitize.d.ts +7 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +69 -0
- package/dist/schema.d.ts +2175 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +1382 -0
- package/dist/sdkConstants.d.ts +15 -0
- package/dist/sdkConstants.d.ts.map +1 -0
- package/dist/sdkConstants.js +43 -0
- package/dist/slackSend.d.ts +38 -0
- package/dist/slackSend.d.ts.map +1 -0
- package/dist/slackSend.js +14 -0
- package/dist/slug.d.ts +5 -0
- package/dist/slug.d.ts.map +1 -0
- package/dist/slug.js +34 -0
- package/dist/slugifyTitle.d.ts +2 -0
- package/dist/slugifyTitle.d.ts.map +1 -0
- package/dist/slugifyTitle.js +11 -0
- package/dist/sources.d.ts +43 -0
- package/dist/sources.d.ts.map +1 -0
- package/dist/sources.js +73 -0
- package/dist/ssrf.d.ts +3 -0
- package/dist/ssrf.d.ts.map +1 -0
- package/dist/ssrf.js +46 -0
- package/dist/tallyUsageKinds.d.ts +9 -0
- package/dist/tallyUsageKinds.d.ts.map +1 -0
- package/dist/tallyUsageKinds.js +20 -0
- package/dist/telegramSend.d.ts +28 -0
- package/dist/telegramSend.d.ts.map +1 -0
- package/dist/telegramSend.js +9 -0
- package/dist/toolCatalog.d.ts +452 -0
- package/dist/toolCatalog.d.ts.map +1 -0
- package/dist/toolCatalog.js +552 -0
- package/dist/validateMessageVariables.d.ts +7 -0
- package/dist/validateMessageVariables.d.ts.map +1 -0
- package/dist/validateMessageVariables.js +16 -0
- package/dist/vendorError.d.ts +2 -0
- package/dist/vendorError.d.ts.map +1 -0
- package/dist/vendorError.js +25 -0
- package/dist/whatsappSend.d.ts +31 -0
- package/dist/whatsappSend.d.ts.map +1 -0
- package/dist/whatsappSend.js +11 -0
- package/package.json +76 -0
- package/src/apiError.ts +40 -0
- package/src/attachment.ts +97 -0
- package/src/base64.ts +60 -0
- package/src/channelDebounce.ts +76 -0
- package/src/channelNotifier.ts +39 -0
- package/src/chunking.ts +131 -0
- package/src/cliConstants.ts +50 -0
- package/src/coerce.ts +9 -0
- package/src/constants.ts +2542 -0
- package/src/crypto.ts +108 -0
- package/src/customCodeProject.ts +182 -0
- package/src/customCodeToken.ts +198 -0
- package/src/deadline.ts +43 -0
- package/src/discordSend.ts +41 -0
- package/src/embeddable.ts +4 -0
- package/src/exposedResource.ts +40 -0
- package/src/extractedDocument.ts +62 -0
- package/src/fetcher.ts +82 -0
- package/src/formatFilename.ts +19 -0
- package/src/formatRelative.ts +36 -0
- package/src/formatRelativeTime.ts +45 -0
- package/src/getEnv.ts +13 -0
- package/src/gmailSend.ts +34 -0
- package/src/index.ts +397 -0
- package/src/jsonSchemaToZodShape.ts +111 -0
- package/src/l2Normalize.ts +19 -0
- package/src/languageCookieDomain.ts +37 -0
- package/src/localizeZodIssue.ts +124 -0
- package/src/mailHeaders.ts +12 -0
- package/src/mcpProxy.ts +20 -0
- package/src/mimeMessage.ts +82 -0
- package/src/oauth.ts +103 -0
- package/src/oauthProviders.ts +118 -0
- package/src/outlookSend.ts +44 -0
- package/src/parseHttpError.ts +16 -0
- package/src/planLimitError.ts +50 -0
- package/src/processQueueBatch.ts +46 -0
- package/src/reservedToolName.ts +27 -0
- package/src/resourceUri.ts +17 -0
- package/src/retry.ts +43 -0
- package/src/sanitize.ts +67 -0
- package/src/schema.ts +1624 -0
- package/src/sdkConstants.ts +44 -0
- package/src/slackSend.ts +65 -0
- package/src/slug.ts +37 -0
- package/src/slugifyTitle.ts +8 -0
- package/src/sources.ts +117 -0
- package/src/ssrf.ts +34 -0
- package/src/tallyUsageKinds.ts +20 -0
- package/src/telegramSend.ts +39 -0
- package/src/toolCatalog.ts +635 -0
- package/src/validateMessageVariables.ts +18 -0
- package/src/vendorError.ts +19 -0
- package/src/whatsappSend.ts +47 -0
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
// The catalog of tools this platform ships: the groups the dashboard renders as
|
|
2
|
+
// cards, and the definitions inside them.
|
|
3
|
+
//
|
|
4
|
+
// This is code and not database rows, because a catalog entry is meaningless
|
|
5
|
+
// without a handler to run it. The MCP boot loop resolves an installed tool
|
|
6
|
+
// through `toolRegistry`, and a key with no handler there is skipped silently —
|
|
7
|
+
// the tool simply stops appearing on the customer's server, with nothing in the
|
|
8
|
+
// UI to say why. Declaring the catalog here makes the registry exhaustive
|
|
9
|
+
// against `ToolKey`, so that mismatch is a build failure instead.
|
|
10
|
+
//
|
|
11
|
+
// It also removes a class of drift that was real: these rows were seeded out of
|
|
12
|
+
// band, one environment at a time, so a definition could exist on dev and not on
|
|
13
|
+
// production. Now they ship with the code that implements them.
|
|
14
|
+
//
|
|
15
|
+
// Adding a tool: add the entry here, add its handler to `toolRegistry` under the
|
|
16
|
+
// same key. TypeScript fails the build until both exist.
|
|
17
|
+
|
|
18
|
+
export interface CatalogTool {
|
|
19
|
+
// Doubles as the MCP tool name for native tools, which is why it is also what
|
|
20
|
+
// `isReservedToolName` protects from user-authored tools.
|
|
21
|
+
key: string;
|
|
22
|
+
title: string;
|
|
23
|
+
description: string | null;
|
|
24
|
+
// The single OAuth scope this tool needs beyond the group's baseline, used to
|
|
25
|
+
// prompt for incremental re-authorization. Null when the group's grant covers
|
|
26
|
+
// it.
|
|
27
|
+
requiredScopes: string | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface CatalogGroup {
|
|
31
|
+
key: string;
|
|
32
|
+
title: string;
|
|
33
|
+
description: string | null;
|
|
34
|
+
icon: string | null;
|
|
35
|
+
// The OAuth provider whose credential this group's tools run on, or null for
|
|
36
|
+
// groups that need no connection. Resolved per call at boot.
|
|
37
|
+
provider: string | null;
|
|
38
|
+
tools: readonly CatalogTool[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Ordered deliberately: the query this replaced had no ORDER BY, so the cards
|
|
42
|
+
// rendered in whatever order Postgres returned them and could change between
|
|
43
|
+
// deploys. Integrations first, then the platform's own groups, then the three
|
|
44
|
+
// definitions whose tools the user authors.
|
|
45
|
+
export const TOOL_CATALOG = [
|
|
46
|
+
{
|
|
47
|
+
key: 'gmail',
|
|
48
|
+
title: 'Gmail',
|
|
49
|
+
description: 'Send, read, search, and manage emails',
|
|
50
|
+
icon: 'https://www.gstatic.com/images/branding/product/1x/gmail_2020q4_48dp.png',
|
|
51
|
+
provider: 'google-gmail',
|
|
52
|
+
tools: [
|
|
53
|
+
{
|
|
54
|
+
key: 'gmail-batch-modify-labels',
|
|
55
|
+
title: 'Batch Modify Labels',
|
|
56
|
+
description:
|
|
57
|
+
'Add or remove labels on many emails at once (archive, mark read, etc.).',
|
|
58
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.modify'
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: 'gmail-create-draft',
|
|
62
|
+
title: 'Create Draft',
|
|
63
|
+
description: 'Save a new draft in Gmail without sending it yet.',
|
|
64
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.compose'
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
key: 'gmail-delete-draft',
|
|
68
|
+
title: 'Delete Draft',
|
|
69
|
+
description: 'Permanently delete a draft.',
|
|
70
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.compose'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: 'gmail-forward-email',
|
|
74
|
+
title: 'Forward Email',
|
|
75
|
+
description: 'Forward an email to a new recipient.',
|
|
76
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.send'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
key: 'gmail-get-draft',
|
|
80
|
+
title: 'Get Draft',
|
|
81
|
+
description: 'Open a saved draft to review its contents.',
|
|
82
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.compose'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
key: 'gmail-get-profile',
|
|
86
|
+
title: 'Get Profile',
|
|
87
|
+
description:
|
|
88
|
+
'Show the email address and inbox stats for the connected Gmail account.',
|
|
89
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.readonly'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
key: 'gmail-get-thread',
|
|
93
|
+
title: 'Get Thread',
|
|
94
|
+
description: 'See every message inside one conversation.',
|
|
95
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.readonly'
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: 'gmail-list-drafts',
|
|
99
|
+
title: 'List Drafts',
|
|
100
|
+
description: 'Browse your saved drafts.',
|
|
101
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.compose'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
key: 'gmail-list-emails',
|
|
105
|
+
title: 'List Emails',
|
|
106
|
+
description: 'Browse your Gmail inbox, with optional search filters.',
|
|
107
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.readonly'
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
key: 'gmail-list-labels',
|
|
111
|
+
title: 'List Labels',
|
|
112
|
+
description: 'See all of your Gmail labels and folders.',
|
|
113
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.labels'
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
key: 'gmail-list-threads',
|
|
117
|
+
title: 'List Threads',
|
|
118
|
+
description: 'List your Gmail conversations.',
|
|
119
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.readonly'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
key: 'gmail-modify-labels',
|
|
123
|
+
title: 'Modify Labels',
|
|
124
|
+
description:
|
|
125
|
+
'Add or remove labels on a single email — archive it, mark it read, star it, and more.',
|
|
126
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.modify'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
key: 'gmail-read-email',
|
|
130
|
+
title: 'Read Email',
|
|
131
|
+
description: 'Open and read a specific email.',
|
|
132
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.readonly'
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
key: 'gmail-reply-email',
|
|
136
|
+
title: 'Reply Email',
|
|
137
|
+
description:
|
|
138
|
+
'Reply to an email so the response stays in the same conversation.',
|
|
139
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.send'
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
key: 'gmail-send-draft',
|
|
143
|
+
title: 'Send Draft',
|
|
144
|
+
description: "Send a draft you've already saved.",
|
|
145
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.send'
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
key: 'gmail-send-email',
|
|
149
|
+
title: 'Send Email',
|
|
150
|
+
description:
|
|
151
|
+
'Compose and send a new email from your connected Gmail account.',
|
|
152
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.send'
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
key: 'gmail-trash-email',
|
|
156
|
+
title: 'Move to Trash',
|
|
157
|
+
description:
|
|
158
|
+
'Move an email to Trash. It stays recoverable for 30 days.',
|
|
159
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.modify'
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
key: 'gmail-update-draft',
|
|
163
|
+
title: 'Update Draft',
|
|
164
|
+
description: 'Edit the contents of a saved draft.',
|
|
165
|
+
requiredScopes: 'https://www.googleapis.com/auth/gmail.compose'
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
key: 'outlook',
|
|
171
|
+
title: 'Outlook',
|
|
172
|
+
description: 'Microsoft Outlook mail tools backed by Microsoft Graph.',
|
|
173
|
+
icon: 'https://api.iconify.design/vscode-icons:file-type-outlook.svg',
|
|
174
|
+
provider: 'microsoft-outlook',
|
|
175
|
+
tools: [
|
|
176
|
+
{
|
|
177
|
+
key: 'outlook-batch-move-messages',
|
|
178
|
+
title: 'Batch Move Messages',
|
|
179
|
+
description: 'Move up to 20 messages to the same folder.',
|
|
180
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.ReadWrite'
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
key: 'outlook-create-draft',
|
|
184
|
+
title: 'Create Draft',
|
|
185
|
+
description: 'Create a draft email saved in Drafts.',
|
|
186
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.ReadWrite'
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
key: 'outlook-delete-draft',
|
|
190
|
+
title: 'Delete Draft',
|
|
191
|
+
description: 'Permanently delete a draft.',
|
|
192
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.ReadWrite'
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
key: 'outlook-forward-email',
|
|
196
|
+
title: 'Forward',
|
|
197
|
+
description: 'Forward an existing message to a new recipient.',
|
|
198
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Send'
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
key: 'outlook-get-draft',
|
|
202
|
+
title: 'Get Draft',
|
|
203
|
+
description: 'Read the full contents of a draft.',
|
|
204
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Read'
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
key: 'outlook-get-profile',
|
|
208
|
+
title: 'Get Profile',
|
|
209
|
+
description: "Get the connected account's profile and inbox totals.",
|
|
210
|
+
requiredScopes: 'https://graph.microsoft.com/User.Read'
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
key: 'outlook-get-thread',
|
|
214
|
+
title: 'Get Thread',
|
|
215
|
+
description: 'Get summaries of every message in a conversation.',
|
|
216
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Read'
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
key: 'outlook-list-drafts',
|
|
220
|
+
title: 'List Drafts',
|
|
221
|
+
description: 'List drafts in the Drafts folder.',
|
|
222
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Read'
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
key: 'outlook-list-emails',
|
|
226
|
+
title: 'List Emails',
|
|
227
|
+
description: 'List inbox messages, optionally filtered by search.',
|
|
228
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Read'
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
key: 'outlook-list-folders',
|
|
232
|
+
title: 'List Folders',
|
|
233
|
+
description: 'List every mail folder on the account.',
|
|
234
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Read'
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
key: 'outlook-list-threads',
|
|
238
|
+
title: 'List Threads',
|
|
239
|
+
description: 'List inbox conversation threads.',
|
|
240
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Read'
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
key: 'outlook-move-message',
|
|
244
|
+
title: 'Move Message',
|
|
245
|
+
description: 'Move a message to a different folder.',
|
|
246
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.ReadWrite'
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
key: 'outlook-read-email',
|
|
250
|
+
title: 'Read Email',
|
|
251
|
+
description: 'Read the full contents of one message by ID.',
|
|
252
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Read'
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
key: 'outlook-reply-email',
|
|
256
|
+
title: 'Reply',
|
|
257
|
+
description:
|
|
258
|
+
'Reply to an existing message, preserving the conversation.',
|
|
259
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Send'
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
key: 'outlook-send-draft',
|
|
263
|
+
title: 'Send Draft',
|
|
264
|
+
description: 'Send an existing draft as-is.',
|
|
265
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Send'
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
key: 'outlook-send-email',
|
|
269
|
+
title: 'Send Email',
|
|
270
|
+
description: 'Send a brand-new email from the connected account.',
|
|
271
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.Send'
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
key: 'outlook-trash-email',
|
|
275
|
+
title: 'Move to Trash',
|
|
276
|
+
description: 'Move a message to the Deleted Items folder.',
|
|
277
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.ReadWrite'
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
key: 'outlook-update-draft',
|
|
281
|
+
title: 'Update Draft',
|
|
282
|
+
description: 'Replace the contents of an existing draft.',
|
|
283
|
+
requiredScopes: 'https://graph.microsoft.com/Mail.ReadWrite'
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
key: 'slack',
|
|
289
|
+
title: 'Slack',
|
|
290
|
+
description:
|
|
291
|
+
'Post messages, browse channels, and upload files in Slack via Web API.',
|
|
292
|
+
icon: 'https://api.iconify.design/logos:slack-icon.svg',
|
|
293
|
+
provider: 'slack',
|
|
294
|
+
tools: [
|
|
295
|
+
{
|
|
296
|
+
key: 'slack-get-user',
|
|
297
|
+
title: 'Get User',
|
|
298
|
+
description: 'Look up a Slack user by ID or email.',
|
|
299
|
+
requiredScopes: 'users:read,users:read.email'
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
key: 'slack-list-channels',
|
|
303
|
+
title: 'List Channels',
|
|
304
|
+
description: 'Browse the channels and DMs the agent can see.',
|
|
305
|
+
requiredScopes: 'channels:read,groups:read,mpim:read,im:read'
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
key: 'slack-send-message',
|
|
309
|
+
title: 'Send Message',
|
|
310
|
+
description: 'Post a message to a Slack channel, DM, or thread.',
|
|
311
|
+
requiredScopes: 'chat:write'
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
key: 'slack-upload-file',
|
|
315
|
+
title: 'Upload File',
|
|
316
|
+
description: 'Upload a stored resource into a Slack channel.',
|
|
317
|
+
requiredScopes: 'files:write,chat:write'
|
|
318
|
+
}
|
|
319
|
+
]
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
key: 'slack-user',
|
|
323
|
+
title: 'Slack Search',
|
|
324
|
+
description:
|
|
325
|
+
'Workspace-wide message search for Slack. Backed by a user (xoxp) token because Slack does not allow bot tokens to call search.messages.',
|
|
326
|
+
icon: 'https://api.iconify.design/logos:slack-icon.svg',
|
|
327
|
+
provider: 'slack-user',
|
|
328
|
+
tools: [
|
|
329
|
+
{
|
|
330
|
+
key: 'slack-search-messages',
|
|
331
|
+
title: 'Search Messages',
|
|
332
|
+
description:
|
|
333
|
+
'Search messages across the workspace. Requires a Slack user token (xoxp).',
|
|
334
|
+
requiredScopes: 'search:read'
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
key: 'google-calendar',
|
|
340
|
+
title: 'Google Calendar',
|
|
341
|
+
description: 'Create and manage calendar events, and find open time slots',
|
|
342
|
+
icon: 'https://api.iconify.design/logos:google-calendar.svg',
|
|
343
|
+
provider: 'google-calendar',
|
|
344
|
+
tools: [
|
|
345
|
+
{
|
|
346
|
+
key: 'calendar-create-event',
|
|
347
|
+
title: 'Create Event',
|
|
348
|
+
description: 'Add a new event to a calendar.',
|
|
349
|
+
requiredScopes: 'https://www.googleapis.com/auth/calendar.events'
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
key: 'calendar-delete-event',
|
|
353
|
+
title: 'Delete Event',
|
|
354
|
+
description: 'Permanently remove an event from a calendar.',
|
|
355
|
+
requiredScopes: 'https://www.googleapis.com/auth/calendar.events'
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
key: 'calendar-find-free-slots',
|
|
359
|
+
title: 'Find Free Slots',
|
|
360
|
+
description: 'Find open time gaps on a calendar.',
|
|
361
|
+
requiredScopes: 'https://www.googleapis.com/auth/calendar.readonly'
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
key: 'calendar-list-calendars',
|
|
365
|
+
title: 'List Calendars',
|
|
366
|
+
description: 'See all calendars on the connected Google account.',
|
|
367
|
+
requiredScopes: 'https://www.googleapis.com/auth/calendar.readonly'
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
key: 'calendar-list-events',
|
|
371
|
+
title: 'List Events',
|
|
372
|
+
description: 'Browse events on a calendar within a time range.',
|
|
373
|
+
requiredScopes: 'https://www.googleapis.com/auth/calendar.readonly'
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
key: 'calendar-update-event',
|
|
377
|
+
title: 'Update Event',
|
|
378
|
+
description: 'Change the details of an existing event.',
|
|
379
|
+
requiredScopes: 'https://www.googleapis.com/auth/calendar.events'
|
|
380
|
+
}
|
|
381
|
+
]
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
key: 'calcom',
|
|
385
|
+
title: 'Cal.com',
|
|
386
|
+
description: 'Check availability and book or cancel meetings on Cal.com',
|
|
387
|
+
icon: 'https://api.iconify.design/simple-icons:caldotcom.svg',
|
|
388
|
+
provider: 'calcom',
|
|
389
|
+
tools: [
|
|
390
|
+
{
|
|
391
|
+
key: 'calcom-cancel-booking',
|
|
392
|
+
title: 'Cancel Booking',
|
|
393
|
+
description: 'Cancel an existing booking by its UID.',
|
|
394
|
+
requiredScopes: null
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
key: 'calcom-create-booking',
|
|
398
|
+
title: 'Create Booking',
|
|
399
|
+
description: 'Book an available slot for an attendee.',
|
|
400
|
+
requiredScopes: null
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
key: 'calcom-list-available-slots',
|
|
404
|
+
title: 'List Available Slots',
|
|
405
|
+
description:
|
|
406
|
+
'Find open booking times for an event type in a date range.',
|
|
407
|
+
requiredScopes: null
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
key: 'calcom-list-event-types',
|
|
411
|
+
title: 'List Event Types',
|
|
412
|
+
description:
|
|
413
|
+
'See the bookable meeting types on the connected Cal.com account.',
|
|
414
|
+
requiredScopes: null
|
|
415
|
+
}
|
|
416
|
+
]
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
key: 'web',
|
|
420
|
+
title: 'Web Search',
|
|
421
|
+
description:
|
|
422
|
+
'Search the live web and extract page content, powered by Tavily.',
|
|
423
|
+
icon: 'https://api.iconify.design/mdi:web.svg',
|
|
424
|
+
provider: 'tavily',
|
|
425
|
+
tools: [
|
|
426
|
+
{
|
|
427
|
+
key: 'web-extract',
|
|
428
|
+
title: 'Web Extract',
|
|
429
|
+
description:
|
|
430
|
+
'Fetch the full cleaned text of specific web pages by URL for in-depth reading.',
|
|
431
|
+
requiredScopes: null
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
key: 'web-search',
|
|
435
|
+
title: 'Web Search',
|
|
436
|
+
description:
|
|
437
|
+
'Search the live web and return the top results plus a synthesized answer so the model can cite sources.',
|
|
438
|
+
requiredScopes: null
|
|
439
|
+
}
|
|
440
|
+
]
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
key: 'builtin',
|
|
444
|
+
title: 'Built-in',
|
|
445
|
+
description: 'Core tools available to every MCP server',
|
|
446
|
+
icon: null,
|
|
447
|
+
provider: null,
|
|
448
|
+
tools: [
|
|
449
|
+
{
|
|
450
|
+
key: 'list-prompts',
|
|
451
|
+
title: 'List Prompts',
|
|
452
|
+
description:
|
|
453
|
+
'List the prompts and commands this assistant exposes, and how to run them on the current channel.',
|
|
454
|
+
requiredScopes: null
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
key: 'list-resources',
|
|
458
|
+
title: 'List Resources',
|
|
459
|
+
description: 'List every resource available to this assistant.',
|
|
460
|
+
requiredScopes: null
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
key: 'read-resource',
|
|
464
|
+
title: 'Read Resource',
|
|
465
|
+
description: 'Read the contents of a stored resource.',
|
|
466
|
+
requiredScopes: null
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
key: 'search-resources',
|
|
470
|
+
title: 'Search Resources',
|
|
471
|
+
description:
|
|
472
|
+
'Find the resources most relevant to a question using semantic search.',
|
|
473
|
+
requiredScopes: null
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
key: 'send-resource',
|
|
477
|
+
title: 'Send Resource',
|
|
478
|
+
description: 'Deliver a resource to the user as a chat attachment.',
|
|
479
|
+
requiredScopes: null
|
|
480
|
+
}
|
|
481
|
+
]
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
key: 'greeting',
|
|
485
|
+
title: 'Greeting',
|
|
486
|
+
description: 'Simple greeting utilities',
|
|
487
|
+
icon: null,
|
|
488
|
+
provider: null,
|
|
489
|
+
tools: [
|
|
490
|
+
{
|
|
491
|
+
key: 'greeting',
|
|
492
|
+
title: 'Greeting',
|
|
493
|
+
description:
|
|
494
|
+
'Reply with a friendly hello in English or Spanish (demo tool).',
|
|
495
|
+
requiredScopes: null
|
|
496
|
+
}
|
|
497
|
+
]
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
key: 'http-endpoint',
|
|
501
|
+
title: 'HTTP Endpoints',
|
|
502
|
+
description:
|
|
503
|
+
'Expose your own HTTP APIs to the agent as named tools. Each endpoint you add becomes a tool the assistant can call.',
|
|
504
|
+
icon: 'https://api.iconify.design/mdi:api.svg',
|
|
505
|
+
provider: null,
|
|
506
|
+
tools: [
|
|
507
|
+
{
|
|
508
|
+
key: 'http-endpoint',
|
|
509
|
+
title: 'HTTP Endpoint',
|
|
510
|
+
description:
|
|
511
|
+
'A user-configured HTTP request exposed to the agent as its own named tool.',
|
|
512
|
+
requiredScopes: null
|
|
513
|
+
}
|
|
514
|
+
]
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
key: 'mcp-proxy',
|
|
518
|
+
title: 'MCP Servers',
|
|
519
|
+
description:
|
|
520
|
+
"Connect a vendor's official remote MCP server and expose its tools to the agent. Each server you add brings its own set of tools.",
|
|
521
|
+
icon: 'https://api.iconify.design/mdi:server-network.svg',
|
|
522
|
+
provider: null,
|
|
523
|
+
tools: [
|
|
524
|
+
{
|
|
525
|
+
key: 'mcp-proxy',
|
|
526
|
+
title: 'MCP Server',
|
|
527
|
+
description:
|
|
528
|
+
'A connected remote MCP server. Each server you add exposes its tools to the agent under a vendor prefix.',
|
|
529
|
+
requiredScopes: null
|
|
530
|
+
}
|
|
531
|
+
]
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
key: 'custom-code',
|
|
535
|
+
title: 'Custom code',
|
|
536
|
+
description:
|
|
537
|
+
'Write your own tools as a Cloudflare Worker and deploy them to this MCP server.',
|
|
538
|
+
icon: null,
|
|
539
|
+
provider: null,
|
|
540
|
+
tools: [
|
|
541
|
+
{
|
|
542
|
+
key: 'custom-code',
|
|
543
|
+
title: 'Custom code',
|
|
544
|
+
description:
|
|
545
|
+
'Tools implemented by your own code. One script per artifact; names and schemas come from the published version.',
|
|
546
|
+
requiredScopes: null
|
|
547
|
+
}
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
] as const satisfies readonly CatalogGroup[];
|
|
551
|
+
|
|
552
|
+
// Every native tool key, as a union. `toolRegistry` in apps/mcp is typed against
|
|
553
|
+
// this, which is what turns "a catalog entry with no handler" into a type error.
|
|
554
|
+
export type ToolKey = (typeof TOOL_CATALOG)[number]['tools'][number]['key'];
|
|
555
|
+
export type ToolGroupKey = (typeof TOOL_CATALOG)[number]['key'];
|
|
556
|
+
|
|
557
|
+
const TOOL_INDEX = new Map<
|
|
558
|
+
string,
|
|
559
|
+
{ tool: CatalogTool; group: CatalogGroup }
|
|
560
|
+
>();
|
|
561
|
+
for (const group of TOOL_CATALOG) {
|
|
562
|
+
for (const tool of group.tools) {
|
|
563
|
+
TOOL_INDEX.set(tool.key, { tool, group });
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const GROUP_INDEX = new Map<string, CatalogGroup>(
|
|
568
|
+
TOOL_CATALOG.map(group => [group.key, group])
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
export const TOOL_KEYS = [...TOOL_INDEX.keys()] as ToolKey[];
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Look up one tool and the group it belongs to.
|
|
575
|
+
*
|
|
576
|
+
* Returns undefined rather than throwing, because the callers that matter are
|
|
577
|
+
* reading a STORED `artifact_tool.tool_key` — a row written before a tool was
|
|
578
|
+
* retired still has to be readable. The MCP boot loop skips what it can't
|
|
579
|
+
* resolve; it must never fail the whole artifact over one row.
|
|
580
|
+
*/
|
|
581
|
+
export const findCatalogTool = (
|
|
582
|
+
key: string
|
|
583
|
+
): { tool: CatalogTool; group: CatalogGroup } | undefined =>
|
|
584
|
+
TOOL_INDEX.get(key);
|
|
585
|
+
|
|
586
|
+
export const findCatalogGroup = (key: string): CatalogGroup | undefined =>
|
|
587
|
+
GROUP_INDEX.get(key);
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Is this a tool the platform ships? Used on the WRITE path, where installing an
|
|
591
|
+
* unknown key has to be refused — unlike the read path above, which is lenient
|
|
592
|
+
* on purpose.
|
|
593
|
+
*/
|
|
594
|
+
export const isToolKey = (key: string): key is ToolKey => TOOL_INDEX.has(key);
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* One installed tool's catalog entry, shaped for an API response.
|
|
598
|
+
*
|
|
599
|
+
* `artifact_tool` rows carry only a key, so every surface that renders a tool —
|
|
600
|
+
* the dashboard's cards, a channel's usage attribution — needs the title,
|
|
601
|
+
* description and group that used to arrive on the join. Attaching it
|
|
602
|
+
* server-side keeps those responses self-describing, so a client never has to
|
|
603
|
+
* hold its own copy of the catalog to render a row.
|
|
604
|
+
*
|
|
605
|
+
* Null for a key the catalog no longer offers. Callers render what they can
|
|
606
|
+
* (the key is still on the row) rather than dropping the tool.
|
|
607
|
+
*/
|
|
608
|
+
export interface CatalogToolDescriptor {
|
|
609
|
+
key: string;
|
|
610
|
+
title: string;
|
|
611
|
+
description: string | null;
|
|
612
|
+
requiredScopes: string | null;
|
|
613
|
+
group: Omit<CatalogGroup, 'tools'>;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
export const describeCatalogTool = (
|
|
617
|
+
key: string
|
|
618
|
+
): CatalogToolDescriptor | null => {
|
|
619
|
+
const found = TOOL_INDEX.get(key);
|
|
620
|
+
if (!found) return null;
|
|
621
|
+
const { tool, group } = found;
|
|
622
|
+
return {
|
|
623
|
+
key: tool.key,
|
|
624
|
+
title: tool.title,
|
|
625
|
+
description: tool.description,
|
|
626
|
+
requiredScopes: tool.requiredScopes,
|
|
627
|
+
group: {
|
|
628
|
+
key: group.key,
|
|
629
|
+
title: group.title,
|
|
630
|
+
description: group.description,
|
|
631
|
+
icon: group.icon,
|
|
632
|
+
provider: group.provider
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const validateMessageVariables = (
|
|
2
|
+
messages: Array<{ role: string; content: string }>,
|
|
3
|
+
schema: { properties?: Record<string, unknown> }
|
|
4
|
+
) => {
|
|
5
|
+
const schemaKeys = Object.keys(schema.properties ?? {});
|
|
6
|
+
const variablePattern = /\{\{(\w+)\}\}/g;
|
|
7
|
+
|
|
8
|
+
for (const msg of messages) {
|
|
9
|
+
let match;
|
|
10
|
+
while ((match = variablePattern.exec(msg.content)) !== null) {
|
|
11
|
+
if (!schemaKeys.includes(match[1])) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`Variable "{{${match[1]}}}" in message is not defined in schema properties`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Pull a readable message out of an error body returned by a vendor API.
|
|
2
|
+
//
|
|
3
|
+
// The resource-handler container forwards the vendor's own error body verbatim,
|
|
4
|
+
// and the vendors disagree about its shape: Gmail and Microsoft Graph answer
|
|
5
|
+
// with `{ error: { code, message, … } }` — an OBJECT — while Slack and the
|
|
6
|
+
// container's own guards use a plain string. Reading `.error` straight into an
|
|
7
|
+
// Error message turns a perfectly diagnosable failure into "[object Object]",
|
|
8
|
+
// which is what every one of these call sites did until a real Gmail rejection
|
|
9
|
+
// was put through them.
|
|
10
|
+
export const describeVendorError = (body: unknown, fallback: string): string => {
|
|
11
|
+
const error = (body as { error?: unknown } | null | undefined)?.error;
|
|
12
|
+
if (typeof error === 'string' && error) return error;
|
|
13
|
+
if (error && typeof error === 'object') {
|
|
14
|
+
const message = (error as { message?: unknown }).message;
|
|
15
|
+
if (typeof message === 'string' && message) return message;
|
|
16
|
+
return JSON.stringify(error).slice(0, 500);
|
|
17
|
+
}
|
|
18
|
+
return fallback;
|
|
19
|
+
};
|