@zackbart/connecta 0.28.0 → 0.29.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/CHANGELOG.md +961 -5
- package/README.md +62 -39
- package/bin/connecta.mjs +110 -139
- package/bin/meta-tool-names.d.mts +2 -0
- package/bin/meta-tool-names.mjs +9 -0
- package/bin/version.mjs +3 -0
- package/dist/access-tokens.js +53 -63
- package/dist/activity-request.js +8 -0
- package/dist/activity.d.ts +76 -42
- package/dist/activity.js +110 -42
- package/dist/auth/clerk-sdk/client.d.ts +65 -0
- package/dist/auth/clerk-sdk/client.js +5 -0
- package/dist/auth/clerk-sdk/generated.js +1845 -0
- package/dist/auth/clerk-transport.js +19 -0
- package/dist/auth/clerk.d.ts +17 -7
- package/dist/auth/clerk.js +189 -107
- package/dist/auth/cloudflare-access.js +25 -26
- package/dist/auth/downstream-client-metadata.d.ts +29 -0
- package/dist/auth/downstream-client-metadata.js +133 -0
- package/dist/auth/downstream-oauth.js +1632 -1509
- package/dist/auth/downstream-revocation.js +106 -0
- package/dist/auth/oauth-token-response.js +231 -0
- package/dist/auth/oauth-v2-migration.js +116 -0
- package/dist/auth/static-oauth.js +526 -0
- package/dist/auth-elicitation.js +283 -0
- package/dist/branding.d.ts +8 -16
- package/dist/branding.js +26 -59
- package/dist/byte-read-response.js +39 -0
- package/dist/call-admission.js +12 -16
- package/dist/catalog-cache.js +739 -0
- package/dist/catalog-drift.d.ts +50 -15
- package/dist/catalog-drift.js +365 -128
- package/dist/catalog-fingerprint.js +2 -4
- package/dist/catalog-freshness.js +13 -0
- package/dist/catalog-limits.js +2 -2
- package/dist/catalog-service.js +368 -224
- package/dist/catalog.js +43 -84
- package/dist/concurrency.js +3 -4
- package/dist/config-defaults.d.ts +39 -0
- package/dist/config-defaults.js +46 -0
- package/dist/config-schema.d.ts +181 -0
- package/dist/config-schema.js +435 -0
- package/dist/config-value-sources.js +102 -0
- package/dist/config.d.ts +631 -0
- package/dist/config.js +503 -0
- package/dist/connector-access.d.ts +1 -0
- package/dist/connector-access.js +13 -15
- package/dist/connector-caller.d.ts +8 -0
- package/dist/connector-caller.js +15 -6
- package/dist/connector-scope.js +1 -1
- package/dist/connectors/api-connector.d.ts +220 -0
- package/dist/connectors/api-connector.js +214 -0
- package/dist/connectors/api.d.ts +8 -71
- package/dist/connectors/api.js +13 -99
- package/dist/connectors/guarded-fetch.d.ts +144 -0
- package/dist/connectors/guarded-fetch.js +108 -25
- package/dist/connectors/negotiation-cache.js +46 -0
- package/dist/connectors/option-shapes.js +27 -0
- package/dist/connectors/remote-mcp.d.ts +30 -4
- package/dist/connectors/remote-mcp.js +1780 -351
- package/dist/connectors/resource-uri.js +335 -0
- package/dist/credential-contract.d.ts +10 -0
- package/dist/credential-rules.js +1 -3
- package/dist/credential-url.js +108 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +27 -18
- package/dist/d1.d.ts +130 -0
- package/dist/d1.js +290 -0
- package/dist/describe-config.d.ts +165 -0
- package/dist/describe-config.js +315 -0
- package/dist/described.js +106 -0
- package/dist/downstream-input-context.js +119 -0
- package/dist/downstream-input.js +323 -0
- package/dist/errors.d.ts +97 -20
- package/dist/errors.js +158 -80
- package/dist/execute.js +453 -305
- package/dist/executor-admission.d.ts +1 -0
- package/dist/executor-admission.js +11 -15
- package/dist/executor-contract.d.ts +20 -0
- package/dist/executor-contract.js +48 -0
- package/dist/executor-result.js +24 -9
- package/dist/executors/quickjs-child.js +3 -4
- package/dist/executors/quickjs-runtime.js +147 -59
- package/dist/executors/quickjs.js +29 -35
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +188 -0
- package/dist/guest-types.d.ts +176 -0
- package/dist/guest-types.js +1 -0
- package/dist/html-security.js +24 -0
- package/dist/identity.js +1 -3
- package/dist/inbound-credential.js +52 -0
- package/dist/index.d.ts +25 -257
- package/dist/index.js +65 -478
- package/dist/invocation-auth.js +69 -0
- package/dist/invocation.js +230 -73
- package/dist/json-schema.d.ts +1 -1
- package/dist/mcp-client-context.js +35 -0
- package/dist/mcp-result.js +11 -7
- package/dist/meta-output.js +76 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +285 -209
- package/dist/module-contracts.d.ts +8 -23
- package/dist/node.d.ts +0 -2
- package/dist/node.js +2 -2
- package/dist/oauth-callback-outcome.js +1 -3
- package/dist/oauth-handoff.js +117 -0
- package/dist/oauth-partition.js +17 -0
- package/dist/oauth-sealing.js +20 -0
- package/dist/operator-record.d.ts +137 -0
- package/dist/operator-record.js +420 -0
- package/dist/operator-ui/assets.js +31 -0
- package/dist/operator-ui/contract.d.ts +72 -0
- package/dist/operator-ui/contract.js +1 -0
- package/dist/operator-ui/fix-prompts.d.ts +18 -0
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/model.d.ts +12 -87
- package/dist/operator-ui/model.js +2 -9
- package/dist/operator-ui/setup-commands.js +1 -3
- package/dist/operator-ui/view.d.ts +323 -0
- package/dist/operator-ui/view.js +62 -189
- package/dist/page-styles.js +2 -3
- package/dist/program-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +55 -18
- package/dist/provider.d.ts +142 -0
- package/dist/provider.js +187 -0
- package/dist/providers/_shared/google/result-size.js +57 -0
- package/dist/providers/_shared/google/service-account.d.ts +58 -0
- package/dist/providers/_shared/google/service-account.js +500 -0
- package/dist/providers/_shared/google/workspace.d.ts +276 -0
- package/dist/providers/_shared/google/workspace.js +518 -0
- package/dist/providers/basecamp/index.d.ts +43 -0
- package/dist/providers/basecamp/index.js +997 -0
- package/dist/providers/basecamp/skill.generated.js +9 -0
- package/dist/providers/breeze/index.d.ts +34 -0
- package/dist/providers/breeze/index.js +1446 -0
- package/dist/providers/breeze/skill.generated.js +9 -0
- package/dist/providers/ccb/index.d.ts +103 -0
- package/dist/providers/ccb/index.js +1725 -0
- package/dist/providers/ccb/skill.generated.js +9 -0
- package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
- package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
- package/dist/providers/cloudflare/skill.generated.js +10 -0
- package/dist/providers/docs/index.d.ts +54 -0
- package/dist/providers/docs/index.js +1237 -0
- package/dist/providers/docs/skill.generated.js +9 -0
- package/dist/providers/drive/index.d.ts +53 -0
- package/dist/providers/drive/index.js +1523 -0
- package/dist/providers/drive/skill.generated.js +9 -0
- package/dist/providers/forms/index.d.ts +54 -0
- package/dist/providers/forms/index.js +1217 -0
- package/dist/providers/forms/skill.generated.js +11 -0
- package/dist/providers/github/auth.d.ts +32 -0
- package/dist/providers/github/auth.js +361 -0
- package/dist/providers/github/hosted.js +218 -0
- package/dist/providers/github/index.d.ts +13 -0
- package/dist/providers/github/index.js +140 -0
- package/dist/providers/github/key.js +100 -0
- package/dist/providers/github/rest.js +321 -0
- package/dist/providers/github/scope.d.ts +29 -0
- package/dist/providers/github/scope.js +124 -0
- package/dist/providers/github/skill.generated.js +8 -0
- package/dist/providers/gmail/index.d.ts +51 -0
- package/dist/providers/gmail/index.js +1436 -0
- package/dist/providers/gmail/skill.generated.js +9 -0
- package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
- package/dist/providers/linear/index.js +352 -0
- package/dist/providers/linear/skill.generated.js +8 -0
- package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
- package/dist/providers/mixpanel/index.js +416 -0
- package/dist/providers/mixpanel/skill.generated.js +9 -0
- package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
- package/dist/providers/{notion.js → notion/index.js} +226 -239
- package/dist/providers/notion/skill.generated.js +10 -0
- package/dist/providers/overflow/index.d.ts +60 -0
- package/dist/providers/overflow/index.js +1535 -0
- package/dist/providers/overflow/skill.generated.js +8 -0
- package/dist/providers/planning-center/index.d.ts +59 -0
- package/dist/providers/planning-center/index.js +2199 -0
- package/dist/providers/planning-center/skill.generated.js +10 -0
- package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
- package/dist/providers/revenuecat/index.js +557 -0
- package/dist/providers/revenuecat/skill.generated.js +11 -0
- package/dist/providers/sheets/index.d.ts +54 -0
- package/dist/providers/sheets/index.js +1237 -0
- package/dist/providers/sheets/skill.generated.js +10 -0
- package/dist/providers/slides/index.d.ts +53 -0
- package/dist/providers/slides/index.js +2645 -0
- package/dist/providers/slides/skill.generated.js +9 -0
- package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
- package/dist/providers/stripe/index.js +266 -0
- package/dist/providers/stripe/skill.generated.js +11 -0
- package/dist/providers/tithely/index.d.ts +49 -0
- package/dist/providers/tithely/index.js +1003 -0
- package/dist/providers/tithely/skill.generated.js +8 -0
- package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
- package/dist/providers/vercel/index.js +1038 -0
- package/dist/providers/vercel/mcp-ownership.js +212 -0
- package/dist/providers/vercel/skill.generated.js +11 -0
- package/dist/registry.d.ts +108 -171
- package/dist/registry.js +513 -925
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +100 -0
- package/dist/result-shapes.js +17 -49
- package/dist/retired-toolkits.js +1 -1
- package/dist/routes/access-tokens.js +3 -6
- package/dist/routes/activity-context.js +21 -0
- package/dist/routes/activity-disclosure.js +40 -0
- package/dist/routes/activity.js +59 -21
- package/dist/routes/actor-labels.js +3 -50
- package/dist/routes/connect.js +221 -0
- package/dist/routes/credentials.js +15 -27
- package/dist/routes/mcp.js +356 -130
- package/dist/routes/oauth-client-metadata.js +15 -0
- package/dist/routes/oauth-management.js +45 -107
- package/dist/routes/oauth.js +136 -57
- package/dist/routes/operator.js +3 -3
- package/dist/routes/shared.d.ts +25 -64
- package/dist/routes/shared.js +160 -80
- package/dist/routes/skills.js +30 -0
- package/dist/routes/ui-config.js +225 -0
- package/dist/routes/ui-data.js +40 -35
- package/dist/routes/ui.js +66 -56
- package/dist/runtime/admission.js +4 -2
- package/dist/runtime/call-admission.js +3 -1
- package/dist/runtime/connector-scope.js +1 -4
- package/dist/runtime/run.js +10 -39
- package/dist/runtime/services.js +12 -117
- package/dist/runtime/shared-read.js +1 -3
- package/dist/runtime/storage.js +8 -1
- package/dist/sent-secrets.d.ts +52 -0
- package/dist/sent-secrets.js +474 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +406 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +166 -0
- package/dist/storage/keys.js +428 -0
- package/dist/storage/memory.js +7 -0
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +534 -0
- package/dist/timeout.js +4 -2
- package/dist/tool-name.js +17 -0
- package/dist/tool-safety.d.ts +9 -35
- package/dist/tool-safety.js +20 -40
- package/dist/types.d.ts +320 -54
- package/dist/types.js +0 -1
- package/dist/ui.d.ts +7 -19
- package/dist/ui.js +76 -90
- package/dist/url-safety.js +3 -6
- package/dist/usage-guide.js +137 -0
- package/dist/validate.d.ts +7 -0
- package/dist/validate.js +309 -47
- package/dist/version.d.ts +1 -7
- package/dist/version.js +3 -7
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +434 -0
- package/documentation/architecture.md +665 -230
- package/documentation/auth.md +962 -458
- package/documentation/code-mode.md +501 -312
- package/documentation/meta-tools.md +449 -200
- package/documentation/operator-tests.md +93 -0
- package/documentation/provider-migration-0.29.md +60 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +286 -255
- package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
- package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
- package/examples/worker/src/connecta.config.ts +151 -0
- package/examples/worker/src/index.ts +14 -197
- package/examples/worker/wrangler.jsonc +15 -35
- package/package.json +125 -35
- package/templates/node/.dockerignore +1 -2
- package/templates/node/.env.example +20 -21
- package/templates/node/AGENTS.md +21 -17
- package/templates/node/Dockerfile +3 -5
- package/templates/node/README.md +133 -58
- package/templates/node/docker-compose.yml +11 -12
- package/templates/node/package.json +4 -2
- package/templates/node/src/connecta.config.ts +119 -0
- package/templates/node/src/index.ts +9 -154
- package/templates/node/src/provision-token.ts +17 -0
- package/AGENTS.md +0 -170
- package/dist/artifacts/connector.d.ts +0 -58
- package/dist/artifacts/connector.js +0 -730
- package/dist/artifacts/document.js +0 -86
- package/dist/artifacts/guide.js +0 -140
- package/dist/artifacts/html-scan.js +0 -329
- package/dist/artifacts/json.js +0 -78
- package/dist/artifacts/kv-store.d.ts +0 -20
- package/dist/artifacts/kv-store.js +0 -140
- package/dist/artifacts/markdown.js +0 -478
- package/dist/artifacts/module.d.ts +0 -37
- package/dist/artifacts/module.js +0 -66
- package/dist/artifacts/operations.d.ts +0 -197
- package/dist/artifacts/operations.js +0 -1002
- package/dist/artifacts/refresh.d.ts +0 -55
- package/dist/artifacts/refresh.js +0 -236
- package/dist/artifacts/routes.js +0 -206
- package/dist/artifacts/types.d.ts +0 -214
- package/dist/artifacts/types.js +0 -22
- package/dist/artifacts/validate.d.ts +0 -62
- package/dist/artifacts/validate.js +0 -651
- package/dist/artifacts.d.ts +0 -6
- package/dist/artifacts.js +0 -9
- package/dist/auth/bearer.d.ts +0 -11
- package/dist/auth/bearer.js +0 -50
- package/dist/providers/linear.js +0 -217
- package/dist/providers/mixpanel.js +0 -247
- package/dist/providers/revenuecat.js +0 -317
- package/dist/providers/stripe.js +0 -253
- package/dist/providers/vercel.js +0 -1253
- package/dist/storage/file.d.ts +0 -15
- package/dist/storage/file.js +0 -455
- package/ethos.md +0 -93
- package/examples/worker/src/cloudflare-kv.ts +0 -43
- package/examples/worker/src/d1-activity-row.ts +0 -155
- package/examples/worker/src/d1-activity.ts +0 -147
- package/examples/worker/src/d1-storage.ts +0 -138
- package/examples/worker/src/r2-artifact-blobs.ts +0 -29
- package/templates/node/src/file-activity.ts +0 -182
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { skill } from "./skill.generated.js";
|
|
2
|
+
import { apiConnector as api } from "../../connectors/api-connector.js";
|
|
3
|
+
import { remoteMcp } from "../../connectors/remote-mcp.js";
|
|
4
|
+
import { reviewedCatalog } from "../../catalog-drift.js";
|
|
5
|
+
import { guardedFetch, retryAfterMs } from "../../connectors/guarded-fetch.js";
|
|
6
|
+
import { ConnectorCallError } from "../../errors.js";
|
|
7
|
+
import { keys, optionsOf, variants } from "../../config-schema.js";
|
|
8
|
+
import { PROVIDER_COMMON } from "../../connectors/option-shapes.js";
|
|
9
|
+
import { defineProvider } from "../../provider.js";
|
|
6
10
|
/** Notion's REST origin. Every tool below speaks to exactly this host. */
|
|
7
11
|
export const NOTION_API_BASE_URL = "https://api.notion.com";
|
|
8
12
|
/** Notion's official hosted MCP endpoint. */
|
|
@@ -23,7 +27,7 @@ const DEFAULT_PAGE_SIZE = 25;
|
|
|
23
27
|
/** Notion's cap on `children` per append, and on blocks per page create. */
|
|
24
28
|
const MAX_CHILDREN_PER_REQUEST = 100;
|
|
25
29
|
/**
|
|
26
|
-
* Ceiling on the fetches one `
|
|
30
|
+
* Ceiling on the fetches one `integration_get_page_content` walk may spend. Call admission
|
|
27
31
|
* meters tool calls, not the requests inside them, so a deep `depth` would
|
|
28
32
|
* otherwise drain the budget invisibly; the walk stops here and reports
|
|
29
33
|
* `truncated: true` instead.
|
|
@@ -86,13 +90,15 @@ function notionFailure(status, body, headers) {
|
|
|
86
90
|
}
|
|
87
91
|
if (status === 529) {
|
|
88
92
|
// Notion documents 529 alongside 429: back off and respect Retry-After.
|
|
89
|
-
return new ConnectorCallError("unavailable", `${labelled} Notion is overloaded; retry after the reported window.`, {
|
|
93
|
+
return new ConnectorCallError("unavailable", `${labelled} Notion is overloaded; retry after the reported window.`, {
|
|
94
|
+
retryAfterMs: retryAfter ?? 5_000,
|
|
95
|
+
});
|
|
90
96
|
}
|
|
91
97
|
if (status === 401) {
|
|
92
98
|
return new ConnectorCallError("auth_required", `${labelled} The Notion integration token is missing or invalid. Call authorize_connector for recovery options. When available, an operator can set a valid token in this connection in the operator UI.`);
|
|
93
99
|
}
|
|
94
100
|
if (status === 403) {
|
|
95
|
-
return new ConnectorCallError("
|
|
101
|
+
return new ConnectorCallError("provider_permission_denied", `${labelled} The token is valid but this integration is not allowed to perform this operation. An operator must enable the matching capability on the Notion integration (comment capabilities are off by default) or share the object with it. Re-authorizing will not help.`, { retryable: false });
|
|
96
102
|
}
|
|
97
103
|
if (status === 404) {
|
|
98
104
|
return new ConnectorCallError("connector_call_failed", `${labelled} Notion returns this both for an object that does not exist and for one that exists but has not been shared with this integration — do not treat it as proof of deletion. Confirm the id, then confirm the page or database is shared with the integration in Notion.`, { retryable: false });
|
|
@@ -141,9 +147,7 @@ const send = guardedFetch({
|
|
|
141
147
|
async function notionRequest(ctx, request) {
|
|
142
148
|
return await send(request, ctx, async (response) => {
|
|
143
149
|
const parsed = await response.jsonResult();
|
|
144
|
-
const payload = "value" in parsed
|
|
145
|
-
? parsed.value
|
|
146
|
-
: undefined;
|
|
150
|
+
const payload = "value" in parsed ? parsed.value : undefined;
|
|
147
151
|
if (!response.ok) {
|
|
148
152
|
throw notionFailure(response.status, payload, response.headers);
|
|
149
153
|
}
|
|
@@ -167,9 +171,7 @@ async function notionRequest(ctx, request) {
|
|
|
167
171
|
function plainText(value) {
|
|
168
172
|
if (!Array.isArray(value))
|
|
169
173
|
return "";
|
|
170
|
-
return value
|
|
171
|
-
.map((run) => (typeof run?.plain_text === "string" ? run.plain_text : ""))
|
|
172
|
-
.join("");
|
|
174
|
+
return value.map((run) => (typeof run?.plain_text === "string" ? run.plain_text : "")).join("");
|
|
173
175
|
}
|
|
174
176
|
/** Wrap a plain string as the single-run rich-text array Notion expects. */
|
|
175
177
|
function richText(value) {
|
|
@@ -349,7 +351,7 @@ function projectPage(page, select) {
|
|
|
349
351
|
/**
|
|
350
352
|
* Identity fields only, no properties. A 25-result search across a populated
|
|
351
353
|
* database would otherwise drag back hundreds of flattened values for results
|
|
352
|
-
* the agent is about to discard; `
|
|
354
|
+
* the agent is about to discard; `integration_get_page` fetches them for the one that hit.
|
|
353
355
|
*/
|
|
354
356
|
function projectSearchHit(hit) {
|
|
355
357
|
if (hit?.object === "data_source") {
|
|
@@ -492,7 +494,7 @@ function projectSchemaProperty(property) {
|
|
|
492
494
|
// Shared schema fragments
|
|
493
495
|
// ---------------------------------------------------------------------------
|
|
494
496
|
// The compact renderer inlines every property description, so these three
|
|
495
|
-
// shared strings are paid for once per tool that uses them. `
|
|
497
|
+
// shared strings are paid for once per tool that uses them. `integration_query_data_source`
|
|
496
498
|
// carries all three plus a filter grammar and rendered past the 1,024-byte
|
|
497
499
|
// compact budget until they were cut to the fact each one actually adds
|
|
498
500
|
// ([#342](https://github.com/zackbart/connecta/issues/342)); the long versions
|
|
@@ -568,12 +570,12 @@ const PAGE_OUTPUT_SCHEMA = {
|
|
|
568
570
|
name: { type: "string" },
|
|
569
571
|
id: {
|
|
570
572
|
type: ["string", "null"],
|
|
571
|
-
description: "Pass as property_id to
|
|
573
|
+
description: "Pass as property_id to integration_get_page_property.",
|
|
572
574
|
},
|
|
573
575
|
},
|
|
574
576
|
required: ["name", "id"],
|
|
575
577
|
},
|
|
576
|
-
description: "Properties Notion truncated at 25 entries. Each carries the property_id
|
|
578
|
+
description: "Properties Notion truncated at 25 entries. Each carries the property_id integration_get_page_property needs to read the complete value.",
|
|
577
579
|
},
|
|
578
580
|
},
|
|
579
581
|
required: ["id", "title", "properties"],
|
|
@@ -656,9 +658,7 @@ function pagination(args, defaultPageSize) {
|
|
|
656
658
|
function requireExactlyOne(provided, hint) {
|
|
657
659
|
const present = provided.filter(([, value]) => value !== undefined && value !== null && value !== "");
|
|
658
660
|
if (present.length !== 1) {
|
|
659
|
-
throw new ConnectorCallError("invalid_args", `Provide exactly one of ${provided
|
|
660
|
-
.map(([name]) => name)
|
|
661
|
-
.join(", ")}. ${hint}`);
|
|
661
|
+
throw new ConnectorCallError("invalid_args", `Provide exactly one of ${provided.map(([name]) => name).join(", ")}. ${hint}`);
|
|
662
662
|
}
|
|
663
663
|
return present[0];
|
|
664
664
|
}
|
|
@@ -666,8 +666,8 @@ function buildTools(defaultPageSize) {
|
|
|
666
666
|
return [
|
|
667
667
|
// ---------------------------------------------------------------- reads
|
|
668
668
|
{
|
|
669
|
-
name: "
|
|
670
|
-
description: "Find pages and data sources by title across everything shared with this integration. Never searches page content — use
|
|
669
|
+
name: "integration_search",
|
|
670
|
+
description: "Find pages and data sources by title across everything shared with this integration. Never searches page content — use integration_query_data_source for rows inside a database. Returns identity fields only.",
|
|
671
671
|
annotations: { readOnlyHint: true },
|
|
672
672
|
inputSchema: {
|
|
673
673
|
type: "object",
|
|
@@ -736,8 +736,8 @@ function buildTools(defaultPageSize) {
|
|
|
736
736
|
},
|
|
737
737
|
},
|
|
738
738
|
{
|
|
739
|
-
name: "
|
|
740
|
-
description: "Fetch one page's metadata and flattened property values by id. Returns the page's properties, not its body content — use
|
|
739
|
+
name: "integration_get_page",
|
|
740
|
+
description: "Fetch one page's metadata and flattened property values by id. Returns the page's properties, not its body content — use integration_get_page_content for the blocks.",
|
|
741
741
|
annotations: { readOnlyHint: true },
|
|
742
742
|
inputSchema: {
|
|
743
743
|
type: "object",
|
|
@@ -764,7 +764,7 @@ function buildTools(defaultPageSize) {
|
|
|
764
764
|
},
|
|
765
765
|
},
|
|
766
766
|
{
|
|
767
|
-
name: "
|
|
767
|
+
name: "integration_get_page_content",
|
|
768
768
|
// `raw: true` returns the requested level exactly as Notion sent it and
|
|
769
769
|
// does not walk nested children, so `depth` is ignored alongside it: a
|
|
770
770
|
// raw read of a deep page yields one level.
|
|
@@ -847,8 +847,8 @@ function buildTools(defaultPageSize) {
|
|
|
847
847
|
},
|
|
848
848
|
},
|
|
849
849
|
{
|
|
850
|
-
name: "
|
|
851
|
-
description: "Fetch one page property completely, paginating past the 25-entry limit that
|
|
850
|
+
name: "integration_get_page_property",
|
|
851
|
+
description: "Fetch one page property completely, paginating past the 25-entry limit that integration_get_page reports in truncated_properties. Use for title, rich_text, relation, and people properties — the four Notion paginates.",
|
|
852
852
|
annotations: { readOnlyHint: true },
|
|
853
853
|
inputSchema: {
|
|
854
854
|
type: "object",
|
|
@@ -856,7 +856,7 @@ function buildTools(defaultPageSize) {
|
|
|
856
856
|
page_id: { type: "string", description: "Notion page id." },
|
|
857
857
|
property_id: {
|
|
858
858
|
type: "string",
|
|
859
|
-
description: "The property's id, from
|
|
859
|
+
description: "The property's id, from integration_get_data_source_schema or integration_get_page's truncated_properties — not its name.",
|
|
860
860
|
},
|
|
861
861
|
page_size: PAGE_SIZE_PROPERTY,
|
|
862
862
|
start_cursor: START_CURSOR_PROPERTY,
|
|
@@ -871,7 +871,7 @@ function buildTools(defaultPageSize) {
|
|
|
871
871
|
properties: {
|
|
872
872
|
type: {
|
|
873
873
|
type: ["string", "null"],
|
|
874
|
-
description:
|
|
874
|
+
description: 'The property\'s own type, never the "property_item" envelope.',
|
|
875
875
|
},
|
|
876
876
|
value: { description: "Flattened value for a single-value property." },
|
|
877
877
|
results: {
|
|
@@ -906,8 +906,8 @@ function buildTools(defaultPageSize) {
|
|
|
906
906
|
},
|
|
907
907
|
},
|
|
908
908
|
{
|
|
909
|
-
name: "
|
|
910
|
-
description: "Fetch a database container and list the data sources inside it. A database id cannot be queried directly — start here to get the data_source_id that
|
|
909
|
+
name: "integration_get_database",
|
|
910
|
+
description: "Fetch a database container and list the data sources inside it. A database id cannot be queried directly — start here to get the data_source_id that integration_query_data_source and integration_get_data_source_schema need.",
|
|
911
911
|
annotations: { readOnlyHint: true },
|
|
912
912
|
inputSchema: {
|
|
913
913
|
type: "object",
|
|
@@ -958,7 +958,7 @@ function buildTools(defaultPageSize) {
|
|
|
958
958
|
},
|
|
959
959
|
},
|
|
960
960
|
{
|
|
961
|
-
name: "
|
|
961
|
+
name: "integration_get_data_source_schema",
|
|
962
962
|
description: "List a data source's properties with their ids, types, and select/status options. Read this before filtering, sorting, or writing — filters and property names that do not match the schema exactly are rejected.",
|
|
963
963
|
annotations: { readOnlyHint: true },
|
|
964
964
|
inputSchema: {
|
|
@@ -966,7 +966,7 @@ function buildTools(defaultPageSize) {
|
|
|
966
966
|
properties: {
|
|
967
967
|
data_source_id: {
|
|
968
968
|
type: "string",
|
|
969
|
-
description: "Data source id from
|
|
969
|
+
description: "Data source id from integration_get_database or integration_search, not a database id.",
|
|
970
970
|
},
|
|
971
971
|
raw: RAW_PROPERTY,
|
|
972
972
|
},
|
|
@@ -981,7 +981,7 @@ function buildTools(defaultPageSize) {
|
|
|
981
981
|
database_id: { type: ["string", "null"] },
|
|
982
982
|
title_property: {
|
|
983
983
|
type: ["string", "null"],
|
|
984
|
-
description: "Name of the title-typed property.
|
|
984
|
+
description: "Name of the title-typed property. integration_create_page needs this to title a row.",
|
|
985
985
|
},
|
|
986
986
|
properties: {
|
|
987
987
|
type: "object",
|
|
@@ -1014,7 +1014,7 @@ function buildTools(defaultPageSize) {
|
|
|
1014
1014
|
},
|
|
1015
1015
|
},
|
|
1016
1016
|
{
|
|
1017
|
-
name: "
|
|
1017
|
+
name: "integration_query_data_source",
|
|
1018
1018
|
description: "List rows in a data source with optional filtering and sorting, returning each row's properties already flattened. Requires a data_source_id, never a database_id. Narrow with the properties argument to keep results small.",
|
|
1019
1019
|
annotations: { readOnlyHint: true },
|
|
1020
1020
|
inputSchema: {
|
|
@@ -1022,11 +1022,11 @@ function buildTools(defaultPageSize) {
|
|
|
1022
1022
|
properties: {
|
|
1023
1023
|
data_source_id: {
|
|
1024
1024
|
type: "string",
|
|
1025
|
-
description: "Data source id from
|
|
1025
|
+
description: "Data source id from integration_get_database or integration_search.",
|
|
1026
1026
|
},
|
|
1027
1027
|
filter: {
|
|
1028
1028
|
type: "object",
|
|
1029
|
-
description: 'Notion filter object, passed through unchanged. Single condition: {"property":"Status","status":{"equals":"Done"}}. Compound: {"and":[...]} or {"or":[...]}. Property names must match
|
|
1029
|
+
description: 'Notion filter object, passed through unchanged. Single condition: {"property":"Status","status":{"equals":"Done"}}. Compound: {"and":[...]} or {"or":[...]}. Property names must match integration_get_data_source_schema exactly.',
|
|
1030
1030
|
},
|
|
1031
1031
|
sorts: {
|
|
1032
1032
|
type: "array",
|
|
@@ -1078,7 +1078,7 @@ function buildTools(defaultPageSize) {
|
|
|
1078
1078
|
},
|
|
1079
1079
|
},
|
|
1080
1080
|
{
|
|
1081
|
-
name: "
|
|
1081
|
+
name: "integration_list_users",
|
|
1082
1082
|
description: "List workspace users and bots with their ids, for assigning people properties or attributing edits. Requires the integration's user-information capability.",
|
|
1083
1083
|
annotations: { readOnlyHint: true },
|
|
1084
1084
|
inputSchema: {
|
|
@@ -1101,7 +1101,7 @@ function buildTools(defaultPageSize) {
|
|
|
1101
1101
|
},
|
|
1102
1102
|
},
|
|
1103
1103
|
{
|
|
1104
|
-
name: "
|
|
1104
|
+
name: "integration_get_self",
|
|
1105
1105
|
description: "Identify the integration this connector authenticates as, and the workspace it is installed in. The cheapest way to confirm the token works before a longer sequence.",
|
|
1106
1106
|
annotations: { readOnlyHint: true },
|
|
1107
1107
|
inputSchema: {
|
|
@@ -1132,7 +1132,7 @@ function buildTools(defaultPageSize) {
|
|
|
1132
1132
|
},
|
|
1133
1133
|
},
|
|
1134
1134
|
{
|
|
1135
|
-
name: "
|
|
1135
|
+
name: "integration_list_comments",
|
|
1136
1136
|
description: "List unresolved comments on a page or block as plain text with their discussion ids. Requires the integration's read-comment capability, which is off by default.",
|
|
1137
1137
|
annotations: { readOnlyHint: true },
|
|
1138
1138
|
inputSchema: {
|
|
@@ -1166,7 +1166,7 @@ function buildTools(defaultPageSize) {
|
|
|
1166
1166
|
},
|
|
1167
1167
|
// --------------------------------------------------------------- writes
|
|
1168
1168
|
{
|
|
1169
|
-
name: "
|
|
1169
|
+
name: "integration_create_page",
|
|
1170
1170
|
description: "Create a page, either as a child of another page or as a row in a data source. Notion has no idempotency key: a retried create makes a second page, so confirm with search before repeating one.",
|
|
1171
1171
|
annotations: { readOnlyHint: false },
|
|
1172
1172
|
inputSchema: {
|
|
@@ -1189,11 +1189,11 @@ function buildTools(defaultPageSize) {
|
|
|
1189
1189
|
title: { type: "string", description: "Plain-text title." },
|
|
1190
1190
|
title_property: {
|
|
1191
1191
|
type: "string",
|
|
1192
|
-
description: 'Name of the title-typed property, from
|
|
1192
|
+
description: 'Name of the title-typed property, from integration_get_data_source_schema. Required in practice for a data-source parent, whose title column is rarely called "title". Defaults to "title", which is the only valid key under a page parent.',
|
|
1193
1193
|
},
|
|
1194
1194
|
properties: {
|
|
1195
1195
|
type: "object",
|
|
1196
|
-
description:
|
|
1196
|
+
description: 'Additional Notion property values, keyed by property name and in Notion\'s own wrapped form, e.g. {"Status":{"status":{"name":"Todo"}}}. Read integration_get_data_source_schema first.',
|
|
1197
1197
|
},
|
|
1198
1198
|
markdown: {
|
|
1199
1199
|
type: "string",
|
|
@@ -1214,7 +1214,7 @@ function buildTools(defaultPageSize) {
|
|
|
1214
1214
|
const [parentKey, parentValue] = requireExactlyOne([
|
|
1215
1215
|
["parent_page_id", args.parent_page_id],
|
|
1216
1216
|
["parent_data_source_id", args.parent_data_source_id],
|
|
1217
|
-
], "A page needs exactly one parent, and a data source is addressed by its data_source_id from
|
|
1217
|
+
], "A page needs exactly one parent, and a data source is addressed by its data_source_id from integration_get_database — never by a database_id.");
|
|
1218
1218
|
if (args.markdown !== undefined && args.children !== undefined) {
|
|
1219
1219
|
throw new ConnectorCallError("invalid_args", "Provide either markdown or children for the page body, not both.");
|
|
1220
1220
|
}
|
|
@@ -1245,7 +1245,7 @@ function buildTools(defaultPageSize) {
|
|
|
1245
1245
|
},
|
|
1246
1246
|
},
|
|
1247
1247
|
{
|
|
1248
|
-
name: "
|
|
1248
|
+
name: "integration_append_blocks",
|
|
1249
1249
|
description: "Append content to the end of a page or block, or insert it at a chosen position. Appending only adds: existing blocks are never moved or replaced, and an appended block cannot be relocated later through the API.",
|
|
1250
1250
|
annotations: { readOnlyHint: false },
|
|
1251
1251
|
inputSchema: {
|
|
@@ -1329,7 +1329,7 @@ function buildTools(defaultPageSize) {
|
|
|
1329
1329
|
},
|
|
1330
1330
|
},
|
|
1331
1331
|
{
|
|
1332
|
-
name: "
|
|
1332
|
+
name: "integration_update_page_properties",
|
|
1333
1333
|
// Deliberately no locking, templates, or `erase_content` (#409): locking
|
|
1334
1334
|
// is coordination state, templates finish asynchronously, and
|
|
1335
1335
|
// `erase_content` permanently deletes every child block. None belongs
|
|
@@ -1347,11 +1347,11 @@ function buildTools(defaultPageSize) {
|
|
|
1347
1347
|
},
|
|
1348
1348
|
title_property: {
|
|
1349
1349
|
type: "string",
|
|
1350
|
-
description: 'Name of the title-typed property, from
|
|
1350
|
+
description: 'Name of the title-typed property, from integration_get_data_source_schema. Defaults to "title".',
|
|
1351
1351
|
},
|
|
1352
1352
|
properties: {
|
|
1353
1353
|
type: "object",
|
|
1354
|
-
description: "Notion property values keyed by property name, in Notion's wrapped form. Read
|
|
1354
|
+
description: "Notion property values keyed by property name, in Notion's wrapped form. Read integration_get_data_source_schema for names, types, and valid option names.",
|
|
1355
1355
|
},
|
|
1356
1356
|
icon: { type: "string", description: "Replacement emoji icon." },
|
|
1357
1357
|
},
|
|
@@ -1383,7 +1383,7 @@ function buildTools(defaultPageSize) {
|
|
|
1383
1383
|
},
|
|
1384
1384
|
},
|
|
1385
1385
|
{
|
|
1386
|
-
name: "
|
|
1386
|
+
name: "integration_trash_page",
|
|
1387
1387
|
description: "Move a page to the workspace trash, or restore one from it. Trashing hides the page and its content from reads; it is reversible through this same tool with restore: true.",
|
|
1388
1388
|
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
1389
1389
|
inputSchema: {
|
|
@@ -1421,7 +1421,7 @@ function buildTools(defaultPageSize) {
|
|
|
1421
1421
|
},
|
|
1422
1422
|
},
|
|
1423
1423
|
{
|
|
1424
|
-
name: "
|
|
1424
|
+
name: "integration_add_comment",
|
|
1425
1425
|
description: "Start a comment discussion on a page, or reply to an existing discussion. Requires the integration's insert-comment capability, which is off by default.",
|
|
1426
1426
|
annotations: { readOnlyHint: false },
|
|
1427
1427
|
inputSchema: {
|
|
@@ -1433,7 +1433,7 @@ function buildTools(defaultPageSize) {
|
|
|
1433
1433
|
},
|
|
1434
1434
|
discussion_id: {
|
|
1435
1435
|
type: "string",
|
|
1436
|
-
description: "Reply to this existing discussion, from
|
|
1436
|
+
description: "Reply to this existing discussion, from integration_list_comments.",
|
|
1437
1437
|
},
|
|
1438
1438
|
text: { type: "string", description: "Comment body as plain text." },
|
|
1439
1439
|
},
|
|
@@ -1451,9 +1451,7 @@ function buildTools(defaultPageSize) {
|
|
|
1451
1451
|
}
|
|
1452
1452
|
const body = {
|
|
1453
1453
|
rich_text: richText(args.text),
|
|
1454
|
-
...(kind === "page_id"
|
|
1455
|
-
? { parent: { type: "page_id", page_id: value } }
|
|
1456
|
-
: { discussion_id: value }),
|
|
1454
|
+
...(kind === "page_id" ? { parent: { type: "page_id", page_id: value } } : { discussion_id: value }),
|
|
1457
1455
|
};
|
|
1458
1456
|
return projectComment(await notionRequest(ctx, {
|
|
1459
1457
|
method: "POST",
|
|
@@ -1470,205 +1468,182 @@ function buildTools(defaultPageSize) {
|
|
|
1470
1468
|
/**
|
|
1471
1469
|
* Marked `required` for one reason: a Notion database is a container, and the
|
|
1472
1470
|
* rows and schema live in a data source inside it. The id in a database URL is a
|
|
1473
|
-
* database id, and passing it to `
|
|
1471
|
+
* database id, and passing it to `integration_query_data_source` or `integration_create_page` fails —
|
|
1474
1472
|
* a trap no input schema can teach, so the guide has to.
|
|
1475
1473
|
*/
|
|
1476
1474
|
function apiUsageGuide(purpose, instructions) {
|
|
1477
1475
|
const accountInstructions = instructions?.trim();
|
|
1478
1476
|
return `# Notion usage
|
|
1479
1477
|
|
|
1480
|
-
Workspace purpose: ${purpose}
|
|
1481
|
-
|
|
1482
|
-
## Databases contain data sources
|
|
1483
|
-
|
|
1484
|
-
A Notion database is a container; the rows and the schema live in a *data
|
|
1485
|
-
source* inside it. The two ids are not interchangeable and Notion rejects the
|
|
1486
|
-
wrong one.
|
|
1487
|
-
|
|
1488
|
-
- The id in a Notion database URL is a **database id**.
|
|
1489
|
-
- \`get_database\` turns it into the \`data_sources\` list — usually one entry.
|
|
1490
|
-
- \`get_data_source_schema\` and \`query_data_source\` take that
|
|
1491
|
-
**data_source_id**, and so does \`create_page\` when adding a row.
|
|
1492
|
-
|
|
1493
|
-
So the sequence for "find rows in this database" is \`get_database\` →
|
|
1494
|
-
\`get_data_source_schema\` → \`query_data_source\`. \`search\` returns data
|
|
1495
|
-
sources directly and skips the first step.
|
|
1496
|
-
|
|
1497
|
-
## Property quirks that break writes
|
|
1498
|
-
|
|
1499
|
-
- Property names in filters, sorts, and writes must match the schema exactly,
|
|
1500
|
-
including case. Read \`get_data_source_schema\` before composing one.
|
|
1501
|
-
- \`select\` and \`status\` writes must use an existing option name; inventing
|
|
1502
|
-
one fails. The schema lists the valid options.
|
|
1503
|
-
- Writes **replace** a property. Sending one item to a \`multi_select\` or
|
|
1504
|
-
\`relation\` drops the others, so send the complete intended value.
|
|
1505
|
-
- \`rollup\`, \`formula\`, \`unique_id\`, and the created/edited fields are
|
|
1506
|
-
computed. They cannot be written.
|
|
1507
|
-
- A page's title column is rarely called "title" — pass \`title_property\` from
|
|
1508
|
-
the schema when creating or updating a row.
|
|
1509
|
-
- Notion truncates \`title\`, \`rich_text\`, \`relation\`, and \`people\` at 25
|
|
1510
|
-
entries. \`get_page\` reports each one in \`truncated_properties\` as
|
|
1511
|
-
\`{ name, id }\`; pass that \`id\` as \`property_id\` to
|
|
1512
|
-
\`get_page_property\` for the complete value.
|
|
1513
|
-
|
|
1514
|
-
## Reading page content
|
|
1515
|
-
|
|
1516
|
-
\`get_page\` returns properties. \`get_page_content\` returns the body as flat
|
|
1517
|
-
blocks. Nested blocks (toggles, list children, table rows) need \`depth\`, and
|
|
1518
|
-
each level multiplies requests — a deep read stops at an internal ceiling and
|
|
1519
|
-
reports \`truncated: true\` rather than spending the whole rate-limit budget.
|
|
1520
|
-
|
|
1521
|
-
## Appending is append-only
|
|
1522
|
-
|
|
1523
|
-
\`append_blocks\` adds children and nothing else. It cannot move, reorder, or
|
|
1524
|
-
replace an existing block, and a block appended through the API can never be
|
|
1525
|
-
relocated by it afterwards. Get the position right the first time with
|
|
1526
|
-
\`position\` and \`after_block_id\`. Notion caps one call at 100 blocks.
|
|
1527
|
-
|
|
1528
|
-
## Lean by default, raw on request
|
|
1529
|
-
|
|
1530
|
-
Every read projects Notion's payload down to ids, plain text, and flattened
|
|
1531
|
-
property values. Where the dropped detail can matter — \`search\`, \`get_page\`,
|
|
1532
|
-
\`get_page_content\`, \`get_page_property\`, \`get_data_source_schema\`,
|
|
1533
|
-
\`query_data_source\`, \`list_comments\` — pass \`raw: true\` to get Notion's
|
|
1534
|
-
untouched response instead. It is much larger; reach for it only when a
|
|
1535
|
-
specific field is missing. Narrow \`query_data_source\` and \`get_page\` with
|
|
1536
|
-
\`properties\` instead whenever the goal is fewer fields, not more.
|
|
1537
|
-
|
|
1538
|
-
\`get_page_content\` with \`raw: true\` returns one level exactly as Notion
|
|
1539
|
-
sent it and does not walk nested children, so \`depth\` is ignored alongside
|
|
1540
|
-
it. A block type this projection does not model keeps its payload under
|
|
1541
|
-
\`raw\` on the block itself, so nothing silently flattens to an empty string.
|
|
1542
|
-
|
|
1543
|
-
## Failures worth reading carefully
|
|
1544
|
-
|
|
1545
|
-
- **404** means "no such object" *or* "not shared with this integration", and
|
|
1546
|
-
Notion will not say which. Never conclude a page was deleted from it; check
|
|
1547
|
-
that the page is shared with the integration in Notion.
|
|
1548
|
-
- **403** is not an expired token. The integration is missing a capability
|
|
1549
|
-
(comment capabilities are off by default) or the object was never shared.
|
|
1550
|
-
Re-authorizing cannot fix it; an operator must change it in Notion.
|
|
1551
|
-
- **429** carries a retry window. Notion allows roughly three requests per
|
|
1552
|
-
second per integration, so wait it out rather than retrying immediately.
|
|
1553
|
-
|
|
1554
|
-
## No escape hatch
|
|
1555
|
-
|
|
1556
|
-
This connection has no guarded raw-REST tool, deliberately. Notion's public
|
|
1557
|
-
API is small and slow-moving enough for the named surface to cover it, so
|
|
1558
|
-
there is no \`notion_api_*\` to reach for — an operation absent from the tool
|
|
1559
|
-
list is absent from this connection, not hidden behind a generic call.
|
|
1560
|
-
|
|
1561
|
-
## Writes and pagination
|
|
1562
|
-
|
|
1563
|
-
- Notion has **no idempotency key**. A retried \`create_page\` or
|
|
1564
|
-
\`add_comment\` creates a duplicate. Confirm with \`search\` before repeating
|
|
1565
|
-
a write that may have partially succeeded.
|
|
1566
|
-
- List tools take \`page_size\` (max 100) and return \`has_more\` with
|
|
1567
|
-
\`next_cursor\`. Pass a cursor back verbatim — it is opaque and must never be
|
|
1568
|
-
parsed or constructed. Follow pages inside \`execute_code\` and reduce there.
|
|
1569
|
-
${accountInstructions
|
|
1570
|
-
? `\n## Workspace instructions\n\n${accountInstructions}\n`
|
|
1571
|
-
: ""}`;
|
|
1478
|
+
Workspace purpose: ${purpose}${skill.fragments.guide_0}${accountInstructions ? `\n## ${skill.instructionsHeading}\n\n${accountInstructions}\n` : ""}`;
|
|
1572
1479
|
}
|
|
1573
|
-
/**
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
"notion-
|
|
1582
|
-
"notion-search-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
"notion-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
"notion-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Reviewed in #705's provider audit against https://developers.notion.com/guides/mcp/mcp-supported-tools.
|
|
1482
|
+
* Retains the release-reviewed inventory, including names absent from today's
|
|
1483
|
+
* public reference. Live annotations were not reverified without credentials.
|
|
1484
|
+
* No schema digest is asserted without a captured schema to review.
|
|
1485
|
+
*/
|
|
1486
|
+
const NOTION_MCP_CLASSIFICATION = {
|
|
1487
|
+
tools: {
|
|
1488
|
+
"notion-search": { "verdict": "read", "reason": "Retrieves Notion information without changing vendor state." },
|
|
1489
|
+
"notion-search-skills": {
|
|
1490
|
+
"verdict": "read",
|
|
1491
|
+
"reason": "Retrieves Notion skills information without changing vendor state.",
|
|
1492
|
+
},
|
|
1493
|
+
"notion-fetch": {
|
|
1494
|
+
"verdict": "read",
|
|
1495
|
+
"reason": "Retrieves Notion fetch information without changing vendor state.",
|
|
1496
|
+
},
|
|
1497
|
+
"notion-download-attachment": {
|
|
1498
|
+
"verdict": "read",
|
|
1499
|
+
"reason": "Reads attachment content; creating uploads and attachments uses separate writes.",
|
|
1500
|
+
},
|
|
1501
|
+
"notion-query-data-sources": {
|
|
1502
|
+
"verdict": "read",
|
|
1503
|
+
"reason": "Retrieves Notion query data sources information without changing vendor state.",
|
|
1504
|
+
},
|
|
1505
|
+
"notion-query-meeting-notes": {
|
|
1506
|
+
"verdict": "read",
|
|
1507
|
+
"reason": "Retrieves Notion query meeting notes information without changing vendor state.",
|
|
1508
|
+
},
|
|
1509
|
+
"notion-search-agents": {
|
|
1510
|
+
"verdict": "read",
|
|
1511
|
+
"reason": "Retrieves Notion agents information without changing vendor state.",
|
|
1512
|
+
},
|
|
1513
|
+
"notion-list-agents": {
|
|
1514
|
+
"verdict": "read",
|
|
1515
|
+
"reason": "Retrieves Notion agents information without changing vendor state.",
|
|
1516
|
+
},
|
|
1517
|
+
"notion-query-sessions": {
|
|
1518
|
+
"verdict": "read",
|
|
1519
|
+
"reason": "Retrieves Notion query sessions information without changing vendor state.",
|
|
1520
|
+
},
|
|
1521
|
+
"notion-search-sessions": {
|
|
1522
|
+
"verdict": "read",
|
|
1523
|
+
"reason": "Retrieves Notion sessions information without changing vendor state.",
|
|
1524
|
+
},
|
|
1525
|
+
"notion-get-session-status": {
|
|
1526
|
+
"verdict": "read",
|
|
1527
|
+
"reason": "Retrieves Notion session status information without changing vendor state.",
|
|
1528
|
+
},
|
|
1529
|
+
"notion-wait-session": {
|
|
1530
|
+
"verdict": "read",
|
|
1531
|
+
"reason": "Waits for existing session state; it does not start or message a session.",
|
|
1532
|
+
},
|
|
1533
|
+
"notion-list-session-events": {
|
|
1534
|
+
"verdict": "read",
|
|
1535
|
+
"reason": "Retrieves Notion session events information without changing vendor state.",
|
|
1536
|
+
},
|
|
1537
|
+
"notion-read-session-event": {
|
|
1538
|
+
"verdict": "read",
|
|
1539
|
+
"reason": "Retrieves Notion read session event information without changing vendor state.",
|
|
1540
|
+
},
|
|
1541
|
+
"notion-get-comments": {
|
|
1542
|
+
"verdict": "read",
|
|
1543
|
+
"reason": "Retrieves Notion comments information without changing vendor state.",
|
|
1544
|
+
},
|
|
1545
|
+
"notion-get-teams": {
|
|
1546
|
+
"verdict": "read",
|
|
1547
|
+
"reason": "Retrieves Notion teams information without changing vendor state.",
|
|
1548
|
+
},
|
|
1549
|
+
"notion-get-users": {
|
|
1550
|
+
"verdict": "read",
|
|
1551
|
+
"reason": "Retrieves Notion users information without changing vendor state.",
|
|
1552
|
+
},
|
|
1553
|
+
"notion-get-async-task": {
|
|
1554
|
+
"verdict": "read",
|
|
1555
|
+
"reason": "Retrieves Notion async task information without changing vendor state.",
|
|
1556
|
+
},
|
|
1557
|
+
"notion-create-file-upload": { "verdict": "write", "reason": "Allocates upload state for a workspace file." },
|
|
1558
|
+
"notion-create-attachment": {
|
|
1559
|
+
"verdict": "write",
|
|
1560
|
+
"reason": "create attachment creates or appends Notion state; it has side effects.",
|
|
1561
|
+
},
|
|
1562
|
+
"notion-create-pages": {
|
|
1563
|
+
"verdict": "write",
|
|
1564
|
+
"reason": "create pages creates or appends Notion state; it has side effects.",
|
|
1565
|
+
},
|
|
1566
|
+
"notion-duplicate-page": {
|
|
1567
|
+
"verdict": "write",
|
|
1568
|
+
"reason": "duplicate page creates or appends Notion state; it has side effects.",
|
|
1569
|
+
},
|
|
1570
|
+
"notion-create-database": {
|
|
1571
|
+
"verdict": "write",
|
|
1572
|
+
"reason": "create database creates or appends Notion state; it has side effects.",
|
|
1573
|
+
},
|
|
1574
|
+
"notion-create-folder": {
|
|
1575
|
+
"verdict": "write",
|
|
1576
|
+
"reason": "create folder creates or appends Notion state; it has side effects.",
|
|
1577
|
+
},
|
|
1578
|
+
"notion-create-view": {
|
|
1579
|
+
"verdict": "write",
|
|
1580
|
+
"reason": "create view creates or appends Notion state; it has side effects.",
|
|
1581
|
+
},
|
|
1582
|
+
"notion-spawn-session": {
|
|
1583
|
+
"verdict": "write",
|
|
1584
|
+
"reason": "Starts asynchronous agent work and creates session state.",
|
|
1585
|
+
},
|
|
1586
|
+
"notion-send-message-to-session": {
|
|
1587
|
+
"verdict": "write",
|
|
1588
|
+
"reason": "Appends a message to a running session and may trigger further work.",
|
|
1589
|
+
},
|
|
1590
|
+
"notion-create-comment": {
|
|
1591
|
+
"verdict": "write",
|
|
1592
|
+
"reason": "create comment creates or appends Notion state; it has side effects.",
|
|
1593
|
+
},
|
|
1594
|
+
"notion-update-page": {
|
|
1595
|
+
"verdict": "destructive",
|
|
1596
|
+
"reason": "update page changes existing Notion state or removes it.",
|
|
1597
|
+
},
|
|
1598
|
+
"notion-convert-page-to-skill": {
|
|
1599
|
+
"verdict": "destructive",
|
|
1600
|
+
"reason": "Changes the role and content of an existing workspace page.",
|
|
1601
|
+
},
|
|
1602
|
+
"notion-move-pages": {
|
|
1603
|
+
"verdict": "destructive",
|
|
1604
|
+
"reason": "move pages changes existing Notion state or removes it.",
|
|
1605
|
+
},
|
|
1606
|
+
"notion-update-data-source": {
|
|
1607
|
+
"verdict": "destructive",
|
|
1608
|
+
"reason": "update data source changes existing Notion state or removes it.",
|
|
1609
|
+
},
|
|
1610
|
+
"notion-update-view": {
|
|
1611
|
+
"verdict": "destructive",
|
|
1612
|
+
"reason": "update view changes existing Notion state or removes it.",
|
|
1613
|
+
},
|
|
1614
|
+
"notion-stop-session": { "verdict": "destructive", "reason": "Stops an existing session and interrupts its work." },
|
|
1615
|
+
},
|
|
1616
|
+
};
|
|
1614
1617
|
function mcpUsageGuide(purpose, instructions) {
|
|
1615
1618
|
const accountInstructions = instructions?.trim();
|
|
1616
|
-
return
|
|
1617
|
-
|
|
1618
|
-
Official MCP interface: tool names, descriptions, argument schemas, and result
|
|
1619
|
-
schemas come from Notion's live server. Connecta preserves that catalog and
|
|
1620
|
-
only fills in release-reviewed safety annotations when Notion leaves them out.
|
|
1621
|
-
|
|
1622
|
-
Workspace purpose: ${purpose}
|
|
1623
|
-
|
|
1624
|
-
- Discover the live catalog before assuming a tool exists. Notion can gate
|
|
1625
|
-
tools by workspace, account, client, and rollout independently of Connecta.
|
|
1626
|
-
- Start broad discovery with \`notion-search\`, then use \`notion-fetch\` on
|
|
1627
|
-
the exact page, database, data source, or object before changing it.
|
|
1628
|
-
- Use the live input schema as the contract. Notion owns these MCP schemas;
|
|
1629
|
-
the REST schemas in Connecta's API interface do not apply to MCP tools with
|
|
1630
|
-
similar names.
|
|
1631
|
-
- Session and agent tools can launch asynchronous work. Read session state and
|
|
1632
|
-
events before sending another message, waiting, or stopping a session.
|
|
1633
|
-
- File uploads and attachment tools create durable workspace state. Keep
|
|
1634
|
-
downloads inside the requested task and do not expose signed attachment URLs.
|
|
1635
|
-
- An \`auth_required\` failure means this connector's OAuth grant is missing or
|
|
1636
|
-
expired. Run \`authorize_connector\` for this connector id, then retry.
|
|
1637
|
-
${accountInstructions
|
|
1638
|
-
? `\n## Workspace instructions\n\n${accountInstructions}\n`
|
|
1639
|
-
: ""}`;
|
|
1619
|
+
return `${skill.fragments.guide_1}${purpose}${skill.fragments.guide_2}${accountInstructions ? `\n## ${skill.instructionsHeading}\n\n${accountInstructions}\n` : ""}`;
|
|
1640
1620
|
}
|
|
1641
|
-
function notionMcp(id, purpose, options) {
|
|
1621
|
+
function notionMcp(id, purpose, options, provider) {
|
|
1642
1622
|
const connector = remoteMcp(id, {
|
|
1643
1623
|
url: NOTION_MCP_ENDPOINT,
|
|
1644
|
-
...
|
|
1645
|
-
authScope: options.authScope,
|
|
1646
|
-
callAdmission: options.callAdmission,
|
|
1647
|
-
maxResultBytes: options.maxResultBytes,
|
|
1648
|
-
}),
|
|
1624
|
+
...provider.connectorOptions,
|
|
1649
1625
|
title: options.title ?? "Notion (MCP)",
|
|
1650
1626
|
description: `Notion's official hosted MCP interface: ${purpose}`,
|
|
1651
1627
|
auth: { type: "oauth" },
|
|
1652
1628
|
requireHttps: true,
|
|
1629
|
+
classify: provider.classify,
|
|
1653
1630
|
usageGuide: {
|
|
1654
1631
|
content: mcpUsageGuide(purpose, options.instructions),
|
|
1655
1632
|
summary: "Official MCP. Live Notion schemas, object discovery, sessions, agents, attachments, and OAuth ownership.",
|
|
1656
1633
|
required: true,
|
|
1657
1634
|
},
|
|
1658
1635
|
});
|
|
1659
|
-
return
|
|
1636
|
+
return connector;
|
|
1660
1637
|
}
|
|
1661
1638
|
function notionApi(id, purpose, options) {
|
|
1662
1639
|
const defaultPageSize = options.defaultPageSize ?? DEFAULT_PAGE_SIZE;
|
|
1663
|
-
if (!Number.isInteger(defaultPageSize) ||
|
|
1664
|
-
defaultPageSize < 1 ||
|
|
1665
|
-
defaultPageSize > MAX_PAGE_SIZE) {
|
|
1640
|
+
if (!Number.isInteger(defaultPageSize) || defaultPageSize < 1 || defaultPageSize > MAX_PAGE_SIZE) {
|
|
1666
1641
|
throw new Error(`notion() defaultPageSize must be a whole number between 1 and ${MAX_PAGE_SIZE}.`);
|
|
1667
1642
|
}
|
|
1668
1643
|
return api(id, {
|
|
1669
1644
|
...(options.authScope ? { authScope: options.authScope } : {}),
|
|
1670
|
-
title: options.title ?? "Notion",
|
|
1671
|
-
description: `Notion
|
|
1645
|
+
title: options.title ?? "Notion integration",
|
|
1646
|
+
description: `Notion internal integration: ${purpose}`,
|
|
1672
1647
|
credential: {
|
|
1673
1648
|
label: options.credentialLabel ?? "Notion integration token",
|
|
1674
1649
|
description: "Internal integration token from notion.so/profile/integrations. Every page or database the agent should reach must also be shared with that integration, and its capabilities decide which tools succeed — comment capabilities are off by default.",
|
|
@@ -1685,31 +1660,43 @@ function notionApi(id, purpose, options) {
|
|
|
1685
1660
|
catch (error) {
|
|
1686
1661
|
return {
|
|
1687
1662
|
ok: false,
|
|
1688
|
-
message: error instanceof ConnectorCallError
|
|
1689
|
-
? error.message
|
|
1690
|
-
: "Notion rejected the token.",
|
|
1663
|
+
message: error instanceof ConnectorCallError ? error.message : "Notion rejected the token.",
|
|
1691
1664
|
};
|
|
1692
1665
|
}
|
|
1693
1666
|
},
|
|
1694
1667
|
callAdmission: NOTION_ADMISSION,
|
|
1695
1668
|
usageGuide: {
|
|
1696
1669
|
content: apiUsageGuide(purpose, options.instructions),
|
|
1697
|
-
summary: "
|
|
1670
|
+
summary: "Internal integration identity. Exact REST queries, JSON blocks, properties, paging and bot-scoped content writes.",
|
|
1698
1671
|
required: true,
|
|
1699
1672
|
},
|
|
1700
1673
|
tools: buildTools(defaultPageSize),
|
|
1701
|
-
...(options.maxResultBytes !== undefined
|
|
1702
|
-
? { maxResultBytes: options.maxResultBytes }
|
|
1703
|
-
: {}),
|
|
1674
|
+
...(options.maxResultBytes !== undefined ? { maxResultBytes: options.maxResultBytes } : {}),
|
|
1704
1675
|
});
|
|
1705
1676
|
}
|
|
1677
|
+
/** The closed options notion() accepts; see `assertKnownOptions`. */
|
|
1678
|
+
const NOTION_OPTIONS = variants("surface", {
|
|
1679
|
+
api: optionsOf()({
|
|
1680
|
+
...keys("title", "authScope", "purpose", "instructions", "maxResultBytes"),
|
|
1681
|
+
...keys("surface", "credentialLabel", "defaultPageSize"),
|
|
1682
|
+
}).shape,
|
|
1683
|
+
mcp: optionsOf()({ ...PROVIDER_COMMON, ...keys("surface") }).shape,
|
|
1684
|
+
}, "mcp");
|
|
1706
1685
|
/** A maintained Notion connection using the selected provider interface. */
|
|
1707
|
-
export
|
|
1686
|
+
export const notion = defineProvider({
|
|
1687
|
+
name: "notion",
|
|
1688
|
+
title: "Notion",
|
|
1689
|
+
kind: "composed",
|
|
1690
|
+
readme: "Notion",
|
|
1691
|
+
bundle: { "baselineGzip": 145300, "maxGzip": 205300 },
|
|
1692
|
+
skill,
|
|
1693
|
+
options: NOTION_OPTIONS,
|
|
1694
|
+
classify: NOTION_MCP_CLASSIFICATION,
|
|
1695
|
+
create: notionConnector,
|
|
1696
|
+
});
|
|
1697
|
+
function notionConnector(id, options, provider) {
|
|
1708
1698
|
const purpose = options.purpose.trim();
|
|
1709
|
-
|
|
1710
|
-
throw new Error("notion() requires a non-empty workspace purpose.");
|
|
1711
|
-
}
|
|
1712
|
-
return options.surface === "mcp"
|
|
1713
|
-
? notionMcp(id, purpose, options)
|
|
1714
|
-
: notionApi(id, purpose, options);
|
|
1699
|
+
return options.surface === "api" ? notionApi(id, purpose, options) : notionMcp(id, purpose, options, provider);
|
|
1715
1700
|
}
|
|
1701
|
+
/** @deprecated Read `notion.definition.classify` instead. Kept for existing imports. */
|
|
1702
|
+
export const NOTION_MCP_VETTED_CATALOG = reviewedCatalog(notion.definition.classify, 'defineProvider("notion")');
|