@koda-sl/baker-cli 0.417.0 → 0.418.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/README.md +4 -2
- package/dist/cli.js +150 -40
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -865,7 +865,7 @@ baker ads x targeting-constants --constant tv_shows --locale en-US
|
|
|
865
865
|
|
|
866
866
|
### ChatGPT Ads (`baker ads chatgpt`)
|
|
867
867
|
|
|
868
|
-
Read the company's ChatGPT Ads account (OpenAI's ads inside ChatGPT conversations) and how it performs, and stage changes to it that apply when the chat is published. The company connects one account in the
|
|
868
|
+
Read the company's ChatGPT Ads account (OpenAI's ads inside ChatGPT conversations) and how it performs, and stage changes to it that apply when the chat is published. The company connects one account with an API key from its Ads Manager, pasted in the chat's connect card (`request_connection` `{ platform: "chatgpt-ads" }`) or in Brain → Integrations → ChatGPT Ads; the key stays in Baker and never reaches the CLI, so there is no account id to pass.
|
|
869
869
|
|
|
870
870
|
| Subcommand | What it returns |
|
|
871
871
|
|---|---|
|
|
@@ -3730,12 +3730,13 @@ Permissions enforced server-side:
|
|
|
3730
3730
|
|
|
3731
3731
|
---
|
|
3732
3732
|
|
|
3733
|
-
### `baker mcp connected | list | add | remove`
|
|
3733
|
+
### `baker mcp connected | catalog | list | add | remove`
|
|
3734
3734
|
|
|
3735
3735
|
See everything a chat can reach — managed integrations, custom servers, and connected platforms — and manage **custom MCP servers** by pointing the agent at any remote HTTPS MCP endpoint. Registered tools appear as `mcp__<name>__*` on the next chat message.
|
|
3736
3736
|
|
|
3737
3737
|
```bash
|
|
3738
3738
|
baker mcp connected
|
|
3739
|
+
baker mcp catalog --search notion
|
|
3739
3740
|
baker mcp list
|
|
3740
3741
|
baker mcp add --name weather --url https://mcp.example.com/mcp
|
|
3741
3742
|
baker mcp add --name acme --url https://acme.dev/mcp --header "Authorization: Bearer sk-…"
|
|
@@ -3744,6 +3745,7 @@ baker mcp remove --name weather
|
|
|
3744
3745
|
```
|
|
3745
3746
|
|
|
3746
3747
|
- `connected` returns three lists. `managed` and `custom` are MCP tools the agent calls directly; `platforms` are the accounts the company signed in to (HubSpot, Google Ads, GA4, Search Console, Tag Manager, LinkedIn Ads), each with its login and the resources it may read. A platform has **no** `mcp__*` tools — it is read through its own command family — so it is listed here to keep the agent from concluding a working connection is missing.
|
|
3748
|
+
- `catalog --search <name> [--limit 1-20]` searches the managed apps a user can connect when a vendor has no MCP server of its own. Each app reports its slug (`app`), how the user connects it (`sign-in` or `key`; apps that need no sign-in cannot be connected and are left out) — never a managed copy of one of Baker's own connections: those come back under `platforms`, to ask for with `{ platform }` and whether this chat already reaches it (`connected`).
|
|
3747
3749
|
- `--url` must be the **full MCP endpoint** (commonly ending in `/mcp`), HTTPS and public; loopback / private / cloud-metadata hosts are rejected. A bare domain frequently accepts the OAuth sign-in and then serves no tools, so every address is handshake-checked after it changes: `connected` and `list` report `usable: false` plus a `problem` (and a `suggestedAddress` when the server advertises a better endpoint) for a server that isn't serving tools, or `lastCheck: failed` when the last check only hit an outage — that one may work anyway, and a later turn re-checks it automatically. Repointing a server at a different host clears its saved sign-in: a token belongs to the host that issued it, so the server has to be connected again.
|
|
3748
3750
|
- Scope is two independent choices — audience (just you / everyone) × level (this company / whole org):
|
|
3749
3751
|
- `--scope company` (default) — everyone in this company.
|
package/dist/cli.js
CHANGED
|
@@ -34614,7 +34614,7 @@ var chatgptAdsConversionReportRequestSchema = z38.object({
|
|
|
34614
34614
|
var CHATGPT_ADS_TRUNCATED_HEADER = "X-Baker-Truncated";
|
|
34615
34615
|
|
|
34616
34616
|
// src/commands/ads/chatgpt/shared.ts
|
|
34617
|
-
var CONNECT_EXPLANATION =
|
|
34617
|
+
var CONNECT_EXPLANATION = 'Ask for ChatGPT Ads with request_connection `{ platform: "chatgpt-ads" }`: the card asks for the API key from the company\'s ChatGPT Ads Manager (Settings \u2192 API keys), and the user pastes it there \u2014 never ask for it in this chat. If they skip it, carry on with the rest of the task and say what stays unavailable until it is connected.';
|
|
34618
34618
|
var OPENAI_ADS_DOCS = "https://developers.openai.com/ads";
|
|
34619
34619
|
var CHATGPT_ADS_REFERENCE = {
|
|
34620
34620
|
account: `${OPENAI_ADS_DOCS}/api-reference/ad-account.md`,
|
|
@@ -34691,7 +34691,7 @@ function chatgptFailure(err, reference = CHATGPT_ADS_REFERENCE.overview) {
|
|
|
34691
34691
|
message: err.message,
|
|
34692
34692
|
fix: {
|
|
34693
34693
|
action: "authenticate",
|
|
34694
|
-
explanation: `${err.message}
|
|
34694
|
+
explanation: `${err.message} Open request_connection \`{ platform: "chatgpt-ads" }\` so they can replace the key in the card; never ask them to paste it in this chat.`
|
|
34695
34695
|
},
|
|
34696
34696
|
retryable: false
|
|
34697
34697
|
}
|
|
@@ -93825,9 +93825,60 @@ Subcommands:
|
|
|
93825
93825
|
}
|
|
93826
93826
|
});
|
|
93827
93827
|
|
|
93828
|
+
// ../api/src/mcp-catalog.ts
|
|
93829
|
+
import { z as z65 } from "zod";
|
|
93830
|
+
var MCP_CATALOG_DEFAULT_LIMIT = 8;
|
|
93831
|
+
var MCP_CATALOG_DESCRIPTION_MAX = 160;
|
|
93832
|
+
var mcpCatalogRequestSchema = z65.object({
|
|
93833
|
+
search: z65.string().trim().min(1, "Provide --search").max(100),
|
|
93834
|
+
limit: z65.coerce.number().int().min(1).max(20).default(MCP_CATALOG_DEFAULT_LIMIT)
|
|
93835
|
+
});
|
|
93836
|
+
var mcpCatalogConnectSchema = z65.enum(["sign-in", "key"]);
|
|
93837
|
+
var mcpCatalogEntrySchema = z65.object({
|
|
93838
|
+
/** The toolkit slug — what request_connection `{ app }` takes. */
|
|
93839
|
+
app: z65.string(),
|
|
93840
|
+
name: z65.string(),
|
|
93841
|
+
description: z65.string().max(MCP_CATALOG_DESCRIPTION_MAX),
|
|
93842
|
+
connect: mcpCatalogConnectSchema,
|
|
93843
|
+
connected: z65.boolean()
|
|
93844
|
+
});
|
|
93845
|
+
var mcpCatalogResponseSchema = z65.object({
|
|
93846
|
+
apps: z65.array(mcpCatalogEntrySchema),
|
|
93847
|
+
/** The company has managed apps switched off: nothing here can be connected, so `apps` is empty. */
|
|
93848
|
+
managedDisabled: z65.boolean().optional(),
|
|
93849
|
+
/** Baker's own connections this search matched — ask for these with `{ platform }`, never a managed copy. */
|
|
93850
|
+
platforms: z65.array(z65.string()).optional()
|
|
93851
|
+
});
|
|
93852
|
+
|
|
93828
93853
|
// src/commands/mcp/index.ts
|
|
93829
93854
|
import { defineCommand as defineCommand211 } from "citty";
|
|
93830
93855
|
|
|
93856
|
+
// src/commands/mcp/catalog.ts
|
|
93857
|
+
var PREFER_VENDOR_HINT = 'The vendor\'s own MCP server comes before any app here. If you have not yet, WebSearch "<vendor> MCP server" and WebFetch its official docs for the remote https address and how it signs in, then ask for it with request_connection `{ server: { name, url, auth, keyHeader } }`. Only when the vendor has none, ask for an app from this catalog with request_connection `{ app: "<slug>", reason }` \u2014 the user connects it in the chat and its tools load right after, in this same turn.';
|
|
93858
|
+
var ALREADY_CONNECTED_HINT = "An app marked connected is already reachable \u2014 use its mcp__composio_* tools; do not ask again.";
|
|
93859
|
+
var NO_MATCH_HINT = "Nothing in the catalog matches. WebSearch for the vendor's official remote MCP server (its docs, its developer site) before telling the user it can't be connected \u2014 if one exists, ask for it with request_connection `{ server }`. Only when the web shows no official remote server either, say plainly this tool can't be connected yet and offer a Task.";
|
|
93860
|
+
var MANAGED_DISABLED_HINT = "Managed apps are switched off for this company, so none can be connected here. Use the vendor's own MCP server \u2014 WebSearch \"<vendor> MCP server\" and WebFetch its official docs, then request_connection `{ server }`; when it has none, say plainly this tool can't be connected yet and offer a Task.";
|
|
93861
|
+
function firstPartyHint(platforms) {
|
|
93862
|
+
const asks = platforms.map((p) => `request_connection \`{ platform: "${p}" }\``).join(" or ");
|
|
93863
|
+
return `This is one of Baker's own connections \u2014 ask for it with ${asks}. It is the one Baker's commands, staging and publish work with, so never connect it as a catalog app or as an MCP server, even one the vendor publishes or the user names. If it is already connected, read it with its own baker command family instead.`;
|
|
93864
|
+
}
|
|
93865
|
+
function catalogHints(apps, { managedDisabled = false, platforms = [] } = {}) {
|
|
93866
|
+
if (platforms.length > 0) {
|
|
93867
|
+
return [firstPartyHint(platforms)];
|
|
93868
|
+
}
|
|
93869
|
+
if (managedDisabled) {
|
|
93870
|
+
return [MANAGED_DISABLED_HINT];
|
|
93871
|
+
}
|
|
93872
|
+
const hints2 = [PREFER_VENDOR_HINT];
|
|
93873
|
+
if (apps.some((a) => a.connected)) {
|
|
93874
|
+
hints2.push(ALREADY_CONNECTED_HINT);
|
|
93875
|
+
}
|
|
93876
|
+
if (apps.length === 0) {
|
|
93877
|
+
hints2.push(NO_MATCH_HINT);
|
|
93878
|
+
}
|
|
93879
|
+
return hints2;
|
|
93880
|
+
}
|
|
93881
|
+
|
|
93831
93882
|
// src/commands/mcp/platforms.ts
|
|
93832
93883
|
function readsKey(label) {
|
|
93833
93884
|
const [first = "", ...rest] = label.split(" ");
|
|
@@ -93937,7 +93988,7 @@ A tool or platform the user names that is NOT listed anywhere here is simply not
|
|
|
93937
93988
|
);
|
|
93938
93989
|
}
|
|
93939
93990
|
hints2.push(
|
|
93940
|
-
"Not listed anywhere = not connected
|
|
93991
|
+
"Not listed anywhere = not connected \u2014 connect it from the chat with request_connection, never by sending the user to the dashboard: a Baker platform (HubSpot, Google Ads, GA4, \u2026) \u2192 { platform }; anything else \u2192 the vendor's own MCP server FIRST: use the address the user gave you, or WebSearch '<vendor> MCP server' and WebFetch its official docs for the remote https address and how it signs in, then { server: { name, url, auth, keyHeader } }; only when the vendor has none \u2192 `baker mcp catalog --search <name>`, then { app }. Research before you ask the user anything. What they connect loads into this same turn."
|
|
93941
93992
|
);
|
|
93942
93993
|
writeJson({
|
|
93943
93994
|
ok: true,
|
|
@@ -93949,6 +94000,61 @@ A tool or platform the user names that is NOT listed anywhere here is simply not
|
|
|
93949
94000
|
}
|
|
93950
94001
|
}
|
|
93951
94002
|
});
|
|
94003
|
+
var catalogArgs = {
|
|
94004
|
+
search: { type: "string", description: "App or vendor name, e.g. notion, clarity, pipedrive", required: true },
|
|
94005
|
+
limit: { type: "string", description: "Max apps to return, 1-20 (default 8)", required: false }
|
|
94006
|
+
};
|
|
94007
|
+
registerSchema({
|
|
94008
|
+
command: "mcp.catalog",
|
|
94009
|
+
description: "Search the managed apps you can ask the user to connect when a vendor has no MCP server of its own. Each app says how the user connects it (sign-in | key) and whether this chat already reaches it. Example: baker mcp catalog --search notion",
|
|
94010
|
+
args: catalogArgs
|
|
94011
|
+
});
|
|
94012
|
+
var catalogCommand2 = defineCommand211({
|
|
94013
|
+
meta: {
|
|
94014
|
+
name: "catalog",
|
|
94015
|
+
description: `Managed apps you can ask the user to connect when a vendor has no MCP server of its own.
|
|
94016
|
+
|
|
94017
|
+
For a tool \`baker mcp connected\` does not list whose vendor has no official remote MCP server:
|
|
94018
|
+
baker mcp catalog --search notion
|
|
94019
|
+
baker mcp catalog --search "microsoft clarity" --limit 3
|
|
94020
|
+
|
|
94021
|
+
Each app: app (slug for request_connection), name, description, connect (sign-in | key), connected.
|
|
94022
|
+
Prefer the vendor's own MCP server when it publishes one; a catalog app is the fallback.`
|
|
94023
|
+
},
|
|
94024
|
+
args: catalogArgs,
|
|
94025
|
+
run: async ({ args: args8 }) => {
|
|
94026
|
+
const parsed = mcpCatalogRequestSchema.safeParse({ search: args8.search, limit: args8.limit });
|
|
94027
|
+
if (!parsed.success) {
|
|
94028
|
+
writeJson({
|
|
94029
|
+
ok: false,
|
|
94030
|
+
error: { code: "VALIDATION_ERROR", message: parsed.error.issues[0]?.message ?? "Invalid arguments" }
|
|
94031
|
+
});
|
|
94032
|
+
process.exit(1);
|
|
94033
|
+
}
|
|
94034
|
+
try {
|
|
94035
|
+
const user = actingUserId();
|
|
94036
|
+
const data = await apiGet("/api/mcp/catalog", {
|
|
94037
|
+
search: parsed.data.search,
|
|
94038
|
+
limit: String(parsed.data.limit),
|
|
94039
|
+
...user ? { actingUserId: user } : {}
|
|
94040
|
+
});
|
|
94041
|
+
writeJson({
|
|
94042
|
+
ok: true,
|
|
94043
|
+
data: {
|
|
94044
|
+
apps: data.apps,
|
|
94045
|
+
...data.platforms?.length ? { platforms: data.platforms } : {},
|
|
94046
|
+
...data.managedDisabled ? { managedDisabled: true } : {}
|
|
94047
|
+
},
|
|
94048
|
+
hints: catalogHints(data.apps, {
|
|
94049
|
+
managedDisabled: data.managedDisabled === true,
|
|
94050
|
+
platforms: data.platforms ?? []
|
|
94051
|
+
})
|
|
94052
|
+
});
|
|
94053
|
+
} catch (err) {
|
|
94054
|
+
fail10(err);
|
|
94055
|
+
}
|
|
94056
|
+
}
|
|
94057
|
+
});
|
|
93952
94058
|
registerSchema({
|
|
93953
94059
|
command: "mcp.list",
|
|
93954
94060
|
description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
|
|
@@ -93995,6 +94101,8 @@ var addCommand2 = defineCommand211({
|
|
|
93995
94101
|
meta: {
|
|
93996
94102
|
name: "add",
|
|
93997
94103
|
description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
|
|
94104
|
+
For a server the USER asks for, use request_connection { server } instead: they confirm who can use it,
|
|
94105
|
+
type any key into the card (never the chat), and its tools load in this same turn.
|
|
93998
94106
|
|
|
93999
94107
|
Scope: company (default \u2014 every chat in the company) | org (all companies in the org; needs an admin key) | user (only the current message sender).
|
|
94000
94108
|
|
|
@@ -94075,6 +94183,7 @@ Managed here are **company-scoped** servers; user- and org-scoped servers are ma
|
|
|
94075
94183
|
|
|
94076
94184
|
Start here:
|
|
94077
94185
|
baker mcp connected # everything this chat can reach: managed integrations, custom servers, connected platforms
|
|
94186
|
+
baker mcp catalog --search notion # managed apps you can connect when a vendor has no MCP server of its own
|
|
94078
94187
|
|
|
94079
94188
|
Examples:
|
|
94080
94189
|
baker mcp add --name weather --url https://mcp.example.com/mcp
|
|
@@ -94084,6 +94193,7 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
|
94084
94193
|
},
|
|
94085
94194
|
subCommands: {
|
|
94086
94195
|
connected: connectedCommand,
|
|
94196
|
+
catalog: catalogCommand2,
|
|
94087
94197
|
list: listCommand18,
|
|
94088
94198
|
add: addCommand2,
|
|
94089
94199
|
remove: removeCommand6
|
|
@@ -94094,8 +94204,8 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
|
94094
94204
|
import { defineCommand as defineCommand217 } from "citty";
|
|
94095
94205
|
|
|
94096
94206
|
// ../api/src/media-sources.ts
|
|
94097
|
-
import { z as
|
|
94098
|
-
var mediaSourcePlatformSchema =
|
|
94207
|
+
import { z as z66 } from "zod";
|
|
94208
|
+
var mediaSourcePlatformSchema = z66.enum([
|
|
94099
94209
|
"instagram",
|
|
94100
94210
|
"tiktok",
|
|
94101
94211
|
"youtube",
|
|
@@ -94103,55 +94213,55 @@ var mediaSourcePlatformSchema = z65.enum([
|
|
|
94103
94213
|
"facebook",
|
|
94104
94214
|
"google_drive"
|
|
94105
94215
|
]);
|
|
94106
|
-
var mediaSourceRefreshIntervalSchema =
|
|
94107
|
-
var mediaSourceSyncStatusSchema =
|
|
94108
|
-
var mediaSourceHalfSchema =
|
|
94109
|
-
sourceId:
|
|
94216
|
+
var mediaSourceRefreshIntervalSchema = z66.enum(["never", "daily", "weekly", "monthly"]);
|
|
94217
|
+
var mediaSourceSyncStatusSchema = z66.enum(["idle", "fetching", "processing", "error"]);
|
|
94218
|
+
var mediaSourceHalfSchema = z66.object({
|
|
94219
|
+
sourceId: z66.string(),
|
|
94110
94220
|
syncStatus: mediaSourceSyncStatusSchema,
|
|
94111
|
-
storedCount:
|
|
94112
|
-
pendingItems:
|
|
94113
|
-
failedItems:
|
|
94114
|
-
lastSyncedAt:
|
|
94115
|
-
errorMessage:
|
|
94116
|
-
});
|
|
94117
|
-
var mediaSourceSummarySchema =
|
|
94118
|
-
key:
|
|
94221
|
+
storedCount: z66.number().optional(),
|
|
94222
|
+
pendingItems: z66.number().optional(),
|
|
94223
|
+
failedItems: z66.number().optional(),
|
|
94224
|
+
lastSyncedAt: z66.number().optional(),
|
|
94225
|
+
errorMessage: z66.string().optional()
|
|
94226
|
+
});
|
|
94227
|
+
var mediaSourceSummarySchema = z66.object({
|
|
94228
|
+
key: z66.string(),
|
|
94119
94229
|
platform: mediaSourcePlatformSchema,
|
|
94120
|
-
platformLabel:
|
|
94121
|
-
handle:
|
|
94122
|
-
label:
|
|
94123
|
-
profileUrl:
|
|
94124
|
-
profileImageUrl:
|
|
94230
|
+
platformLabel: z66.string(),
|
|
94231
|
+
handle: z66.string(),
|
|
94232
|
+
label: z66.string(),
|
|
94233
|
+
profileUrl: z66.string(),
|
|
94234
|
+
profileImageUrl: z66.string().optional(),
|
|
94125
94235
|
refreshInterval: mediaSourceRefreshIntervalSchema,
|
|
94126
94236
|
/** Absent for a platform that feeds no images (YouTube). */
|
|
94127
94237
|
images: mediaSourceHalfSchema.optional(),
|
|
94128
94238
|
videos: mediaSourceHalfSchema.optional(),
|
|
94129
|
-
createdAt:
|
|
94239
|
+
createdAt: z66.number()
|
|
94130
94240
|
});
|
|
94131
|
-
var mediaSourceProfileSchema =
|
|
94241
|
+
var mediaSourceProfileSchema = z66.object({
|
|
94132
94242
|
platform: mediaSourcePlatformSchema,
|
|
94133
|
-
handle:
|
|
94134
|
-
displayName:
|
|
94135
|
-
avatarUrl:
|
|
94136
|
-
bio:
|
|
94137
|
-
followers:
|
|
94138
|
-
postCount:
|
|
94139
|
-
isPrivate:
|
|
94140
|
-
profileUrl:
|
|
94141
|
-
channelId:
|
|
94142
|
-
});
|
|
94143
|
-
var mediaSourcesAddRequestSchema =
|
|
94243
|
+
handle: z66.string(),
|
|
94244
|
+
displayName: z66.string(),
|
|
94245
|
+
avatarUrl: z66.string(),
|
|
94246
|
+
bio: z66.string(),
|
|
94247
|
+
followers: z66.number().optional(),
|
|
94248
|
+
postCount: z66.number().optional(),
|
|
94249
|
+
isPrivate: z66.boolean(),
|
|
94250
|
+
profileUrl: z66.string(),
|
|
94251
|
+
channelId: z66.string().optional()
|
|
94252
|
+
});
|
|
94253
|
+
var mediaSourcesAddRequestSchema = z66.object({
|
|
94144
94254
|
/** A profile URL or a Drive folder link, or an @handle together with `platform`. */
|
|
94145
|
-
input:
|
|
94255
|
+
input: z66.string().trim().min(1, "Pass the account's profile URL or @handle"),
|
|
94146
94256
|
/** Needed only when `input` is a bare handle; a URL names its own platform. */
|
|
94147
94257
|
platform: mediaSourcePlatformSchema.optional(),
|
|
94148
94258
|
/** Auto-sync cadence. Omitted = weekly, for every platform. */
|
|
94149
94259
|
every: mediaSourceRefreshIntervalSchema.optional()
|
|
94150
94260
|
});
|
|
94151
|
-
var mediaSourceKeySchema =
|
|
94152
|
-
var mediaSourcesSyncRequestSchema =
|
|
94153
|
-
var mediaSourcesRemoveRequestSchema =
|
|
94154
|
-
var mediaSourcesScheduleRequestSchema =
|
|
94261
|
+
var mediaSourceKeySchema = z66.string().trim().regex(/^(instagram|tiktok|youtube|linkedin|facebook|google_drive):.+$/, "Pass a source key like tiktok:nike");
|
|
94262
|
+
var mediaSourcesSyncRequestSchema = z66.object({ key: mediaSourceKeySchema });
|
|
94263
|
+
var mediaSourcesRemoveRequestSchema = z66.object({ key: mediaSourceKeySchema });
|
|
94264
|
+
var mediaSourcesScheduleRequestSchema = z66.object({
|
|
94155
94265
|
key: mediaSourceKeySchema,
|
|
94156
94266
|
every: mediaSourceRefreshIntervalSchema
|
|
94157
94267
|
});
|