diff --git a/apps/docs/content/docs/en/integrations/cloudflare.mdx b/apps/docs/content/docs/en/integrations/cloudflare.mdx index 85f5a12beb2..8338f2d0c08 100644 --- a/apps/docs/content/docs/en/integrations/cloudflare.mdx +++ b/apps/docs/content/docs/en/integrations/cloudflare.mdx @@ -1,6 +1,6 @@ --- title: Cloudflare -description: Manage DNS, domains, certificates, and cache +description: Manage DNS, WAF, Zero Trust access, and edge infrastructure --- import { BlockInfoCard } from "@/components/ui/block-info-card" @@ -28,7 +28,7 @@ This integration enables streamlined, secure management of your site's infrastru ## Usage Instructions -Integrate Cloudflare into the workflow. Manage zones (domains), DNS records, SSL/TLS certificates, zone settings, DNS analytics, and cache purging via the Cloudflare API. +Integrate Cloudflare into the workflow. Manage zones (domains), DNS records, SSL/TLS certificates, zone settings, DNS analytics, and cache purging. Configure WAF rulesets, managed rule overrides, and rate limiting rules through the current Rulesets engine. Administer Cloudflare Access (Zero Trust) applications, policies, groups, identity providers, and service tokens, and inspect R2 buckets, Workers scripts and routes, and Cloudflare Tunnels. @@ -282,7 +282,7 @@ Creates a new DNS record for a zone. | `content` | string | Yes | DNS record content \(e.g., IP address for A records, target for CNAME\) | | `ttl` | number | No | Time to live in seconds \(1 = automatic, default: 1\) | | `proxied` | boolean | No | Whether to enable Cloudflare proxy \(default: false\) | -| `priority` | number | No | Priority for MX and SRV records | +| `priority` | number | No | Record priority. Cloudflare accepts this top-level field for MX and URI records only; an SRV record carries its priority, weight, port, and target inside the record content instead | | `comment` | string | No | Comment for the DNS record | | `tags` | string | No | Comma-separated tags for the DNS record | | `apiKey` | string | Yes | Cloudflare API Token | @@ -301,7 +301,7 @@ Creates a new DNS record for a zone. | `proxied` | boolean | Whether Cloudflare proxy is enabled | | `ttl` | number | Time to live in seconds \(1 = automatic\) | | `locked` | boolean | Whether the record is locked | -| `priority` | number | Priority for MX and SRV records | +| `priority` | number | Record priority, returned for MX and URI records | | `comment` | string | Comment associated with the record | | `tags` | array | Tags associated with the record | | `comment_modified_on` | string | ISO 8601 timestamp when the comment was last modified | @@ -382,7 +382,7 @@ Lists SSL/TLS certificate packs for a zone. | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `zoneId` | string | Yes | The zone ID to list certificates for | -| `status` | string | No | Filter certificate packs by status \(e.g., "all", "active", "pending"\) | +| `status` | string | No | Set to "all" to include every certificate pack regardless of status. Cloudflare documents no other value for this filter; omitting it returns only active packs | | `page` | number | No | Page number of paginated results \(default: 1\) | | `per_page` | number | No | Number of certificate packs per page \(default: 20, min: 5, max: 50\) | | `deploy` | string | No | Filter by deployment environment: "staging" or "production" | @@ -455,7 +455,7 @@ Gets all settings for a zone including SSL mode, caching level, and security set | --------- | ---- | ----------- | | `settings` | array | List of zone settings | | ↳ `id` | string | Setting identifier \(e.g., ssl, cache_level, security_level, always_use_https\) | -| ↳ `value` | string | Setting value as a string. Simple values returned as-is \(e.g., "full", "on"\). Complex values are JSON-stringified \(e.g., \ | +| ↳ `value` | string | Setting value as a string. Simple values returned as-is \(e.g., "full", "on"\). Complex values are JSON-stringified \(e.g., \{"css":"on","html":"on","js":"on"\}\). | | ↳ `editable` | boolean | Whether the setting can be modified for the current zone plan | | ↳ `modified_on` | string | ISO 8601 timestamp when the setting was last modified | | ↳ `time_remaining` | number | Seconds remaining until the setting can be modified again \(only present for rate-limited settings\) | @@ -470,7 +470,7 @@ Updates a specific zone setting such as SSL mode, security level, cache level, o | --------- | ---- | -------- | ----------- | | `zoneId` | string | Yes | The zone ID to update settings for | | `settingId` | string | Yes | Setting to update \(e.g., "ssl", "security_level", "cache_level", "always_use_https", "browser_cache_ttl", "http3", "min_tls_version", "ciphers"\) | -| `value` | string | Yes | New value for the setting as a string or JSON string for complex values \(e.g., "full" for SSL, "medium" for security_level, "aggressive" for cache_level, \'\["ECDHE-RSA-AES128-GCM-SHA256"\]\' for ciphers\) | +| `value` | string | Yes | New value for the setting as a string, or a JSON string for complex values \(e.g., "full" for SSL, "medium" for security_level, "aggressive" for cache_level, \["ECDHE-RSA-AES128-GCM-SHA256"\] for ciphers\) | | `apiKey` | string | Yes | Cloudflare API Token | #### Output @@ -565,4 +565,1163 @@ Purges cached content for a zone. Can purge everything or specific files/tags/ho | --------- | ---- | ----------- | | `id` | string | Purge request identifier returned by Cloudflare | +### Cloudflare List Rulesets + +Lists every ruleset defined on a zone across all phases (WAF custom rules, managed rules, rate limiting, transform rules, and more). The list response deliberately omits the rules inside each ruleset — use "Get Ruleset" to read them. Requires an API token with Zone WAF Read (or another matching ruleset Read permission). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID to list rulesets for | +| `per_page` | number | No | Number of rulesets to return per page | +| `cursor` | string | No | Cursor for the next page, taken from the cursor output of a previous call. This endpoint paginates by cursor, not by page number | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `rulesets` | array | Rulesets defined on the zone | +| ↳ `id` | string | Ruleset identifier | +| ↳ `name` | string | Ruleset name | +| ↳ `description` | string | Ruleset description | +| ↳ `kind` | string | Ruleset kind \(managed, custom, root, or zone\) | +| ↳ `phase` | string | Phase the ruleset runs in \(e.g., http_request_firewall_custom, http_request_firewall_managed, http_ratelimit\) | +| ↳ `version` | string | Ruleset version | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| `total_count` | number | Number of rulesets returned on this page | +| `cursor` | string | Cursor to pass to the next call to read the following page, when more remain | + +### Cloudflare Get Ruleset + +Reads a single zone ruleset including every rule it contains, in evaluation order. Requires an API token with Zone WAF Read (or another matching ruleset Read permission). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID that owns the ruleset | +| `rulesetId` | string | Yes | The ruleset ID to read | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Ruleset identifier | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind \(managed, custom, root, or zone\) | +| `phase` | string | Phase the ruleset runs in | +| `version` | string | Ruleset version | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rules contained in the ruleset, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action the rule performs \(e.g., block, challenge, log, skip, execute\) | +| ↳ `action_parameters` | json | Action-specific parameters, including managed-ruleset overrides on execute rules | +| ↳ `expression` | string | Filter expression selecting matching requests. Empty on managed-ruleset rules | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag that survives rule updates | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration for rules in the http_ratelimit phase | + +### Cloudflare Get Phase Entry Point Ruleset + +Reads the entry point ruleset for a phase on a zone, including all of its rules. This is how you find the ruleset ID you need before adding, updating, or deleting a rule — for example http_request_firewall_custom for WAF custom rules, http_request_firewall_managed for managed-ruleset deployments and overrides, or http_ratelimit for rate limiting rules. Requires an API token with Zone WAF Read (or another matching ruleset Read permission). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID to read the phase entry point for | +| `phase` | string | Yes | The ruleset phase, e.g. http_request_firewall_custom, http_request_firewall_managed, http_ratelimit, http_request_transform, http_request_dynamic_redirect | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Entry point ruleset identifier | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind \(managed, custom, root, or zone\) | +| `phase` | string | Phase the ruleset runs in | +| `version` | string | Ruleset version | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rules contained in the ruleset, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action the rule performs \(e.g., block, challenge, log, skip, execute\) | +| ↳ `action_parameters` | json | Action-specific parameters, including managed-ruleset overrides on execute rules | +| ↳ `expression` | string | Filter expression selecting matching requests. Empty on managed-ruleset rules | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag that survives rule updates | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration for rules in the http_ratelimit phase | + +### Cloudflare Create Ruleset + +Creates a zone ruleset for a phase, optionally seeded with its first rules. Use this when a phase has no entry point ruleset yet — reading the entry point returns 404 on a zone that has never had a rule in that phase, and rules can only be appended to a ruleset that already exists. Create the entry point with kind "zone" and the target phase (for example http_ratelimit for rate limiting rules or http_request_firewall_custom for WAF custom rules), then use the returned ruleset ID for later rule operations. Requires an API token with Zone WAF Edit (or another matching ruleset Edit permission). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID to create the ruleset in | +| `name` | string | Yes | Human-readable name for the ruleset | +| `phase` | string | Yes | The ruleset phase, e.g. http_ratelimit, http_request_firewall_custom, http_request_firewall_managed, http_request_transform, http_request_dynamic_redirect | +| `kind` | string | No | Ruleset kind: zone, custom, managed, or root. Use zone to create a phase entry point ruleset. Defaults to zone | +| `description` | string | No | Description of the ruleset | +| `rules` | json | No | JSON array of rules to seed the ruleset with, in evaluation order. Each rule takes action, expression, and optionally description, enabled, action_parameters, and ratelimit | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Ruleset identifier | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind \(managed, custom, root, or zone\) | +| `phase` | string | Phase the ruleset runs in | +| `version` | string | Ruleset version | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rules contained in the ruleset, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action the rule performs \(e.g., block, challenge, log, skip, execute\) | +| ↳ `action_parameters` | json | Action-specific parameters, including managed-ruleset overrides on execute rules | +| ↳ `expression` | string | Filter expression selecting matching requests. Empty on managed-ruleset rules | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag that survives rule updates | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration for rules in the http_ratelimit phase | + +### Cloudflare Create Ruleset Rule + +Adds a rule to a zone ruleset. Use "Get Phase Entry Point Ruleset" first to find the ruleset ID for the phase you want (for example http_request_firewall_custom for a WAF custom rule, or http_request_firewall_managed with action "execute" to deploy a managed ruleset). The rule is appended to the end of the ruleset unless a position is given. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID that owns the ruleset | +| `rulesetId` | string | Yes | The ruleset ID to add the rule to | +| `action` | string | Yes | The action the rule performs. Valid values depend on the phase — e.g. block, challenge, js_challenge, managed_challenge, log, skip, or execute \(to deploy a managed ruleset\) | +| `expression` | string | Yes | Cloudflare filter expression selecting matching requests, e.g. \(ip.src.country in \{"GB" "FR"\}\). Use "true" to match every request | +| `description` | string | No | Human-readable description of the rule | +| `enabled` | boolean | No | Whether the rule is enabled | +| `ref` | string | No | Reference tag that stays stable across rule updates | +| `actionParameters` | string | No | JSON object of action-specific parameters. For an "execute" rule this carries the managed ruleset id and any overrides, e.g. \{"id":"<MANAGED_RULESET_ID>","overrides":\{"action":"log"\}\} | +| `position` | string | No | JSON object placing the rule within the ruleset. Exactly one of \{"before":"<RULE_ID>"\}, \{"after":"<RULE_ID>"\}, or \{"index":<1-based position>\} | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Ruleset identifier | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind \(managed, custom, root, or zone\) | +| `phase` | string | Phase the ruleset runs in | +| `version` | string | Ruleset version after the change | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rules in the ruleset after the change, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action the rule performs | +| ↳ `action_parameters` | json | Action-specific parameters | +| ↳ `expression` | string | Filter expression | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration | + +### Cloudflare Update Ruleset Rule + +Updates a rule in a zone ruleset. Cloudflare replaces the rule definition rather than merging it, so you must send every field you want the rule to keep — any field you omit is reset to its default. Read the current rule with "Get Ruleset" first. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID that owns the ruleset | +| `rulesetId` | string | Yes | The ruleset ID containing the rule | +| `ruleId` | string | Yes | The rule ID to update | +| `action` | string | Yes | The action the rule performs, e.g. block, challenge, js_challenge, managed_challenge, log, skip, or execute. Required because this endpoint replaces the rule definition — omitting it resets the stored action | +| `expression` | string | Yes | Cloudflare filter expression selecting matching requests. Required because this endpoint replaces the rule definition — omitting it resets the stored expression | +| `description` | string | No | Human-readable description of the rule | +| `enabled` | boolean | No | Whether the rule is enabled | +| `ref` | string | No | Reference tag that stays stable across rule updates | +| `actionParameters` | string | No | JSON object of action-specific parameters, e.g. \{"id":"<MANAGED_RULESET_ID>","overrides":\{"rules":\[\{"id":"<RULE_ID>","action":"log","enabled":true,"score_threshold":40\}\]\}\} | +| `ratelimit` | string | No | JSON rate limiting configuration to preserve on a rule in the http_ratelimit phase, e.g. \{"characteristics":\["cf.colo.id","ip.src"\],"period":60,"requests_per_period":100\}. Because the update replaces the rule, omitting this on a rate limiting rule stops it rate limiting | +| `logging` | string | No | JSON logging configuration to preserve, e.g. \{"enabled":true\}. Omitting it on a rule that had logging configured resets it to the default | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Ruleset identifier | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind \(managed, custom, root, or zone\) | +| `phase` | string | Phase the ruleset runs in | +| `version` | string | Ruleset version after the change | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rules in the ruleset after the change, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action the rule performs | +| ↳ `action_parameters` | json | Action-specific parameters | +| ↳ `expression` | string | Filter expression | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration | + +### Cloudflare Delete Ruleset Rule + +Permanently deletes a rule from a zone ruleset. This takes effect immediately on live traffic and cannot be undone — deleting a WAF custom rule, a managed-ruleset deployment, or a rate limiting rule removes that protection from the zone. Also use this to delete rate limiting rules, which live in the http_ratelimit phase ruleset. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID that owns the ruleset | +| `rulesetId` | string | Yes | The ruleset ID containing the rule | +| `ruleId` | string | Yes | The rule ID to delete permanently | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Ruleset identifier | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind \(managed, custom, root, or zone\) | +| `phase` | string | Phase the ruleset runs in | +| `version` | string | Ruleset version after the change | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rules remaining in the ruleset, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action the rule performs | +| ↳ `action_parameters` | json | Action-specific parameters | +| ↳ `expression` | string | Filter expression | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration | + +### Cloudflare List Managed Ruleset Overrides + +Lists the WAF managed rulesets deployed on a zone together with the overrides applied to each one. Cloudflare has no dedicated overrides endpoint — overrides live on the "execute" rules of the http_request_firewall_managed phase entry point ruleset, which this reads. Requires an API token with Zone WAF Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID to read managed ruleset deployments and overrides for | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `ruleset_id` | string | Ruleset ID of the http_request_firewall_managed entry point, needed to edit a deployment rule | +| `deployments` | array | Managed rulesets deployed on the zone and the overrides applied to each | +| ↳ `rule_id` | string | ID of the execute rule that deploys the managed ruleset | +| ↳ `managed_ruleset_id` | string | ID of the deployed managed ruleset | +| ↳ `description` | string | Description of the deployment rule | +| ↳ `expression` | string | Filter expression scoping which requests the managed ruleset runs on | +| ↳ `enabled` | boolean | Whether the deployment is enabled | +| ↳ `overrides` | json | Overrides applied to the managed ruleset, at three levels. Cloudflare documents action, enabled, and sensitivity_level at the ruleset \(top\) level; category, action, enabled, and sensitivity_level per category; and id, action, enabled, score_threshold, and sensitivity_level per rule. Rule overrides beat category overrides, which beat the ruleset-level override. sensitivity_level applies only to the DDoS phases, so for a WAF managed ruleset the rule-level properties are action, enabled, and score_threshold | +| `total_count` | number | Number of managed ruleset deployments found | + +### Cloudflare List Rate Limiting Rules + +Lists the rate limiting rules on a zone by reading the http_ratelimit phase entry point ruleset. This uses the current Rulesets-based rate limiting API; the legacy rate_limits endpoint is no longer available. The returned ruleset ID is what "Create Rate Limiting Rule", "Update Rate Limiting Rule", and "Delete Ruleset Rule" need. Requires an API token with Zone WAF Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID to list rate limiting rules for | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Ruleset ID of the http_ratelimit entry point, needed to create or edit rules | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind | +| `phase` | string | Phase the ruleset runs in \(http_ratelimit\) | +| `version` | string | Ruleset version | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rate limiting rules, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action applied once the rate limit is exceeded | +| ↳ `action_parameters` | json | Action-specific parameters, such as a custom block response | +| ↳ `expression` | string | Filter expression selecting the requests the rule applies to | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration \(characteristics, period, requests_per_period, mitigation_timeout, counting_expression, requests_to_origin\) | + +### Cloudflare Create Rate Limiting Rule + +Creates a rate limiting rule in the http_ratelimit phase entry point ruleset of a zone, using the current Rulesets-based rate limiting API (the legacy rate_limits endpoint is no longer available). Run "List Rate Limiting Rules" first to get the ruleset ID. Requires an API token with Zone WAF Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID to add the rate limiting rule to | +| `rulesetId` | string | Yes | The http_ratelimit entry point ruleset ID, as returned by "List Rate Limiting Rules" | +| `expression` | string | Yes | Cloudflare filter expression selecting the requests the rule applies to, e.g. \(http.request.uri.path matches "^/api/"\) | +| `characteristics` | string | Yes | Comma-separated counting characteristics. cf.colo.id is mandatory, plus exactly one of ip.src or cf.unique_visitor_id. Example: cf.colo.id,ip.src | +| `period` | number | Yes | Counting window in seconds. Cloudflare accepts only 10, 60, 120, 300, 600, or 3600 | +| `requestsPerPeriod` | number | Yes | Number of requests allowed within the counting period before the action fires | +| `action` | string | No | Action applied once the limit is exceeded, e.g. block, managed_challenge, js_challenge, challenge, or log. Defaults to block | +| `mitigationTimeout` | number | No | Seconds the action stays applied after the limit is exceeded. Cloudflare accepts only 0, 10, 60, 120, 300, 600, 3600, or 86400 | +| `counting_expression` | string | No | Optional expression defining which requests are counted, when it differs from the matching expression | +| `requestsToOrigin` | boolean | No | When true, only requests that reach the origin are counted | +| `description` | string | No | Human-readable description of the rule | +| `enabled` | boolean | No | Whether the rule is enabled | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Ruleset ID of the http_ratelimit entry point | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind | +| `phase` | string | Phase the ruleset runs in \(http_ratelimit\) | +| `version` | string | Ruleset version after the change | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rate limiting rules after the change, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action applied once the limit is exceeded | +| ↳ `action_parameters` | json | Action-specific parameters | +| ↳ `expression` | string | Filter expression | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration applied to the rule | + +### Cloudflare Update Rate Limiting Rule + +Updates a rate limiting rule in the http_ratelimit phase entry point ruleset of a zone, using the current Rulesets-based rate limiting API. Cloudflare replaces the rule definition rather than merging it, so send the complete rule — every field you omit is reset. Run "List Rate Limiting Rules" first to read the current definition and get the ruleset ID. Requires an API token with Zone WAF Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID that owns the rule | +| `rulesetId` | string | Yes | The http_ratelimit entry point ruleset ID, as returned by "List Rate Limiting Rules" | +| `ruleId` | string | Yes | The rate limiting rule ID to update | +| `expression` | string | Yes | Cloudflare filter expression selecting the requests the rule applies to | +| `characteristics` | string | Yes | Comma-separated counting characteristics. cf.colo.id is mandatory, plus exactly one of ip.src or cf.unique_visitor_id | +| `period` | number | Yes | Counting window in seconds. Cloudflare accepts only 10, 60, 120, 300, 600, or 3600 | +| `requestsPerPeriod` | number | Yes | Number of requests allowed within the counting period before the action fires | +| `action` | string | Yes | Action applied once the limit is exceeded: block, managed_challenge, js_challenge, challenge, or log. Required because this endpoint replaces the rule rather than merging into it — a defaulted action would silently convert an existing log or challenge rule into a hard block | +| `mitigationTimeout` | number | No | Seconds the action stays applied. Cloudflare accepts only 0, 10, 60, 120, 300, 600, 3600, or 86400 | +| `counting_expression` | string | No | Optional expression defining which requests are counted | +| `requestsToOrigin` | boolean | No | When true, only requests that reach the origin are counted | +| `description` | string | No | Human-readable description of the rule | +| `enabled` | boolean | No | Whether the rule is enabled | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Ruleset ID of the http_ratelimit entry point | +| `name` | string | Ruleset name | +| `description` | string | Ruleset description | +| `kind` | string | Ruleset kind | +| `phase` | string | Phase the ruleset runs in \(http_ratelimit\) | +| `version` | string | Ruleset version after the change | +| `last_updated` | string | RFC 3339 timestamp of the last change | +| `rules` | array | Rate limiting rules after the change, in evaluation order | +| ↳ `id` | string | Rule identifier | +| ↳ `version` | string | Rule version | +| ↳ `action` | string | Action applied once the limit is exceeded | +| ↳ `action_parameters` | json | Action-specific parameters | +| ↳ `expression` | string | Filter expression | +| ↳ `description` | string | Rule description | +| ↳ `enabled` | boolean | Whether the rule is enabled | +| ↳ `ref` | string | Rule reference tag | +| ↳ `last_updated` | string | RFC 3339 timestamp of the last change | +| ↳ `categories` | array | Managed-rule categories | +| ↳ `logging` | json | Logging configuration | +| ↳ `ratelimit` | json | Rate limiting configuration applied to the rule | + +### Cloudflare List Access Applications + +Lists the Cloudflare Access (Zero Trust) applications protecting an account. Requires an API token with Account Access: Apps and Policies Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `name` | string | No | Filter by application name | +| `domain` | string | No | Filter by the primary hostname the application secures | +| `aud` | string | No | Filter by application audience \(AUD\) tag | +| `search` | string | No | Free-text search across applications | +| `exact` | boolean | No | Whether the name and domain filters must match exactly | +| `page` | number | No | Page number for pagination | +| `per_page` | number | No | Number of applications per page | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `applications` | array | Access applications in the account | +| ↳ `id` | string | Access application identifier | +| ↳ `name` | string | Application name | +| ↳ `domain` | string | Primary hostname and path secured by Access | +| ↳ `type` | string | Application type \(e.g., self_hosted, saas, ssh, app_launcher, bookmark\) | +| ↳ `aud` | string | Audience tag used to verify Access JWTs | +| ↳ `session_duration` | string | How long an Access session stays valid \(e.g., 24h\) | +| ↳ `allowed_idps` | array | Identity provider IDs users may authenticate with | +| ↳ `app_launcher_visible` | boolean | Whether the app appears in the App Launcher | +| ↳ `auto_redirect_to_identity` | boolean | Whether users skip the identity provider picker | +| ↳ `custom_deny_message` | string | Message shown when access is denied | +| ↳ `custom_deny_url` | string | URL users are redirected to when access is denied | +| ↳ `logo_url` | string | Logo image URL | +| ↳ `self_hosted_domains` | array | Additional hostnames and paths secured by the application. Cloudflare deprecated this field in favour of destinations, which is the one to read on a current application | +| ↳ `destinations` | json | Public and private destinations secured by the application | +| ↳ `tags` | array | Tags categorizing the application | +| ↳ `policies` | json | Access policies attached to the application | +| `total_count` | number | Total number of Access applications | + +### Cloudflare Get Access Application + +Reads a single Cloudflare Access (Zero Trust) application, including its attached policies. Requires an API token with Account Access: Apps and Policies Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `appId` | string | Yes | The Access application ID \(or audience tag\) to read | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Access application identifier | +| `name` | string | Application name | +| `domain` | string | Primary hostname and path secured by Access | +| `type` | string | Application type \(e.g., self_hosted, saas, ssh, app_launcher, bookmark\) | +| `aud` | string | Audience tag used to verify Access JWTs | +| `session_duration` | string | How long an Access session stays valid \(e.g., 24h\) | +| `allowed_idps` | array | Identity provider IDs users may authenticate with | +| `app_launcher_visible` | boolean | Whether the app appears in the App Launcher | +| `auto_redirect_to_identity` | boolean | Whether users skip the identity provider picker | +| `custom_deny_message` | string | Message shown when access is denied | +| `custom_deny_url` | string | URL users are redirected to when access is denied | +| `logo_url` | string | Logo image URL | +| `self_hosted_domains` | array | Additional hostnames and paths secured by the application. Cloudflare deprecated this field in favour of destinations, which is the one to read on a current application | +| `destinations` | json | Public and private destinations secured by the application | +| `tags` | array | Tags categorizing the application | +| `policies` | json | Access policies attached to the application | + +### Cloudflare Create Access Application + +Creates a Cloudflare Access (Zero Trust) application that puts an identity check in front of a hostname. Until at least one policy is attached the application denies everyone, so pair this with "Create Access Policy". Requires an API token with Account Access: Apps and Policies Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `type` | string | Yes | Application type: self_hosted, saas, ssh, vnc, app_launcher, warp, biso, bookmark, dash_sso, infrastructure, rdp, mcp, mcp_portal, or proxy_endpoint | +| `domain` | string | No | The primary hostname and path secured by Access, e.g. internal.example.com or example.com/admin. Required for the self_hosted, ssh, vnc, rdp, and bookmark types; the saas, app_launcher, warp, biso, dash_sso, infrastructure, mcp, mcp_portal, and proxy_endpoint types do not accept it | +| `name` | string | No | Friendly name shown in the dashboard and App Launcher | +| `sessionDuration` | string | No | How long an Access session stays valid, e.g. 24h or 30m | +| `allowedIdps` | string | No | Comma-separated identity provider IDs users may authenticate with. Leave empty to allow all configured providers | +| `appLauncherVisible` | boolean | No | Whether the application is shown in the App Launcher | +| `autoRedirectToIdentity` | boolean | No | Whether users skip the identity provider picker | +| `customDenyMessage` | string | No | Message shown to users who are denied access | +| `customDenyUrl` | string | No | URL denied users are redirected to | +| `logoUrl` | string | No | Logo image URL shown in the dashboard and App Launcher | +| `tags` | string | No | Comma-separated tag names categorizing the application | +| `policies` | string | No | JSON array of policies to attach. Entries may be reusable policy IDs or inline policy objects, e.g. \["<POLICY_ID>"\] | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Created Access application identifier | +| `name` | string | Application name | +| `domain` | string | Primary hostname and path secured by Access | +| `type` | string | Application type | +| `aud` | string | Audience tag used to verify Access JWTs | +| `session_duration` | string | How long an Access session stays valid | +| `allowed_idps` | array | Identity provider IDs users may authenticate with | +| `app_launcher_visible` | boolean | Whether the app appears in the App Launcher | +| `auto_redirect_to_identity` | boolean | Whether users skip the identity provider picker | +| `custom_deny_message` | string | Message shown when access is denied | +| `custom_deny_url` | string | URL users are redirected to when access is denied | +| `logo_url` | string | Logo image URL | +| `self_hosted_domains` | array | Additional hostnames and paths secured by the application. Cloudflare deprecated this field in favour of destinations, which is the one to read on a current application | +| `destinations` | json | Public and private destinations secured by the application | +| `tags` | array | Tags categorizing the application | +| `policies` | json | Access policies attached to the application | + +### Cloudflare Update Access Application + +Updates a Cloudflare Access (Zero Trust) application. This replaces the application definition rather than merging it, so send every field the application should keep — anything you omit reverts to its default, which can widen or break access. Read the current configuration with "Get Access Application" first. Requires an API token with Account Access: Apps and Policies Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `appId` | string | Yes | The Access application ID to update | +| `type` | string | Yes | Application type: self_hosted, saas, ssh, vnc, app_launcher, warp, biso, bookmark, dash_sso, infrastructure, rdp, mcp, mcp_portal, or proxy_endpoint | +| `domain` | string | No | The primary hostname and path secured by Access. Required for the self_hosted, ssh, vnc, rdp, and bookmark types; the saas, app_launcher, warp, biso, dash_sso, infrastructure, mcp, mcp_portal, and proxy_endpoint types do not accept it | +| `name` | string | No | Friendly name shown in the dashboard and App Launcher | +| `sessionDuration` | string | No | How long an Access session stays valid, e.g. 24h or 30m | +| `allowedIdps` | string | No | Comma-separated identity provider IDs users may authenticate with | +| `appLauncherVisible` | boolean | No | Whether the application is shown in the App Launcher | +| `autoRedirectToIdentity` | boolean | No | Whether users skip the identity provider picker | +| `customDenyMessage` | string | No | Message shown to users who are denied access | +| `customDenyUrl` | string | No | URL denied users are redirected to | +| `logoUrl` | string | No | Logo image URL shown in the dashboard and App Launcher | +| `tags` | string | No | Comma-separated tag names categorizing the application | +| `policies` | string | No | JSON array of policies to attach. Entries may be reusable policy IDs or inline policy objects | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Access application identifier | +| `name` | string | Application name | +| `domain` | string | Primary hostname and path secured by Access | +| `type` | string | Application type | +| `aud` | string | Audience tag used to verify Access JWTs | +| `session_duration` | string | How long an Access session stays valid | +| `allowed_idps` | array | Identity provider IDs users may authenticate with | +| `app_launcher_visible` | boolean | Whether the app appears in the App Launcher | +| `auto_redirect_to_identity` | boolean | Whether users skip the identity provider picker | +| `custom_deny_message` | string | Message shown when access is denied | +| `custom_deny_url` | string | URL users are redirected to when access is denied | +| `logo_url` | string | Logo image URL | +| `self_hosted_domains` | array | Additional hostnames and paths secured by the application. Cloudflare deprecated this field in favour of destinations, which is the one to read on a current application | +| `destinations` | json | Public and private destinations secured by the application | +| `tags` | array | Tags categorizing the application | +| `policies` | json | Access policies attached to the application | + +### Cloudflare Delete Access Application + +Permanently deletes a Cloudflare Access (Zero Trust) application and every policy attached to it. The hostname it protected is immediately left without an Access identity check, so anyone who can reach it can reach the origin. This cannot be undone. Requires an API token with Account Access: Apps and Policies Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `appId` | string | Yes | The Access application ID to delete permanently | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Identifier of the deleted Access application | + +### Cloudflare List Access Policies + +Lists the Cloudflare Access (Zero Trust) policies attached to an application, in precedence order. Requires an API token with Account Access: Apps and Policies Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `appId` | string | Yes | The Access application ID whose policies should be listed | +| `page` | number | No | Page number for pagination | +| `per_page` | number | No | Number of policies per page | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `policies` | array | Access policies attached to the application | +| ↳ `id` | string | Policy identifier | +| ↳ `name` | string | Policy name | +| ↳ `decision` | string | Decision the policy applies: allow, deny, non_identity, or bypass | +| ↳ `precedence` | number | Evaluation order of the policy within the application | +| ↳ `include` | json | Rules evaluated with OR logic — matching any one selects the policy | +| ↳ `exclude` | json | Rules evaluated with NOT logic — matching any one rejects the request | +| ↳ `require` | json | Rules evaluated with AND logic — all must match | +| ↳ `session_duration` | string | How long a session granted by this policy stays valid | +| ↳ `approval_required` | boolean | Whether an approver must grant each access request | +| ↳ `isolation_required` | boolean | Whether the session must run in a remote browser | +| ↳ `purpose_justification_required` | boolean | Whether users must state a reason for access | +| ↳ `purpose_justification_prompt` | string | Prompt shown when a justification is required | +| ↳ `created_at` | string | Creation timestamp | +| ↳ `updated_at` | string | Last update timestamp | +| `total_count` | number | Total number of policies | + +### Cloudflare Create Access Policy + +Creates a Cloudflare Access (Zero Trust) policy on an application, deciding who may reach it. A policy takes effect on live traffic as soon as it is created — an allow policy with a broad include rule grants access immediately. Requires an API token with Account Access: Apps and Policies Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `appId` | string | Yes | The Access application ID to attach the policy to | +| `name` | string | Yes | Name of the policy | +| `decision` | string | Yes | What the policy does when it matches: allow, deny, non_identity \(service tokens and other non-identity rules\), or bypass \(skip Access entirely\) | +| `include` | string | Yes | JSON array of Access rules evaluated with OR logic — matching any one selects the policy. Example: \[\{"email":\{"email":"user@example.com"\}\}\] or \[\{"email_domain":\{"domain":"example.com"\}\}\] | +| `exclude` | string | No | JSON array of Access rules evaluated with NOT logic — matching any one rejects the request | +| `require` | string | No | JSON array of Access rules evaluated with AND logic — all of them must match | +| `precedence` | number | No | Evaluation order of the policy within the application | +| `sessionDuration` | string | No | How long a session granted by this policy stays valid, e.g. 24h | +| `approvalRequired` | boolean | No | Whether an approver must grant each access request | +| `isolationRequired` | boolean | No | Whether the session must run in a remote isolated browser | +| `purposeJustificationRequired` | boolean | No | Whether users must state a reason for access | +| `purposeJustificationPrompt` | string | No | Prompt shown when a justification is required | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Created policy identifier | +| `name` | string | Policy name | +| `decision` | string | Decision the policy applies: allow, deny, non_identity, or bypass | +| `precedence` | number | Evaluation order of the policy within the application | +| `include` | json | Rules evaluated with OR logic | +| `exclude` | json | Rules evaluated with NOT logic | +| `require` | json | Rules evaluated with AND logic | +| `session_duration` | string | How long a session granted by this policy stays valid | +| `approval_required` | boolean | Whether an approver must grant each access request | +| `isolation_required` | boolean | Whether the session must run in a remote browser | +| `purpose_justification_required` | boolean | Whether users must state a reason for access | +| `purpose_justification_prompt` | string | Prompt shown when a justification is required | +| `created_at` | string | Creation timestamp | +| `updated_at` | string | Last update timestamp | + +### Cloudflare Update Access Policy + +Updates a Cloudflare Access (Zero Trust) policy on an application. This replaces the policy definition rather than merging it, so send every rule the policy should keep — omitted exclude or require rules are dropped, which can widen who gets in. The change applies to live traffic immediately. Read the current policy with "List Access Policies" first. Requires an API token with Account Access: Apps and Policies Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `appId` | string | Yes | The Access application ID that owns the policy | +| `policyId` | string | Yes | The Access policy ID to update | +| `name` | string | Yes | Name of the policy | +| `decision` | string | Yes | What the policy does when it matches: allow, deny, non_identity, or bypass \(skip Access entirely\) | +| `include` | string | Yes | JSON array of Access rules evaluated with OR logic. Example: \[\{"email_domain":\{"domain":"example.com"\}\}\] | +| `exclude` | string | No | JSON array of Access rules evaluated with NOT logic | +| `require` | string | No | JSON array of Access rules evaluated with AND logic | +| `precedence` | number | No | Evaluation order of the policy within the application | +| `sessionDuration` | string | No | How long a session granted by this policy stays valid, e.g. 24h | +| `approvalRequired` | boolean | No | Whether an approver must grant each access request | +| `isolationRequired` | boolean | No | Whether the session must run in a remote isolated browser | +| `purposeJustificationRequired` | boolean | No | Whether users must state a reason for access | +| `purposeJustificationPrompt` | string | No | Prompt shown when a justification is required | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Policy identifier | +| `name` | string | Policy name | +| `decision` | string | Decision the policy applies: allow, deny, non_identity, or bypass | +| `precedence` | number | Evaluation order of the policy within the application | +| `include` | json | Rules evaluated with OR logic | +| `exclude` | json | Rules evaluated with NOT logic | +| `require` | json | Rules evaluated with AND logic | +| `session_duration` | string | How long a session granted by this policy stays valid | +| `approval_required` | boolean | Whether an approver must grant each access request | +| `isolation_required` | boolean | Whether the session must run in a remote browser | +| `purpose_justification_required` | boolean | Whether users must state a reason for access | +| `purpose_justification_prompt` | string | Prompt shown when a justification is required | +| `created_at` | string | Creation timestamp | +| `updated_at` | string | Last update timestamp | + +### Cloudflare Delete Access Policy + +Permanently deletes a Cloudflare Access (Zero Trust) policy from an application. This changes who can reach the application the moment it runs: removing an allow policy locks out everyone it covered, and removing a deny or require policy drops that restriction. This cannot be undone. Requires an API token with Account Access: Apps and Policies Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access applications are account-scoped | +| `appId` | string | Yes | The Access application ID that owns the policy | +| `policyId` | string | Yes | The Access policy ID to delete permanently | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Identifier of the deleted Access policy | + +### Cloudflare List Access Groups + +Lists the reusable Cloudflare Access (Zero Trust) groups in an account. Groups bundle identity rules that policies can reference by ID. Requires an API token with Account Access: Organizations, Identity Providers, and Groups Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Access groups are account-scoped | +| `name` | string | No | Filter by group name | +| `search` | string | No | Free-text search across groups | +| `page` | number | No | Page number for pagination | +| `per_page` | number | No | Number of groups per page | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `groups` | array | Access groups in the account | +| ↳ `id` | string | Access group identifier | +| ↳ `name` | string | Group name | +| ↳ `is_default` | json | Rules that place this group in every Access application by default. Cloudflare returns an array of rule objects here, not a boolean | +| ↳ `include` | json | Rules evaluated with OR logic | +| ↳ `exclude` | json | Rules evaluated with NOT logic | +| ↳ `require` | json | Rules evaluated with AND logic | +| ↳ `created_at` | string | Creation timestamp | +| ↳ `updated_at` | string | Last update timestamp | +| `total_count` | number | Total number of Access groups | + +### Cloudflare List Access Identity Providers + +Lists the identity providers configured for Cloudflare Access (Zero Trust) in an account, such as Okta, Entra ID, Google Workspace, or a one-time PIN. Use the returned IDs to restrict an application with allowed_idps. Requires an API token with Account Access: Organizations, Identity Providers, and Groups Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Identity providers are account-scoped | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `identity_providers` | array | Identity providers configured for Access | +| ↳ `id` | string | Identity provider identifier | +| ↳ `name` | string | Display name shown to users on the login page | +| ↳ `type` | string | Provider type, e.g. azureAD, okta, google, saml, oidc, or onetimepin | +| ↳ `read_only` | boolean | Whether the provider is immutable through the API | +| ↳ `config` | json | Provider-specific configuration parameters | +| ↳ `scim_config` | json | SCIM user and group provisioning configuration | +| `total_count` | number | Total number of identity providers | + +### Cloudflare List Access Service Tokens + +Lists the Cloudflare Access (Zero Trust) service tokens in an account, which let machines authenticate to Access-protected applications. Client secrets are never returned by this endpoint — only on creation. Requires an API token with Account Access: Service Tokens Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Service tokens are account-scoped | +| `name` | string | No | Filter by service token name | +| `search` | string | No | Free-text search across service tokens | +| `page` | number | No | Page number for pagination | +| `per_page` | number | No | Number of service tokens per page | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `service_tokens` | array | Access service tokens in the account | +| ↳ `id` | string | Service token identifier | +| ↳ `name` | string | Service token name | +| ↳ `client_id` | string | Client ID sent in the CF-Access-Client-Id header | +| ↳ `duration` | string | How long the token stays valid before it expires | +| ↳ `enabled` | boolean | Whether the token is active | +| ↳ `expires_at` | string | Expiry timestamp | +| ↳ `last_seen_at` | string | When the token was last used | +| ↳ `created_at` | string | Creation timestamp | +| ↳ `updated_at` | string | Last update timestamp | +| `total_count` | number | Total number of service tokens | + +### Cloudflare Create Access Service Token + +Creates a Cloudflare Access (Zero Trust) service token so a machine can authenticate to Access-protected applications. This is the only response that ever contains the client secret — Cloudflare will not return it again, so capture it in the same run. Requires an API token with Account Access: Service Tokens Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Service tokens are account-scoped | +| `name` | string | Yes | Name of the service token | +| `duration` | string | No | How long the token stays valid before it expires, e.g. 8760h. Defaults to Cloudflare's standard lifetime | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Created service token identifier | +| `name` | string | Service token name | +| `client_id` | string | Client ID sent in the CF-Access-Client-Id header | +| `client_secret` | string | Client secret sent in the CF-Access-Client-Secret header. Returned only once, at creation | +| `duration` | string | How long the token stays valid before it expires | +| `enabled` | boolean | Whether the token is active | +| `expires_at` | string | Expiry timestamp | +| `last_seen_at` | string | When the token was last used | +| `created_at` | string | Creation timestamp | +| `updated_at` | string | Last update timestamp | + +### Cloudflare Revoke Access Service Token + +Permanently deletes a Cloudflare Access (Zero Trust) service token, revoking it. Every machine or integration still presenting that client ID and secret is locked out of the Access-protected applications immediately, and the secret cannot be recovered. This cannot be undone. Requires an API token with Account Access: Service Tokens Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Service tokens are account-scoped | +| `serviceTokenId` | string | Yes | The service token ID to revoke permanently | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Identifier of the revoked service token | +| `name` | string | Service token name | +| `client_id` | string | Client ID that is no longer accepted | +| `duration` | string | Configured token lifetime | +| `enabled` | boolean | Whether the token was active | +| `expires_at` | string | Expiry timestamp | +| `last_seen_at` | string | When the token was last used | +| `created_at` | string | Creation timestamp | +| `updated_at` | string | Last update timestamp | + +### Cloudflare List R2 Buckets + +Lists the R2 object storage buckets in an account. Requires an API token with Account Workers R2 Storage Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. R2 buckets are account-scoped | +| `name_contains` | string | No | Only return buckets whose name contains this substring | +| `start_after` | string | No | Bucket name to start listing after | +| `cursor` | string | No | Pagination cursor returned by a previous call | +| `direction` | string | No | Sort direction by bucket name: asc or desc | +| `per_page` | number | No | Number of buckets per page | +| `jurisdiction` | string | No | Data-residency jurisdiction to list within: default, eu, or fedramp | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `buckets` | array | R2 buckets in the account | +| ↳ `name` | string | Bucket name | +| ↳ `creation_date` | string | Creation timestamp | +| ↳ `location` | string | Location hint the bucket was created with \(apac, eeur, enam, weur, wnam, or oc\) | +| ↳ `storage_class` | string | Default storage class \(Standard or InfrequentAccess\) | +| ↳ `jurisdiction` | string | Data-residency jurisdiction \(default, eu, or fedramp\) | +| `cursor` | string | Pagination cursor to pass to the next call | + +### Cloudflare Get R2 Bucket + +Reads the metadata of a single R2 object storage bucket. Requires an API token with Account Workers R2 Storage Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. R2 buckets are account-scoped | +| `bucketName` | string | Yes | The name of the bucket to read | +| `jurisdiction` | string | No | Data-residency jurisdiction the bucket lives in: default, eu, or fedramp | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `name` | string | Bucket name | +| `creation_date` | string | Creation timestamp | +| `location` | string | Location hint the bucket was created with \(apac, eeur, enam, weur, wnam, or oc\) | +| `storage_class` | string | Default storage class \(Standard or InfrequentAccess\) | +| `jurisdiction` | string | Data-residency jurisdiction \(default, eu, or fedramp\) | + +### Cloudflare Create R2 Bucket + +Creates an R2 object storage bucket in an account. The location hint and jurisdiction are fixed at creation and cannot be changed later. Requires an API token with Account Workers R2 Storage Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. R2 buckets are account-scoped | +| `bucketName` | string | Yes | Name for the new bucket | +| `locationHint` | string | No | Region hint for where the bucket should live: apac, eeur, enam, weur, wnam, or oc. Cannot be changed after creation | +| `storageClass` | string | No | Default storage class for objects: Standard or InfrequentAccess | +| `jurisdiction` | string | No | Data-residency jurisdiction to create the bucket in: default, eu, or fedramp. Cannot be changed after creation | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `name` | string | Created bucket name | +| `creation_date` | string | Creation timestamp | +| `location` | string | Location the bucket was created in | +| `storage_class` | string | Default storage class \(Standard or InfrequentAccess\) | +| `jurisdiction` | string | Data-residency jurisdiction \(default, eu, or fedramp\) | + +### Cloudflare Delete R2 Bucket + +Permanently deletes an R2 object storage bucket. Cloudflare only deletes an empty bucket, and the deletion cannot be undone. Requires an API token with Account Workers R2 Storage Edit. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. R2 buckets are account-scoped | +| `bucketName` | string | Yes | The name of the bucket to delete permanently | +| `jurisdiction` | string | No | Data-residency jurisdiction the bucket lives in: default, eu, or fedramp | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `name` | string | Name of the deleted bucket. Cloudflare returns an empty result body for this endpoint, so the name is echoed from the request | + +### Cloudflare List Worker Scripts + +Lists the Workers scripts deployed in an account. Requires an API token with Account Workers Scripts Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Workers scripts are account-scoped | +| `tags` | string | No | Filter scripts by tag. Cloudflare expects a comma-separated list of tag:allowed pairs where allowed is yes or no, e.g. team:core:yes,deprecated:no | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `scripts` | array | Workers scripts in the account | +| ↳ `id` | string | Script name | +| ↳ `tag` | string | Immutable script identifier, distinct from the script name | +| ↳ `etag` | string | Hash of the script content | +| ↳ `created_on` | string | Creation timestamp | +| ↳ `modified_on` | string | Last deployment timestamp | +| ↳ `usage_model` | string | Billing usage model \(standard, bundled, or unbound\) | +| ↳ `placement_mode` | string | Smart placement mode \(smart or targeted\) | +| ↳ `logpush` | boolean | Whether Workers Logpush is enabled | +| ↳ `has_assets` | boolean | Whether the script ships static assets | +| ↳ `has_modules` | boolean | Whether the script uses ES modules | +| ↳ `compatibility_date` | string | Workers runtime compatibility date | +| ↳ `compatibility_flags` | array | Workers runtime compatibility flags | +| ↳ `routes` | json | Routes the script is bound to | +| ↳ `tail_consumers` | json | Workers that consume this script's tail events | +| `total_count` | number | Number of scripts returned | + +### Cloudflare Get Worker Script Settings + +Reads the deployment settings of a single Workers script — bindings, compatibility date and flags, limits, observability, placement, and tail consumers. The plain "get script" endpoint in the Cloudflare API returns raw JavaScript source rather than JSON, so this settings endpoint is the structured way to inspect one script. Requires an API token with Account Workers Scripts Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Workers scripts are account-scoped | +| `scriptName` | string | Yes | The name of the Workers script to read settings for | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `bindings` | json | Resource bindings available to the script \(KV, R2, D1, secrets, and more\) | +| `compatibility_date` | string | Workers runtime compatibility date | +| `compatibility_flags` | array | Workers runtime compatibility flags | +| `limits` | json | CPU and other execution limits | +| `logpush` | boolean | Whether Workers Logpush is enabled | +| `migrations` | json | Durable Object migrations | +| `observability` | json | Observability and log-sampling configuration | +| `placement` | json | Smart placement configuration | +| `tags` | array | Tags attached to the script | +| `tail_consumers` | json | Workers that consume this script's tail events | +| `usage_model` | string | Billing usage model | + +### Cloudflare List Worker Routes + +Lists the Workers routes on a zone, showing which URL patterns are handled by which Worker script. Unlike the Workers script endpoints, routes are zone-scoped. Requires an API token with Zone Workers Routes Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `zoneId` | string | Yes | The zone ID to list Workers routes for. Routes are zone-scoped, not account-scoped | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `routes` | array | Workers routes on the zone | +| ↳ `id` | string | Route identifier | +| ↳ `pattern` | string | URL pattern the route matches, e.g. example.com/* | +| ↳ `script` | string | Name of the Workers script handling the route | +| `total_count` | number | Number of routes returned | + +### Cloudflare List Tunnels + +Lists the Cloudflare Tunnels (cloudflared) in an account, with their health status and active connections. Requires an API token with Account Cloudflare Tunnel Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Tunnels are account-scoped | +| `name` | string | No | Filter by exact tunnel name | +| `status` | string | No | Filter by tunnel health: inactive, degraded, healthy, or down | +| `uuid` | string | No | Filter by tunnel UUID | +| `is_deleted` | boolean | No | Whether to return deleted tunnels instead of active ones | +| `include_prefix` | string | No | Only include tunnels whose name starts with this prefix | +| `exclude_prefix` | string | No | Exclude tunnels whose name starts with this prefix | +| `existed_at` | string | No | Return tunnels that existed at this RFC 3339 timestamp | +| `was_active_at` | string | No | Return tunnels that were active at this RFC 3339 timestamp | +| `was_inactive_at` | string | No | Return tunnels that were inactive at this RFC 3339 timestamp | +| `page` | number | No | Page number for pagination | +| `per_page` | number | No | Number of tunnels per page | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tunnels` | array | Cloudflare Tunnels in the account | +| ↳ `id` | string | Tunnel identifier | +| ↳ `name` | string | Tunnel name | +| ↳ `account_tag` | string | Account the tunnel belongs to | +| ↳ `config_src` | string | Where the tunnel configuration lives: local or cloudflare | +| ↳ `status` | string | Tunnel health: inactive, degraded, healthy, or down | +| ↳ `tun_type` | string | Tunnel type, e.g. cfd_tunnel, warp_connector, or warp | +| ↳ `remote_config` | boolean | Whether the tunnel is remotely managed | +| ↳ `metadata` | json | Metadata associated with the tunnel | +| ↳ `created_at` | string | Creation timestamp | +| ↳ `deleted_at` | string | Deletion timestamp | +| ↳ `conns_active_at` | string | When the tunnel last had active connections | +| ↳ `conns_inactive_at` | string | When the tunnel last lost all connections | +| ↳ `connections` | json | Active connector connections for the tunnel | +| `total_count` | number | Total number of tunnels | + +### Cloudflare Get Tunnel + +Reads a single Cloudflare Tunnel (cloudflared), including its health status and active connector connections. Requires an API token with Account Cloudflare Tunnel Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Tunnels are account-scoped | +| `tunnelId` | string | Yes | The tunnel ID to read | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Tunnel identifier | +| `name` | string | Tunnel name | +| `account_tag` | string | Account the tunnel belongs to | +| `config_src` | string | Where the tunnel configuration lives: local or cloudflare | +| `status` | string | Tunnel health: inactive, degraded, healthy, or down | +| `tun_type` | string | Tunnel type, e.g. cfd_tunnel, warp_connector, or warp | +| `remote_config` | boolean | Whether the tunnel is remotely managed | +| `metadata` | json | Metadata associated with the tunnel | +| `created_at` | string | Creation timestamp | +| `deleted_at` | string | Deletion timestamp | +| `conns_active_at` | string | When the tunnel last had active connections | +| `conns_inactive_at` | string | When the tunnel last lost all connections | +| `connections` | json | Active connector connections for the tunnel | + +### Cloudflare Get Tunnel Configuration + +Reads the configuration of a remotely-managed Cloudflare Tunnel — its ingress rules, origin request settings, and WARP routing. Only tunnels whose configuration source is "cloudflare" have a remote configuration; locally-managed tunnels keep it in their own config file. Requires an API token with Account Cloudflare Tunnel Read. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `accountId` | string | Yes | The Cloudflare account ID. Tunnels are account-scoped | +| `tunnelId` | string | Yes | The tunnel ID to read the configuration for | +| `apiKey` | string | Yes | Cloudflare API Token | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tunnel_id` | string | Tunnel the configuration belongs to | +| `account_id` | string | Account the tunnel belongs to | +| `version` | number | Configuration version, incremented on every change | +| `source` | string | Where the configuration is managed: local or cloudflare | +| `created_at` | string | Creation timestamp | +| `config` | json | Tunnel configuration with ingress rules, originRequest defaults, and warp-routing settings | + diff --git a/apps/sim/blocks/blocks/cloudflare.ts b/apps/sim/blocks/blocks/cloudflare.ts index bc2707558d5..b4b98e37f1f 100644 --- a/apps/sim/blocks/blocks/cloudflare.ts +++ b/apps/sim/blocks/blocks/cloudflare.ts @@ -2,13 +2,62 @@ import { CloudflareIcon } from '@/components/icons' import { AuthMode, type BlockConfig, type BlockMeta, IntegrationType } from '@/blocks/types' import type { CloudflareResponse } from '@/tools/cloudflare/types' +/** + * Per-operation aliases from a tool param name to the subBlock id that supplies + * it, keyed by operation. + * + * Block state is keyed by subBlock id, so two controls sharing an id share one + * stored value and the last definition in file order wins the seeded default. + * That is fine — and deliberate — when both controls mean the same thing (a zone + * id, a page number, a record name). It is not fine when they differ: a control + * in `mode: 'advanced'` is serialized whenever its stored value is non-empty, + * *before* its own `condition` is evaluated (`shouldSerializeSubBlock` in + * `serializer/index.ts`), so a hidden filter from one operation would otherwise + * arrive as a written value on another — a `list_dns_records` "Content Filter" + * silently overwriting a record's content on `update_dns_record`, or a + * `list_zones` status reaching `list_tunnels`, whose status enum is disjoint. + * + * Every such control therefore carries its own id and is republished here under + * the tool's param name, before any coercion in the mapper reads it. + */ +const SUBBLOCK_ALIASES: Record> = { + create_zone: { type: 'zoneType' }, + list_zones: { name: 'zoneNameFilter' }, + create_dns_record: { type: 'recordType', proxied: 'recordProxied' }, + list_dns_records: { + type: 'dnsTypeFilter', + name: 'dnsNameFilter', + content: 'dnsContentFilter', + order: 'dnsOrder', + proxied: 'dnsProxiedFilter', + }, + list_certificates: { status: 'certificateStatus' }, + purge_cache: { tags: 'purgeTags' }, + create_ruleset: { name: 'rulesetName' }, + create_rate_limit_rule: { action: 'rateLimitAction' }, + update_rate_limit_rule: { action: 'updateRateLimitAction' }, + create_access_application: { type: 'appType', tags: 'accessAppTags' }, + update_access_application: { type: 'updateAppType', tags: 'accessAppTags' }, + update_access_policy: { decision: 'updatePolicyDecision' }, + list_access_applications: { name: 'listNameFilter', domain: 'accessAppDomainFilter' }, + list_access_groups: { name: 'listNameFilter' }, + list_access_service_tokens: { name: 'listNameFilter' }, + list_worker_scripts: { tags: 'workerTagFilter' }, + list_tunnels: { status: 'tunnelStatus', name: 'listNameFilter' }, +} + +/** Every alias subBlock id, so none of them can reach a tool as a param. */ +const ALIASED_SUBBLOCK_IDS = [ + ...new Set(Object.values(SUBBLOCK_ALIASES).flatMap((aliases) => Object.values(aliases))), +] + export const CloudflareBlock: BlockConfig = { type: 'cloudflare', name: 'Cloudflare', - description: 'Manage DNS, domains, certificates, and cache', + description: 'Manage DNS, WAF, Zero Trust access, and edge infrastructure', authMode: AuthMode.ApiKey, longDescription: - 'Integrate Cloudflare into the workflow. Manage zones (domains), DNS records, SSL/TLS certificates, zone settings, DNS analytics, and cache purging via the Cloudflare API.', + 'Integrate Cloudflare into the workflow. Manage zones (domains), DNS records, SSL/TLS certificates, zone settings, DNS analytics, and cache purging. Configure WAF rulesets, managed rule overrides, and rate limiting rules through the current Rulesets engine. Administer Cloudflare Access (Zero Trust) applications, policies, groups, identity providers, and service tokens, and inspect R2 buckets, Workers scripts and routes, and Cloudflare Tunnels.', docsLink: 'https://docs.sim.ai/integrations/cloudflare', category: 'tools', integrationType: IntegrationType.DevOps, @@ -20,7 +69,7 @@ export const CloudflareBlock: BlockConfig = { byOperation: { list_zones: [ 'List zones', - { text: 'named', field: 'name' }, + { text: 'named', field: 'zoneNameFilter' }, { text: ', with status', field: 'status' }, ], get_zone: [{ text: 'Read details of zone', field: 'zoneId', core: true }], @@ -31,12 +80,12 @@ export const CloudflareBlock: BlockConfig = { delete_zone: [{ text: 'Delete zone', field: 'zoneId', core: true }], list_dns_records: [ { text: 'List DNS records in zone', field: 'zoneId', core: true }, - { text: ', of type', field: 'type' }, - { text: ', named', field: 'name' }, + { text: ', of type', field: 'dnsTypeFilter' }, + { text: ', named', field: 'dnsNameFilter' }, ], create_dns_record: [ { text: 'Add DNS record', field: 'name', core: true }, - { text: 'of type', field: 'type' }, + { text: 'of type', field: 'recordType' }, { text: ', pointing at', field: 'content' }, ], update_dns_record: [ @@ -50,7 +99,7 @@ export const CloudflareBlock: BlockConfig = { ], list_certificates: [ { text: 'List certificate packs for zone', field: 'zoneId', core: true }, - { text: ', with status', field: 'status' }, + { text: ', with status', field: 'certificateStatus' }, ], get_zone_settings: [{ text: 'Read all settings of zone', field: 'zoneId', core: true }], update_zone_setting: [ @@ -65,7 +114,124 @@ export const CloudflareBlock: BlockConfig = { ], purge_cache: [ { text: 'Purge cache for zone', field: 'zoneId', core: true }, - { text: ', limited to', field: ['files', 'prefixes', 'hosts', 'tags'] }, + { text: ', limited to', field: ['files', 'prefixes', 'hosts', 'purgeTags'] }, + ], + list_rulesets: [{ text: 'List rulesets in zone', field: 'zoneId', core: true }], + get_ruleset: [ + { text: 'Read ruleset', field: 'rulesetId', core: true }, + { text: 'in zone', field: 'zoneId' }, + ], + get_ruleset_entrypoint: [ + { text: 'Read the entry point ruleset for phase', field: 'phase', core: true }, + { text: 'in zone', field: 'zoneId' }, + ], + create_ruleset: [ + { text: 'Create a ruleset for phase', field: 'phase', core: true }, + { text: 'in zone', field: 'zoneId' }, + ], + create_ruleset_rule: [ + { text: 'Add a rule that runs', field: 'action', core: true }, + { text: 'when', field: 'expression', core: true }, + { text: ', to ruleset', field: 'rulesetId' }, + ], + update_ruleset_rule: [ + { text: 'Update rule', field: 'ruleId', core: true }, + { text: 'in ruleset', field: 'rulesetId' }, + { text: ', to run', field: 'action' }, + ], + delete_ruleset_rule: [ + { text: 'Delete rule', field: 'ruleId', core: true }, + { text: 'from ruleset', field: 'rulesetId' }, + ], + list_managed_ruleset_overrides: [ + { text: 'List WAF managed ruleset overrides for zone', field: 'zoneId', core: true }, + ], + list_rate_limit_rules: [ + { text: 'List rate limiting rules in zone', field: 'zoneId', core: true }, + ], + create_rate_limit_rule: [ + { text: 'Rate limit', field: 'expression', core: true }, + { text: 'to', field: 'requestsPerPeriod', core: true }, + { text: 'requests every', field: 'period' }, + ], + update_rate_limit_rule: [ + { text: 'Update rate limiting rule', field: 'ruleId', core: true }, + { text: 'to', field: 'requestsPerPeriod' }, + { text: 'requests every', field: 'period' }, + ], + list_access_applications: [ + { text: 'List Access applications in account', field: 'accountId', core: true }, + { text: ', matching', field: ['listNameFilter', 'accessAppDomainFilter', 'search'] }, + ], + get_access_application: [{ text: 'Read Access application', field: 'appId', core: true }], + create_access_application: [ + { text: 'Protect', field: 'domain', core: true }, + { text: 'with an Access application named', field: 'name' }, + ], + update_access_application: [ + { text: 'Update Access application', field: 'appId', core: true }, + { text: ', securing', field: 'domain' }, + ], + delete_access_application: [ + { text: 'Delete Access application', field: 'appId', core: true }, + ], + list_access_policies: [ + { text: 'List Access policies on application', field: 'appId', core: true }, + ], + create_access_policy: [ + { text: 'Add Access policy', field: 'name', core: true }, + { text: 'that will', field: 'decision', core: true }, + { text: 'on application', field: 'appId' }, + ], + update_access_policy: [ + { text: 'Update Access policy', field: 'policyId', core: true }, + { text: 'to', field: 'updatePolicyDecision' }, + { text: 'on application', field: 'appId' }, + ], + delete_access_policy: [ + { text: 'Delete Access policy', field: 'policyId', core: true }, + { text: 'from application', field: 'appId' }, + ], + list_access_groups: [ + { text: 'List Access groups in account', field: 'accountId', core: true }, + ], + list_access_identity_providers: [ + { text: 'List Access identity providers in account', field: 'accountId', core: true }, + ], + list_access_service_tokens: [ + { text: 'List Access service tokens in account', field: 'accountId', core: true }, + ], + create_access_service_token: [ + { text: 'Create Access service token', field: 'name', core: true }, + { text: ', valid for', field: 'duration' }, + ], + revoke_access_service_token: [ + { text: 'Revoke Access service token', field: 'serviceTokenId', core: true }, + ], + list_r2_buckets: [ + { text: 'List R2 buckets in account', field: 'accountId', core: true }, + { text: ', named like', field: 'name_contains' }, + ], + get_r2_bucket: [{ text: 'Read R2 bucket', field: 'bucketName', core: true }], + create_r2_bucket: [ + { text: 'Create R2 bucket', field: 'bucketName', core: true }, + { text: 'in', field: 'locationHint' }, + ], + delete_r2_bucket: [{ text: 'Delete R2 bucket', field: 'bucketName', core: true }], + list_worker_scripts: [ + { text: 'List Worker scripts in account', field: 'accountId', core: true }, + ], + get_worker_script_settings: [ + { text: 'Read settings of Worker script', field: 'scriptName', core: true }, + ], + list_worker_routes: [{ text: 'List Worker routes in zone', field: 'zoneId', core: true }], + list_tunnels: [ + { text: 'List tunnels in account', field: 'accountId', core: true }, + { text: ', with status', field: 'tunnelStatus' }, + ], + get_tunnel: [{ text: 'Read tunnel', field: 'tunnelId', core: true }], + get_tunnel_configuration: [ + { text: 'Read the configuration of tunnel', field: 'tunnelId', core: true }, ], }, }, @@ -89,13 +255,48 @@ export const CloudflareBlock: BlockConfig = { { label: 'Update Zone Setting', id: 'update_zone_setting' }, { label: 'DNS Analytics', id: 'dns_analytics' }, { label: 'Purge Cache', id: 'purge_cache' }, + { label: 'List Rulesets', id: 'list_rulesets' }, + { label: 'Get Ruleset', id: 'get_ruleset' }, + { label: 'Get Phase Entry Point Ruleset', id: 'get_ruleset_entrypoint' }, + { label: 'Create Ruleset', id: 'create_ruleset' }, + { label: 'Create Ruleset Rule', id: 'create_ruleset_rule' }, + { label: 'Update Ruleset Rule', id: 'update_ruleset_rule' }, + { label: 'Delete Ruleset Rule', id: 'delete_ruleset_rule' }, + { label: 'List Managed Ruleset Overrides', id: 'list_managed_ruleset_overrides' }, + { label: 'List Rate Limiting Rules', id: 'list_rate_limit_rules' }, + { label: 'Create Rate Limiting Rule', id: 'create_rate_limit_rule' }, + { label: 'Update Rate Limiting Rule', id: 'update_rate_limit_rule' }, + { label: 'List Access Applications', id: 'list_access_applications' }, + { label: 'Get Access Application', id: 'get_access_application' }, + { label: 'Create Access Application', id: 'create_access_application' }, + { label: 'Update Access Application', id: 'update_access_application' }, + { label: 'Delete Access Application', id: 'delete_access_application' }, + { label: 'List Access Policies', id: 'list_access_policies' }, + { label: 'Create Access Policy', id: 'create_access_policy' }, + { label: 'Update Access Policy', id: 'update_access_policy' }, + { label: 'Delete Access Policy', id: 'delete_access_policy' }, + { label: 'List Access Groups', id: 'list_access_groups' }, + { label: 'List Access Identity Providers', id: 'list_access_identity_providers' }, + { label: 'List Access Service Tokens', id: 'list_access_service_tokens' }, + { label: 'Create Access Service Token', id: 'create_access_service_token' }, + { label: 'Revoke Access Service Token', id: 'revoke_access_service_token' }, + { label: 'List R2 Buckets', id: 'list_r2_buckets' }, + { label: 'Get R2 Bucket', id: 'get_r2_bucket' }, + { label: 'Create R2 Bucket', id: 'create_r2_bucket' }, + { label: 'Delete R2 Bucket', id: 'delete_r2_bucket' }, + { label: 'List Worker Scripts', id: 'list_worker_scripts' }, + { label: 'Get Worker Script Settings', id: 'get_worker_script_settings' }, + { label: 'List Worker Routes', id: 'list_worker_routes' }, + { label: 'List Tunnels', id: 'list_tunnels' }, + { label: 'Get Tunnel', id: 'get_tunnel' }, + { label: 'Get Tunnel Configuration', id: 'get_tunnel_configuration' }, ], value: () => 'list_zones', }, // List Zones inputs { - id: 'name', + id: 'zoneNameFilter', title: 'Domain Name', type: 'short-input', placeholder: 'Filter by domain (e.g., example.com)', @@ -244,7 +445,7 @@ export const CloudflareBlock: BlockConfig = { condition: { field: 'operation', value: 'list_dns_records' }, }, { - id: 'type', + id: 'dnsTypeFilter', title: 'Record Type', type: 'dropdown', options: [ @@ -262,7 +463,7 @@ export const CloudflareBlock: BlockConfig = { mode: 'advanced', }, { - id: 'name', + id: 'dnsNameFilter', title: 'Name Filter', type: 'short-input', placeholder: 'Filter by record name (exact match)', @@ -270,7 +471,7 @@ export const CloudflareBlock: BlockConfig = { mode: 'advanced', }, { - id: 'content', + id: 'dnsContentFilter', title: 'Content Filter', type: 'short-input', placeholder: 'Filter by record content (exact match)', @@ -304,7 +505,7 @@ export const CloudflareBlock: BlockConfig = { mode: 'advanced', }, { - id: 'order', + id: 'dnsOrder', title: 'Sort Field', type: 'dropdown', options: [ @@ -320,7 +521,7 @@ export const CloudflareBlock: BlockConfig = { mode: 'advanced', }, { - id: 'proxied', + id: 'dnsProxiedFilter', title: 'Proxied Filter', type: 'dropdown', options: [ @@ -396,7 +597,7 @@ export const CloudflareBlock: BlockConfig = { condition: { field: 'operation', value: 'create_dns_record' }, }, { - id: 'type', + id: 'recordType', title: 'Record Type', type: 'dropdown', options: [ @@ -436,7 +637,7 @@ export const CloudflareBlock: BlockConfig = { mode: 'advanced', }, { - id: 'proxied', + id: 'recordProxied', title: 'Proxied', type: 'dropdown', options: [ @@ -597,13 +798,12 @@ export const CloudflareBlock: BlockConfig = { condition: { field: 'operation', value: 'list_certificates' }, }, { - id: 'status', + id: 'certificateStatus', title: 'Status Filter', type: 'dropdown', options: [ - { label: 'All', id: 'all' }, - { label: 'Active', id: 'active' }, - { label: 'Pending', id: 'pending' }, + { label: 'All statuses', id: 'all' }, + { label: 'Active only', id: '' }, ], value: () => 'all', condition: { field: 'operation', value: 'list_certificates' }, @@ -926,7 +1126,7 @@ Return ONLY the comma-separated URLs - no explanations, no extra text.`, }, }, { - id: 'tags', + id: 'purgeTags', title: 'Cache Tags', type: 'short-input', placeholder: 'Comma-separated cache tags (Enterprise only)', @@ -950,166 +1150,1622 @@ Return ONLY the comma-separated URLs - no explanations, no extra text.`, mode: 'advanced', }, - // API Key (common) + // Zone ID for zone-scoped WAF, rate limiting, and Workers routes operations { - id: 'apiKey', - title: 'API Token', + id: 'zoneId', + title: 'Zone ID', type: 'short-input', required: true, - placeholder: 'Enter your Cloudflare API token', - password: true, + placeholder: 'Enter zone ID', + condition: { + field: 'operation', + value: [ + 'list_rulesets', + 'get_ruleset', + 'get_ruleset_entrypoint', + 'create_ruleset', + 'create_ruleset_rule', + 'update_ruleset_rule', + 'delete_ruleset_rule', + 'list_managed_ruleset_overrides', + 'list_rate_limit_rules', + 'create_rate_limit_rule', + 'update_rate_limit_rule', + 'list_worker_routes', + ], + }, }, - ], - tools: { - access: [ - 'cloudflare_list_zones', - 'cloudflare_get_zone', - 'cloudflare_create_zone', - 'cloudflare_delete_zone', - 'cloudflare_list_dns_records', - 'cloudflare_create_dns_record', - 'cloudflare_update_dns_record', - 'cloudflare_delete_dns_record', - 'cloudflare_list_certificates', - 'cloudflare_get_zone_settings', - 'cloudflare_update_zone_setting', - 'cloudflare_dns_analytics', - 'cloudflare_purge_cache', - ], - config: { - tool: (params) => `cloudflare_${params.operation}`, - params: (params) => { - const result = { ...params } - - if (result.ttl) result.ttl = Number(result.ttl) - if (result.priority) result.priority = Number(result.priority) - if (result.limit) result.limit = Number(result.limit) - if (result.page) result.page = Number(result.page) - if (result.per_page) result.per_page = Number(result.per_page) - if (result.proxied === 'true') result.proxied = true - else if (result.proxied === 'false') result.proxied = false - else if (result.proxied === '') result.proxied = undefined + // Account ID for account-scoped Access, R2, Workers scripts, and Tunnels operations + { + id: 'accountId', + title: 'Account ID', + type: 'short-input', + required: true, + placeholder: 'Enter Cloudflare account ID', + condition: { + field: 'operation', + value: [ + 'list_access_applications', + 'get_access_application', + 'create_access_application', + 'update_access_application', + 'delete_access_application', + 'list_access_policies', + 'create_access_policy', + 'update_access_policy', + 'delete_access_policy', + 'list_access_groups', + 'list_access_identity_providers', + 'list_access_service_tokens', + 'create_access_service_token', + 'revoke_access_service_token', + 'list_r2_buckets', + 'get_r2_bucket', + 'create_r2_bucket', + 'delete_r2_bucket', + 'list_worker_scripts', + 'get_worker_script_settings', + 'list_tunnels', + 'get_tunnel', + 'get_tunnel_configuration', + ], + }, + }, - if (result.purge_everything === 'true') result.purge_everything = true - else if (result.purge_everything === 'false') result.purge_everything = false + // Ruleset inputs + { + id: 'phase', + title: 'Phase', + type: 'dropdown', + options: [ + { label: 'WAF Custom Rules', id: 'http_request_firewall_custom' }, + { label: 'WAF Managed Rules', id: 'http_request_firewall_managed' }, + { label: 'Rate Limiting', id: 'http_ratelimit' }, + { label: 'Request Transform', id: 'http_request_transform' }, + { label: 'Late Request Transform', id: 'http_request_late_transform' }, + { label: 'Dynamic Redirects', id: 'http_request_dynamic_redirect' }, + { label: 'Request Cache Settings', id: 'http_request_cache_settings' }, + { label: 'Config Settings', id: 'http_config_settings' }, + { label: 'Origin', id: 'http_request_origin' }, + { label: 'Response Headers Transform', id: 'http_response_headers_transform' }, + { label: 'Response Compression', id: 'http_response_compression' }, + { label: 'Custom Errors', id: 'http_custom_errors' }, + { label: 'Super Bot Fight Mode', id: 'http_request_sbfm' }, + ], + value: () => 'http_request_firewall_custom', + required: true, + condition: { field: 'operation', value: ['get_ruleset_entrypoint', 'create_ruleset'] }, + }, + { + id: 'rulesetName', + title: 'Ruleset Name', + type: 'short-input', + required: true, + placeholder: 'e.g. Zone rate limiting ruleset', + condition: { field: 'operation', value: 'create_ruleset' }, + }, + { + id: 'kind', + title: 'Ruleset Kind', + type: 'dropdown', + options: [ + { label: 'Zone (phase entry point)', id: 'zone' }, + { label: 'Custom', id: 'custom' }, + { label: 'Root', id: 'root' }, + ], + value: () => 'zone', + condition: { field: 'operation', value: 'create_ruleset' }, + mode: 'advanced', + }, + { + id: 'rules', + title: 'Initial Rules', + type: 'long-input', + placeholder: 'JSON array of rules to seed the ruleset with', + condition: { field: 'operation', value: 'create_ruleset' }, + mode: 'advanced', + wandConfig: { + enabled: true, + maintainHistory: true, + prompt: `Generate a Cloudflare ruleset rules array from the user's description. - if (result.type === '' && result.operation !== 'create_dns_record') { - result.type = undefined - } - if (result.status === '') result.status = undefined - if (result.order === '') result.order = undefined - if (result.direction === '') result.direction = undefined - if (result.match === '') result.match = undefined - if (result.tag_match === '') result.tag_match = undefined - if (result.deploy === '') result.deploy = undefined +Each rule is an object with: +- "action": the action to take, e.g. "block", "challenge", "managed_challenge", "js_challenge", "log", "skip", "execute" +- "expression": a Cloudflare filter expression selecting matching requests +- "description": optional human-readable description +- "enabled": optional boolean, defaults to true - if (result.operation === 'update_dns_record') { - if (result.content === '') result.content = undefined - if (result.name === '') result.name = undefined - if (result.comment === '') result.comment = undefined - } +A rate limiting rule (http_ratelimit phase) also takes "ratelimit" with "characteristics", "period", and "requests_per_period". - if (result.operation === 'create_zone' && result.zoneType) { - result.type = result.zoneType - } +Examples: +- "block traffic from Russia" -> [{"action":"block","expression":"(ip.geoip.country eq \\"RU\\")","description":"Block RU"}] +- "rate limit the login endpoint to 10 requests a minute per IP" -> [{"action":"block","expression":"(http.request.uri.path eq \\"/login\\")","description":"Login rate limit","ratelimit":{"characteristics":["ip.src","cf.colo.id"],"period":60,"requests_per_period":10}}] - return result +Return ONLY the JSON array - no explanations, no markdown fences.`, + placeholder: 'Describe the rules to seed this ruleset with...', + generationType: 'json-array', }, }, - }, - inputs: { - operation: { type: 'string', description: 'Operation to perform' }, - apiKey: { type: 'string', description: 'Cloudflare API token' }, - zoneId: { type: 'string', description: 'Zone ID' }, - accountId: { type: 'string', description: 'Cloudflare account ID' }, - zoneType: { type: 'string', description: 'Zone type (full, partial, or secondary)' }, - order: { type: 'string', description: 'Sort field for listing zones' }, - direction: { type: 'string', description: 'Sort direction (asc, desc)' }, - match: { type: 'string', description: 'Match logic for filters (any, all)' }, - recordId: { type: 'string', description: 'DNS record ID' }, - name: { type: 'string', description: 'Domain or record name' }, - type: { type: 'string', description: 'DNS record type' }, - content: { type: 'string', description: 'DNS record content' }, - ttl: { type: 'number', description: 'Time to live in seconds' }, - proxied: { type: 'boolean', description: 'Whether Cloudflare proxy is enabled' }, - priority: { type: 'number', description: 'Record priority (MX/SRV)' }, - comment: { type: 'string', description: 'Record comment' }, - search: { type: 'string', description: 'Free-text search across record properties' }, - tag: { type: 'string', description: 'Filter by an exact tag name' }, - tag_match: { type: 'string', description: 'Tag filter match logic (any, all)' }, - commentFilter: { type: 'string', description: 'Filter records by comment content' }, - settingId: { type: 'string', description: 'Zone setting ID' }, - value: { type: 'string', description: 'Setting value' }, - since: { type: 'string', description: 'Start date for analytics' }, - until: { type: 'string', description: 'End date for analytics' }, - metrics: { type: 'string', description: 'Comma-separated metrics to retrieve' }, - dimensions: { type: 'string', description: 'Comma-separated dimensions to group by' }, - filters: { type: 'string', description: 'Filters to apply (e.g., queryType==A)' }, - sort: { type: 'string', description: 'Sort order for results' }, - limit: { type: 'number', description: 'Maximum number of results' }, - status: { type: 'string', description: 'Status filter for zones or certificates' }, - page: { type: 'number', description: 'Page number for pagination' }, - per_page: { type: 'number', description: 'Number of results per page' }, - deploy: { - type: 'string', - description: 'Filter certificates by deployment environment (staging, production)', + { + id: 'rulesetId', + title: 'Ruleset ID', + type: 'short-input', + required: true, + placeholder: 'From "List Rulesets" or "Get Phase Entry Point Ruleset"', + condition: { + field: 'operation', + value: ['get_ruleset', 'create_ruleset_rule', 'update_ruleset_rule', 'delete_ruleset_rule'], + }, }, - purge_everything: { type: 'boolean', description: 'Purge all cached content' }, - files: { type: 'string', description: 'Comma-separated URLs to purge' }, - tags: { type: 'string', description: 'Comma-separated cache tags to purge (Enterprise only)' }, - hosts: { type: 'string', description: 'Comma-separated hostnames to purge (Enterprise only)' }, - prefixes: { - type: 'string', - description: 'Comma-separated URL prefixes to purge (Enterprise only)', + { + id: 'rulesetId', + title: 'Rate Limiting Ruleset ID', + type: 'short-input', + required: true, + placeholder: 'From "List Rate Limiting Rules"', + condition: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, }, - }, - outputs: { - zones: { type: 'json', description: 'List of zones/domains' }, - records: { type: 'json', description: 'List of DNS records' }, - certificates: { type: 'json', description: 'List of SSL/TLS certificate packs' }, - settings: { type: 'json', description: 'List of zone settings' }, - totals: { type: 'json', description: 'Aggregate DNS analytics totals' }, - min: { type: 'json', description: 'Minimum values across the DNS analytics period' }, - max: { type: 'json', description: 'Maximum values across the DNS analytics period' }, - query: { type: 'json', description: 'Echo of the DNS analytics query parameters sent' }, - validation_errors: { type: 'json', description: 'Validation issues for certificate packs' }, - data: { type: 'json', description: 'Raw analytics data rows from the DNS analytics report' }, - data_lag: { - type: 'number', - description: 'Processing lag in seconds before analytics data becomes available', + { + id: 'ruleId', + title: 'Rule ID', + type: 'short-input', + required: true, + placeholder: 'Enter rule ID', + condition: { + field: 'operation', + value: ['update_ruleset_rule', 'delete_ruleset_rule', 'update_rate_limit_rule'], + }, }, - rows: { type: 'number', description: 'Total number of rows in the DNS analytics result set' }, - id: { type: 'string', description: 'Resource ID' }, - zone_id: { type: 'string', description: 'Zone ID the record belongs to' }, - zone_name: { type: 'string', description: 'Zone domain name' }, - name: { type: 'string', description: 'Resource name' }, - status: { type: 'string', description: 'Resource status' }, - paused: { type: 'boolean', description: 'Whether the zone is paused' }, - type: { type: 'string', description: 'Zone or record type' }, - name_servers: { type: 'json', description: 'Assigned Cloudflare name servers' }, - original_name_servers: { type: 'json', description: 'Original registrar name servers' }, - plan: { - type: 'json', - description: - 'Zone plan information (id, name, price, currency, frequency, is_subscribed, legacy_id)', + { + id: 'action', + title: 'Action', + type: 'short-input', + required: { + field: 'operation', + value: ['create_ruleset_rule', 'update_ruleset_rule'], + }, + placeholder: 'block, challenge, managed_challenge, js_challenge, log, skip, execute', + condition: { + field: 'operation', + value: ['create_ruleset_rule', 'update_ruleset_rule'], + }, }, - account: { type: 'json', description: 'Account the zone belongs to (id, name)' }, - owner: { type: 'json', description: 'Zone owner information (id, name, type)' }, - activated_on: { type: 'string', description: 'ISO 8601 date when the zone was activated' }, - development_mode: { - type: 'number', - description: 'Seconds remaining in development mode (0 = off)', + { + id: 'rateLimitAction', + title: 'Action', + type: 'dropdown', + options: [ + { label: 'Block', id: 'block' }, + { label: 'Managed Challenge', id: 'managed_challenge' }, + { label: 'JS Challenge', id: 'js_challenge' }, + { label: 'Interactive Challenge', id: 'challenge' }, + { label: 'Log', id: 'log' }, + ], + value: () => 'block', + condition: { field: 'operation', value: 'create_rate_limit_rule' }, + }, + { + /** + * The update endpoint replaces the rule, so a seeded action would rewrite + * whatever the rule currently does the moment anything else is edited. + * This control carries no default: the user has to state the action the + * replaced rule should end up with. + */ + id: 'updateRateLimitAction', + title: 'Action', + type: 'dropdown', + options: [ + { label: 'Block', id: 'block' }, + { label: 'Managed Challenge', id: 'managed_challenge' }, + { label: 'JS Challenge', id: 'js_challenge' }, + { label: 'Interactive Challenge', id: 'challenge' }, + { label: 'Log', id: 'log' }, + ], + required: true, + condition: { field: 'operation', value: 'update_rate_limit_rule' }, }, - meta: { - type: 'json', - description: 'Resource metadata (zone: cdn_only, dns_only, etc.; DNS record: source)', + { + id: 'expression', + title: 'Expression', + type: 'long-input', + required: { + field: 'operation', + value: [ + 'create_ruleset_rule', + 'update_ruleset_rule', + 'create_rate_limit_rule', + 'update_rate_limit_rule', + ], + }, + placeholder: '(http.request.uri.path matches "^/api/")', + condition: { + field: 'operation', + value: [ + 'create_ruleset_rule', + 'update_ruleset_rule', + 'create_rate_limit_rule', + 'update_rate_limit_rule', + ], + }, + wandConfig: { + enabled: true, + prompt: `Generate a Cloudflare Ruleset Engine filter expression from the user's description. + +Syntax uses fields, operators, and logical connectors: +- ip.src, ip.src.country, ip.src.asnum +- http.host, http.request.uri.path, http.request.uri.query, http.request.method +- http.user_agent, http.referer +- cf.threat_score, cf.bot_management.score, cf.client.bot +- ssl + +Operators: eq, ne, lt, gt, contains, matches (regex), in { } +Connectors: and, or, not, with parentheses + +Examples: +- "block traffic from the UK and France" -> (ip.src.country in {"GB" "FR"}) +- "everything under /api" -> (http.request.uri.path matches "^/api/") +- "the login page from non-verified bots" -> (http.request.uri.path eq "/login" and cf.client.bot) +- "all requests" -> true + +Return ONLY the expression - no explanations, no quotes around the whole expression, no extra text.`, + placeholder: + 'Describe the traffic to match (e.g., "requests to /api from outside the US")...', + }, }, - vanity_name_servers: { type: 'json', description: 'Custom vanity name servers' }, - permissions: { type: 'json', description: 'User permissions for the zone' }, - content: { type: 'string', description: 'DNS record value (e.g., IP address)' }, - proxiable: { type: 'boolean', description: 'Whether the record can be proxied' }, - proxied: { type: 'boolean', description: 'Whether Cloudflare proxy is enabled' }, + { + id: 'description', + title: 'Description', + type: 'short-input', + placeholder: 'Human-readable description of the rule', + condition: { + field: 'operation', + value: [ + 'create_ruleset', + 'create_ruleset_rule', + 'update_ruleset_rule', + 'create_rate_limit_rule', + 'update_rate_limit_rule', + ], + }, + }, + { + id: 'enabled', + title: 'Enabled', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { + field: 'operation', + value: [ + 'create_ruleset_rule', + 'update_ruleset_rule', + 'create_rate_limit_rule', + 'update_rate_limit_rule', + ], + }, + mode: 'advanced', + }, + { + id: 'ref', + title: 'Reference Tag', + type: 'short-input', + placeholder: 'Stable reference that survives rule updates', + condition: { + field: 'operation', + value: ['create_ruleset_rule', 'update_ruleset_rule'], + }, + mode: 'advanced', + }, + { + id: 'ratelimit', + title: 'Rate Limiting Configuration', + type: 'long-input', + placeholder: + '{"characteristics":["cf.colo.id","ip.src"],"period":60,"requests_per_period":100}', + condition: { field: 'operation', value: 'update_ruleset_rule' }, + mode: 'advanced', + }, + { + id: 'logging', + title: 'Logging Configuration', + type: 'long-input', + placeholder: '{"enabled":true}', + condition: { field: 'operation', value: 'update_ruleset_rule' }, + mode: 'advanced', + }, + { + id: 'actionParameters', + title: 'Action Parameters', + type: 'long-input', + placeholder: '{"id":"","overrides":{"action":"log"}}', + condition: { + field: 'operation', + value: ['create_ruleset_rule', 'update_ruleset_rule'], + }, + wandConfig: { + enabled: true, + prompt: `Generate the JSON action_parameters object for a Cloudflare ruleset rule from the user's description. + +For an "execute" rule that deploys a WAF managed ruleset: +{"id":""} + +To override the whole managed ruleset: +{"id":"","overrides":{"action":"log"}} + +To override specific categories: +{"id":"","overrides":{"categories":[{"category":"wordpress","action":"block","enabled":true}]}} + +To override specific rules: +{"id":"","overrides":{"rules":[{"id":"","action":"log","enabled":true}]}} + +"action" and "enabled" are overridable at every level. Individual managed rulesets may accept more: an OWASP Core Ruleset rule override also takes "score_threshold", e.g. +{"id":"","overrides":{"rules":[{"id":"","score_threshold":60,"action":"managed_challenge"}]}} + +Return ONLY the JSON object - no explanations, no markdown fences.`, + placeholder: + 'Describe the action parameters (e.g., "deploy the Cloudflare Managed Ruleset in log mode")...', + generationType: 'json-object', + }, + }, + { + id: 'position', + title: 'Position', + type: 'short-input', + placeholder: '{"index":1} or {"before":""} or {"after":""}', + condition: { field: 'operation', value: 'create_ruleset_rule' }, + mode: 'advanced', + }, + + // Rate limiting inputs + { + id: 'characteristics', + title: 'Characteristics', + type: 'short-input', + required: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + placeholder: 'cf.colo.id,ip.src', + condition: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + wandConfig: { + enabled: true, + prompt: `Generate a comma-separated list of Cloudflare rate limiting counting characteristics from the user's description. + +cf.colo.id is mandatory in every list. Include exactly one of ip.src or cf.unique_visitor_id. + +Available characteristics: +- cf.colo.id (mandatory) +- ip.src +- cf.unique_visitor_id +- http.host +- http.request.uri.path +- ip.src.asnum +- ip.src.country +- http.request.headers[""] +- http.request.cookies[""] +- http.request.uri.args[""] +- cf.bot_management.ja3_hash +- cf.bot_management.ja4 + +Examples: +- "per IP address" -> cf.colo.id,ip.src +- "per visitor" -> cf.colo.id,cf.unique_visitor_id +- "per API key header" -> cf.colo.id,ip.src,http.request.headers["x-api-key"] +- "per country" -> cf.colo.id,ip.src.country + +Return ONLY the comma-separated list - no explanations, no extra text.`, + placeholder: + 'Describe how to group counters (e.g., "per IP address", "per API key header")...', + }, + }, + { + id: 'period', + title: 'Period (seconds)', + type: 'dropdown', + options: [ + { label: '10 seconds', id: '10' }, + { label: '1 minute', id: '60' }, + { label: '2 minutes', id: '120' }, + { label: '5 minutes', id: '300' }, + { label: '10 minutes', id: '600' }, + { label: '1 hour', id: '3600' }, + ], + value: () => '60', + required: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + condition: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + }, + { + id: 'requestsPerPeriod', + title: 'Requests Per Period', + type: 'short-input', + required: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + placeholder: 'e.g., 100', + condition: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + }, + { + id: 'mitigationTimeout', + title: 'Mitigation Timeout (seconds)', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'No timeout', id: '0' }, + { label: '10 seconds', id: '10' }, + { label: '1 minute', id: '60' }, + { label: '2 minutes', id: '120' }, + { label: '5 minutes', id: '300' }, + { label: '10 minutes', id: '600' }, + { label: '1 hour', id: '3600' }, + { label: '1 day', id: '86400' }, + ], + value: () => '', + condition: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + mode: 'advanced', + }, + { + id: 'counting_expression', + title: 'Counting Expression', + type: 'long-input', + placeholder: 'Expression selecting which requests are counted, if different from the match', + condition: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + mode: 'advanced', + }, + { + id: 'requestsToOrigin', + title: 'Count Only Origin Requests', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { + field: 'operation', + value: ['create_rate_limit_rule', 'update_rate_limit_rule'], + }, + mode: 'advanced', + }, + + // Access application inputs + { + id: 'appId', + title: 'Application ID', + type: 'short-input', + required: true, + placeholder: 'Enter Access application ID', + condition: { + field: 'operation', + value: [ + 'get_access_application', + 'update_access_application', + 'delete_access_application', + 'list_access_policies', + 'create_access_policy', + 'update_access_policy', + 'delete_access_policy', + ], + }, + }, + { + id: 'appType', + title: 'Application Type', + type: 'dropdown', + options: [ + { label: 'Self-Hosted', id: 'self_hosted' }, + { label: 'SaaS', id: 'saas' }, + { label: 'SSH', id: 'ssh' }, + { label: 'VNC', id: 'vnc' }, + { label: 'App Launcher', id: 'app_launcher' }, + { label: 'WARP', id: 'warp' }, + { label: 'Browser Isolation', id: 'biso' }, + { label: 'Bookmark', id: 'bookmark' }, + { label: 'Dashboard SSO', id: 'dash_sso' }, + { label: 'Infrastructure', id: 'infrastructure' }, + { label: 'RDP', id: 'rdp' }, + { label: 'MCP', id: 'mcp' }, + { label: 'MCP Portal', id: 'mcp_portal' }, + { label: 'Proxy Endpoint', id: 'proxy_endpoint' }, + ], + value: () => 'self_hosted', + required: true, + condition: { field: 'operation', value: 'create_access_application' }, + }, + { + /** + * Updating an Access application replaces it, so a seeded type would + * rewrite what a live application IS as soon as anything else is edited. + * No default: the caller states the type the replaced application keeps. + */ + id: 'updateAppType', + title: 'Application Type', + type: 'dropdown', + options: [ + { label: 'Self-Hosted', id: 'self_hosted' }, + { label: 'SaaS', id: 'saas' }, + { label: 'SSH', id: 'ssh' }, + { label: 'VNC', id: 'vnc' }, + { label: 'App Launcher', id: 'app_launcher' }, + { label: 'WARP', id: 'warp' }, + { label: 'Browser Isolation', id: 'biso' }, + { label: 'Bookmark', id: 'bookmark' }, + { label: 'Dashboard SSO', id: 'dash_sso' }, + { label: 'Infrastructure', id: 'infrastructure' }, + { label: 'RDP', id: 'rdp' }, + { label: 'MCP', id: 'mcp' }, + { label: 'MCP Portal', id: 'mcp_portal' }, + { label: 'Proxy Endpoint', id: 'proxy_endpoint' }, + ], + required: true, + condition: { field: 'operation', value: 'update_access_application' }, + }, + { + id: 'domain', + title: 'Domain', + type: 'short-input', + placeholder: 'Required for self_hosted, ssh, vnc, rdp, and bookmark apps', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + }, + { + id: 'accessAppDomainFilter', + title: 'Domain Filter', + type: 'short-input', + placeholder: 'Filter by the hostname the application secures', + condition: { field: 'operation', value: 'list_access_applications' }, + mode: 'advanced', + }, + { + id: 'name', + title: 'Application Name', + type: 'short-input', + placeholder: 'Friendly name shown in the dashboard', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + }, + { + id: 'listNameFilter', + title: 'Name Filter', + type: 'short-input', + placeholder: 'Filter by name', + condition: { + field: 'operation', + value: [ + 'list_access_applications', + 'list_access_groups', + 'list_access_service_tokens', + 'list_tunnels', + ], + }, + mode: 'advanced', + }, + { + id: 'aud', + title: 'Audience Tag', + type: 'short-input', + placeholder: 'Filter by application AUD tag', + condition: { field: 'operation', value: 'list_access_applications' }, + mode: 'advanced', + }, + { + id: 'search', + title: 'Search', + type: 'short-input', + placeholder: 'Free-text search', + condition: { + field: 'operation', + value: ['list_access_applications', 'list_access_groups', 'list_access_service_tokens'], + }, + mode: 'advanced', + }, + { + id: 'exact', + title: 'Exact Match', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { field: 'operation', value: 'list_access_applications' }, + mode: 'advanced', + }, + { + id: 'sessionDuration', + title: 'Session Duration', + type: 'short-input', + placeholder: 'e.g., 24h', + condition: { + field: 'operation', + value: [ + 'create_access_application', + 'update_access_application', + 'create_access_policy', + 'update_access_policy', + ], + }, + mode: 'advanced', + }, + { + id: 'allowedIdps', + title: 'Allowed Identity Providers', + type: 'short-input', + placeholder: 'Comma-separated identity provider IDs', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + mode: 'advanced', + }, + { + id: 'appLauncherVisible', + title: 'Show in App Launcher', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + mode: 'advanced', + }, + { + id: 'autoRedirectToIdentity', + title: 'Auto Redirect to Identity Provider', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + mode: 'advanced', + }, + { + id: 'customDenyMessage', + title: 'Custom Deny Message', + type: 'short-input', + placeholder: 'Message shown to denied users', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + mode: 'advanced', + }, + { + id: 'customDenyUrl', + title: 'Custom Deny URL', + type: 'short-input', + placeholder: 'https://example.com/denied', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + mode: 'advanced', + }, + { + id: 'logoUrl', + title: 'Logo URL', + type: 'short-input', + placeholder: 'https://example.com/logo.png', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + mode: 'advanced', + }, + { + id: 'accessAppTags', + title: 'Tags', + type: 'short-input', + placeholder: 'Comma-separated tag names', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + mode: 'advanced', + }, + { + id: 'policies', + title: 'Policies', + type: 'long-input', + placeholder: 'JSON array of reusable policy IDs or inline policy objects', + condition: { + field: 'operation', + value: ['create_access_application', 'update_access_application'], + }, + mode: 'advanced', + }, + + // Access policy inputs + { + id: 'policyId', + title: 'Policy ID', + type: 'short-input', + required: true, + placeholder: 'Enter Access policy ID', + condition: { + field: 'operation', + value: ['update_access_policy', 'delete_access_policy'], + }, + }, + { + id: 'name', + title: 'Policy Name', + type: 'short-input', + required: true, + placeholder: 'e.g., Allow engineering team', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + }, + { + id: 'decision', + title: 'Decision', + type: 'dropdown', + options: [ + { label: 'Allow', id: 'allow' }, + { label: 'Deny', id: 'deny' }, + { label: 'Non-Identity (service tokens)', id: 'non_identity' }, + { label: 'Bypass (skip Access entirely)', id: 'bypass' }, + ], + value: () => 'allow', + required: true, + condition: { field: 'operation', value: 'create_access_policy' }, + }, + { + /** + * Updating a policy replaces it, so a seeded allow would silently widen a + * live deny, bypass, or non_identity policy the moment its rules are + * edited. No default: the caller states the decision. + */ + id: 'updatePolicyDecision', + title: 'Decision', + type: 'dropdown', + options: [ + { label: 'Allow', id: 'allow' }, + { label: 'Deny', id: 'deny' }, + { label: 'Non-Identity (service tokens)', id: 'non_identity' }, + { label: 'Bypass (skip Access entirely)', id: 'bypass' }, + ], + required: true, + condition: { field: 'operation', value: 'update_access_policy' }, + }, + { + id: 'include', + title: 'Include Rules', + type: 'long-input', + required: true, + placeholder: '[{"email_domain":{"domain":"example.com"}}]', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + wandConfig: { + enabled: true, + prompt: `Generate a JSON array of Cloudflare Access rules from the user's description. These are evaluated with OR logic. + +Rule shapes: +- {"email":{"email":"user@example.com"}} +- {"email_domain":{"domain":"example.com"}} +- {"email_list":{"id":""}} +- {"everyone":{}} +- {"ip":{"ip":"192.0.2.1/32"}} +- {"ip_list":{"id":""}} +- {"group":{"id":""}} +- {"service_token":{"token_id":""}} +- {"any_valid_service_token":{}} +- {"certificate":{}} +- {"geo":{"country_code":"US"}} +- {"azureAD":{"id":"","connection_id":""}} +- {"okta":{"name":"","connection_id":""}} +- {"gsuite":{"email":"","connection_id":""}} + +Examples: +- "anyone at example.com" -> [{"email_domain":{"domain":"example.com"}}] +- "a specific person" -> [{"email":{"email":"user@example.com"}}] +- "any service token" -> [{"any_valid_service_token":{}}] +- "everyone" -> [{"everyone":{}}] + +Return ONLY the JSON array - no explanations, no markdown fences.`, + placeholder: 'Describe who should match (e.g., "anyone with an @example.com email")...', + generationType: 'json-array', + }, + }, + { + id: 'exclude', + title: 'Exclude Rules', + type: 'long-input', + placeholder: 'JSON array of Access rules evaluated with NOT logic', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + mode: 'advanced', + }, + { + id: 'require', + title: 'Require Rules', + type: 'long-input', + placeholder: 'JSON array of Access rules evaluated with AND logic', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + mode: 'advanced', + }, + { + id: 'precedence', + title: 'Precedence', + type: 'short-input', + placeholder: 'Evaluation order within the application', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + mode: 'advanced', + }, + { + id: 'approvalRequired', + title: 'Approval Required', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + mode: 'advanced', + }, + { + id: 'isolationRequired', + title: 'Browser Isolation Required', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + mode: 'advanced', + }, + { + id: 'purposeJustificationRequired', + title: 'Purpose Justification Required', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + mode: 'advanced', + }, + { + id: 'purposeJustificationPrompt', + title: 'Purpose Justification Prompt', + type: 'short-input', + placeholder: 'Why do you need access?', + condition: { + field: 'operation', + value: ['create_access_policy', 'update_access_policy'], + }, + mode: 'advanced', + }, + + // Access service token inputs + { + id: 'name', + title: 'Service Token Name', + type: 'short-input', + required: true, + placeholder: 'e.g., ci-pipeline', + condition: { field: 'operation', value: 'create_access_service_token' }, + }, + { + id: 'duration', + title: 'Duration', + type: 'short-input', + placeholder: 'e.g., 8760h', + condition: { field: 'operation', value: 'create_access_service_token' }, + mode: 'advanced', + }, + { + id: 'serviceTokenId', + title: 'Service Token ID', + type: 'short-input', + required: true, + placeholder: 'Enter the service token ID to revoke', + condition: { field: 'operation', value: 'revoke_access_service_token' }, + }, + + // R2 inputs + { + id: 'bucketName', + title: 'Bucket Name', + type: 'short-input', + required: true, + placeholder: 'Enter R2 bucket name', + condition: { + field: 'operation', + value: ['get_r2_bucket', 'create_r2_bucket', 'delete_r2_bucket'], + }, + }, + { + id: 'locationHint', + title: 'Location Hint', + type: 'dropdown', + options: [ + { label: 'Automatic', id: '' }, + { label: 'Asia-Pacific', id: 'apac' }, + { label: 'Eastern Europe', id: 'eeur' }, + { label: 'Eastern North America', id: 'enam' }, + { label: 'Western Europe', id: 'weur' }, + { label: 'Western North America', id: 'wnam' }, + { label: 'Oceania', id: 'oc' }, + ], + value: () => '', + condition: { field: 'operation', value: 'create_r2_bucket' }, + mode: 'advanced', + }, + { + id: 'storageClass', + title: 'Storage Class', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Standard', id: 'Standard' }, + { label: 'Infrequent Access', id: 'InfrequentAccess' }, + ], + value: () => '', + condition: { field: 'operation', value: 'create_r2_bucket' }, + mode: 'advanced', + }, + { + id: 'jurisdiction', + title: 'Jurisdiction', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'European Union', id: 'eu' }, + { label: 'FedRAMP', id: 'fedramp' }, + ], + value: () => '', + condition: { + field: 'operation', + value: ['list_r2_buckets', 'get_r2_bucket', 'create_r2_bucket', 'delete_r2_bucket'], + }, + mode: 'advanced', + }, + { + id: 'name_contains', + title: 'Name Contains', + type: 'short-input', + placeholder: 'Filter buckets by name substring', + condition: { field: 'operation', value: 'list_r2_buckets' }, + mode: 'advanced', + }, + { + id: 'start_after', + title: 'Start After', + type: 'short-input', + placeholder: 'Bucket name to start listing after', + condition: { field: 'operation', value: 'list_r2_buckets' }, + mode: 'advanced', + }, + { + id: 'cursor', + title: 'Cursor', + type: 'short-input', + placeholder: 'Pagination cursor from a previous call', + condition: { field: 'operation', value: ['list_r2_buckets', 'list_rulesets'] }, + mode: 'advanced', + }, + { + id: 'direction', + title: 'Sort Direction', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Ascending', id: 'asc' }, + { label: 'Descending', id: 'desc' }, + ], + value: () => '', + condition: { field: 'operation', value: 'list_r2_buckets' }, + mode: 'advanced', + }, + + // Workers inputs + { + id: 'scriptName', + title: 'Script Name', + type: 'short-input', + required: true, + placeholder: 'Enter Worker script name', + condition: { field: 'operation', value: 'get_worker_script_settings' }, + }, + { + id: 'workerTagFilter', + title: 'Tag Filter', + type: 'short-input', + placeholder: 'Filter scripts by tag', + condition: { field: 'operation', value: 'list_worker_scripts' }, + mode: 'advanced', + }, + + // Tunnel inputs + { + id: 'tunnelId', + title: 'Tunnel ID', + type: 'short-input', + required: true, + placeholder: 'Enter tunnel ID', + condition: { field: 'operation', value: ['get_tunnel', 'get_tunnel_configuration'] }, + }, + { + id: 'tunnelStatus', + title: 'Status Filter', + type: 'dropdown', + options: [ + { label: 'All', id: '' }, + { label: 'Healthy', id: 'healthy' }, + { label: 'Degraded', id: 'degraded' }, + { label: 'Down', id: 'down' }, + { label: 'Inactive', id: 'inactive' }, + ], + value: () => '', + condition: { field: 'operation', value: 'list_tunnels' }, + mode: 'advanced', + }, + { + id: 'uuid', + title: 'Tunnel UUID', + type: 'short-input', + placeholder: 'Filter by tunnel UUID', + condition: { field: 'operation', value: 'list_tunnels' }, + mode: 'advanced', + }, + { + id: 'is_deleted', + title: 'Show Deleted Tunnels', + type: 'dropdown', + options: [ + { label: 'Default', id: '' }, + { label: 'Yes', id: 'true' }, + { label: 'No', id: 'false' }, + ], + value: () => '', + condition: { field: 'operation', value: 'list_tunnels' }, + mode: 'advanced', + }, + { + id: 'include_prefix', + title: 'Include Name Prefix', + type: 'short-input', + placeholder: 'Only tunnels whose name starts with this prefix', + condition: { field: 'operation', value: 'list_tunnels' }, + mode: 'advanced', + }, + { + id: 'exclude_prefix', + title: 'Exclude Name Prefix', + type: 'short-input', + placeholder: 'Skip tunnels whose name starts with this prefix', + condition: { field: 'operation', value: 'list_tunnels' }, + mode: 'advanced', + }, + { + id: 'existed_at', + title: 'Existed At', + type: 'short-input', + placeholder: 'RFC 3339 timestamp', + condition: { field: 'operation', value: 'list_tunnels' }, + mode: 'advanced', + }, + { + id: 'was_active_at', + title: 'Was Active At', + type: 'short-input', + placeholder: 'RFC 3339 timestamp', + condition: { field: 'operation', value: 'list_tunnels' }, + mode: 'advanced', + }, + { + id: 'was_inactive_at', + title: 'Was Inactive At', + type: 'short-input', + placeholder: 'RFC 3339 timestamp', + condition: { field: 'operation', value: 'list_tunnels' }, + mode: 'advanced', + }, + + // Shared pagination for the new list operations + { + id: 'page', + title: 'Page', + type: 'short-input', + placeholder: 'Page number (default: 1)', + condition: { + field: 'operation', + value: [ + 'list_access_applications', + 'list_access_policies', + 'list_access_groups', + 'list_access_service_tokens', + 'list_tunnels', + ], + }, + mode: 'advanced', + }, + { + id: 'per_page', + title: 'Per Page', + type: 'short-input', + placeholder: 'Results per page', + condition: { + field: 'operation', + value: [ + 'list_access_applications', + 'list_access_policies', + 'list_access_groups', + 'list_access_service_tokens', + 'list_r2_buckets', + 'list_rulesets', + 'list_tunnels', + ], + }, + mode: 'advanced', + }, + + // API Key (common) + { + id: 'apiKey', + title: 'API Token', + type: 'short-input', + required: true, + placeholder: 'Enter your Cloudflare API token', + password: true, + }, + ], + tools: { + access: [ + 'cloudflare_list_zones', + 'cloudflare_get_zone', + 'cloudflare_create_zone', + 'cloudflare_delete_zone', + 'cloudflare_list_dns_records', + 'cloudflare_create_dns_record', + 'cloudflare_update_dns_record', + 'cloudflare_delete_dns_record', + 'cloudflare_list_certificates', + 'cloudflare_get_zone_settings', + 'cloudflare_update_zone_setting', + 'cloudflare_dns_analytics', + 'cloudflare_purge_cache', + 'cloudflare_list_rulesets', + 'cloudflare_get_ruleset', + 'cloudflare_get_ruleset_entrypoint', + 'cloudflare_create_ruleset', + 'cloudflare_create_ruleset_rule', + 'cloudflare_update_ruleset_rule', + 'cloudflare_delete_ruleset_rule', + 'cloudflare_list_managed_ruleset_overrides', + 'cloudflare_list_rate_limit_rules', + 'cloudflare_create_rate_limit_rule', + 'cloudflare_update_rate_limit_rule', + 'cloudflare_list_access_applications', + 'cloudflare_get_access_application', + 'cloudflare_create_access_application', + 'cloudflare_update_access_application', + 'cloudflare_delete_access_application', + 'cloudflare_list_access_policies', + 'cloudflare_create_access_policy', + 'cloudflare_update_access_policy', + 'cloudflare_delete_access_policy', + 'cloudflare_list_access_groups', + 'cloudflare_list_access_identity_providers', + 'cloudflare_list_access_service_tokens', + 'cloudflare_create_access_service_token', + 'cloudflare_revoke_access_service_token', + 'cloudflare_list_r2_buckets', + 'cloudflare_get_r2_bucket', + 'cloudflare_create_r2_bucket', + 'cloudflare_delete_r2_bucket', + 'cloudflare_list_worker_scripts', + 'cloudflare_get_worker_script_settings', + 'cloudflare_list_worker_routes', + 'cloudflare_list_tunnels', + 'cloudflare_get_tunnel', + 'cloudflare_get_tunnel_configuration', + ], + config: { + tool: (params) => `cloudflare_${params.operation}`, + params: (params) => { + const result: Record = { ...params } + const operation = typeof result.operation === 'string' ? result.operation : '' + + for (const [toolParam, aliasId] of Object.entries(SUBBLOCK_ALIASES[operation] ?? {})) { + result[toolParam] = result[aliasId] + } + /** + * The executor merges this mapper's output over the raw inputs + * (`finalInputs = { ...inputs, ...transformedParams }` in + * `executor/handlers/generic/generic-handler.ts`), so a key this mapper + * merely omits survives as its raw subBlock string. Every alias id must + * therefore be assigned `undefined` rather than destructured away. + */ + for (const aliasId of ALIASED_SUBBLOCK_IDS) { + result[aliasId] = undefined + } + + if (result.ttl) result.ttl = Number(result.ttl) + if (result.priority) result.priority = Number(result.priority) + if (result.limit) result.limit = Number(result.limit) + if (result.page) result.page = Number(result.page) + if (result.per_page) result.per_page = Number(result.per_page) + + if (result.proxied === 'true') result.proxied = true + else if (result.proxied === 'false') result.proxied = false + else if (result.proxied === '') result.proxied = undefined + + if (result.purge_everything === 'true') result.purge_everything = true + else if (result.purge_everything === 'false') result.purge_everything = false + + if (result.type === '') result.type = undefined + if (result.status === '') result.status = undefined + if (result.order === '') result.order = undefined + if (result.direction === '') result.direction = undefined + if (result.match === '') result.match = undefined + if (result.tag_match === '') result.tag_match = undefined + if (result.deploy === '') result.deploy = undefined + + if (result.operation === 'update_dns_record') { + if (result.content === '') result.content = undefined + if (result.name === '') result.name = undefined + if (result.comment === '') result.comment = undefined + } + + const numericFields = [ + 'period', + 'requestsPerPeriod', + 'mitigationTimeout', + 'precedence', + ] as const + for (const field of numericFields) { + if (result[field] === '' || result[field] === undefined) { + result[field] = undefined + } else { + result[field] = Number(result[field]) + } + } + + const booleanFields = [ + 'enabled', + 'exact', + 'appLauncherVisible', + 'autoRedirectToIdentity', + 'approvalRequired', + 'isolationRequired', + 'purposeJustificationRequired', + 'requestsToOrigin', + 'is_deleted', + ] as const + for (const field of booleanFields) { + if (result[field] === 'true') result[field] = true + else if (result[field] === 'false') result[field] = false + else if (result[field] === '') result[field] = undefined + } + + const optionalStringFields = [ + 'phase', + 'action', + 'locationHint', + 'storageClass', + 'jurisdiction', + ] as const + for (const field of optionalStringFields) { + if (result[field] === '') result[field] = undefined + } + + return result + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiKey: { type: 'string', description: 'Cloudflare API token' }, + zoneId: { type: 'string', description: 'Zone ID' }, + accountId: { type: 'string', description: 'Cloudflare account ID' }, + zoneType: { type: 'string', description: 'Zone type (full, partial, or secondary)' }, + order: { type: 'string', description: 'Sort field when listing zones' }, + direction: { type: 'string', description: 'Sort direction (asc, desc)' }, + match: { type: 'string', description: 'Match logic for filters (any, all)' }, + recordId: { type: 'string', description: 'DNS record ID' }, + name: { type: 'string', description: 'Domain or record name' }, + type: { type: 'string', description: 'DNS record type' }, + recordType: { type: 'string', description: 'DNS record type for record creation' }, + recordProxied: { + type: 'string', + description: 'Whether the created DNS record is proxied through Cloudflare', + }, + certificateStatus: { type: 'string', description: 'Certificate pack status filter' }, + zoneNameFilter: { type: 'string', description: 'Domain name filter when listing zones' }, + dnsTypeFilter: { type: 'string', description: 'DNS record type filter when listing records' }, + dnsNameFilter: { type: 'string', description: 'Record name filter when listing records' }, + dnsContentFilter: { type: 'string', description: 'Record content filter when listing records' }, + dnsOrder: { type: 'string', description: 'Sort field when listing DNS records' }, + dnsProxiedFilter: { type: 'string', description: 'Proxied filter when listing DNS records' }, + purgeTags: { type: 'string', description: 'Comma-separated cache tags to purge' }, + workerTagFilter: { type: 'string', description: 'Tag filter when listing Worker scripts' }, + accessAppTags: { type: 'string', description: 'Tag names applied to an Access application' }, + listNameFilter: { + type: 'string', + description: + 'Name filter shared by the Access application, group, service token, and tunnel list operations', + }, + accessAppDomainFilter: { + type: 'string', + description: 'Domain filter when listing Access applications', + }, + tunnelStatus: { type: 'string', description: 'Status filter when listing tunnels' }, + + appType: { type: 'string', description: 'Access application type' }, + updateAppType: { + type: 'string', + description: 'Access application type a replaced application ends up with', + }, + updatePolicyDecision: { + type: 'string', + description: 'Decision a replaced Access policy ends up applying', + }, + rateLimitAction: { + type: 'string', + description: 'Action applied once a rate limit is exceeded', + }, + updateRateLimitAction: { + type: 'string', + description: 'Action a replaced rate limiting rule ends up applying', + }, + content: { type: 'string', description: 'DNS record content' }, + ttl: { type: 'number', description: 'Time to live in seconds' }, + proxied: { type: 'boolean', description: 'Whether Cloudflare proxy is enabled' }, + priority: { type: 'number', description: 'Record priority (MX/SRV)' }, + comment: { type: 'string', description: 'Record comment' }, + search: { type: 'string', description: 'Free-text search across record properties' }, + tag: { type: 'string', description: 'Filter by an exact tag name' }, + tag_match: { type: 'string', description: 'Tag filter match logic (any, all)' }, + commentFilter: { type: 'string', description: 'Filter records by comment content' }, + settingId: { type: 'string', description: 'Zone setting ID' }, + value: { type: 'string', description: 'Setting value' }, + since: { type: 'string', description: 'Start date for analytics' }, + until: { type: 'string', description: 'End date for analytics' }, + metrics: { type: 'string', description: 'Comma-separated metrics to retrieve' }, + dimensions: { type: 'string', description: 'Comma-separated dimensions to group by' }, + filters: { type: 'string', description: 'Filters to apply (e.g., queryType==A)' }, + sort: { type: 'string', description: 'Sort order for results' }, + limit: { type: 'number', description: 'Maximum number of results' }, + status: { type: 'string', description: 'Status filter when listing zones' }, + page: { type: 'number', description: 'Page number for pagination' }, + per_page: { type: 'number', description: 'Number of results per page' }, + deploy: { + type: 'string', + description: 'Filter certificates by deployment environment (staging, production)', + }, + purge_everything: { type: 'boolean', description: 'Purge all cached content' }, + files: { type: 'string', description: 'Comma-separated URLs to purge' }, + tags: { type: 'string', description: 'Comma-separated DNS record tags' }, + hosts: { type: 'string', description: 'Comma-separated hostnames to purge (Enterprise only)' }, + prefixes: { + type: 'string', + description: 'Comma-separated URL prefixes to purge (Enterprise only)', + }, + rulesetId: { type: 'string', description: 'Ruleset ID' }, + ruleId: { type: 'string', description: 'Rule ID within a ruleset' }, + phase: { type: 'string', description: 'Ruleset phase' }, + rulesetName: { type: 'string', description: 'Name for a newly created ruleset' }, + kind: { type: 'string', description: 'Ruleset kind for ruleset creation' }, + rules: { type: 'string', description: 'JSON array of rules to seed a new ruleset with' }, + action: { type: 'string', description: 'Action a rule performs' }, + expression: { type: 'string', description: 'Cloudflare filter expression' }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { type: 'string', description: 'Rule reference tag' }, + actionParameters: { type: 'string', description: 'JSON action parameters for a rule' }, + ratelimit: { + type: 'string', + description: 'JSON rate limiting configuration to preserve when replacing a rule', + }, + logging: { + type: 'string', + description: 'JSON logging configuration to preserve when replacing a rule', + }, + position: { type: 'string', description: 'JSON position object for a new rule' }, + characteristics: { + type: 'string', + description: 'Comma-separated rate limiting counting characteristics', + }, + period: { type: 'number', description: 'Rate limiting counting period in seconds' }, + requestsPerPeriod: { + type: 'number', + description: 'Requests allowed within the rate limiting period', + }, + mitigationTimeout: { + type: 'number', + description: 'Seconds the rate limiting action stays applied', + }, + counting_expression: { + type: 'string', + description: 'Expression selecting which requests are counted', + }, + requestsToOrigin: { + type: 'boolean', + description: 'Whether only requests reaching the origin are counted', + }, + appId: { type: 'string', description: 'Access application ID' }, + policyId: { type: 'string', description: 'Access policy ID' }, + serviceTokenId: { type: 'string', description: 'Access service token ID' }, + domain: { type: 'string', description: 'Hostname and path secured by Access' }, + aud: { type: 'string', description: 'Access application audience tag' }, + exact: { type: 'boolean', description: 'Whether Access list filters must match exactly' }, + sessionDuration: { type: 'string', description: 'Access session duration' }, + allowedIdps: { type: 'string', description: 'Comma-separated identity provider IDs' }, + appLauncherVisible: { + type: 'boolean', + description: 'Whether the application appears in the App Launcher', + }, + autoRedirectToIdentity: { + type: 'boolean', + description: 'Whether users skip the identity provider picker', + }, + customDenyMessage: { type: 'string', description: 'Message shown when access is denied' }, + customDenyUrl: { type: 'string', description: 'URL denied users are redirected to' }, + logoUrl: { type: 'string', description: 'Application logo URL' }, + policies: { type: 'string', description: 'JSON array of policies to attach' }, + decision: { type: 'string', description: 'Access policy decision' }, + include: { type: 'string', description: 'JSON array of Access rules evaluated with OR logic' }, + exclude: { type: 'string', description: 'JSON array of Access rules evaluated with NOT logic' }, + require: { type: 'string', description: 'JSON array of Access rules evaluated with AND logic' }, + precedence: { type: 'number', description: 'Access policy evaluation order' }, + approvalRequired: { + type: 'boolean', + description: 'Whether an approver must grant each access request', + }, + isolationRequired: { + type: 'boolean', + description: 'Whether sessions must run in a remote isolated browser', + }, + purposeJustificationRequired: { + type: 'boolean', + description: 'Whether users must state a reason for access', + }, + purposeJustificationPrompt: { + type: 'string', + description: 'Prompt shown when a justification is required', + }, + duration: { type: 'string', description: 'Service token lifetime' }, + bucketName: { type: 'string', description: 'R2 bucket name' }, + locationHint: { type: 'string', description: 'R2 bucket location hint' }, + storageClass: { type: 'string', description: 'R2 default storage class' }, + jurisdiction: { type: 'string', description: 'R2 data-residency jurisdiction' }, + name_contains: { type: 'string', description: 'Filter R2 buckets by name substring' }, + start_after: { type: 'string', description: 'R2 bucket name to start listing after' }, + cursor: { type: 'string', description: 'Pagination cursor' }, + scriptName: { type: 'string', description: 'Workers script name' }, + tunnelId: { type: 'string', description: 'Cloudflare Tunnel ID' }, + uuid: { type: 'string', description: 'Filter tunnels by UUID' }, + is_deleted: { type: 'boolean', description: 'Whether to return deleted tunnels' }, + include_prefix: { type: 'string', description: 'Only include tunnels with this name prefix' }, + exclude_prefix: { type: 'string', description: 'Exclude tunnels with this name prefix' }, + existed_at: { type: 'string', description: 'Return tunnels that existed at this timestamp' }, + was_active_at: { + type: 'string', + description: 'Return tunnels that were active at this timestamp', + }, + was_inactive_at: { + type: 'string', + description: 'Return tunnels that were inactive at this timestamp', + }, + }, + outputs: { + zones: { type: 'json', description: 'List of zones/domains' }, + records: { type: 'json', description: 'List of DNS records' }, + certificates: { type: 'json', description: 'List of SSL/TLS certificate packs' }, + settings: { type: 'json', description: 'List of zone settings' }, + totals: { type: 'json', description: 'Aggregate DNS analytics totals' }, + min: { type: 'json', description: 'Minimum values across the DNS analytics period' }, + max: { type: 'json', description: 'Maximum values across the DNS analytics period' }, + query: { type: 'json', description: 'Echo of the DNS analytics query parameters sent' }, + validation_errors: { type: 'json', description: 'Validation issues for certificate packs' }, + data: { type: 'json', description: 'Raw analytics data rows from the DNS analytics report' }, + data_lag: { + type: 'number', + description: 'Processing lag in seconds before analytics data becomes available', + }, + rows: { type: 'number', description: 'Total number of rows in the DNS analytics result set' }, + id: { type: 'string', description: 'Resource ID' }, + zone_id: { type: 'string', description: 'Zone ID the record belongs to' }, + zone_name: { type: 'string', description: 'Zone domain name' }, + name: { type: 'string', description: 'Resource name' }, + status: { type: 'string', description: 'Resource status' }, + paused: { type: 'boolean', description: 'Whether the zone is paused' }, + type: { type: 'string', description: 'Zone or record type' }, + name_servers: { type: 'json', description: 'Assigned Cloudflare name servers' }, + original_name_servers: { type: 'json', description: 'Original registrar name servers' }, + plan: { + type: 'json', + description: + 'Zone plan information (id, name, price, currency, frequency, is_subscribed, legacy_id)', + }, + account: { type: 'json', description: 'Account the zone belongs to (id, name)' }, + owner: { type: 'json', description: 'Zone owner information (id, name, type)' }, + activated_on: { type: 'string', description: 'ISO 8601 date when the zone was activated' }, + development_mode: { + type: 'number', + description: 'Seconds remaining in development mode (0 = off)', + }, + meta: { + type: 'json', + description: 'Resource metadata (zone: cdn_only, dns_only, etc.; DNS record: source)', + }, + vanity_name_servers: { type: 'json', description: 'Custom vanity name servers' }, + permissions: { type: 'json', description: 'User permissions for the zone' }, + content: { type: 'string', description: 'DNS record value (e.g., IP address)' }, + proxiable: { type: 'boolean', description: 'Whether the record can be proxied' }, + proxied: { type: 'boolean', description: 'Whether Cloudflare proxy is enabled' }, ttl: { type: 'number', description: 'TTL in seconds (1 = automatic)' }, locked: { type: 'boolean', description: 'Whether the record is locked' }, priority: { type: 'number', description: 'Priority for MX and SRV records' }, @@ -1129,6 +2785,112 @@ Return ONLY the comma-separated URLs - no explanations, no extra text.`, editable: { type: 'boolean', description: 'Whether the setting can be modified' }, time_remaining: { type: 'number', description: 'Seconds until setting can be modified again' }, total_count: { type: 'number', description: 'Total count of results' }, + rulesets: { type: 'json', description: 'Rulesets defined on the zone' }, + rules: { type: 'json', description: 'Rules contained in a ruleset, in evaluation order' }, + kind: { type: 'string', description: 'Ruleset kind (managed, custom, root, or zone)' }, + description: { type: 'string', description: 'Ruleset, rule, or resource description' }, + phase: { type: 'string', description: 'Phase the ruleset runs in' }, + version: { type: 'string', description: 'Ruleset or rule version' }, + last_updated: { type: 'string', description: 'RFC 3339 timestamp of the last change' }, + ruleset_id: { type: 'string', description: 'Entry point ruleset ID' }, + deployments: { + type: 'json', + description: 'Managed rulesets deployed on the zone and their overrides', + }, + applications: { type: 'json', description: 'Access applications in the account' }, + policies: { type: 'json', description: 'Access policies' }, + groups: { type: 'json', description: 'Access groups in the account' }, + identity_providers: { type: 'json', description: 'Access identity providers in the account' }, + service_tokens: { type: 'json', description: 'Access service tokens in the account' }, + domain: { type: 'string', description: 'Hostname and path secured by Access' }, + aud: { type: 'string', description: 'Access application audience tag' }, + session_duration: { type: 'string', description: 'How long an Access session stays valid' }, + allowed_idps: { type: 'json', description: 'Identity provider IDs allowed on the application' }, + app_launcher_visible: { + type: 'boolean', + description: 'Whether the application appears in the App Launcher', + }, + auto_redirect_to_identity: { + type: 'boolean', + description: 'Whether users skip the identity provider picker', + }, + custom_deny_message: { type: 'string', description: 'Message shown when access is denied' }, + custom_deny_url: { type: 'string', description: 'URL denied users are redirected to' }, + logo_url: { type: 'string', description: 'Application logo URL' }, + self_hosted_domains: { + type: 'json', + description: 'Additional hostnames and paths secured by the application', + }, + destinations: { type: 'json', description: 'Destinations secured by the application' }, + decision: { type: 'string', description: 'Access policy decision' }, + precedence: { type: 'number', description: 'Access policy evaluation order' }, + include: { type: 'json', description: 'Access rules evaluated with OR logic' }, + exclude: { type: 'json', description: 'Access rules evaluated with NOT logic' }, + require: { type: 'json', description: 'Access rules evaluated with AND logic' }, + approval_required: { + type: 'boolean', + description: 'Whether an approver must grant each access request', + }, + isolation_required: { + type: 'boolean', + description: 'Whether sessions must run in a remote isolated browser', + }, + purpose_justification_required: { + type: 'boolean', + description: 'Whether users must state a reason for access', + }, + purpose_justification_prompt: { + type: 'string', + description: 'Prompt shown when a justification is required', + }, + created_at: { type: 'string', description: 'Creation timestamp' }, + updated_at: { type: 'string', description: 'Last update timestamp' }, + client_id: { type: 'string', description: 'Service token client ID' }, + client_secret: { + type: 'string', + description: 'Service token client secret, returned only once at creation', + }, + expires_at: { type: 'string', description: 'Service token expiry timestamp' }, + last_seen_at: { type: 'string', description: 'When the service token was last used' }, + duration: { type: 'string', description: 'Service token lifetime' }, + enabled: { type: 'boolean', description: 'Whether the resource is enabled' }, + buckets: { type: 'json', description: 'R2 buckets in the account' }, + creation_date: { type: 'string', description: 'R2 bucket creation timestamp' }, + location: { type: 'string', description: 'R2 bucket location' }, + storage_class: { type: 'string', description: 'R2 bucket default storage class' }, + jurisdiction: { type: 'string', description: 'R2 data-residency jurisdiction' }, + cursor: { type: 'string', description: 'Pagination cursor for the next page' }, + scripts: { type: 'json', description: 'Workers scripts in the account' }, + routes: { type: 'json', description: 'Workers routes on the zone' }, + bindings: { type: 'json', description: 'Resource bindings available to a Workers script' }, + compatibility_date: { type: 'string', description: 'Workers runtime compatibility date' }, + compatibility_flags: { type: 'json', description: 'Workers runtime compatibility flags' }, + limits: { type: 'json', description: 'Workers execution limits' }, + logpush: { type: 'boolean', description: 'Whether Workers Logpush is enabled' }, + migrations: { type: 'json', description: 'Durable Object migrations' }, + observability: { type: 'json', description: 'Workers observability configuration' }, + placement: { type: 'json', description: 'Workers smart placement configuration' }, + tail_consumers: { type: 'json', description: 'Workers consuming tail events' }, + usage_model: { type: 'string', description: 'Workers billing usage model' }, + tunnels: { type: 'json', description: 'Cloudflare Tunnels in the account' }, + tunnel_id: { type: 'string', description: 'Tunnel the configuration belongs to' }, + account_id: { type: 'string', description: 'Account the tunnel belongs to' }, + account_tag: { type: 'string', description: 'Account tag the tunnel belongs to' }, + config: { type: 'json', description: 'Tunnel ingress and origin request configuration' }, + config_src: { type: 'string', description: 'Where the tunnel configuration is managed' }, + source: { type: 'string', description: 'Where the tunnel configuration is managed' }, + tun_type: { type: 'string', description: 'Tunnel type' }, + remote_config: { type: 'boolean', description: 'Whether the tunnel is remotely managed' }, + deleted_at: { type: 'string', description: 'Tunnel deletion timestamp' }, + conns_active_at: { + type: 'string', + description: 'When the tunnel last had active connections', + }, + conns_inactive_at: { + type: 'string', + description: 'When the tunnel last lost all connections', + }, + connections: { type: 'json', description: 'Active connector connections for the tunnel' }, }, } @@ -1203,6 +2965,25 @@ export const CloudflareBlockMeta = { category: 'engineering', tags: ['devops', 'enterprise', 'monitoring'], }, + { + icon: CloudflareIcon, + title: 'Cloudflare WAF and rate limit rollout', + prompt: + 'Build a workflow that reads a table of WAF rules — expression, action, and rate limit — validates each row against the zone it targets, deploys it into the matching Cloudflare ruleset phase, and posts a Slack summary of every rule created, changed, or skipped.', + modules: ['tables', 'agent', 'workflows'], + category: 'engineering', + tags: ['devops', 'security', 'infrastructure'], + alsoIntegrations: ['slack'], + }, + { + icon: CloudflareIcon, + title: 'Cloudflare Zero Trust access review', + prompt: + 'Create a scheduled monthly workflow that lists every Cloudflare Access application and its policies, flags applications with no policy, overly broad email-domain rules, or bypass decisions, logs the findings to a table, and emails an access review to security leadership.', + modules: ['scheduled', 'tables', 'agent', 'workflows'], + category: 'engineering', + tags: ['security', 'enterprise', 'monitoring'], + }, ], skills: [ { @@ -1240,5 +3021,26 @@ export const CloudflareBlockMeta = { content: '# Set Up Email Authentication Records\n\nEmail providers (Google Workspace, Microsoft 365, transactional senders) require SPF, DKIM, and DMARC TXT records to authenticate mail and avoid it being marked as spam.\n\n## Steps\n1. Resolve the zone ID for the sending domain.\n2. List existing TXT records to check for conflicting or duplicate SPF/DMARC entries.\n3. Create or update the SPF TXT record (`v=spf1 ...`), the DKIM selector TXT record, and the DMARC TXT record (`_dmarc` name, `v=DMARC1; ...` policy) with the values the mail provider supplies.\n4. Confirm each record was created with the correct name, type, and content.\n\n## Output\nA confirmation of the SPF, DKIM, and DMARC records now in place, with their record IDs and TTLs.', }, + { + name: 'deploy-waf-custom-rule', + description: + 'Add a WAF custom rule to a Cloudflare zone through the Rulesets engine, blocking or challenging traffic that matches a filter expression.', + content: + '# Deploy a WAF Custom Rule\n\nWAF custom rules live in the `http_request_firewall_custom` phase of the Rulesets engine, so the ruleset ID has to be resolved before a rule can be added.\n\n## Steps\n1. Resolve the zone ID for the target domain.\n2. Read the `http_request_firewall_custom` phase entry point ruleset for that zone to get its ruleset ID and current rules.\n3. Write the filter expression for the traffic to act on (e.g. `(ip.src.country in {"GB" "FR"})` or `(http.request.uri.path matches "^/admin")`).\n4. Create the rule in that ruleset with the chosen action — `block`, `managed_challenge`, `js_challenge`, `challenge`, `skip`, or `log`. Start with `log` to observe impact before enforcing.\n5. Read the ruleset back and confirm the new rule appears in the intended evaluation order.\n\n## Output\nThe ruleset ID, the new rule ID, its expression and action, and its position in the evaluation order.\n\n## Cautions\nRules take effect on live traffic immediately. A broad expression with `block` can lock out legitimate users, so verify the expression in `log` mode first.', + }, + { + name: 'rate-limit-an-api-endpoint', + description: + 'Protect an API path from abuse with a Cloudflare rate limiting rule using the current Rulesets-based rate limiting API.', + content: + '# Rate Limit an API Endpoint\n\nRate limiting rules are rules in the `http_ratelimit` phase entry point ruleset. The legacy `rate_limits` endpoint is no longer the way to do this.\n\n## Steps\n1. Resolve the zone ID for the domain serving the API.\n2. List the existing rate limiting rules to get the `http_ratelimit` entry point ruleset ID and see what is already in place.\n3. Decide the counting characteristics. `cf.colo.id` is mandatory, plus exactly one of `ip.src` (per IP) or `cf.unique_visitor_id` (per visitor); add `http.request.headers[""]` to count per API key.\n4. Pick a counting period (10, 60, 120, 300, 600, or 3600 seconds) and the request allowance for that period.\n5. Create the rule with the matching expression (e.g. `(http.request.uri.path matches "^/api/")`), the counting configuration, and the mitigation action.\n6. Read the rules back and confirm the new rule and its limit.\n\n## Output\nThe ruleset ID, the new rule ID, the expression, and the effective limit (requests per period, characteristics, and mitigation timeout).\n\n## Cautions\nThe rule applies to live traffic as soon as it is created. Size the allowance against real traffic before choosing `block` over `log` or `managed_challenge`.', + }, + { + name: 'review-zero-trust-access', + description: + 'Audit Cloudflare Access applications and their policies to find unprotected apps, over-broad rules, and bypass decisions.', + content: + '# Review Zero Trust Access\n\nAccess applications and policies are account-scoped. An application with no policy denies everyone; a broad `allow` policy lets in more than intended.\n\n## Steps\n1. List the Access applications in the account.\n2. For each application, list its policies in precedence order.\n3. List the configured identity providers so `allowed_idps` values can be read as names rather than IDs.\n4. Flag applications with no policies, `allow` policies whose include rules are a whole email domain or `everyone`, any `bypass` decision, and applications with no `allowed_idps` restriction.\n5. Note session durations that are longer than the organization allows.\n\n## Output\nA per-application summary of domain, type, identity providers, policy decisions and include rules, and the flagged findings ranked by risk.', + }, ], } as const satisfies BlockMeta diff --git a/apps/sim/lib/integrations/integrations.json b/apps/sim/lib/integrations/integrations.json index 283a7447694..55a59d6773b 100644 --- a/apps/sim/lib/integrations/integrations.json +++ b/apps/sim/lib/integrations/integrations.json @@ -1,5 +1,5 @@ { - "updatedAt": "2026-08-16", + "updatedAt": "2026-08-15", "integrations": [ { "type": "onepassword", @@ -3811,8 +3811,8 @@ "type": "cloudflare", "slug": "cloudflare", "name": "Cloudflare", - "description": "Manage DNS, domains, certificates, and cache", - "longDescription": "Integrate Cloudflare into the workflow. Manage zones (domains), DNS records, SSL/TLS certificates, zone settings, DNS analytics, and cache purging via the Cloudflare API.", + "description": "Manage DNS, WAF, Zero Trust access, and edge infrastructure", + "longDescription": "Integrate Cloudflare into the workflow. Manage zones (domains), DNS records, SSL/TLS certificates, zone settings, DNS analytics, and cache purging. Configure WAF rulesets, managed rule overrides, and rate limiting rules through the current Rulesets engine. Administer Cloudflare Access (Zero Trust) applications, policies, groups, identity providers, and service tokens, and inspect R2 buckets, Workers scripts and routes, and Cloudflare Tunnels.", "bgColor": "#F5F6FA", "iconName": "CloudflareIcon", "docsUrl": "https://docs.sim.ai/integrations/cloudflare", @@ -3868,9 +3868,149 @@ { "name": "Purge Cache", "description": "Purges cached content for a zone. Can purge everything or specific files/tags/hosts/prefixes." + }, + { + "name": "List Rulesets", + "description": "Lists every ruleset defined on a zone across all phases (WAF custom rules, managed rules, rate limiting, transform rules, and more). The list response deliberately omits the rules inside each ruleset — use \"Get Ruleset\" to read them. Requires an API token with Zone WAF Read (or another matching ruleset Read permission)." + }, + { + "name": "Get Ruleset", + "description": "Reads a single zone ruleset including every rule it contains, in evaluation order. Requires an API token with Zone WAF Read (or another matching ruleset Read permission)." + }, + { + "name": "Get Phase Entry Point Ruleset", + "description": "Reads the entry point ruleset for a phase on a zone, including all of its rules. This is how you find the ruleset ID you need before adding, updating, or deleting a rule — for example http_request_firewall_custom for WAF custom rules, http_request_firewall_managed for managed-ruleset deployments and overrides, or http_ratelimit for rate limiting rules. Requires an API token with Zone WAF Read (or another matching ruleset Read permission)." + }, + { + "name": "Create Ruleset", + "description": "" + }, + { + "name": "Create Ruleset Rule", + "description": "Adds a rule to a zone ruleset. Use \"Get Phase Entry Point Ruleset\" first to find the ruleset ID for the phase you want (for example http_request_firewall_custom for a WAF custom rule, or http_request_firewall_managed with action \"execute\" to deploy a managed ruleset). The rule is appended to the end of the ruleset unless a position is given. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission)." + }, + { + "name": "Update Ruleset Rule", + "description": "Updates a rule in a zone ruleset. Cloudflare replaces the rule definition rather than merging it, so you must send every field you want the rule to keep — any field you omit is reset to its default. Read the current rule with \"Get Ruleset\" first. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission)." + }, + { + "name": "Delete Ruleset Rule", + "description": "Permanently deletes a rule from a zone ruleset. This takes effect immediately on live traffic and cannot be undone — deleting a WAF custom rule, a managed-ruleset deployment, or a rate limiting rule removes that protection from the zone. Also use this to delete rate limiting rules, which live in the http_ratelimit phase ruleset. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission)." + }, + { + "name": "List Managed Ruleset Overrides", + "description": "Lists the WAF managed rulesets deployed on a zone together with the overrides applied to each one. Cloudflare has no dedicated overrides endpoint — overrides live on the \"execute\" rules of the http_request_firewall_managed phase entry point ruleset, which this reads. Requires an API token with Zone WAF Read." + }, + { + "name": "List Rate Limiting Rules", + "description": "Lists the rate limiting rules on a zone by reading the http_ratelimit phase entry point ruleset. This uses the current Rulesets-based rate limiting API; the legacy rate_limits endpoint is no longer available. The returned ruleset ID is what \"Create Rate Limiting Rule\", \"Update Rate Limiting Rule\", and \"Delete Ruleset Rule\" need. Requires an API token with Zone WAF Read." + }, + { + "name": "Create Rate Limiting Rule", + "description": "Creates a rate limiting rule in the http_ratelimit phase entry point ruleset of a zone, using the current Rulesets-based rate limiting API (the legacy rate_limits endpoint is no longer available). Run \"List Rate Limiting Rules\" first to get the ruleset ID. Requires an API token with Zone WAF Edit." + }, + { + "name": "Update Rate Limiting Rule", + "description": "Updates a rate limiting rule in the http_ratelimit phase entry point ruleset of a zone, using the current Rulesets-based rate limiting API. Cloudflare replaces the rule definition rather than merging it, so send the complete rule — every field you omit is reset. Run \"List Rate Limiting Rules\" first to read the current definition and get the ruleset ID. Requires an API token with Zone WAF Edit." + }, + { + "name": "List Access Applications", + "description": "Lists the Cloudflare Access (Zero Trust) applications protecting an account. Requires an API token with Account Access: Apps and Policies Read." + }, + { + "name": "Get Access Application", + "description": "Reads a single Cloudflare Access (Zero Trust) application, including its attached policies. Requires an API token with Account Access: Apps and Policies Read." + }, + { + "name": "Create Access Application", + "description": "Creates a Cloudflare Access (Zero Trust) application that puts an identity check in front of a hostname. Until at least one policy is attached the application denies everyone, so pair this with \"Create Access Policy\". Requires an API token with Account Access: Apps and Policies Edit." + }, + { + "name": "Update Access Application", + "description": "Updates a Cloudflare Access (Zero Trust) application. This replaces the application definition rather than merging it, so send every field the application should keep — anything you omit reverts to its default, which can widen or break access. Read the current configuration with \"Get Access Application\" first. Requires an API token with Account Access: Apps and Policies Edit." + }, + { + "name": "Delete Access Application", + "description": "Permanently deletes a Cloudflare Access (Zero Trust) application and every policy attached to it. The hostname it protected is immediately left without an Access identity check, so anyone who can reach it can reach the origin. This cannot be undone. Requires an API token with Account Access: Apps and Policies Edit." + }, + { + "name": "List Access Policies", + "description": "Lists the Cloudflare Access (Zero Trust) policies attached to an application, in precedence order. Requires an API token with Account Access: Apps and Policies Read." + }, + { + "name": "Create Access Policy", + "description": "Creates a Cloudflare Access (Zero Trust) policy on an application, deciding who may reach it. A policy takes effect on live traffic as soon as it is created — an allow policy with a broad include rule grants access immediately. Requires an API token with Account Access: Apps and Policies Edit." + }, + { + "name": "Update Access Policy", + "description": "Updates a Cloudflare Access (Zero Trust) policy on an application. This replaces the policy definition rather than merging it, so send every rule the policy should keep — omitted exclude or require rules are dropped, which can widen who gets in. The change applies to live traffic immediately. Read the current policy with \"List Access Policies\" first. Requires an API token with Account Access: Apps and Policies Edit." + }, + { + "name": "Delete Access Policy", + "description": "Permanently deletes a Cloudflare Access (Zero Trust) policy from an application. This changes who can reach the application the moment it runs: removing an allow policy locks out everyone it covered, and removing a deny or require policy drops that restriction. This cannot be undone. Requires an API token with Account Access: Apps and Policies Edit." + }, + { + "name": "List Access Groups", + "description": "Lists the reusable Cloudflare Access (Zero Trust) groups in an account. Groups bundle identity rules that policies can reference by ID. Requires an API token with Account Access: Organizations, Identity Providers, and Groups Read." + }, + { + "name": "List Access Identity Providers", + "description": "Lists the identity providers configured for Cloudflare Access (Zero Trust) in an account, such as Okta, Entra ID, Google Workspace, or a one-time PIN. Use the returned IDs to restrict an application with allowed_idps. Requires an API token with Account Access: Organizations, Identity Providers, and Groups Read." + }, + { + "name": "List Access Service Tokens", + "description": "Lists the Cloudflare Access (Zero Trust) service tokens in an account, which let machines authenticate to Access-protected applications. Client secrets are never returned by this endpoint — only on creation. Requires an API token with Account Access: Service Tokens Read." + }, + { + "name": "Create Access Service Token", + "description": "Creates a Cloudflare Access (Zero Trust) service token so a machine can authenticate to Access-protected applications. This is the only response that ever contains the client secret — Cloudflare will not return it again, so capture it in the same run. Requires an API token with Account Access: Service Tokens Edit." + }, + { + "name": "Revoke Access Service Token", + "description": "Permanently deletes a Cloudflare Access (Zero Trust) service token, revoking it. Every machine or integration still presenting that client ID and secret is locked out of the Access-protected applications immediately, and the secret cannot be recovered. This cannot be undone. Requires an API token with Account Access: Service Tokens Edit." + }, + { + "name": "List R2 Buckets", + "description": "Lists the R2 object storage buckets in an account. Requires an API token with Account Workers R2 Storage Read." + }, + { + "name": "Get R2 Bucket", + "description": "Reads the metadata of a single R2 object storage bucket. Requires an API token with Account Workers R2 Storage Read." + }, + { + "name": "Create R2 Bucket", + "description": "Creates an R2 object storage bucket in an account. The location hint and jurisdiction are fixed at creation and cannot be changed later. Requires an API token with Account Workers R2 Storage Edit." + }, + { + "name": "Delete R2 Bucket", + "description": "Permanently deletes an R2 object storage bucket. Cloudflare only deletes an empty bucket, and the deletion cannot be undone. Requires an API token with Account Workers R2 Storage Edit." + }, + { + "name": "List Worker Scripts", + "description": "Lists the Workers scripts deployed in an account. Requires an API token with Account Workers Scripts Read." + }, + { + "name": "Get Worker Script Settings", + "description": "Reads the deployment settings of a single Workers script — bindings, compatibility date and flags, limits, observability, placement, and tail consumers. The plain \"get script\" endpoint in the Cloudflare API returns raw JavaScript source rather than JSON, so this settings endpoint is the structured way to inspect one script. Requires an API token with Account Workers Scripts Read." + }, + { + "name": "List Worker Routes", + "description": "Lists the Workers routes on a zone, showing which URL patterns are handled by which Worker script. Unlike the Workers script endpoints, routes are zone-scoped. Requires an API token with Zone Workers Routes Read." + }, + { + "name": "List Tunnels", + "description": "Lists the Cloudflare Tunnels (cloudflared) in an account, with their health status and active connections. Requires an API token with Account Cloudflare Tunnel Read." + }, + { + "name": "Get Tunnel", + "description": "Reads a single Cloudflare Tunnel (cloudflared), including its health status and active connector connections. Requires an API token with Account Cloudflare Tunnel Read." + }, + { + "name": "Get Tunnel Configuration", + "description": "Reads the configuration of a remotely-managed Cloudflare Tunnel — its ingress rules, origin request settings, and WARP routing. Only tunnels whose configuration source is \"cloudflare\" have a remote configuration; locally-managed tunnels keep it in their own config file. Requires an API token with Account Cloudflare Tunnel Read." } ], - "operationCount": 13, + "operationCount": 48, "triggers": [], "triggerCount": 0, "authType": "api-key", diff --git a/apps/sim/tools/cloudflare/cloudflare.test.ts b/apps/sim/tools/cloudflare/cloudflare.test.ts new file mode 100644 index 00000000000..e3e31b14fc7 --- /dev/null +++ b/apps/sim/tools/cloudflare/cloudflare.test.ts @@ -0,0 +1,332 @@ +/** + * @vitest-environment node + * + * Guards the per-operation subBlock defaults in the Cloudflare block. + * + * SubBlock initial values are seeded into block state keyed by subBlock id + * (`stores/workflows/utils.ts` and `lib/workflows/defaults.ts` both assign + * `subBlocks[subBlock.id] = ...` in a plain forEach), so two controls sharing an + * id leave a single stored value and the LAST definition in file order wins. + * These tests assert the seeded default reaching each tool for operations whose + * control is deliberately not last, so re-introducing a collision goes red. + */ +import { describe, expect, it } from 'vitest' +import { CloudflareBlock } from '@/blocks/blocks/cloudflare' +import * as cloudflareTools from '@/tools/cloudflare' + +const apiKey = 'cf-token' + +const mapParams = CloudflareBlock.tools.config?.params + +/** + * Reproduces what the stores seed into block state: every subBlock default, + * keyed by id, with later definitions overwriting earlier ones. + */ +function seededDefaults(): Record { + const seeded: Record = {} + for (const subBlock of CloudflareBlock.subBlocks) { + if (typeof subBlock.value === 'function') { + seeded[subBlock.id] = (subBlock.value as (p: Record) => unknown)({}) + } + } + return seeded +} + +/** + * Returns what the tool actually receives. The executor merges the mapper's + * output OVER the raw inputs (`finalInputs = { ...inputs, ...transformedParams }` + * in `executor/handlers/generic/generic-handler.ts`), so a key the mapper merely + * omits survives as its raw subBlock string. Asserting on the mapper's return + * alone would let an alias or a stale filter through unnoticed. + */ +function mapFor(operation: string, extra: Record = {}) { + const inputs = { ...seededDefaults(), apiKey, operation, ...extra } + return { ...inputs, ...(mapParams?.(inputs as never) as Record) } +} + +describe('subBlock ids that share a tool param keep their own default', () => { + it('does not leak the Access application type onto DNS record creation', () => { + // The Access "Application Type" control is defined after every DNS type + // control, so a shared id would seed create_dns_record with self_hosted. + const mapped = mapFor('create_dns_record', { + zoneId: 'zone1', + name: 'www.example.com', + content: '203.0.113.10', + }) + + expect(mapped.type).toBe('A') + expect(mapped.type).not.toBe('self_hosted') + }) + + it('keeps the Access application type when creating an application', () => { + expect(mapFor('create_access_application', { accountId: 'acct1' }).type).toBe('self_hosted') + }) + + it('never seeds a type or decision onto an Access resource it is about to replace', () => { + // Both Access updates are full replacements, so a seeded value rewrites what + // the live resource IS as soon as anything else is edited — a policy would + // flip from deny to allow, an application from saas to self_hosted. + const app = mapFor('update_access_application', { accountId: 'acct1', appId: 'app1' }) + expect(app.type).toBeUndefined() + expect( + mapFor('update_access_application', { + accountId: 'acct1', + appId: 'app1', + updateAppType: 'saas', + }).type + ).toBe('saas') + + const policy = mapFor('update_access_policy', { accountId: 'acct1', policyId: 'p1' }) + expect(policy.decision).toBeUndefined() + expect( + mapFor('update_access_policy', { + accountId: 'acct1', + policyId: 'p1', + updatePolicyDecision: 'deny', + }).decision + ).toBe('deny') + }) + + it('leaves the DNS record type unset on the filter operations', () => { + expect(mapFor('list_dns_records', { zoneId: 'zone1' }).type).toBeUndefined() + expect(mapFor('update_dns_record', { zoneId: 'zone1', recordId: 'rec1' }).type).toBeUndefined() + }) + + it('preserves the certificate status default past the later status filters', () => { + // list_tunnels defines the last `status` control and defaults it to empty. + expect(mapFor('list_certificates', { zoneId: 'zone1' }).status).toBe('all') + expect(mapFor('list_zones').status).toBeUndefined() + expect(mapFor('list_tunnels', { accountId: 'acct1' }).status).toBeUndefined() + }) + + it('preserves the created-record proxied default past the later proxied filters', () => { + const mapped = mapFor('create_dns_record', { + zoneId: 'zone1', + name: 'www.example.com', + content: '203.0.113.10', + }) + + expect(mapped.proxied).toBe(false) + expect(mapFor('list_dns_records', { zoneId: 'zone1' }).proxied).toBeUndefined() + }) + + it('does not seed a block action onto a WAF custom rule', () => { + // The rate limiting action dropdown defaults to block and is defined after + // the ruleset-rule action input; sharing an id would make every new WAF + // custom rule silently default to blocking traffic. + const mapped = mapFor('create_ruleset_rule', { + zoneId: 'zone1', + rulesetId: 'rs1', + expression: 'true', + }) + + expect(mapped.action).toBeUndefined() + }) + + it('keeps the block default when creating a rate limiting rule', () => { + expect(mapFor('create_rate_limit_rule', { zoneId: 'zone1', rulesetId: 'rs1' }).action).toBe( + 'block' + ) + }) + + it('never seeds an action onto a rate limiting rule it is about to replace', () => { + // The update endpoint replaces the rule, so a seeded block would convert a + // live log or challenge rule into a hard block the moment anything else is + // edited. The user has to state the action instead. + expect( + mapFor('update_rate_limit_rule', { zoneId: 'zone1', rulesetId: 'rs1', ruleId: 'r1' }).action + ).toBeUndefined() + + expect( + mapFor('update_rate_limit_rule', { + zoneId: 'zone1', + rulesetId: 'rs1', + ruleId: 'r1', + updateRateLimitAction: 'log', + }).action + ).toBe('log') + }) + + it('strips the aliased control ids so they never reach a tool as params', () => { + const mapped = mapFor('create_dns_record', { zoneId: 'zone1' }) + + for (const alias of [ + 'recordType', + 'recordProxied', + 'certificateStatus', + 'appType', + 'updateAppType', + 'updatePolicyDecision', + 'rateLimitAction', + 'updateRateLimitAction', + 'rulesetName', + 'zoneNameFilter', + 'zoneType', + 'dnsTypeFilter', + 'dnsNameFilter', + 'dnsContentFilter', + 'dnsOrder', + 'dnsProxiedFilter', + 'purgeTags', + 'workerTagFilter', + 'accessAppTags', + 'listNameFilter', + 'accessAppDomainFilter', + 'tunnelStatus', + ]) { + expect(mapped[alias], `alias ${alias} reached the tool`).toBeUndefined() + } + }) + + it('sends the ruleset name as the name param when creating a ruleset', () => { + const mapped = mapFor('create_ruleset', { + zoneId: 'zone1', + phase: 'http_ratelimit', + rulesetName: 'Zone rate limiting ruleset', + }) + + expect(mapped.name).toBe('Zone rate limiting ruleset') + expect(mapped.rulesetName).toBeUndefined() + }) +}) + +/** + * `shouldSerializeSubBlock` (serializer/index.ts) short-circuits on + * `mode: 'advanced'` BEFORE evaluating `condition`, so an advanced control whose + * stored value is non-empty is serialized even when the selected operation does + * not render it. That is harmless while every operation that consumes the id + * also exposes a control for it — the user can see and change the value — and it + * is a silent cross-operation write when it does not. + */ +/** + * Two mechanical guards on subBlock id reuse. Block state is keyed by subBlock + * id, so controls sharing an id share one stored value — fine when they mean the + * same thing, a silent cross-operation bug when they do not. These encode the + * two shapes that divergence takes here. + */ +describe('a shared subBlock id means the same thing everywhere', () => { + /** + * Ids that legitimately span reads and writes because they address the + * resource rather than carry payload: credentials, account/zone scope, the + * R2 jurisdiction routing header, the ruleset phase, and resource ids. + */ + const ADDRESSING_IDS = new Set([ + 'apiKey', + 'operation', + 'accountId', + 'zoneId', + 'jurisdiction', + 'phase', + 'appId', + 'bucketName', + 'rulesetId', + ]) + + const WRITE_PREFIXES = ['create_', 'update_', 'delete_', 'purge_', 'revoke_'] + + function operationsFor(subBlock: (typeof CloudflareBlock.subBlocks)[number]): string[] { + const condition = subBlock.condition + if (!condition || typeof condition !== 'object' || !('field' in condition)) return [] + if (condition.field !== 'operation') return [] + const value = condition.value + return Array.isArray(value) ? value.map(String) : [String(value)] + } + + it('never shares an id between a read filter and a written value', () => { + const kindsById = new Map>() + + for (const subBlock of CloudflareBlock.subBlocks) { + if (ADDRESSING_IDS.has(subBlock.id)) continue + for (const operation of operationsFor(subBlock)) { + const kind = WRITE_PREFIXES.some((prefix) => operation.startsWith(prefix)) + ? 'write' + : 'read' + const kinds = kindsById.get(subBlock.id) ?? new Set() + kinds.add(kind) + kindsById.set(subBlock.id, kinds) + } + } + + const mixed = [...kindsById.entries()] + .filter(([, kinds]) => kinds.size > 1) + .map(([id]) => id) + .sort() + + expect(mixed).toEqual([]) + }) + + it('never gives one dropdown id two different option sets', () => { + const optionsById = new Map>() + + for (const subBlock of CloudflareBlock.subBlocks) { + if (subBlock.type !== 'dropdown' || !Array.isArray(subBlock.options)) continue + const signature = JSON.stringify( + subBlock.options.map((option) => + typeof option === 'string' ? option : ((option as { id?: string }).id ?? '') + ) + ) + const signatures = optionsById.get(subBlock.id) ?? new Set() + signatures.add(signature) + optionsById.set(subBlock.id, signatures) + } + + const divergent = [...optionsById.entries()] + .filter(([, signatures]) => signatures.size > 1) + .map(([id, signatures]) => `${id}: ${[...signatures].join(' vs ')}`) + + expect(divergent).toEqual([]) + }) +}) + +describe('no hidden advanced control feeds an operation that cannot show it', () => { + const STALE = '__stale_value__' + + const toolsByOperation = new Map( + Object.values(cloudflareTools).map((tool) => [tool.id.replace(/^cloudflare_/, ''), tool]) + ) + + /** Operations a subBlock's `condition` makes it visible for. */ + function conditionOperations(subBlock: (typeof CloudflareBlock.subBlocks)[number]): string[] { + const condition = subBlock.condition + if (!condition || typeof condition !== 'object' || !('field' in condition)) return [] + if (condition.field !== 'operation') return [] + const value = condition.value + return Array.isArray(value) ? value.map(String) : [String(value)] + } + + it('every advanced id reaching a tool is either shown or remapped for that operation', () => { + const operations = [...toolsByOperation.keys()] + const visibleIdsByOperation = new Map>( + operations.map((operation) => [operation, new Set()]) + ) + for (const subBlock of CloudflareBlock.subBlocks) { + for (const operation of conditionOperations(subBlock)) { + visibleIdsByOperation.get(operation)?.add(subBlock.id) + } + } + + const leaks: string[] = [] + + for (const subBlock of CloudflareBlock.subBlocks) { + if (subBlock.mode !== 'advanced') continue + const ownOperations = new Set(conditionOperations(subBlock)) + + for (const operation of operations) { + if (ownOperations.has(operation)) continue + const tool = toolsByOperation.get(operation) + if (!tool?.params || !(subBlock.id in tool.params)) continue + if (visibleIdsByOperation.get(operation)?.has(subBlock.id)) continue + + // The mapper must overwrite or clear the stale value for this operation. + const mapped = mapFor(operation, { [subBlock.id]: STALE }) + if (mapped[subBlock.id] === STALE) { + leaks.push( + `"${subBlock.id}" (advanced, shown for ${[...ownOperations].join('/') || 'nothing'}) reaches ${operation} as a param it never renders` + ) + } + } + } + + expect(leaks).toEqual([]) + }) +}) diff --git a/apps/sim/tools/cloudflare/create_access_application.ts b/apps/sim/tools/cloudflare/create_access_application.ts new file mode 100644 index 00000000000..0fd9a1e91aa --- /dev/null +++ b/apps/sim/tools/cloudflare/create_access_application.ts @@ -0,0 +1,236 @@ +import type { + CloudflareAccessApplicationResponse, + CloudflareCreateAccessApplicationParams, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyAccessApplication, + mapAccessApplication, + parseCsvParam, + parseJsonArrayParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const createAccessApplicationTool: ToolConfig< + CloudflareCreateAccessApplicationParams, + CloudflareAccessApplicationResponse +> = { + id: 'cloudflare_create_access_application', + name: 'Cloudflare Create Access Application', + description: + 'Creates a Cloudflare Access (Zero Trust) application that puts an identity check in front of a hostname. Until at least one policy is attached the application denies everyone, so pair this with "Create Access Policy". Requires an API token with Account Access: Apps and Policies Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + type: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Application type: self_hosted, saas, ssh, vnc, app_launcher, warp, biso, bookmark, dash_sso, infrastructure, rdp, mcp, mcp_portal, or proxy_endpoint', + }, + domain: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'The primary hostname and path secured by Access, e.g. internal.example.com or example.com/admin. Required for the self_hosted, ssh, vnc, rdp, and bookmark types; the saas, app_launcher, warp, biso, dash_sso, infrastructure, mcp, mcp_portal, and proxy_endpoint types do not accept it', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Friendly name shown in the dashboard and App Launcher', + }, + sessionDuration: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'How long an Access session stays valid, e.g. 24h or 30m', + }, + allowedIdps: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Comma-separated identity provider IDs users may authenticate with. Leave empty to allow all configured providers', + }, + appLauncherVisible: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the application is shown in the App Launcher', + }, + autoRedirectToIdentity: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether users skip the identity provider picker', + }, + customDenyMessage: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Message shown to users who are denied access', + }, + customDenyUrl: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'URL denied users are redirected to', + }, + logoUrl: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Logo image URL shown in the dashboard and App Launcher', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated tag names categorizing the application', + }, + policies: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON array of policies to attach. Entries may be reusable policy IDs or inline policy objects, e.g. [""]', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps`, + method: 'POST', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const body: Record = { type: params.type } + /** + * `domain` exists only on the self_hosted, ssh, vnc, rdp, and bookmark + * request variants; the saas, app_launcher, warp, biso, dash_sso, + * infrastructure, mcp, mcp_portal, and proxy_endpoint variants have no + * such field, so sending a blank one makes those app types unbuildable. + */ + if (params.domain) body.domain = params.domain + if (params.name) body.name = params.name + if (params.sessionDuration) body.session_duration = params.sessionDuration + + const allowedIdps = parseCsvParam(params.allowedIdps) + if (allowedIdps) body.allowed_idps = allowedIdps + + if (params.appLauncherVisible !== undefined) { + body.app_launcher_visible = params.appLauncherVisible + } + if (params.autoRedirectToIdentity !== undefined) { + body.auto_redirect_to_identity = params.autoRedirectToIdentity + } + if (params.customDenyMessage) body.custom_deny_message = params.customDenyMessage + if (params.customDenyUrl) body.custom_deny_url = params.customDenyUrl + if (params.logoUrl) body.logo_url = params.logoUrl + + const tags = parseCsvParam(params.tags) + if (tags) body.tags = tags + + const policies = parseJsonArrayParam(params.policies, 'Policies') + if (policies) body.policies = policies + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyAccessApplication(), + error: cloudflareErrorMessage(data, 'Failed to create Access application'), + } + } + + return { success: true, output: mapAccessApplication(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Created Access application identifier' }, + name: { type: 'string', description: 'Application name', optional: true }, + domain: { + type: 'string', + description: 'Primary hostname and path secured by Access', + optional: true, + }, + type: { type: 'string', description: 'Application type', optional: true }, + aud: { type: 'string', description: 'Audience tag used to verify Access JWTs', optional: true }, + session_duration: { + type: 'string', + description: 'How long an Access session stays valid', + optional: true, + }, + allowed_idps: { + type: 'array', + description: 'Identity provider IDs users may authenticate with', + items: { type: 'string', description: 'Identity provider ID' }, + optional: true, + }, + app_launcher_visible: { + type: 'boolean', + description: 'Whether the app appears in the App Launcher', + optional: true, + }, + auto_redirect_to_identity: { + type: 'boolean', + description: 'Whether users skip the identity provider picker', + optional: true, + }, + custom_deny_message: { + type: 'string', + description: 'Message shown when access is denied', + optional: true, + }, + custom_deny_url: { + type: 'string', + description: 'URL users are redirected to when access is denied', + optional: true, + }, + logo_url: { type: 'string', description: 'Logo image URL', optional: true }, + self_hosted_domains: { + type: 'array', + description: + 'Additional hostnames and paths secured by the application. Cloudflare deprecated this field in favour of destinations, which is the one to read on a current application', + items: { type: 'string', description: 'Hostname and path' }, + optional: true, + }, + destinations: { + type: 'json', + description: 'Public and private destinations secured by the application', + optional: true, + }, + tags: { + type: 'array', + description: 'Tags categorizing the application', + items: { type: 'string', description: 'Tag name' }, + optional: true, + }, + policies: { + type: 'json', + description: 'Access policies attached to the application', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/create_access_policy.ts b/apps/sim/tools/cloudflare/create_access_policy.ts new file mode 100644 index 00000000000..c307a191c01 --- /dev/null +++ b/apps/sim/tools/cloudflare/create_access_policy.ts @@ -0,0 +1,214 @@ +import type { + CloudflareAccessPolicyResponse, + CloudflareCreateAccessPolicyParams, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyAccessPolicy, + mapAccessPolicy, + parseJsonArrayParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const createAccessPolicyTool: ToolConfig< + CloudflareCreateAccessPolicyParams, + CloudflareAccessPolicyResponse +> = { + id: 'cloudflare_create_access_policy', + name: 'Cloudflare Create Access Policy', + description: + 'Creates a Cloudflare Access (Zero Trust) policy on an application, deciding who may reach it. A policy takes effect on live traffic as soon as it is created — an allow policy with a broad include rule grants access immediately. Requires an API token with Account Access: Apps and Policies Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + appId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access application ID to attach the policy to', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name of the policy', + }, + decision: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'What the policy does when it matches: allow, deny, non_identity (service tokens and other non-identity rules), or bypass (skip Access entirely)', + }, + include: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'JSON array of Access rules evaluated with OR logic — matching any one selects the policy. Example: [{"email":{"email":"user@example.com"}}] or [{"email_domain":{"domain":"example.com"}}]', + }, + exclude: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON array of Access rules evaluated with NOT logic — matching any one rejects the request', + }, + require: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'JSON array of Access rules evaluated with AND logic — all of them must match', + }, + precedence: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Evaluation order of the policy within the application', + }, + sessionDuration: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'How long a session granted by this policy stays valid, e.g. 24h', + }, + approvalRequired: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether an approver must grant each access request', + }, + isolationRequired: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the session must run in a remote isolated browser', + }, + purposeJustificationRequired: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether users must state a reason for access', + }, + purposeJustificationPrompt: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Prompt shown when a justification is required', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps/${params.appId.trim()}/policies`, + method: 'POST', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const include = parseJsonArrayParam(params.include, 'Include Rules') + if (!include || include.length === 0) { + throw new Error('Include Rules must contain at least one Access rule') + } + + const body: Record = { + name: params.name, + decision: params.decision, + include, + } + + const exclude = parseJsonArrayParam(params.exclude, 'Exclude Rules') + if (exclude) body.exclude = exclude + + const require = parseJsonArrayParam(params.require, 'Require Rules') + if (require) body.require = require + + if (params.precedence !== undefined) body.precedence = params.precedence + if (params.sessionDuration) body.session_duration = params.sessionDuration + if (params.approvalRequired !== undefined) body.approval_required = params.approvalRequired + if (params.isolationRequired !== undefined) body.isolation_required = params.isolationRequired + if (params.purposeJustificationRequired !== undefined) { + body.purpose_justification_required = params.purposeJustificationRequired + } + if (params.purposeJustificationPrompt) { + body.purpose_justification_prompt = params.purposeJustificationPrompt + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyAccessPolicy(), + error: cloudflareErrorMessage(data, 'Failed to create Access policy'), + } + } + + return { success: true, output: mapAccessPolicy(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Created policy identifier' }, + name: { type: 'string', description: 'Policy name', optional: true }, + decision: { + type: 'string', + description: 'Decision the policy applies: allow, deny, non_identity, or bypass', + optional: true, + }, + precedence: { + type: 'number', + description: 'Evaluation order of the policy within the application', + optional: true, + }, + include: { + type: 'json', + description: 'Rules evaluated with OR logic', + optional: true, + }, + exclude: { type: 'json', description: 'Rules evaluated with NOT logic', optional: true }, + require: { type: 'json', description: 'Rules evaluated with AND logic', optional: true }, + session_duration: { + type: 'string', + description: 'How long a session granted by this policy stays valid', + optional: true, + }, + approval_required: { + type: 'boolean', + description: 'Whether an approver must grant each access request', + optional: true, + }, + isolation_required: { + type: 'boolean', + description: 'Whether the session must run in a remote browser', + optional: true, + }, + purpose_justification_required: { + type: 'boolean', + description: 'Whether users must state a reason for access', + optional: true, + }, + purpose_justification_prompt: { + type: 'string', + description: 'Prompt shown when a justification is required', + optional: true, + }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + updated_at: { type: 'string', description: 'Last update timestamp', optional: true }, + }, +} diff --git a/apps/sim/tools/cloudflare/create_access_service_token.ts b/apps/sim/tools/cloudflare/create_access_service_token.ts new file mode 100644 index 00000000000..dc6487411c7 --- /dev/null +++ b/apps/sim/tools/cloudflare/create_access_service_token.ts @@ -0,0 +1,123 @@ +import type { + CloudflareCreateAccessServiceTokenParams, + CloudflareCreateAccessServiceTokenResponse, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const createAccessServiceTokenTool: ToolConfig< + CloudflareCreateAccessServiceTokenParams, + CloudflareCreateAccessServiceTokenResponse +> = { + id: 'cloudflare_create_access_service_token', + name: 'Cloudflare Create Access Service Token', + description: + 'Creates a Cloudflare Access (Zero Trust) service token so a machine can authenticate to Access-protected applications. This is the only response that ever contains the client secret — Cloudflare will not return it again, so capture it in the same run. Requires an API token with Account Access: Service Tokens Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Service tokens are account-scoped', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name of the service token', + }, + duration: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + "How long the token stays valid before it expires, e.g. 8760h. Defaults to Cloudflare's standard lifetime", + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/service_tokens`, + method: 'POST', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const body: Record = { name: params.name } + if (params.duration) body.duration = params.duration + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { + id: '', + name: null, + client_id: null, + client_secret: null, + duration: null, + enabled: null, + expires_at: null, + last_seen_at: null, + created_at: null, + updated_at: null, + }, + error: cloudflareErrorMessage(data, 'Failed to create Access service token'), + } + } + + const token = data.result + return { + success: true, + output: { + id: token?.id ?? '', + name: token?.name ?? null, + client_id: token?.client_id ?? null, + client_secret: token?.client_secret ?? null, + duration: token?.duration ?? null, + enabled: token?.enabled ?? null, + expires_at: token?.expires_at ?? null, + last_seen_at: token?.last_seen_at ?? null, + created_at: token?.created_at ?? null, + updated_at: token?.updated_at ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Created service token identifier' }, + name: { type: 'string', description: 'Service token name', optional: true }, + client_id: { + type: 'string', + description: 'Client ID sent in the CF-Access-Client-Id header', + optional: true, + }, + client_secret: { + type: 'string', + description: + 'Client secret sent in the CF-Access-Client-Secret header. Returned only once, at creation', + optional: true, + }, + duration: { + type: 'string', + description: 'How long the token stays valid before it expires', + optional: true, + }, + enabled: { type: 'boolean', description: 'Whether the token is active', optional: true }, + expires_at: { type: 'string', description: 'Expiry timestamp', optional: true }, + last_seen_at: { type: 'string', description: 'When the token was last used', optional: true }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + updated_at: { type: 'string', description: 'Last update timestamp', optional: true }, + }, +} diff --git a/apps/sim/tools/cloudflare/create_dns_record.ts b/apps/sim/tools/cloudflare/create_dns_record.ts index a962ce7277d..9fb75216ec8 100644 --- a/apps/sim/tools/cloudflare/create_dns_record.ts +++ b/apps/sim/tools/cloudflare/create_dns_record.ts @@ -54,7 +54,8 @@ export const createDnsRecordTool: ToolConfig< type: 'number', required: false, visibility: 'user-or-llm', - description: 'Priority for MX and SRV records', + description: + 'Record priority. Cloudflare accepts this top-level field for MX and URI records only; an SRV record carries its priority, weight, port, and target inside the record content instead', }, comment: { type: 'string', @@ -77,14 +78,15 @@ export const createDnsRecordTool: ToolConfig< }, request: { - url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records`, + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/dns_records`, method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, 'Content-Type': 'application/json', }), body: (params) => { - const body: Record = { + const body: Record = { type: params.type, name: params.name, content: params.content, @@ -177,7 +179,11 @@ export const createDnsRecordTool: ToolConfig< proxied: { type: 'boolean', description: 'Whether Cloudflare proxy is enabled' }, ttl: { type: 'number', description: 'Time to live in seconds (1 = automatic)' }, locked: { type: 'boolean', description: 'Whether the record is locked' }, - priority: { type: 'number', description: 'Priority for MX and SRV records', optional: true }, + priority: { + type: 'number', + description: 'Record priority, returned for MX and URI records', + optional: true, + }, comment: { type: 'string', description: 'Comment associated with the record', optional: true }, tags: { type: 'array', diff --git a/apps/sim/tools/cloudflare/create_r2_bucket.ts b/apps/sim/tools/cloudflare/create_r2_bucket.ts new file mode 100644 index 00000000000..66524353208 --- /dev/null +++ b/apps/sim/tools/cloudflare/create_r2_bucket.ts @@ -0,0 +1,125 @@ +import type { + CloudflareCreateR2BucketParams, + CloudflareR2BucketResponse, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const createR2BucketTool: ToolConfig< + CloudflareCreateR2BucketParams, + CloudflareR2BucketResponse +> = { + id: 'cloudflare_create_r2_bucket', + name: 'Cloudflare Create R2 Bucket', + description: + 'Creates an R2 object storage bucket in an account. The location hint and jurisdiction are fixed at creation and cannot be changed later. Requires an API token with Account Workers R2 Storage Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. R2 buckets are account-scoped', + }, + bucketName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name for the new bucket', + }, + locationHint: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Region hint for where the bucket should live: apac, eeur, enam, weur, wnam, or oc. Cannot be changed after creation', + }, + storageClass: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Default storage class for objects: Standard or InfrequentAccess', + }, + jurisdiction: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Data-residency jurisdiction to create the bucket in: default, eu, or fedramp. Cannot be changed after creation', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/r2/buckets`, + method: 'POST', + headers: (params) => { + const headers = cloudflareHeaders(params.apiKey) + if (params.jurisdiction) headers['cf-r2-jurisdiction'] = params.jurisdiction + return headers + }, + body: (params) => { + const body: Record = { name: params.bucketName } + if (params.locationHint) body.locationHint = params.locationHint + if (params.storageClass) body.storageClass = params.storageClass + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { + name: '', + creation_date: null, + location: null, + storage_class: null, + jurisdiction: null, + }, + error: cloudflareErrorMessage(data, 'Failed to create R2 bucket'), + } + } + + const bucket = data.result + return { + success: true, + output: { + name: bucket?.name ?? '', + creation_date: bucket?.creation_date ?? null, + location: bucket?.location ?? null, + storage_class: bucket?.storage_class ?? null, + jurisdiction: bucket?.jurisdiction ?? null, + }, + } + }, + + outputs: { + name: { type: 'string', description: 'Created bucket name' }, + creation_date: { type: 'string', description: 'Creation timestamp', optional: true }, + location: { + type: 'string', + description: 'Location the bucket was created in', + optional: true, + }, + storage_class: { + type: 'string', + description: 'Default storage class (Standard or InfrequentAccess)', + optional: true, + }, + jurisdiction: { + type: 'string', + description: 'Data-residency jurisdiction (default, eu, or fedramp)', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/create_rate_limit_rule.ts b/apps/sim/tools/cloudflare/create_rate_limit_rule.ts new file mode 100644 index 00000000000..58e69f7c58b --- /dev/null +++ b/apps/sim/tools/cloudflare/create_rate_limit_rule.ts @@ -0,0 +1,212 @@ +import type { + CloudflareCreateRateLimitRuleParams, + CloudflareRulesetResponse, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, + parseCsvParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const createRateLimitRuleTool: ToolConfig< + CloudflareCreateRateLimitRuleParams, + CloudflareRulesetResponse +> = { + id: 'cloudflare_create_rate_limit_rule', + name: 'Cloudflare Create Rate Limiting Rule', + description: + 'Creates a rate limiting rule in the http_ratelimit phase entry point ruleset of a zone, using the current Rulesets-based rate limiting API (the legacy rate_limits endpoint is no longer available). Run "List Rate Limiting Rules" first to get the ruleset ID. Requires an API token with Zone WAF Edit.', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID to add the rate limiting rule to', + }, + rulesetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The http_ratelimit entry point ruleset ID, as returned by "List Rate Limiting Rules"', + }, + expression: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Cloudflare filter expression selecting the requests the rule applies to, e.g. (http.request.uri.path matches "^/api/")', + }, + characteristics: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Comma-separated counting characteristics. cf.colo.id is mandatory, plus exactly one of ip.src or cf.unique_visitor_id. Example: cf.colo.id,ip.src', + }, + period: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: + 'Counting window in seconds. Cloudflare accepts only 10, 60, 120, 300, 600, or 3600', + }, + requestsPerPeriod: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'Number of requests allowed within the counting period before the action fires', + }, + action: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Action applied once the limit is exceeded, e.g. block, managed_challenge, js_challenge, challenge, or log. Defaults to block', + }, + mitigationTimeout: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: + 'Seconds the action stays applied after the limit is exceeded. Cloudflare accepts only 0, 10, 60, 120, 300, 600, 3600, or 86400', + }, + counting_expression: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Optional expression defining which requests are counted, when it differs from the matching expression', + }, + requestsToOrigin: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'When true, only requests that reach the origin are counted', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Human-readable description of the rule', + }, + enabled: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the rule is enabled', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/${params.rulesetId.trim()}/rules`, + method: 'POST', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const characteristics = parseCsvParam(params.characteristics) + if (!characteristics) { + throw new Error('Characteristics must list at least one counting characteristic') + } + + const ratelimit: Record = { + characteristics, + period: params.period, + requests_per_period: params.requestsPerPeriod, + } + if (params.mitigationTimeout !== undefined) { + ratelimit.mitigation_timeout = params.mitigationTimeout + } + if (params.counting_expression) ratelimit.counting_expression = params.counting_expression + if (params.requestsToOrigin !== undefined) { + ratelimit.requests_to_origin = params.requestsToOrigin + } + + const body: Record = { + action: params.action || 'block', + expression: params.expression, + ratelimit, + } + if (params.description) body.description = params.description + if (params.enabled !== undefined) body.enabled = params.enabled + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to create rate limiting rule'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Ruleset ID of the http_ratelimit entry point' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind' }, + phase: { type: 'string', description: 'Phase the ruleset runs in (http_ratelimit)' }, + version: { type: 'string', description: 'Ruleset version after the change', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rate limiting rules after the change, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { type: 'string', description: 'Action applied once the limit is exceeded' }, + action_parameters: { + type: 'json', + description: 'Action-specific parameters', + optional: true, + }, + expression: { type: 'string', description: 'Filter expression' }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { type: 'string', description: 'Rule reference tag', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { + type: 'json', + description: 'Rate limiting configuration applied to the rule', + optional: true, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/create_ruleset.ts b/apps/sim/tools/cloudflare/create_ruleset.ts new file mode 100644 index 00000000000..89bd79a348a --- /dev/null +++ b/apps/sim/tools/cloudflare/create_ruleset.ts @@ -0,0 +1,167 @@ +import type { + CloudflareCreateRulesetParams, + CloudflareRulesetResponse, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, + parseJsonArrayParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const createRulesetTool: ToolConfig< + CloudflareCreateRulesetParams, + CloudflareRulesetResponse +> = { + id: 'cloudflare_create_ruleset', + name: 'Cloudflare Create Ruleset', + description: + 'Creates a zone ruleset for a phase, optionally seeded with its first rules. Use this when a phase has no entry point ruleset yet — reading the entry point returns 404 on a zone that has never had a rule in that phase, and rules can only be appended to a ruleset that already exists. Create the entry point with kind "zone" and the target phase (for example http_ratelimit for rate limiting rules or http_request_firewall_custom for WAF custom rules), then use the returned ruleset ID for later rule operations. Requires an API token with Zone WAF Edit (or another matching ruleset Edit permission).', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID to create the ruleset in', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Human-readable name for the ruleset', + }, + phase: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The ruleset phase, e.g. http_ratelimit, http_request_firewall_custom, http_request_firewall_managed, http_request_transform, http_request_dynamic_redirect', + }, + kind: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Ruleset kind: zone, custom, managed, or root. Use zone to create a phase entry point ruleset. Defaults to zone', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description of the ruleset', + }, + rules: { + type: 'json', + required: false, + visibility: 'user-or-llm', + description: + 'JSON array of rules to seed the ruleset with, in evaluation order. Each rule takes action, expression, and optionally description, enabled, action_parameters, and ratelimit', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets`, + method: 'POST', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + name: params.name, + kind: params.kind || 'zone', + phase: params.phase, + } + if (params.description) body.description = params.description + + const rules = parseJsonArrayParam(params.rules, 'Rules') + body.rules = rules ?? [] + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to create ruleset'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Ruleset identifier' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind (managed, custom, root, or zone)' }, + phase: { type: 'string', description: 'Phase the ruleset runs in' }, + version: { type: 'string', description: 'Ruleset version', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rules contained in the ruleset, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { + type: 'string', + description: 'Action the rule performs (e.g., block, challenge, log, skip, execute)', + }, + action_parameters: { + type: 'json', + description: + 'Action-specific parameters, including managed-ruleset overrides on execute rules', + optional: true, + }, + expression: { + type: 'string', + description: + 'Filter expression selecting matching requests. Empty on managed-ruleset rules', + }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { + type: 'string', + description: 'Rule reference tag that survives rule updates', + optional: true, + }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { + type: 'json', + description: 'Rate limiting configuration for rules in the http_ratelimit phase', + optional: true, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/create_ruleset_rule.ts b/apps/sim/tools/cloudflare/create_ruleset_rule.ts new file mode 100644 index 00000000000..4ff7bb34156 --- /dev/null +++ b/apps/sim/tools/cloudflare/create_ruleset_rule.ts @@ -0,0 +1,179 @@ +import type { + CloudflareCreateRulesetRuleParams, + CloudflareRulesetResponse, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, + parseJsonObjectParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const createRulesetRuleTool: ToolConfig< + CloudflareCreateRulesetRuleParams, + CloudflareRulesetResponse +> = { + id: 'cloudflare_create_ruleset_rule', + name: 'Cloudflare Create Ruleset Rule', + description: + 'Adds a rule to a zone ruleset. Use "Get Phase Entry Point Ruleset" first to find the ruleset ID for the phase you want (for example http_request_firewall_custom for a WAF custom rule, or http_request_firewall_managed with action "execute" to deploy a managed ruleset). The rule is appended to the end of the ruleset unless a position is given. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission).', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID that owns the ruleset', + }, + rulesetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ruleset ID to add the rule to', + }, + action: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The action the rule performs. Valid values depend on the phase — e.g. block, challenge, js_challenge, managed_challenge, log, skip, or execute (to deploy a managed ruleset)', + }, + expression: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Cloudflare filter expression selecting matching requests, e.g. (ip.src.country in {"GB" "FR"}). Use "true" to match every request', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Human-readable description of the rule', + }, + enabled: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the rule is enabled', + }, + ref: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Reference tag that stays stable across rule updates', + }, + actionParameters: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON object of action-specific parameters. For an "execute" rule this carries the managed ruleset id and any overrides, e.g. {"id":"","overrides":{"action":"log"}}', + }, + position: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON object placing the rule within the ruleset. Exactly one of {"before":""}, {"after":""}, or {"index":<1-based position>}', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/${params.rulesetId.trim()}/rules`, + method: 'POST', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + action: params.action, + expression: params.expression, + } + if (params.description) body.description = params.description + if (params.enabled !== undefined) body.enabled = params.enabled + if (params.ref) body.ref = params.ref + + const actionParameters = parseJsonObjectParam(params.actionParameters, 'Action Parameters') + if (actionParameters) body.action_parameters = actionParameters + + const position = parseJsonObjectParam(params.position, 'Position') + if (position) body.position = position + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to create ruleset rule'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Ruleset identifier' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind (managed, custom, root, or zone)' }, + phase: { type: 'string', description: 'Phase the ruleset runs in' }, + version: { type: 'string', description: 'Ruleset version after the change', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rules in the ruleset after the change, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { type: 'string', description: 'Action the rule performs' }, + action_parameters: { + type: 'json', + description: 'Action-specific parameters', + optional: true, + }, + expression: { type: 'string', description: 'Filter expression' }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { type: 'string', description: 'Rule reference tag', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { + type: 'json', + description: 'Rate limiting configuration', + optional: true, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/create_zone.ts b/apps/sim/tools/cloudflare/create_zone.ts index 03fda6fb181..4cb778bd8c0 100644 --- a/apps/sim/tools/cloudflare/create_zone.ts +++ b/apps/sim/tools/cloudflare/create_zone.ts @@ -47,7 +47,7 @@ export const createZoneTool: ToolConfig { - const body: Record = { + const body: Record = { name: params.name, account: { id: params.accountId }, } diff --git a/apps/sim/tools/cloudflare/delete_access_application.ts b/apps/sim/tools/cloudflare/delete_access_application.ts new file mode 100644 index 00000000000..00c03ab1258 --- /dev/null +++ b/apps/sim/tools/cloudflare/delete_access_application.ts @@ -0,0 +1,63 @@ +import type { + CloudflareDeleteAccessApplicationParams, + CloudflareDeletedIdResponse, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const deleteAccessApplicationTool: ToolConfig< + CloudflareDeleteAccessApplicationParams, + CloudflareDeletedIdResponse +> = { + id: 'cloudflare_delete_access_application', + name: 'Cloudflare Delete Access Application', + description: + 'Permanently deletes a Cloudflare Access (Zero Trust) application and every policy attached to it. The hostname it protected is immediately left without an Access identity check, so anyone who can reach it can reach the origin. This cannot be undone. Requires an API token with Account Access: Apps and Policies Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + appId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access application ID to delete permanently', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps/${params.appId.trim()}`, + method: 'DELETE', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { id: '' }, + error: cloudflareErrorMessage(data, 'Failed to delete Access application'), + } + } + + return { success: true, output: { id: data.result?.id ?? '' } } + }, + + outputs: { + id: { type: 'string', description: 'Identifier of the deleted Access application' }, + }, +} diff --git a/apps/sim/tools/cloudflare/delete_access_policy.ts b/apps/sim/tools/cloudflare/delete_access_policy.ts new file mode 100644 index 00000000000..f13889c6a3b --- /dev/null +++ b/apps/sim/tools/cloudflare/delete_access_policy.ts @@ -0,0 +1,69 @@ +import type { + CloudflareDeleteAccessPolicyParams, + CloudflareDeletedIdResponse, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const deleteAccessPolicyTool: ToolConfig< + CloudflareDeleteAccessPolicyParams, + CloudflareDeletedIdResponse +> = { + id: 'cloudflare_delete_access_policy', + name: 'Cloudflare Delete Access Policy', + description: + 'Permanently deletes a Cloudflare Access (Zero Trust) policy from an application. This changes who can reach the application the moment it runs: removing an allow policy locks out everyone it covered, and removing a deny or require policy drops that restriction. This cannot be undone. Requires an API token with Account Access: Apps and Policies Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + appId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access application ID that owns the policy', + }, + policyId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access policy ID to delete permanently', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps/${params.appId.trim()}/policies/${params.policyId.trim()}`, + method: 'DELETE', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { id: '' }, + error: cloudflareErrorMessage(data, 'Failed to delete Access policy'), + } + } + + return { success: true, output: { id: data.result?.id ?? '' } } + }, + + outputs: { + id: { type: 'string', description: 'Identifier of the deleted Access policy' }, + }, +} diff --git a/apps/sim/tools/cloudflare/delete_dns_record.ts b/apps/sim/tools/cloudflare/delete_dns_record.ts index 4e6bced66f6..d333255f682 100644 --- a/apps/sim/tools/cloudflare/delete_dns_record.ts +++ b/apps/sim/tools/cloudflare/delete_dns_record.ts @@ -36,7 +36,7 @@ export const deleteDnsRecordTool: ToolConfig< request: { url: (params) => - `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records/${params.recordId}`, + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/dns_records/${params.recordId.trim()}`, method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, @@ -47,7 +47,16 @@ export const deleteDnsRecordTool: ToolConfig< transformResponse: async (response: Response) => { const data = await response.json() - if (!data.success) { + /** + * This endpoint is the one Cloudflare v4 response that does NOT carry the + * shared envelope: its documented body is `{ "result": { "id": ... } }` with + * no `success`, `errors`, or `messages`. Branching on `!data.success` would + * therefore report every successful delete as a failure, so the check must + * be an explicit `=== false` — which still fails a real `success: false` + * body if Cloudflare ever starts sending the full envelope here. + * https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/delete/ + */ + if (data.success === false) { return { success: false, output: { id: '' }, diff --git a/apps/sim/tools/cloudflare/delete_r2_bucket.ts b/apps/sim/tools/cloudflare/delete_r2_bucket.ts new file mode 100644 index 00000000000..a239b0f1a35 --- /dev/null +++ b/apps/sim/tools/cloudflare/delete_r2_bucket.ts @@ -0,0 +1,77 @@ +import type { + CloudflareDeleteR2BucketParams, + CloudflareDeleteR2BucketResponse, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const deleteR2BucketTool: ToolConfig< + CloudflareDeleteR2BucketParams, + CloudflareDeleteR2BucketResponse +> = { + id: 'cloudflare_delete_r2_bucket', + name: 'Cloudflare Delete R2 Bucket', + description: + 'Permanently deletes an R2 object storage bucket. Cloudflare only deletes an empty bucket, and the deletion cannot be undone. Requires an API token with Account Workers R2 Storage Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. R2 buckets are account-scoped', + }, + bucketName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the bucket to delete permanently', + }, + jurisdiction: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Data-residency jurisdiction the bucket lives in: default, eu, or fedramp', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/r2/buckets/${encodeURIComponent(params.bucketName)}`, + method: 'DELETE', + headers: (params) => { + const headers = cloudflareHeaders(params.apiKey) + if (params.jurisdiction) headers['cf-r2-jurisdiction'] = params.jurisdiction + return headers + }, + }, + + transformResponse: async (response: Response, params) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { name: '' }, + error: cloudflareErrorMessage(data, 'Failed to delete R2 bucket'), + } + } + + return { success: true, output: { name: params?.bucketName ?? '' } } + }, + + outputs: { + name: { + type: 'string', + description: + 'Name of the deleted bucket. Cloudflare returns an empty result body for this endpoint, so the name is echoed from the request', + }, + }, +} diff --git a/apps/sim/tools/cloudflare/delete_ruleset_rule.ts b/apps/sim/tools/cloudflare/delete_ruleset_rule.ts new file mode 100644 index 00000000000..68ec2c45f9b --- /dev/null +++ b/apps/sim/tools/cloudflare/delete_ruleset_rule.ts @@ -0,0 +1,117 @@ +import type { + CloudflareDeleteRulesetRuleParams, + CloudflareRulesetResponse, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const deleteRulesetRuleTool: ToolConfig< + CloudflareDeleteRulesetRuleParams, + CloudflareRulesetResponse +> = { + id: 'cloudflare_delete_ruleset_rule', + name: 'Cloudflare Delete Ruleset Rule', + description: + 'Permanently deletes a rule from a zone ruleset. This takes effect immediately on live traffic and cannot be undone — deleting a WAF custom rule, a managed-ruleset deployment, or a rate limiting rule removes that protection from the zone. Also use this to delete rate limiting rules, which live in the http_ratelimit phase ruleset. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission).', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID that owns the ruleset', + }, + rulesetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ruleset ID containing the rule', + }, + ruleId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The rule ID to delete permanently', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/${params.rulesetId.trim()}/rules/${params.ruleId.trim()}`, + method: 'DELETE', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to delete ruleset rule'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Ruleset identifier' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind (managed, custom, root, or zone)' }, + phase: { type: 'string', description: 'Phase the ruleset runs in' }, + version: { type: 'string', description: 'Ruleset version after the change', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rules remaining in the ruleset, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { type: 'string', description: 'Action the rule performs' }, + action_parameters: { + type: 'json', + description: 'Action-specific parameters', + optional: true, + }, + expression: { type: 'string', description: 'Filter expression' }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { type: 'string', description: 'Rule reference tag', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { type: 'json', description: 'Rate limiting configuration', optional: true }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/delete_zone.ts b/apps/sim/tools/cloudflare/delete_zone.ts index 7cf15229967..06ddf1d42cb 100644 --- a/apps/sim/tools/cloudflare/delete_zone.ts +++ b/apps/sim/tools/cloudflare/delete_zone.ts @@ -27,7 +27,7 @@ export const deleteZoneTool: ToolConfig `https://api.cloudflare.com/client/v4/zones/${params.zoneId}`, + url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}`, method: 'DELETE', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, diff --git a/apps/sim/tools/cloudflare/dns_analytics.ts b/apps/sim/tools/cloudflare/dns_analytics.ts index 93525b6562f..7b038aeed58 100644 --- a/apps/sim/tools/cloudflare/dns_analytics.ts +++ b/apps/sim/tools/cloudflare/dns_analytics.ts @@ -1,7 +1,9 @@ import type { CloudflareDnsAnalyticsParams, CloudflareDnsAnalyticsResponse, + CloudflareRawDnsAnalyticsReport, } from '@/tools/cloudflare/types' +import { readCloudflareResponse } from '@/tools/cloudflare/utils' import type { ToolConfig } from '@/tools/types' export const dnsAnalyticsTool: ToolConfig< @@ -78,7 +80,7 @@ export const dnsAnalyticsTool: ToolConfig< request: { url: (params) => { const url = new URL( - `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_analytics/report` + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/dns_analytics/report` ) if (params.since) url.searchParams.append('since', params.since) if (params.until) url.searchParams.append('until', params.until) @@ -97,7 +99,7 @@ export const dnsAnalyticsTool: ToolConfig< }, transformResponse: async (response: Response) => { - const data = await response.json() + const data = await readCloudflareResponse(response) if (!data.success) { return { @@ -179,7 +181,7 @@ export const dnsAnalyticsTool: ToolConfig< responseTime99th: result?.max?.responseTime99th ?? 0, }, data: - result?.data?.map((entry: any) => ({ + result?.data?.map((entry) => ({ dimensions: entry.dimensions ?? [], metrics: entry.metrics ?? [], })) ?? [], diff --git a/apps/sim/tools/cloudflare/get_access_application.ts b/apps/sim/tools/cloudflare/get_access_application.ts new file mode 100644 index 00000000000..71f1989c713 --- /dev/null +++ b/apps/sim/tools/cloudflare/get_access_application.ts @@ -0,0 +1,135 @@ +import type { + CloudflareAccessApplicationResponse, + CloudflareGetAccessApplicationParams, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyAccessApplication, + mapAccessApplication, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const getAccessApplicationTool: ToolConfig< + CloudflareGetAccessApplicationParams, + CloudflareAccessApplicationResponse +> = { + id: 'cloudflare_get_access_application', + name: 'Cloudflare Get Access Application', + description: + 'Reads a single Cloudflare Access (Zero Trust) application, including its attached policies. Requires an API token with Account Access: Apps and Policies Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + appId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access application ID (or audience tag) to read', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps/${params.appId.trim()}`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyAccessApplication(), + error: cloudflareErrorMessage(data, 'Failed to get Access application'), + } + } + + return { success: true, output: mapAccessApplication(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Access application identifier' }, + name: { type: 'string', description: 'Application name', optional: true }, + domain: { + type: 'string', + description: 'Primary hostname and path secured by Access', + optional: true, + }, + type: { + type: 'string', + description: 'Application type (e.g., self_hosted, saas, ssh, app_launcher, bookmark)', + optional: true, + }, + aud: { type: 'string', description: 'Audience tag used to verify Access JWTs', optional: true }, + session_duration: { + type: 'string', + description: 'How long an Access session stays valid (e.g., 24h)', + optional: true, + }, + allowed_idps: { + type: 'array', + description: 'Identity provider IDs users may authenticate with', + items: { type: 'string', description: 'Identity provider ID' }, + optional: true, + }, + app_launcher_visible: { + type: 'boolean', + description: 'Whether the app appears in the App Launcher', + optional: true, + }, + auto_redirect_to_identity: { + type: 'boolean', + description: 'Whether users skip the identity provider picker', + optional: true, + }, + custom_deny_message: { + type: 'string', + description: 'Message shown when access is denied', + optional: true, + }, + custom_deny_url: { + type: 'string', + description: 'URL users are redirected to when access is denied', + optional: true, + }, + logo_url: { type: 'string', description: 'Logo image URL', optional: true }, + self_hosted_domains: { + type: 'array', + description: + 'Additional hostnames and paths secured by the application. Cloudflare deprecated this field in favour of destinations, which is the one to read on a current application', + items: { type: 'string', description: 'Hostname and path' }, + optional: true, + }, + destinations: { + type: 'json', + description: 'Public and private destinations secured by the application', + optional: true, + }, + tags: { + type: 'array', + description: 'Tags categorizing the application', + items: { type: 'string', description: 'Tag name' }, + optional: true, + }, + policies: { + type: 'json', + description: 'Access policies attached to the application', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/get_r2_bucket.ts b/apps/sim/tools/cloudflare/get_r2_bucket.ts new file mode 100644 index 00000000000..f144a34f608 --- /dev/null +++ b/apps/sim/tools/cloudflare/get_r2_bucket.ts @@ -0,0 +1,104 @@ +import type { + CloudflareGetR2BucketParams, + CloudflareR2BucketResponse, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const getR2BucketTool: ToolConfig = + { + id: 'cloudflare_get_r2_bucket', + name: 'Cloudflare Get R2 Bucket', + description: + 'Reads the metadata of a single R2 object storage bucket. Requires an API token with Account Workers R2 Storage Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. R2 buckets are account-scoped', + }, + bucketName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the bucket to read', + }, + jurisdiction: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Data-residency jurisdiction the bucket lives in: default, eu, or fedramp', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/r2/buckets/${encodeURIComponent(params.bucketName)}`, + method: 'GET', + headers: (params) => { + const headers = cloudflareHeaders(params.apiKey) + if (params.jurisdiction) headers['cf-r2-jurisdiction'] = params.jurisdiction + return headers + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { + name: '', + creation_date: null, + location: null, + storage_class: null, + jurisdiction: null, + }, + error: cloudflareErrorMessage(data, 'Failed to get R2 bucket'), + } + } + + const bucket = data.result + return { + success: true, + output: { + name: bucket?.name ?? '', + creation_date: bucket?.creation_date ?? null, + location: bucket?.location ?? null, + storage_class: bucket?.storage_class ?? null, + jurisdiction: bucket?.jurisdiction ?? null, + }, + } + }, + + outputs: { + name: { type: 'string', description: 'Bucket name' }, + creation_date: { type: 'string', description: 'Creation timestamp', optional: true }, + location: { + type: 'string', + description: + 'Location hint the bucket was created with (apac, eeur, enam, weur, wnam, or oc)', + optional: true, + }, + storage_class: { + type: 'string', + description: 'Default storage class (Standard or InfrequentAccess)', + optional: true, + }, + jurisdiction: { + type: 'string', + description: 'Data-residency jurisdiction (default, eu, or fedramp)', + optional: true, + }, + }, + } diff --git a/apps/sim/tools/cloudflare/get_ruleset.ts b/apps/sim/tools/cloudflare/get_ruleset.ts new file mode 100644 index 00000000000..badc225f26e --- /dev/null +++ b/apps/sim/tools/cloudflare/get_ruleset.ts @@ -0,0 +1,124 @@ +import type { + CloudflareGetRulesetParams, + CloudflareRulesetResponse, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const getRulesetTool: ToolConfig = { + id: 'cloudflare_get_ruleset', + name: 'Cloudflare Get Ruleset', + description: + 'Reads a single zone ruleset including every rule it contains, in evaluation order. Requires an API token with Zone WAF Read (or another matching ruleset Read permission).', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID that owns the ruleset', + }, + rulesetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ruleset ID to read', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/${params.rulesetId.trim()}`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to get ruleset'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Ruleset identifier' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind (managed, custom, root, or zone)' }, + phase: { type: 'string', description: 'Phase the ruleset runs in' }, + version: { type: 'string', description: 'Ruleset version', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rules contained in the ruleset, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { + type: 'string', + description: 'Action the rule performs (e.g., block, challenge, log, skip, execute)', + }, + action_parameters: { + type: 'json', + description: + 'Action-specific parameters, including managed-ruleset overrides on execute rules', + optional: true, + }, + expression: { + type: 'string', + description: + 'Filter expression selecting matching requests. Empty on managed-ruleset rules', + }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { + type: 'string', + description: 'Rule reference tag that survives rule updates', + optional: true, + }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { + type: 'json', + description: 'Rate limiting configuration for rules in the http_ratelimit phase', + optional: true, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/get_ruleset_entrypoint.ts b/apps/sim/tools/cloudflare/get_ruleset_entrypoint.ts new file mode 100644 index 00000000000..87e460390a3 --- /dev/null +++ b/apps/sim/tools/cloudflare/get_ruleset_entrypoint.ts @@ -0,0 +1,128 @@ +import type { + CloudflareGetRulesetEntrypointParams, + CloudflareRulesetResponse, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const getRulesetEntrypointTool: ToolConfig< + CloudflareGetRulesetEntrypointParams, + CloudflareRulesetResponse +> = { + id: 'cloudflare_get_ruleset_entrypoint', + name: 'Cloudflare Get Phase Entry Point Ruleset', + description: + 'Reads the entry point ruleset for a phase on a zone, including all of its rules. This is how you find the ruleset ID you need before adding, updating, or deleting a rule — for example http_request_firewall_custom for WAF custom rules, http_request_firewall_managed for managed-ruleset deployments and overrides, or http_ratelimit for rate limiting rules. Requires an API token with Zone WAF Read (or another matching ruleset Read permission).', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID to read the phase entry point for', + }, + phase: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The ruleset phase, e.g. http_request_firewall_custom, http_request_firewall_managed, http_ratelimit, http_request_transform, http_request_dynamic_redirect', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/phases/${params.phase.trim()}/entrypoint`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to get phase entry point ruleset'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Entry point ruleset identifier' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind (managed, custom, root, or zone)' }, + phase: { type: 'string', description: 'Phase the ruleset runs in' }, + version: { type: 'string', description: 'Ruleset version', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rules contained in the ruleset, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { + type: 'string', + description: 'Action the rule performs (e.g., block, challenge, log, skip, execute)', + }, + action_parameters: { + type: 'json', + description: + 'Action-specific parameters, including managed-ruleset overrides on execute rules', + optional: true, + }, + expression: { + type: 'string', + description: + 'Filter expression selecting matching requests. Empty on managed-ruleset rules', + }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { + type: 'string', + description: 'Rule reference tag that survives rule updates', + optional: true, + }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { + type: 'json', + description: 'Rate limiting configuration for rules in the http_ratelimit phase', + optional: true, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/get_tunnel.ts b/apps/sim/tools/cloudflare/get_tunnel.ts new file mode 100644 index 00000000000..cf0faf957f0 --- /dev/null +++ b/apps/sim/tools/cloudflare/get_tunnel.ts @@ -0,0 +1,133 @@ +import type { CloudflareGetTunnelParams, CloudflareTunnelResponse } from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const getTunnelTool: ToolConfig = { + id: 'cloudflare_get_tunnel', + name: 'Cloudflare Get Tunnel', + description: + 'Reads a single Cloudflare Tunnel (cloudflared), including its health status and active connector connections. Requires an API token with Account Cloudflare Tunnel Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Tunnels are account-scoped', + }, + tunnelId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The tunnel ID to read', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/cfd_tunnel/${params.tunnelId.trim()}`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { + id: '', + name: null, + account_tag: null, + config_src: null, + status: null, + tun_type: null, + remote_config: null, + metadata: null, + created_at: null, + deleted_at: null, + conns_active_at: null, + conns_inactive_at: null, + connections: null, + }, + error: cloudflareErrorMessage(data, 'Failed to get tunnel'), + } + } + + const tunnel = data.result + return { + success: true, + output: { + id: tunnel?.id ?? '', + name: tunnel?.name ?? null, + account_tag: tunnel?.account_tag ?? null, + config_src: tunnel?.config_src ?? null, + status: tunnel?.status ?? null, + tun_type: tunnel?.tun_type ?? null, + remote_config: tunnel?.remote_config ?? null, + metadata: tunnel?.metadata ?? null, + created_at: tunnel?.created_at ?? null, + deleted_at: tunnel?.deleted_at ?? null, + conns_active_at: tunnel?.conns_active_at ?? null, + conns_inactive_at: tunnel?.conns_inactive_at ?? null, + connections: tunnel?.connections ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Tunnel identifier' }, + name: { type: 'string', description: 'Tunnel name', optional: true }, + account_tag: { type: 'string', description: 'Account the tunnel belongs to', optional: true }, + config_src: { + type: 'string', + description: 'Where the tunnel configuration lives: local or cloudflare', + optional: true, + }, + status: { + type: 'string', + description: 'Tunnel health: inactive, degraded, healthy, or down', + optional: true, + }, + tun_type: { + type: 'string', + description: 'Tunnel type, e.g. cfd_tunnel, warp_connector, or warp', + optional: true, + }, + remote_config: { + type: 'boolean', + description: 'Whether the tunnel is remotely managed', + optional: true, + }, + metadata: { + type: 'json', + description: 'Metadata associated with the tunnel', + optional: true, + }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + deleted_at: { type: 'string', description: 'Deletion timestamp', optional: true }, + conns_active_at: { + type: 'string', + description: 'When the tunnel last had active connections', + optional: true, + }, + conns_inactive_at: { + type: 'string', + description: 'When the tunnel last lost all connections', + optional: true, + }, + connections: { + type: 'json', + description: 'Active connector connections for the tunnel', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/get_tunnel_configuration.ts b/apps/sim/tools/cloudflare/get_tunnel_configuration.ts new file mode 100644 index 00000000000..8b76c3590a8 --- /dev/null +++ b/apps/sim/tools/cloudflare/get_tunnel_configuration.ts @@ -0,0 +1,99 @@ +import type { + CloudflareGetTunnelConfigurationParams, + CloudflareGetTunnelConfigurationResponse, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const getTunnelConfigurationTool: ToolConfig< + CloudflareGetTunnelConfigurationParams, + CloudflareGetTunnelConfigurationResponse +> = { + id: 'cloudflare_get_tunnel_configuration', + name: 'Cloudflare Get Tunnel Configuration', + description: + 'Reads the configuration of a remotely-managed Cloudflare Tunnel — its ingress rules, origin request settings, and WARP routing. Only tunnels whose configuration source is "cloudflare" have a remote configuration; locally-managed tunnels keep it in their own config file. Requires an API token with Account Cloudflare Tunnel Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Tunnels are account-scoped', + }, + tunnelId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The tunnel ID to read the configuration for', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/cfd_tunnel/${params.tunnelId.trim()}/configurations`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { + tunnel_id: '', + account_id: '', + version: null, + source: null, + created_at: null, + config: null, + }, + error: cloudflareErrorMessage(data, 'Failed to get tunnel configuration'), + } + } + + const result = data.result + return { + success: true, + output: { + tunnel_id: result?.tunnel_id ?? '', + account_id: result?.account_id ?? '', + version: result?.version ?? null, + source: result?.source ?? null, + created_at: result?.created_at ?? null, + config: result?.config ?? null, + }, + } + }, + + outputs: { + tunnel_id: { type: 'string', description: 'Tunnel the configuration belongs to' }, + account_id: { type: 'string', description: 'Account the tunnel belongs to' }, + version: { + type: 'number', + description: 'Configuration version, incremented on every change', + optional: true, + }, + source: { + type: 'string', + description: 'Where the configuration is managed: local or cloudflare', + optional: true, + }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + config: { + type: 'json', + description: + 'Tunnel configuration with ingress rules, originRequest defaults, and warp-routing settings', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/get_worker_script_settings.ts b/apps/sim/tools/cloudflare/get_worker_script_settings.ts new file mode 100644 index 00000000000..dcc787391cf --- /dev/null +++ b/apps/sim/tools/cloudflare/get_worker_script_settings.ts @@ -0,0 +1,131 @@ +import type { + CloudflareGetWorkerScriptSettingsParams, + CloudflareGetWorkerScriptSettingsResponse, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const getWorkerScriptSettingsTool: ToolConfig< + CloudflareGetWorkerScriptSettingsParams, + CloudflareGetWorkerScriptSettingsResponse +> = { + id: 'cloudflare_get_worker_script_settings', + name: 'Cloudflare Get Worker Script Settings', + description: + 'Reads the deployment settings of a single Workers script — bindings, compatibility date and flags, limits, observability, placement, and tail consumers. The plain "get script" endpoint in the Cloudflare API returns raw JavaScript source rather than JSON, so this settings endpoint is the structured way to inspect one script. Requires an API token with Account Workers Scripts Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Workers scripts are account-scoped', + }, + scriptName: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The name of the Workers script to read settings for', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/workers/scripts/${encodeURIComponent(params.scriptName)}/settings`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { + bindings: null, + compatibility_date: null, + compatibility_flags: null, + limits: null, + logpush: null, + migrations: null, + observability: null, + placement: null, + tags: null, + tail_consumers: null, + usage_model: null, + }, + error: cloudflareErrorMessage(data, 'Failed to get Worker script settings'), + } + } + + const settings = data.result + return { + success: true, + output: { + bindings: settings?.bindings ?? null, + compatibility_date: settings?.compatibility_date ?? null, + compatibility_flags: settings?.compatibility_flags ?? null, + limits: settings?.limits ?? null, + logpush: settings?.logpush ?? null, + migrations: settings?.migrations ?? null, + observability: settings?.observability ?? null, + placement: settings?.placement ?? null, + tags: settings?.tags ?? null, + tail_consumers: settings?.tail_consumers ?? null, + usage_model: settings?.usage_model ?? null, + }, + } + }, + + outputs: { + bindings: { + type: 'json', + description: 'Resource bindings available to the script (KV, R2, D1, secrets, and more)', + optional: true, + }, + compatibility_date: { + type: 'string', + description: 'Workers runtime compatibility date', + optional: true, + }, + compatibility_flags: { + type: 'array', + description: 'Workers runtime compatibility flags', + items: { type: 'string', description: 'Compatibility flag' }, + optional: true, + }, + limits: { type: 'json', description: 'CPU and other execution limits', optional: true }, + logpush: { type: 'boolean', description: 'Whether Workers Logpush is enabled', optional: true }, + migrations: { type: 'json', description: 'Durable Object migrations', optional: true }, + observability: { + type: 'json', + description: 'Observability and log-sampling configuration', + optional: true, + }, + placement: { type: 'json', description: 'Smart placement configuration', optional: true }, + tags: { + type: 'array', + description: 'Tags attached to the script', + items: { type: 'string', description: 'Tag name' }, + optional: true, + }, + tail_consumers: { + type: 'json', + description: "Workers that consume this script's tail events", + optional: true, + }, + usage_model: { + type: 'string', + description: 'Billing usage model', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/get_zone.ts b/apps/sim/tools/cloudflare/get_zone.ts index 2e926a0f6f5..398c05f6a69 100644 --- a/apps/sim/tools/cloudflare/get_zone.ts +++ b/apps/sim/tools/cloudflare/get_zone.ts @@ -23,7 +23,7 @@ export const getZoneTool: ToolConfig `https://api.cloudflare.com/client/v4/zones/${params.zoneId}`, + url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, diff --git a/apps/sim/tools/cloudflare/get_zone_settings.ts b/apps/sim/tools/cloudflare/get_zone_settings.ts index ac37f47ed6b..cb730d51cc5 100644 --- a/apps/sim/tools/cloudflare/get_zone_settings.ts +++ b/apps/sim/tools/cloudflare/get_zone_settings.ts @@ -30,7 +30,7 @@ export const getZoneSettingsTool: ToolConfig< }, request: { - url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/settings`, + url: (params) => `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/settings`, method: 'GET', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, @@ -83,8 +83,7 @@ export const getZoneSettingsTool: ToolConfig< }, value: { type: 'string', - description: - 'Setting value as a string. Simple values returned as-is (e.g., "full", "on"). Complex values are JSON-stringified (e.g., \'{"css":"on","html":"on","js":"on"}\').', + description: `Setting value as a string. Simple values returned as-is (e.g., "full", "on"). Complex values are JSON-stringified (e.g., {"css":"on","html":"on","js":"on"}).`, }, editable: { type: 'boolean', diff --git a/apps/sim/tools/cloudflare/index.ts b/apps/sim/tools/cloudflare/index.ts index e3f21d34c9b..d19e5f28ba6 100644 --- a/apps/sim/tools/cloudflare/index.ts +++ b/apps/sim/tools/cloudflare/index.ts @@ -1,27 +1,97 @@ +import { createAccessApplicationTool } from '@/tools/cloudflare/create_access_application' +import { createAccessPolicyTool } from '@/tools/cloudflare/create_access_policy' +import { createAccessServiceTokenTool } from '@/tools/cloudflare/create_access_service_token' import { createDnsRecordTool } from '@/tools/cloudflare/create_dns_record' +import { createR2BucketTool } from '@/tools/cloudflare/create_r2_bucket' +import { createRateLimitRuleTool } from '@/tools/cloudflare/create_rate_limit_rule' +import { createRulesetTool } from '@/tools/cloudflare/create_ruleset' +import { createRulesetRuleTool } from '@/tools/cloudflare/create_ruleset_rule' import { createZoneTool } from '@/tools/cloudflare/create_zone' +import { deleteAccessApplicationTool } from '@/tools/cloudflare/delete_access_application' +import { deleteAccessPolicyTool } from '@/tools/cloudflare/delete_access_policy' import { deleteDnsRecordTool } from '@/tools/cloudflare/delete_dns_record' +import { deleteR2BucketTool } from '@/tools/cloudflare/delete_r2_bucket' +import { deleteRulesetRuleTool } from '@/tools/cloudflare/delete_ruleset_rule' import { deleteZoneTool } from '@/tools/cloudflare/delete_zone' import { dnsAnalyticsTool } from '@/tools/cloudflare/dns_analytics' +import { getAccessApplicationTool } from '@/tools/cloudflare/get_access_application' +import { getR2BucketTool } from '@/tools/cloudflare/get_r2_bucket' +import { getRulesetTool } from '@/tools/cloudflare/get_ruleset' +import { getRulesetEntrypointTool } from '@/tools/cloudflare/get_ruleset_entrypoint' +import { getTunnelTool } from '@/tools/cloudflare/get_tunnel' +import { getTunnelConfigurationTool } from '@/tools/cloudflare/get_tunnel_configuration' +import { getWorkerScriptSettingsTool } from '@/tools/cloudflare/get_worker_script_settings' import { getZoneTool } from '@/tools/cloudflare/get_zone' import { getZoneSettingsTool } from '@/tools/cloudflare/get_zone_settings' +import { listAccessApplicationsTool } from '@/tools/cloudflare/list_access_applications' +import { listAccessGroupsTool } from '@/tools/cloudflare/list_access_groups' +import { listAccessIdentityProvidersTool } from '@/tools/cloudflare/list_access_identity_providers' +import { listAccessPoliciesTool } from '@/tools/cloudflare/list_access_policies' +import { listAccessServiceTokensTool } from '@/tools/cloudflare/list_access_service_tokens' import { listCertificatesTool } from '@/tools/cloudflare/list_certificates' import { listDnsRecordsTool } from '@/tools/cloudflare/list_dns_records' +import { listManagedRulesetOverridesTool } from '@/tools/cloudflare/list_managed_ruleset_overrides' +import { listR2BucketsTool } from '@/tools/cloudflare/list_r2_buckets' +import { listRateLimitRulesTool } from '@/tools/cloudflare/list_rate_limit_rules' +import { listRulesetsTool } from '@/tools/cloudflare/list_rulesets' +import { listTunnelsTool } from '@/tools/cloudflare/list_tunnels' +import { listWorkerRoutesTool } from '@/tools/cloudflare/list_worker_routes' +import { listWorkerScriptsTool } from '@/tools/cloudflare/list_worker_scripts' import { listZonesTool } from '@/tools/cloudflare/list_zones' import { purgeCacheTool } from '@/tools/cloudflare/purge_cache' +import { revokeAccessServiceTokenTool } from '@/tools/cloudflare/revoke_access_service_token' +import { updateAccessApplicationTool } from '@/tools/cloudflare/update_access_application' +import { updateAccessPolicyTool } from '@/tools/cloudflare/update_access_policy' import { updateDnsRecordTool } from '@/tools/cloudflare/update_dns_record' +import { updateRateLimitRuleTool } from '@/tools/cloudflare/update_rate_limit_rule' +import { updateRulesetRuleTool } from '@/tools/cloudflare/update_ruleset_rule' import { updateZoneSettingTool } from '@/tools/cloudflare/update_zone_setting' +export const cloudflareCreateAccessApplicationTool = createAccessApplicationTool +export const cloudflareCreateAccessPolicyTool = createAccessPolicyTool +export const cloudflareCreateAccessServiceTokenTool = createAccessServiceTokenTool export const cloudflareCreateDnsRecordTool = createDnsRecordTool +export const cloudflareCreateR2BucketTool = createR2BucketTool +export const cloudflareCreateRateLimitRuleTool = createRateLimitRuleTool +export const cloudflareCreateRulesetTool = createRulesetTool +export const cloudflareCreateRulesetRuleTool = createRulesetRuleTool export const cloudflareCreateZoneTool = createZoneTool +export const cloudflareDeleteAccessApplicationTool = deleteAccessApplicationTool +export const cloudflareDeleteAccessPolicyTool = deleteAccessPolicyTool export const cloudflareDeleteDnsRecordTool = deleteDnsRecordTool +export const cloudflareDeleteR2BucketTool = deleteR2BucketTool +export const cloudflareDeleteRulesetRuleTool = deleteRulesetRuleTool export const cloudflareDeleteZoneTool = deleteZoneTool export const cloudflareDnsAnalyticsTool = dnsAnalyticsTool +export const cloudflareGetAccessApplicationTool = getAccessApplicationTool +export const cloudflareGetR2BucketTool = getR2BucketTool +export const cloudflareGetRulesetTool = getRulesetTool +export const cloudflareGetRulesetEntrypointTool = getRulesetEntrypointTool +export const cloudflareGetTunnelTool = getTunnelTool +export const cloudflareGetTunnelConfigurationTool = getTunnelConfigurationTool +export const cloudflareGetWorkerScriptSettingsTool = getWorkerScriptSettingsTool export const cloudflareGetZoneTool = getZoneTool export const cloudflareGetZoneSettingsTool = getZoneSettingsTool +export const cloudflareListAccessApplicationsTool = listAccessApplicationsTool +export const cloudflareListAccessGroupsTool = listAccessGroupsTool +export const cloudflareListAccessIdentityProvidersTool = listAccessIdentityProvidersTool +export const cloudflareListAccessPoliciesTool = listAccessPoliciesTool +export const cloudflareListAccessServiceTokensTool = listAccessServiceTokensTool export const cloudflareListCertificatesTool = listCertificatesTool export const cloudflareListDnsRecordsTool = listDnsRecordsTool +export const cloudflareListManagedRulesetOverridesTool = listManagedRulesetOverridesTool +export const cloudflareListR2BucketsTool = listR2BucketsTool +export const cloudflareListRateLimitRulesTool = listRateLimitRulesTool +export const cloudflareListRulesetsTool = listRulesetsTool +export const cloudflareListTunnelsTool = listTunnelsTool +export const cloudflareListWorkerRoutesTool = listWorkerRoutesTool +export const cloudflareListWorkerScriptsTool = listWorkerScriptsTool export const cloudflareListZonesTool = listZonesTool export const cloudflarePurgeCacheTool = purgeCacheTool +export const cloudflareRevokeAccessServiceTokenTool = revokeAccessServiceTokenTool +export const cloudflareUpdateAccessApplicationTool = updateAccessApplicationTool +export const cloudflareUpdateAccessPolicyTool = updateAccessPolicyTool export const cloudflareUpdateDnsRecordTool = updateDnsRecordTool +export const cloudflareUpdateRateLimitRuleTool = updateRateLimitRuleTool +export const cloudflareUpdateRulesetRuleTool = updateRulesetRuleTool export const cloudflareUpdateZoneSettingTool = updateZoneSettingTool diff --git a/apps/sim/tools/cloudflare/list_access_applications.ts b/apps/sim/tools/cloudflare/list_access_applications.ts new file mode 100644 index 00000000000..97938fcd247 --- /dev/null +++ b/apps/sim/tools/cloudflare/list_access_applications.ts @@ -0,0 +1,204 @@ +import type { + CloudflareListAccessApplicationsParams, + CloudflareListAccessApplicationsResponse, +} from '@/tools/cloudflare/types' +import { + appendParam, + cloudflareErrorMessage, + cloudflareHeaders, + mapAccessApplication, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listAccessApplicationsTool: ToolConfig< + CloudflareListAccessApplicationsParams, + CloudflareListAccessApplicationsResponse +> = { + id: 'cloudflare_list_access_applications', + name: 'Cloudflare List Access Applications', + description: + 'Lists the Cloudflare Access (Zero Trust) applications protecting an account. Requires an API token with Account Access: Apps and Policies Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by application name', + }, + domain: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by the primary hostname the application secures', + }, + aud: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by application audience (AUD) tag', + }, + search: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Free-text search across applications', + }, + exact: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the name and domain filters must match exactly', + }, + page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Page number for pagination', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of applications per page', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps` + ) + appendParam(url, 'name', params.name) + appendParam(url, 'domain', params.domain) + appendParam(url, 'aud', params.aud) + appendParam(url, 'search', params.search) + if (params.exact !== undefined) url.searchParams.append('exact', String(params.exact)) + appendParam(url, 'page', params.page) + appendParam(url, 'per_page', params.per_page) + return url.toString() + }, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { applications: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list Access applications'), + } + } + + const applications = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + applications: applications.map(mapAccessApplication), + total_count: data.result_info?.total_count ?? applications.length, + }, + } + }, + + outputs: { + applications: { + type: 'array', + description: 'Access applications in the account', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Access application identifier' }, + name: { type: 'string', description: 'Application name', optional: true }, + domain: { + type: 'string', + description: 'Primary hostname and path secured by Access', + optional: true, + }, + type: { + type: 'string', + description: 'Application type (e.g., self_hosted, saas, ssh, app_launcher, bookmark)', + optional: true, + }, + aud: { + type: 'string', + description: 'Audience tag used to verify Access JWTs', + optional: true, + }, + session_duration: { + type: 'string', + description: 'How long an Access session stays valid (e.g., 24h)', + optional: true, + }, + allowed_idps: { + type: 'array', + description: 'Identity provider IDs users may authenticate with', + items: { type: 'string', description: 'Identity provider ID' }, + optional: true, + }, + app_launcher_visible: { + type: 'boolean', + description: 'Whether the app appears in the App Launcher', + optional: true, + }, + auto_redirect_to_identity: { + type: 'boolean', + description: 'Whether users skip the identity provider picker', + optional: true, + }, + custom_deny_message: { + type: 'string', + description: 'Message shown when access is denied', + optional: true, + }, + custom_deny_url: { + type: 'string', + description: 'URL users are redirected to when access is denied', + optional: true, + }, + logo_url: { type: 'string', description: 'Logo image URL', optional: true }, + self_hosted_domains: { + type: 'array', + description: + 'Additional hostnames and paths secured by the application. Cloudflare deprecated this field in favour of destinations, which is the one to read on a current application', + items: { type: 'string', description: 'Hostname and path' }, + optional: true, + }, + destinations: { + type: 'json', + description: 'Public and private destinations secured by the application', + optional: true, + }, + tags: { + type: 'array', + description: 'Tags categorizing the application', + items: { type: 'string', description: 'Tag name' }, + optional: true, + }, + policies: { + type: 'json', + description: 'Access policies attached to the application', + optional: true, + }, + }, + }, + }, + total_count: { type: 'number', description: 'Total number of Access applications' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_access_groups.ts b/apps/sim/tools/cloudflare/list_access_groups.ts new file mode 100644 index 00000000000..65ed2b03cb2 --- /dev/null +++ b/apps/sim/tools/cloudflare/list_access_groups.ts @@ -0,0 +1,138 @@ +import type { + CloudflareListAccessGroupsParams, + CloudflareListAccessGroupsResponse, + CloudflareRawAccessGroup, +} from '@/tools/cloudflare/types' +import { + appendParam, + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listAccessGroupsTool: ToolConfig< + CloudflareListAccessGroupsParams, + CloudflareListAccessGroupsResponse +> = { + id: 'cloudflare_list_access_groups', + name: 'Cloudflare List Access Groups', + description: + 'Lists the reusable Cloudflare Access (Zero Trust) groups in an account. Groups bundle identity rules that policies can reference by ID. Requires an API token with Account Access: Organizations, Identity Providers, and Groups Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access groups are account-scoped', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by group name', + }, + search: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Free-text search across groups', + }, + page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Page number for pagination', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of groups per page', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/groups` + ) + appendParam(url, 'name', params.name) + appendParam(url, 'search', params.search) + appendParam(url, 'page', params.page) + appendParam(url, 'per_page', params.per_page) + return url.toString() + }, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse(response) + + if (!data.success) { + return { + success: false, + output: { groups: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list Access groups'), + } + } + + const groups = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + groups: groups.map((group) => ({ + id: group.id ?? '', + name: group.name ?? null, + is_default: group.is_default ?? null, + include: group.include ?? null, + exclude: group.exclude ?? null, + require: group.require ?? null, + created_at: group.created_at ?? null, + updated_at: group.updated_at ?? null, + })), + total_count: data.result_info?.total_count ?? groups.length, + }, + } + }, + + outputs: { + groups: { + type: 'array', + description: 'Access groups in the account', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Access group identifier' }, + name: { type: 'string', description: 'Group name', optional: true }, + is_default: { + type: 'json', + description: + 'Rules that place this group in every Access application by default. Cloudflare returns an array of rule objects here, not a boolean', + optional: true, + }, + include: { + type: 'json', + description: 'Rules evaluated with OR logic', + optional: true, + }, + exclude: { type: 'json', description: 'Rules evaluated with NOT logic', optional: true }, + require: { type: 'json', description: 'Rules evaluated with AND logic', optional: true }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + updated_at: { type: 'string', description: 'Last update timestamp', optional: true }, + }, + }, + }, + total_count: { type: 'number', description: 'Total number of Access groups' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_access_identity_providers.ts b/apps/sim/tools/cloudflare/list_access_identity_providers.ts new file mode 100644 index 00000000000..c6568fcb499 --- /dev/null +++ b/apps/sim/tools/cloudflare/list_access_identity_providers.ts @@ -0,0 +1,112 @@ +import type { + CloudflareListAccessIdentityProvidersParams, + CloudflareListAccessIdentityProvidersResponse, + CloudflareRawAccessIdentityProvider, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listAccessIdentityProvidersTool: ToolConfig< + CloudflareListAccessIdentityProvidersParams, + CloudflareListAccessIdentityProvidersResponse +> = { + id: 'cloudflare_list_access_identity_providers', + name: 'Cloudflare List Access Identity Providers', + description: + 'Lists the identity providers configured for Cloudflare Access (Zero Trust) in an account, such as Okta, Entra ID, Google Workspace, or a one-time PIN. Use the returned IDs to restrict an application with allowed_idps. Requires an API token with Account Access: Organizations, Identity Providers, and Groups Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Identity providers are account-scoped', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/identity_providers`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse(response) + + if (!data.success) { + return { + success: false, + output: { identity_providers: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list Access identity providers'), + } + } + + const providers = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + identity_providers: providers.map((provider) => ({ + id: provider.id ?? '', + name: provider.name ?? null, + type: provider.type ?? null, + read_only: provider.read_only ?? null, + config: provider.config ?? null, + scim_config: provider.scim_config ?? null, + })), + total_count: data.result_info?.total_count ?? providers.length, + }, + } + }, + + outputs: { + identity_providers: { + type: 'array', + description: 'Identity providers configured for Access', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Identity provider identifier' }, + name: { + type: 'string', + description: 'Display name shown to users on the login page', + optional: true, + }, + type: { + type: 'string', + description: 'Provider type, e.g. azureAD, okta, google, saml, oidc, or onetimepin', + optional: true, + }, + read_only: { + type: 'boolean', + description: 'Whether the provider is immutable through the API', + optional: true, + }, + config: { + type: 'json', + description: 'Provider-specific configuration parameters', + optional: true, + }, + scim_config: { + type: 'json', + description: 'SCIM user and group provisioning configuration', + optional: true, + }, + }, + }, + }, + total_count: { type: 'number', description: 'Total number of identity providers' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_access_policies.ts b/apps/sim/tools/cloudflare/list_access_policies.ts new file mode 100644 index 00000000000..0ec5e0c645c --- /dev/null +++ b/apps/sim/tools/cloudflare/list_access_policies.ts @@ -0,0 +1,157 @@ +import type { + CloudflareListAccessPoliciesParams, + CloudflareListAccessPoliciesResponse, +} from '@/tools/cloudflare/types' +import { + appendParam, + cloudflareErrorMessage, + cloudflareHeaders, + mapAccessPolicy, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listAccessPoliciesTool: ToolConfig< + CloudflareListAccessPoliciesParams, + CloudflareListAccessPoliciesResponse +> = { + id: 'cloudflare_list_access_policies', + name: 'Cloudflare List Access Policies', + description: + 'Lists the Cloudflare Access (Zero Trust) policies attached to an application, in precedence order. Requires an API token with Account Access: Apps and Policies Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + appId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access application ID whose policies should be listed', + }, + page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Page number for pagination', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of policies per page', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps/${params.appId.trim()}/policies` + ) + appendParam(url, 'page', params.page) + appendParam(url, 'per_page', params.per_page) + return url.toString() + }, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { policies: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list Access policies'), + } + } + + const policies = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + policies: policies.map(mapAccessPolicy), + total_count: data.result_info?.total_count ?? policies.length, + }, + } + }, + + outputs: { + policies: { + type: 'array', + description: 'Access policies attached to the application', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Policy identifier' }, + name: { type: 'string', description: 'Policy name', optional: true }, + decision: { + type: 'string', + description: 'Decision the policy applies: allow, deny, non_identity, or bypass', + optional: true, + }, + precedence: { + type: 'number', + description: 'Evaluation order of the policy within the application', + optional: true, + }, + include: { + type: 'json', + description: 'Rules evaluated with OR logic — matching any one selects the policy', + optional: true, + }, + exclude: { + type: 'json', + description: 'Rules evaluated with NOT logic — matching any one rejects the request', + optional: true, + }, + require: { + type: 'json', + description: 'Rules evaluated with AND logic — all must match', + optional: true, + }, + session_duration: { + type: 'string', + description: 'How long a session granted by this policy stays valid', + optional: true, + }, + approval_required: { + type: 'boolean', + description: 'Whether an approver must grant each access request', + optional: true, + }, + isolation_required: { + type: 'boolean', + description: 'Whether the session must run in a remote browser', + optional: true, + }, + purpose_justification_required: { + type: 'boolean', + description: 'Whether users must state a reason for access', + optional: true, + }, + purpose_justification_prompt: { + type: 'string', + description: 'Prompt shown when a justification is required', + optional: true, + }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + updated_at: { type: 'string', description: 'Last update timestamp', optional: true }, + }, + }, + }, + total_count: { type: 'number', description: 'Total number of policies' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_access_service_tokens.ts b/apps/sim/tools/cloudflare/list_access_service_tokens.ts new file mode 100644 index 00000000000..75e0737752a --- /dev/null +++ b/apps/sim/tools/cloudflare/list_access_service_tokens.ts @@ -0,0 +1,143 @@ +import type { + CloudflareListAccessServiceTokensParams, + CloudflareListAccessServiceTokensResponse, + CloudflareRawAccessServiceToken, +} from '@/tools/cloudflare/types' +import { + appendParam, + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listAccessServiceTokensTool: ToolConfig< + CloudflareListAccessServiceTokensParams, + CloudflareListAccessServiceTokensResponse +> = { + id: 'cloudflare_list_access_service_tokens', + name: 'Cloudflare List Access Service Tokens', + description: + 'Lists the Cloudflare Access (Zero Trust) service tokens in an account, which let machines authenticate to Access-protected applications. Client secrets are never returned by this endpoint — only on creation. Requires an API token with Account Access: Service Tokens Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Service tokens are account-scoped', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by service token name', + }, + search: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Free-text search across service tokens', + }, + page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Page number for pagination', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of service tokens per page', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/service_tokens` + ) + appendParam(url, 'name', params.name) + appendParam(url, 'search', params.search) + appendParam(url, 'page', params.page) + appendParam(url, 'per_page', params.per_page) + return url.toString() + }, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse(response) + + if (!data.success) { + return { + success: false, + output: { service_tokens: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list Access service tokens'), + } + } + + const tokens = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + service_tokens: tokens.map((token) => ({ + id: token.id ?? '', + name: token.name ?? null, + client_id: token.client_id ?? null, + duration: token.duration ?? null, + enabled: token.enabled ?? null, + expires_at: token.expires_at ?? null, + last_seen_at: token.last_seen_at ?? null, + created_at: token.created_at ?? null, + updated_at: token.updated_at ?? null, + })), + total_count: data.result_info?.total_count ?? tokens.length, + }, + } + }, + + outputs: { + service_tokens: { + type: 'array', + description: 'Access service tokens in the account', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Service token identifier' }, + name: { type: 'string', description: 'Service token name', optional: true }, + client_id: { + type: 'string', + description: 'Client ID sent in the CF-Access-Client-Id header', + optional: true, + }, + duration: { + type: 'string', + description: 'How long the token stays valid before it expires', + optional: true, + }, + enabled: { type: 'boolean', description: 'Whether the token is active', optional: true }, + expires_at: { type: 'string', description: 'Expiry timestamp', optional: true }, + last_seen_at: { + type: 'string', + description: 'When the token was last used', + optional: true, + }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + updated_at: { type: 'string', description: 'Last update timestamp', optional: true }, + }, + }, + }, + total_count: { type: 'number', description: 'Total number of service tokens' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_certificates.ts b/apps/sim/tools/cloudflare/list_certificates.ts index 41a44803d5c..3bec7e6799a 100644 --- a/apps/sim/tools/cloudflare/list_certificates.ts +++ b/apps/sim/tools/cloudflare/list_certificates.ts @@ -1,7 +1,9 @@ import type { CloudflareListCertificatesParams, CloudflareListCertificatesResponse, + CloudflareRawCertificatePack, } from '@/tools/cloudflare/types' +import { readCloudflareResponse } from '@/tools/cloudflare/utils' import type { ToolConfig } from '@/tools/types' export const listCertificatesTool: ToolConfig< @@ -24,7 +26,8 @@ export const listCertificatesTool: ToolConfig< type: 'string', required: false, visibility: 'user-or-llm', - description: 'Filter certificate packs by status (e.g., "all", "active", "pending")', + description: + 'Set to "all" to include every certificate pack regardless of status. Cloudflare documents no other value for this filter; omitting it returns only active packs', }, page: { type: 'number', @@ -55,7 +58,7 @@ export const listCertificatesTool: ToolConfig< request: { url: (params) => { const url = new URL( - `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/ssl/certificate_packs` + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/ssl/certificate_packs` ) if (params.status) url.searchParams.append('status', params.status) if (params.page) url.searchParams.append('page', String(params.page)) @@ -71,7 +74,7 @@ export const listCertificatesTool: ToolConfig< }, transformResponse: async (response: Response) => { - const data = await response.json() + const data = await readCloudflareResponse(response) if (!data.success) { return { @@ -85,14 +88,14 @@ export const listCertificatesTool: ToolConfig< success: true, output: { certificates: - data.result?.map((cert: any) => ({ + data.result?.map((cert) => ({ id: cert.id ?? '', type: cert.type ?? '', hosts: cert.hosts ?? [], primary_certificate: cert.primary_certificate ?? '', status: cert.status ?? '', certificates: - cert.certificates?.map((c: any) => ({ + cert.certificates?.map((c) => ({ id: c.id ?? '', hosts: c.hosts ?? [], issuer: c.issuer ?? '', @@ -111,11 +114,11 @@ export const listCertificatesTool: ToolConfig< validity_days: cert.validity_days ?? 0, certificate_authority: cert.certificate_authority ?? '', validation_errors: - cert.validation_errors?.map((e: any) => ({ + cert.validation_errors?.map((e) => ({ message: e.message ?? '', })) ?? [], validation_records: - cert.validation_records?.map((r: any) => ({ + cert.validation_records?.map((r) => ({ cname: r.cname ?? '', cname_target: r.cname_target ?? '', emails: r.emails ?? [], @@ -126,7 +129,7 @@ export const listCertificatesTool: ToolConfig< txt_value: r.txt_value ?? '', })) ?? [], dcv_delegation_records: - cert.dcv_delegation_records?.map((r: any) => ({ + cert.dcv_delegation_records?.map((r) => ({ cname: r.cname ?? '', cname_target: r.cname_target ?? '', emails: r.emails ?? [], diff --git a/apps/sim/tools/cloudflare/list_dns_records.ts b/apps/sim/tools/cloudflare/list_dns_records.ts index 28520193bb3..36b91d12dce 100644 --- a/apps/sim/tools/cloudflare/list_dns_records.ts +++ b/apps/sim/tools/cloudflare/list_dns_records.ts @@ -1,7 +1,9 @@ import type { CloudflareListDnsRecordsParams, CloudflareListDnsRecordsResponse, + CloudflareRawDnsRecord, } from '@/tools/cloudflare/types' +import { readCloudflareResponse } from '@/tools/cloudflare/utils' import type { ToolConfig } from '@/tools/types' export const listDnsRecordsTool: ToolConfig< @@ -109,7 +111,9 @@ export const listDnsRecordsTool: ToolConfig< request: { url: (params) => { - const url = new URL(`https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records`) + const url = new URL( + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/dns_records` + ) if (params.type) url.searchParams.append('type', params.type) if (params.name) url.searchParams.append('name.exact', params.name) if (params.content) url.searchParams.append('content.exact', params.content) @@ -133,7 +137,7 @@ export const listDnsRecordsTool: ToolConfig< }, transformResponse: async (response: Response) => { - const data = await response.json() + const data = await readCloudflareResponse(response) if (!data.success) { return { @@ -147,7 +151,7 @@ export const listDnsRecordsTool: ToolConfig< success: true, output: { records: - data.result?.map((record: any) => ({ + data.result?.map((record) => ({ id: record.id ?? '', zone_id: record.zone_id ?? '', zone_name: record.zone_name ?? '', diff --git a/apps/sim/tools/cloudflare/list_managed_ruleset_overrides.ts b/apps/sim/tools/cloudflare/list_managed_ruleset_overrides.ts new file mode 100644 index 00000000000..603a58d2990 --- /dev/null +++ b/apps/sim/tools/cloudflare/list_managed_ruleset_overrides.ts @@ -0,0 +1,116 @@ +import type { + CloudflareListManagedRulesetOverridesParams, + CloudflareListManagedRulesetOverridesResponse, + CloudflareRawRuleset, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listManagedRulesetOverridesTool: ToolConfig< + CloudflareListManagedRulesetOverridesParams, + CloudflareListManagedRulesetOverridesResponse +> = { + id: 'cloudflare_list_managed_ruleset_overrides', + name: 'Cloudflare List Managed Ruleset Overrides', + description: + 'Lists the WAF managed rulesets deployed on a zone together with the overrides applied to each one. Cloudflare has no dedicated overrides endpoint — overrides live on the "execute" rules of the http_request_firewall_managed phase entry point ruleset, which this reads. Requires an API token with Zone WAF Read.', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID to read managed ruleset deployments and overrides for', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/phases/http_request_firewall_managed/entrypoint`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse(response) + + if (!data.success) { + return { + success: false, + output: { ruleset_id: '', deployments: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list managed ruleset overrides'), + } + } + + const rules = Array.isArray(data.result?.rules) ? data.result.rules : [] + const deployments = rules + .filter((rule) => rule.action === 'execute') + .map((rule) => ({ + rule_id: rule.id ?? '', + managed_ruleset_id: rule.action_parameters?.id ?? null, + description: rule.description ?? '', + expression: rule.expression ?? '', + enabled: rule.enabled ?? false, + overrides: rule.action_parameters?.overrides ?? null, + })) + + return { + success: true, + output: { + ruleset_id: data.result?.id ?? '', + deployments, + total_count: deployments.length, + }, + } + }, + + outputs: { + ruleset_id: { + type: 'string', + description: + 'Ruleset ID of the http_request_firewall_managed entry point, needed to edit a deployment rule', + }, + deployments: { + type: 'array', + description: 'Managed rulesets deployed on the zone and the overrides applied to each', + items: { + type: 'object', + properties: { + rule_id: { + type: 'string', + description: 'ID of the execute rule that deploys the managed ruleset', + }, + managed_ruleset_id: { + type: 'string', + description: 'ID of the deployed managed ruleset', + optional: true, + }, + description: { type: 'string', description: 'Description of the deployment rule' }, + expression: { + type: 'string', + description: 'Filter expression scoping which requests the managed ruleset runs on', + }, + enabled: { type: 'boolean', description: 'Whether the deployment is enabled' }, + overrides: { + type: 'json', + description: + 'Overrides applied to the managed ruleset, at three levels. Cloudflare documents action, enabled, and sensitivity_level at the ruleset (top) level; category, action, enabled, and sensitivity_level per category; and id, action, enabled, score_threshold, and sensitivity_level per rule. Rule overrides beat category overrides, which beat the ruleset-level override. sensitivity_level applies only to the DDoS phases, so for a WAF managed ruleset the rule-level properties are action, enabled, and score_threshold', + optional: true, + }, + }, + }, + }, + total_count: { type: 'number', description: 'Number of managed ruleset deployments found' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_r2_buckets.ts b/apps/sim/tools/cloudflare/list_r2_buckets.ts new file mode 100644 index 00000000000..cd73043771d --- /dev/null +++ b/apps/sim/tools/cloudflare/list_r2_buckets.ts @@ -0,0 +1,160 @@ +import type { + CloudflareListR2BucketsParams, + CloudflareListR2BucketsResponse, + CloudflareRawR2Bucket, +} from '@/tools/cloudflare/types' +import { + appendParam, + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listR2BucketsTool: ToolConfig< + CloudflareListR2BucketsParams, + CloudflareListR2BucketsResponse +> = { + id: 'cloudflare_list_r2_buckets', + name: 'Cloudflare List R2 Buckets', + description: + 'Lists the R2 object storage buckets in an account. Requires an API token with Account Workers R2 Storage Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. R2 buckets are account-scoped', + }, + name_contains: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Only return buckets whose name contains this substring', + }, + start_after: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Bucket name to start listing after', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination cursor returned by a previous call', + }, + direction: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Sort direction by bucket name: asc or desc', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of buckets per page', + }, + jurisdiction: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Data-residency jurisdiction to list within: default, eu, or fedramp', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/r2/buckets` + ) + appendParam(url, 'name_contains', params.name_contains) + appendParam(url, 'start_after', params.start_after) + appendParam(url, 'cursor', params.cursor) + appendParam(url, 'direction', params.direction) + appendParam(url, 'per_page', params.per_page) + // `direction` only means something alongside an ordering field, and `name` + // is the sole value Cloudflare documents for `order`. + if (params.direction) url.searchParams.append('order', 'name') + return url.toString() + }, + method: 'GET', + headers: (params) => { + const headers = cloudflareHeaders(params.apiKey) + if (params.jurisdiction) headers['cf-r2-jurisdiction'] = params.jurisdiction + return headers + }, + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse<{ buckets?: CloudflareRawR2Bucket[] }>(response) + + if (!data.success) { + return { + success: false, + output: { buckets: [], cursor: null }, + error: cloudflareErrorMessage(data, 'Failed to list R2 buckets'), + } + } + + const buckets = Array.isArray(data.result?.buckets) ? data.result.buckets : [] + + return { + success: true, + output: { + buckets: buckets.map((bucket) => ({ + name: bucket.name ?? '', + creation_date: bucket.creation_date ?? null, + location: bucket.location ?? null, + storage_class: bucket.storage_class ?? null, + jurisdiction: bucket.jurisdiction ?? null, + })), + cursor: data.result_info?.cursor ?? null, + }, + } + }, + + outputs: { + buckets: { + type: 'array', + description: 'R2 buckets in the account', + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Bucket name' }, + creation_date: { type: 'string', description: 'Creation timestamp', optional: true }, + location: { + type: 'string', + description: + 'Location hint the bucket was created with (apac, eeur, enam, weur, wnam, or oc)', + optional: true, + }, + storage_class: { + type: 'string', + description: 'Default storage class (Standard or InfrequentAccess)', + optional: true, + }, + jurisdiction: { + type: 'string', + description: 'Data-residency jurisdiction (default, eu, or fedramp)', + optional: true, + }, + }, + }, + }, + cursor: { + type: 'string', + description: 'Pagination cursor to pass to the next call', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_rate_limit_rules.ts b/apps/sim/tools/cloudflare/list_rate_limit_rules.ts new file mode 100644 index 00000000000..09a723c58ec --- /dev/null +++ b/apps/sim/tools/cloudflare/list_rate_limit_rules.ts @@ -0,0 +1,119 @@ +import type { + CloudflareListRateLimitRulesParams, + CloudflareRulesetResponse, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listRateLimitRulesTool: ToolConfig< + CloudflareListRateLimitRulesParams, + CloudflareRulesetResponse +> = { + id: 'cloudflare_list_rate_limit_rules', + name: 'Cloudflare List Rate Limiting Rules', + description: + 'Lists the rate limiting rules on a zone by reading the http_ratelimit phase entry point ruleset. This uses the current Rulesets-based rate limiting API; the legacy rate_limits endpoint is no longer available. The returned ruleset ID is what "Create Rate Limiting Rule", "Update Rate Limiting Rule", and "Delete Ruleset Rule" need. Requires an API token with Zone WAF Read.', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID to list rate limiting rules for', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/phases/http_ratelimit/entrypoint`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to list rate limiting rules'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { + type: 'string', + description: 'Ruleset ID of the http_ratelimit entry point, needed to create or edit rules', + }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind' }, + phase: { type: 'string', description: 'Phase the ruleset runs in (http_ratelimit)' }, + version: { type: 'string', description: 'Ruleset version', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rate limiting rules, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { + type: 'string', + description: 'Action applied once the rate limit is exceeded', + }, + action_parameters: { + type: 'json', + description: 'Action-specific parameters, such as a custom block response', + optional: true, + }, + expression: { + type: 'string', + description: 'Filter expression selecting the requests the rule applies to', + }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { type: 'string', description: 'Rule reference tag', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { + type: 'json', + description: + 'Rate limiting configuration (characteristics, period, requests_per_period, mitigation_timeout, counting_expression, requests_to_origin)', + optional: true, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_rulesets.ts b/apps/sim/tools/cloudflare/list_rulesets.ts new file mode 100644 index 00000000000..25cffb0a1ee --- /dev/null +++ b/apps/sim/tools/cloudflare/list_rulesets.ts @@ -0,0 +1,131 @@ +import type { + CloudflareListRulesetsParams, + CloudflareListRulesetsResponse, + CloudflareRawRuleset, +} from '@/tools/cloudflare/types' +import { + appendParam, + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listRulesetsTool: ToolConfig< + CloudflareListRulesetsParams, + CloudflareListRulesetsResponse +> = { + id: 'cloudflare_list_rulesets', + name: 'Cloudflare List Rulesets', + description: + 'Lists every ruleset defined on a zone across all phases (WAF custom rules, managed rules, rate limiting, transform rules, and more). The list response deliberately omits the rules inside each ruleset — use "Get Ruleset" to read them. Requires an API token with Zone WAF Read (or another matching ruleset Read permission).', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID to list rulesets for', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of rulesets to return per page', + }, + cursor: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Cursor for the next page, taken from the cursor output of a previous call. This endpoint paginates by cursor, not by page number', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets` + ) + appendParam(url, 'per_page', params.per_page) + appendParam(url, 'cursor', params.cursor) + return url.toString() + }, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse(response) + + if (!data.success) { + return { + success: false, + output: { rulesets: [], total_count: 0, cursor: null }, + error: cloudflareErrorMessage(data, 'Failed to list rulesets'), + } + } + + const rulesets = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + rulesets: rulesets.map((ruleset) => ({ + id: ruleset.id ?? '', + name: ruleset.name ?? '', + description: ruleset.description ?? '', + kind: ruleset.kind ?? '', + phase: ruleset.phase ?? '', + version: ruleset.version ?? null, + last_updated: ruleset.last_updated ?? null, + })), + total_count: rulesets.length, + cursor: data.result_info?.cursors?.after ?? null, + }, + } + }, + + outputs: { + rulesets: { + type: 'array', + description: 'Rulesets defined on the zone', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Ruleset identifier' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { + type: 'string', + description: 'Ruleset kind (managed, custom, root, or zone)', + }, + phase: { + type: 'string', + description: + 'Phase the ruleset runs in (e.g., http_request_firewall_custom, http_request_firewall_managed, http_ratelimit)', + }, + version: { type: 'string', description: 'Ruleset version', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + }, + }, + }, + total_count: { type: 'number', description: 'Number of rulesets returned on this page' }, + cursor: { + type: 'string', + description: 'Cursor to pass to the next call to read the following page, when more remain', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_tunnels.ts b/apps/sim/tools/cloudflare/list_tunnels.ts new file mode 100644 index 00000000000..14f8821e1da --- /dev/null +++ b/apps/sim/tools/cloudflare/list_tunnels.ts @@ -0,0 +1,226 @@ +import type { + CloudflareListTunnelsParams, + CloudflareListTunnelsResponse, + CloudflareRawTunnel, +} from '@/tools/cloudflare/types' +import { + appendParam, + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listTunnelsTool: ToolConfig< + CloudflareListTunnelsParams, + CloudflareListTunnelsResponse +> = { + id: 'cloudflare_list_tunnels', + name: 'Cloudflare List Tunnels', + description: + 'Lists the Cloudflare Tunnels (cloudflared) in an account, with their health status and active connections. Requires an API token with Account Cloudflare Tunnel Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Tunnels are account-scoped', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by exact tunnel name', + }, + status: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by tunnel health: inactive, degraded, healthy, or down', + }, + uuid: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by tunnel UUID', + }, + is_deleted: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether to return deleted tunnels instead of active ones', + }, + include_prefix: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Only include tunnels whose name starts with this prefix', + }, + exclude_prefix: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Exclude tunnels whose name starts with this prefix', + }, + existed_at: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Return tunnels that existed at this RFC 3339 timestamp', + }, + was_active_at: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Return tunnels that were active at this RFC 3339 timestamp', + }, + was_inactive_at: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Return tunnels that were inactive at this RFC 3339 timestamp', + }, + page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Page number for pagination', + }, + per_page: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Number of tunnels per page', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/cfd_tunnel` + ) + appendParam(url, 'name', params.name) + appendParam(url, 'status', params.status) + appendParam(url, 'uuid', params.uuid) + if (params.is_deleted !== undefined) { + url.searchParams.append('is_deleted', String(params.is_deleted)) + } + appendParam(url, 'include_prefix', params.include_prefix) + appendParam(url, 'exclude_prefix', params.exclude_prefix) + appendParam(url, 'existed_at', params.existed_at) + appendParam(url, 'was_active_at', params.was_active_at) + appendParam(url, 'was_inactive_at', params.was_inactive_at) + appendParam(url, 'page', params.page) + appendParam(url, 'per_page', params.per_page) + return url.toString() + }, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse(response) + + if (!data.success) { + return { + success: false, + output: { tunnels: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list tunnels'), + } + } + + const tunnels = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + tunnels: tunnels.map((tunnel) => ({ + id: tunnel.id ?? '', + name: tunnel.name ?? null, + account_tag: tunnel.account_tag ?? null, + config_src: tunnel.config_src ?? null, + status: tunnel.status ?? null, + tun_type: tunnel.tun_type ?? null, + remote_config: tunnel.remote_config ?? null, + metadata: tunnel.metadata ?? null, + created_at: tunnel.created_at ?? null, + deleted_at: tunnel.deleted_at ?? null, + conns_active_at: tunnel.conns_active_at ?? null, + conns_inactive_at: tunnel.conns_inactive_at ?? null, + connections: tunnel.connections ?? null, + })), + total_count: data.result_info?.total_count ?? tunnels.length, + }, + } + }, + + outputs: { + tunnels: { + type: 'array', + description: 'Cloudflare Tunnels in the account', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Tunnel identifier' }, + name: { type: 'string', description: 'Tunnel name', optional: true }, + account_tag: { + type: 'string', + description: 'Account the tunnel belongs to', + optional: true, + }, + config_src: { + type: 'string', + description: 'Where the tunnel configuration lives: local or cloudflare', + optional: true, + }, + status: { + type: 'string', + description: 'Tunnel health: inactive, degraded, healthy, or down', + optional: true, + }, + tun_type: { + type: 'string', + description: 'Tunnel type, e.g. cfd_tunnel, warp_connector, or warp', + optional: true, + }, + remote_config: { + type: 'boolean', + description: 'Whether the tunnel is remotely managed', + optional: true, + }, + metadata: { + type: 'json', + description: 'Metadata associated with the tunnel', + optional: true, + }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + deleted_at: { type: 'string', description: 'Deletion timestamp', optional: true }, + conns_active_at: { + type: 'string', + description: 'When the tunnel last had active connections', + optional: true, + }, + conns_inactive_at: { + type: 'string', + description: 'When the tunnel last lost all connections', + optional: true, + }, + connections: { + type: 'json', + description: 'Active connector connections for the tunnel', + optional: true, + }, + }, + }, + }, + total_count: { type: 'number', description: 'Total number of tunnels' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_worker_routes.ts b/apps/sim/tools/cloudflare/list_worker_routes.ts new file mode 100644 index 00000000000..96dffef09f9 --- /dev/null +++ b/apps/sim/tools/cloudflare/list_worker_routes.ts @@ -0,0 +1,94 @@ +import type { + CloudflareListWorkerRoutesParams, + CloudflareListWorkerRoutesResponse, + CloudflareRawWorkerRoute, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listWorkerRoutesTool: ToolConfig< + CloudflareListWorkerRoutesParams, + CloudflareListWorkerRoutesResponse +> = { + id: 'cloudflare_list_worker_routes', + name: 'Cloudflare List Worker Routes', + description: + 'Lists the Workers routes on a zone, showing which URL patterns are handled by which Worker script. Unlike the Workers script endpoints, routes are zone-scoped. Requires an API token with Zone Workers Routes Read.', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The zone ID to list Workers routes for. Routes are zone-scoped, not account-scoped', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/workers/routes`, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse(response) + + if (!data.success) { + return { + success: false, + output: { routes: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list Worker routes'), + } + } + + const routes = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + routes: routes.map((route) => ({ + id: route.id ?? '', + pattern: route.pattern ?? '', + script: route.script ?? null, + })), + total_count: routes.length, + }, + } + }, + + outputs: { + routes: { + type: 'array', + description: 'Workers routes on the zone', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Route identifier' }, + pattern: { + type: 'string', + description: 'URL pattern the route matches, e.g. example.com/*', + }, + script: { + type: 'string', + description: 'Name of the Workers script handling the route', + optional: true, + }, + }, + }, + }, + total_count: { type: 'number', description: 'Number of routes returned' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_worker_scripts.ts b/apps/sim/tools/cloudflare/list_worker_scripts.ts new file mode 100644 index 00000000000..c41bfdd2542 --- /dev/null +++ b/apps/sim/tools/cloudflare/list_worker_scripts.ts @@ -0,0 +1,158 @@ +import type { + CloudflareListWorkerScriptsParams, + CloudflareListWorkerScriptsResponse, + CloudflareRawWorkerScript, +} from '@/tools/cloudflare/types' +import { + appendParam, + cloudflareErrorMessage, + cloudflareHeaders, + readCloudflareResponse, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const listWorkerScriptsTool: ToolConfig< + CloudflareListWorkerScriptsParams, + CloudflareListWorkerScriptsResponse +> = { + id: 'cloudflare_list_worker_scripts', + name: 'Cloudflare List Worker Scripts', + description: + 'Lists the Workers scripts deployed in an account. Requires an API token with Account Workers Scripts Read.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Workers scripts are account-scoped', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Filter scripts by tag. Cloudflare expects a comma-separated list of tag:allowed pairs where allowed is yes or no, e.g. team:core:yes,deprecated:no', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => { + const url = new URL( + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/workers/scripts` + ) + appendParam(url, 'tags', params.tags) + return url.toString() + }, + method: 'GET', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await readCloudflareResponse(response) + + if (!data.success) { + return { + success: false, + output: { scripts: [], total_count: 0 }, + error: cloudflareErrorMessage(data, 'Failed to list Worker scripts'), + } + } + + const scripts = Array.isArray(data.result) ? data.result : [] + + return { + success: true, + output: { + scripts: scripts.map((script) => ({ + id: script.id ?? '', + tag: script.tag ?? null, + etag: script.etag ?? null, + created_on: script.created_on ?? null, + modified_on: script.modified_on ?? null, + usage_model: script.usage_model ?? null, + placement_mode: script.placement_mode ?? null, + logpush: script.logpush ?? null, + has_assets: script.has_assets ?? null, + has_modules: script.has_modules ?? null, + compatibility_date: script.compatibility_date ?? null, + compatibility_flags: script.compatibility_flags ?? null, + routes: script.routes ?? null, + tail_consumers: script.tail_consumers ?? null, + })), + total_count: scripts.length, + }, + } + }, + + outputs: { + scripts: { + type: 'array', + description: 'Workers scripts in the account', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Script name' }, + tag: { + type: 'string', + description: 'Immutable script identifier, distinct from the script name', + optional: true, + }, + etag: { type: 'string', description: 'Hash of the script content', optional: true }, + created_on: { type: 'string', description: 'Creation timestamp', optional: true }, + modified_on: { type: 'string', description: 'Last deployment timestamp', optional: true }, + usage_model: { + type: 'string', + description: 'Billing usage model (standard, bundled, or unbound)', + optional: true, + }, + placement_mode: { + type: 'string', + description: 'Smart placement mode (smart or targeted)', + optional: true, + }, + logpush: { + type: 'boolean', + description: 'Whether Workers Logpush is enabled', + optional: true, + }, + has_assets: { + type: 'boolean', + description: 'Whether the script ships static assets', + optional: true, + }, + has_modules: { + type: 'boolean', + description: 'Whether the script uses ES modules', + optional: true, + }, + compatibility_date: { + type: 'string', + description: 'Workers runtime compatibility date', + optional: true, + }, + compatibility_flags: { + type: 'array', + description: 'Workers runtime compatibility flags', + items: { type: 'string', description: 'Compatibility flag' }, + optional: true, + }, + routes: { type: 'json', description: 'Routes the script is bound to', optional: true }, + tail_consumers: { + type: 'json', + description: "Workers that consume this script's tail events", + optional: true, + }, + }, + }, + }, + total_count: { type: 'number', description: 'Number of scripts returned' }, + }, +} diff --git a/apps/sim/tools/cloudflare/list_zones.ts b/apps/sim/tools/cloudflare/list_zones.ts index 10bfe850b76..f9328127388 100644 --- a/apps/sim/tools/cloudflare/list_zones.ts +++ b/apps/sim/tools/cloudflare/list_zones.ts @@ -1,7 +1,9 @@ import type { CloudflareListZonesParams, CloudflareListZonesResponse, + CloudflareRawZone, } from '@/tools/cloudflare/types' +import { readCloudflareResponse } from '@/tools/cloudflare/utils' import type { ToolConfig } from '@/tools/types' export const listZonesTool: ToolConfig = { @@ -88,7 +90,7 @@ export const listZonesTool: ToolConfig { - const data = await response.json() + const data = await readCloudflareResponse(response) if (!data.success) { return { @@ -102,7 +104,7 @@ export const listZonesTool: ToolConfig ({ + data.result?.map((zone) => ({ id: zone.id ?? '', name: zone.name ?? '', status: zone.status ?? '', diff --git a/apps/sim/tools/cloudflare/purge_cache.ts b/apps/sim/tools/cloudflare/purge_cache.ts index 0eee61ce25d..7acd4155571 100644 --- a/apps/sim/tools/cloudflare/purge_cache.ts +++ b/apps/sim/tools/cloudflare/purge_cache.ts @@ -59,7 +59,8 @@ export const purgeCacheTool: ToolConfig `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/purge_cache`, + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/purge_cache`, method: 'POST', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, @@ -106,6 +107,20 @@ export const purgeCacheTool: ToolConfig 1) { + throw new Error( + `Only one purge target kind is allowed per request, but ${targets.join(' and ')} were provided. Run a separate purge for each.` + ) + } + return body }, }, diff --git a/apps/sim/tools/cloudflare/revoke_access_service_token.ts b/apps/sim/tools/cloudflare/revoke_access_service_token.ts new file mode 100644 index 00000000000..2215d8d777a --- /dev/null +++ b/apps/sim/tools/cloudflare/revoke_access_service_token.ts @@ -0,0 +1,99 @@ +import type { + CloudflareAccessServiceTokenResponse, + CloudflareRevokeAccessServiceTokenParams, +} from '@/tools/cloudflare/types' +import { cloudflareErrorMessage, cloudflareHeaders } from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const revokeAccessServiceTokenTool: ToolConfig< + CloudflareRevokeAccessServiceTokenParams, + CloudflareAccessServiceTokenResponse +> = { + id: 'cloudflare_revoke_access_service_token', + name: 'Cloudflare Revoke Access Service Token', + description: + 'Permanently deletes a Cloudflare Access (Zero Trust) service token, revoking it. Every machine or integration still presenting that client ID and secret is locked out of the Access-protected applications immediately, and the secret cannot be recovered. This cannot be undone. Requires an API token with Account Access: Service Tokens Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Service tokens are account-scoped', + }, + serviceTokenId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The service token ID to revoke permanently', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/service_tokens/${params.serviceTokenId.trim()}`, + method: 'DELETE', + headers: (params) => cloudflareHeaders(params.apiKey), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: { + id: '', + name: null, + client_id: null, + duration: null, + enabled: null, + expires_at: null, + last_seen_at: null, + created_at: null, + updated_at: null, + }, + error: cloudflareErrorMessage(data, 'Failed to revoke Access service token'), + } + } + + const token = data.result + return { + success: true, + output: { + id: token?.id ?? '', + name: token?.name ?? null, + client_id: token?.client_id ?? null, + duration: token?.duration ?? null, + enabled: token?.enabled ?? null, + expires_at: token?.expires_at ?? null, + last_seen_at: token?.last_seen_at ?? null, + created_at: token?.created_at ?? null, + updated_at: token?.updated_at ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Identifier of the revoked service token' }, + name: { type: 'string', description: 'Service token name', optional: true }, + client_id: { + type: 'string', + description: 'Client ID that is no longer accepted', + optional: true, + }, + duration: { type: 'string', description: 'Configured token lifetime', optional: true }, + enabled: { type: 'boolean', description: 'Whether the token was active', optional: true }, + expires_at: { type: 'string', description: 'Expiry timestamp', optional: true }, + last_seen_at: { type: 'string', description: 'When the token was last used', optional: true }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + updated_at: { type: 'string', description: 'Last update timestamp', optional: true }, + }, +} diff --git a/apps/sim/tools/cloudflare/types.ts b/apps/sim/tools/cloudflare/types.ts index cc52a9b1f36..cd5073fa547 100644 --- a/apps/sim/tools/cloudflare/types.ts +++ b/apps/sim/tools/cloudflare/types.ts @@ -4,6 +4,327 @@ interface CloudflareBaseParams { apiKey: string } +/** + * Pagination metadata Cloudflare attaches to list endpoints. Page-based + * endpoints populate `page`/`per_page`/`total_count`; the Rulesets engine and + * R2 use cursors instead, so every field is optional. + */ +export interface CloudflareResultInfo { + page?: number + per_page?: number + count?: number + total_count?: number + cursor?: string + cursors?: { + before?: string + after?: string + } +} + +/** + * The Cloudflare v4 response envelope. Every endpoint answers with this shape, + * and a `200 OK` carrying `success: false` is a failure — callers must branch + * on `success` rather than the HTTP status. `result` is absent on failures. + */ +export interface CloudflareEnvelope { + success?: boolean + errors?: Array<{ code?: number; message?: string }> + messages?: unknown[] + result?: TResult + result_info?: CloudflareResultInfo +} + +/** Raw rule payload inside a ruleset, as returned by the Rulesets API. */ +export interface CloudflareRawRule { + id?: string + version?: string + action?: string + action_parameters?: { + id?: string + overrides?: Record + [key: string]: unknown + } + expression?: string + description?: string + enabled?: boolean + ref?: string + last_updated?: string + categories?: string[] + logging?: Record + ratelimit?: Record +} + +/** Raw ruleset payload. `rules` is omitted by the list-rulesets endpoint. */ +export interface CloudflareRawRuleset { + id?: string + name?: string + description?: string + kind?: string + phase?: string + version?: string + last_updated?: string + rules?: CloudflareRawRule[] +} + +/** Raw Cloudflare Access application payload. */ +export interface CloudflareRawAccessApplication { + id?: string + name?: string + domain?: string + type?: string + aud?: string + session_duration?: string + allowed_idps?: string[] + app_launcher_visible?: boolean + auto_redirect_to_identity?: boolean + custom_deny_message?: string + custom_deny_url?: string + logo_url?: string + self_hosted_domains?: string[] + destinations?: unknown[] + tags?: string[] + policies?: unknown[] +} + +/** Raw Cloudflare Access policy payload. */ +export interface CloudflareRawAccessPolicy { + id?: string + name?: string + decision?: string + precedence?: number + include?: unknown[] + exclude?: unknown[] + require?: unknown[] + session_duration?: string + approval_required?: boolean + isolation_required?: boolean + purpose_justification_required?: boolean + purpose_justification_prompt?: string + created_at?: string + updated_at?: string +} + +/** Raw Cloudflare Access group payload. */ +export interface CloudflareRawAccessGroup { + id?: string + name?: string + is_default?: unknown[] + include?: unknown[] + exclude?: unknown[] + require?: unknown[] + created_at?: string + updated_at?: string +} + +/** Raw Cloudflare Access identity provider payload. */ +export interface CloudflareRawAccessIdentityProvider { + id?: string + name?: string + type?: string + read_only?: boolean + config?: Record + scim_config?: Record +} + +/** Raw Cloudflare Access service token payload. `client_secret` only on create. */ +export interface CloudflareRawAccessServiceToken { + id?: string + name?: string + client_id?: string + client_secret?: string + duration?: string + enabled?: boolean + expires_at?: string + last_seen_at?: string + created_at?: string + updated_at?: string +} + +/** Raw R2 bucket payload. */ +export interface CloudflareRawR2Bucket { + name?: string + creation_date?: string + location?: string + storage_class?: string + jurisdiction?: string +} + +/** Raw Workers script payload from the list-scripts endpoint. */ +export interface CloudflareRawWorkerScript { + id?: string + tag?: string + etag?: string + created_on?: string + modified_on?: string + usage_model?: string + placement_mode?: string + logpush?: boolean + has_assets?: boolean + has_modules?: boolean + compatibility_date?: string + compatibility_flags?: string[] + routes?: unknown[] + tail_consumers?: unknown[] +} + +/** Raw Workers route payload. */ +export interface CloudflareRawWorkerRoute { + id?: string + pattern?: string + script?: string +} + +/** Raw Cloudflare Tunnel (cloudflared) payload. */ +export interface CloudflareRawTunnel { + id?: string + name?: string + account_tag?: string + config_src?: string + status?: string + tun_type?: string + remote_config?: boolean + metadata?: Record + created_at?: string + deleted_at?: string + conns_active_at?: string + conns_inactive_at?: string + connections?: unknown[] +} + +/** Raw zone payload from the zones endpoints. */ +export interface CloudflareRawZone { + id?: string + name?: string + status?: string + paused?: boolean + type?: string + name_servers?: string[] + original_name_servers?: string[] + created_on?: string + modified_on?: string + activated_on?: string + development_mode?: number + plan?: { + id?: string + name?: string + price?: number + is_subscribed?: boolean + frequency?: string + currency?: string + legacy_id?: string + } + account?: { id?: string; name?: string } + owner?: { id?: string; name?: string; type?: string } + meta?: { + cdn_only?: boolean + custom_certificate_quota?: number + dns_only?: boolean + foundation_dns?: boolean + page_rule_quota?: number + phishing_detected?: boolean + step?: number + } + vanity_name_servers?: string[] + permissions?: string[] +} + +/** Raw DNS record payload. */ +export interface CloudflareRawDnsRecord { + id?: string + zone_id?: string + zone_name?: string + type?: string + name?: string + content?: string + proxiable?: boolean + proxied?: boolean + ttl?: number + locked?: boolean + priority?: number + comment?: string + tags?: string[] + comment_modified_on?: string + tags_modified_on?: string + meta?: CloudflareDnsRecordMeta + created_on?: string + modified_on?: string +} + +/** Raw hostname-validation record shared by certificate pack validation fields. */ +export interface CloudflareRawValidationRecord { + cname?: string + cname_target?: string + emails?: string[] + http_body?: string + http_url?: string + status?: string + txt_name?: string + txt_value?: string +} + +/** Raw certificate inside a certificate pack. */ +export interface CloudflareRawCertificate { + id?: string + hosts?: string[] + issuer?: string + signature?: string + status?: string + bundle_method?: string + zone_id?: string + uploaded_on?: string + modified_on?: string + expires_on?: string + priority?: number + geo_restrictions?: CloudflareCertificateGeoRestrictions +} + +/** Raw certificate pack payload. */ +export interface CloudflareRawCertificatePack { + id?: string + type?: string + hosts?: string[] + primary_certificate?: string + status?: string + certificates?: CloudflareRawCertificate[] + cloudflare_branding?: boolean + validation_method?: string + validity_days?: number + certificate_authority?: string + validation_errors?: Array<{ message?: string }> + validation_records?: CloudflareRawValidationRecord[] + dcv_delegation_records?: CloudflareRawValidationRecord[] +} + +/** Raw DNS analytics aggregate block (`totals`, `min`, and `max` share this shape). */ +export interface CloudflareRawDnsAnalyticsAggregate { + queryCount?: number + uncachedCount?: number + staleCount?: number + responseTimeAvg?: number + responseTimeMedian?: number + responseTime90th?: number + responseTime99th?: number +} + +/** Raw DNS analytics report payload. */ +export interface CloudflareRawDnsAnalyticsReport { + totals?: CloudflareRawDnsAnalyticsAggregate + min?: CloudflareRawDnsAnalyticsAggregate + max?: CloudflareRawDnsAnalyticsAggregate + data?: Array<{ dimensions?: string[]; metrics?: number[] }> + data_lag?: number + rows?: number + query?: { + since?: string + until?: string + metrics?: string[] + dimensions?: string[] + filters?: string + sort?: string[] + limit?: number + } +} + export interface CloudflareListZonesParams extends CloudflareBaseParams { name?: string status?: string @@ -179,7 +500,7 @@ interface CloudflareDnsRecord { proxied: boolean ttl: number locked: boolean - priority?: number + priority?: number | null comment?: string | null tags: string[] comment_modified_on?: string | null @@ -438,7 +759,591 @@ export interface CloudflareUpdateZoneSettingResponse extends ToolResponse { } } +export interface CloudflareListRulesetsParams extends CloudflareBaseParams { + zoneId: string + per_page?: number + cursor?: string +} + +interface CloudflareRulesetSummary { + id: string + name: string + description: string + kind: string + phase: string + version: string | null + last_updated: string | null +} + +export interface CloudflareListRulesetsResponse extends ToolResponse { + output: { + rulesets: CloudflareRulesetSummary[] + total_count: number + cursor: string | null + } +} + +interface CloudflareRule { + id: string + version: string | null + action: string + action_parameters: Record | null + expression: string + description: string + enabled: boolean + ref: string | null + last_updated: string | null + categories: string[] + logging: Record | null + ratelimit: Record | null +} + +interface CloudflareRuleset extends CloudflareRulesetSummary { + rules: CloudflareRule[] +} + +export interface CloudflareGetRulesetParams extends CloudflareBaseParams { + zoneId: string + rulesetId: string +} + +export interface CloudflareRulesetResponse extends ToolResponse { + output: CloudflareRuleset +} + +export interface CloudflareCreateRulesetRuleParams extends CloudflareBaseParams { + zoneId: string + rulesetId: string + action: string + expression: string + description?: string + enabled?: boolean + ref?: string + position?: string + actionParameters?: string +} + +export interface CloudflareUpdateRulesetRuleParams extends CloudflareBaseParams { + zoneId: string + rulesetId: string + ruleId: string + action: string + expression: string + description?: string + enabled?: boolean + ref?: string + actionParameters?: string + ratelimit?: string + logging?: string +} + +export interface CloudflareDeleteRulesetRuleParams extends CloudflareBaseParams { + zoneId: string + rulesetId: string + ruleId: string +} + +export interface CloudflareGetRulesetEntrypointParams extends CloudflareBaseParams { + zoneId: string + phase: string +} + +export interface CloudflareCreateRulesetParams extends CloudflareBaseParams { + zoneId: string + name: string + phase: string + kind?: string + description?: string + rules?: unknown +} + +export interface CloudflareListRateLimitRulesParams extends CloudflareBaseParams { + zoneId: string +} + +export interface CloudflareListManagedRulesetOverridesParams extends CloudflareBaseParams { + zoneId: string +} + +export interface CloudflareListManagedRulesetOverridesResponse extends ToolResponse { + output: { + ruleset_id: string + deployments: Array<{ + rule_id: string + managed_ruleset_id: string | null + description: string + expression: string + enabled: boolean + overrides: Record | null + }> + total_count: number + } +} + +export interface CloudflareCreateRateLimitRuleParams extends CloudflareBaseParams { + zoneId: string + rulesetId: string + expression: string + characteristics: string + period: number + requestsPerPeriod: number + action?: string + mitigationTimeout?: number + counting_expression?: string + requestsToOrigin?: boolean + description?: string + enabled?: boolean +} + +export interface CloudflareUpdateRateLimitRuleParams extends CloudflareBaseParams { + zoneId: string + rulesetId: string + ruleId: string + expression: string + characteristics: string + period: number + requestsPerPeriod: number + action: string + mitigationTimeout?: number + counting_expression?: string + requestsToOrigin?: boolean + description?: string + enabled?: boolean +} + +interface CloudflareAccessApplication { + id: string + name: string | null + domain: string | null + type: string | null + aud: string | null + session_duration: string | null + allowed_idps: string[] | null + app_launcher_visible: boolean | null + auto_redirect_to_identity: boolean | null + custom_deny_message: string | null + custom_deny_url: string | null + logo_url: string | null + self_hosted_domains: string[] | null + destinations: unknown[] | null + tags: string[] | null + policies: unknown[] | null +} + +export interface CloudflareListAccessApplicationsParams extends CloudflareBaseParams { + accountId: string + name?: string + domain?: string + aud?: string + search?: string + exact?: boolean + page?: number + per_page?: number +} + +export interface CloudflareListAccessApplicationsResponse extends ToolResponse { + output: { + applications: CloudflareAccessApplication[] + total_count: number + } +} + +export interface CloudflareGetAccessApplicationParams extends CloudflareBaseParams { + accountId: string + appId: string +} + +export interface CloudflareAccessApplicationResponse extends ToolResponse { + output: CloudflareAccessApplication +} + +export interface CloudflareCreateAccessApplicationParams extends CloudflareBaseParams { + accountId: string + type: string + domain?: string + name?: string + sessionDuration?: string + allowedIdps?: string + appLauncherVisible?: boolean + autoRedirectToIdentity?: boolean + customDenyMessage?: string + customDenyUrl?: string + logoUrl?: string + tags?: string + policies?: string +} + +export interface CloudflareUpdateAccessApplicationParams + extends CloudflareCreateAccessApplicationParams { + appId: string +} + +export interface CloudflareDeleteAccessApplicationParams extends CloudflareBaseParams { + accountId: string + appId: string +} + +export interface CloudflareDeletedIdResponse extends ToolResponse { + output: { + id: string + } +} + +interface CloudflareAccessPolicy { + id: string + name: string | null + decision: string | null + precedence: number | null + include: unknown[] | null + exclude: unknown[] | null + require: unknown[] | null + session_duration: string | null + approval_required: boolean | null + isolation_required: boolean | null + purpose_justification_required: boolean | null + purpose_justification_prompt: string | null + created_at: string | null + updated_at: string | null +} + +export interface CloudflareListAccessPoliciesParams extends CloudflareBaseParams { + accountId: string + appId: string + page?: number + per_page?: number +} + +export interface CloudflareListAccessPoliciesResponse extends ToolResponse { + output: { + policies: CloudflareAccessPolicy[] + total_count: number + } +} + +export interface CloudflareCreateAccessPolicyParams extends CloudflareBaseParams { + accountId: string + appId: string + name: string + decision: string + include: string + exclude?: string + require?: string + precedence?: number + sessionDuration?: string + approvalRequired?: boolean + isolationRequired?: boolean + purposeJustificationRequired?: boolean + purposeJustificationPrompt?: string +} + +export interface CloudflareUpdateAccessPolicyParams extends CloudflareCreateAccessPolicyParams { + policyId: string +} + +export interface CloudflareAccessPolicyResponse extends ToolResponse { + output: CloudflareAccessPolicy +} + +export interface CloudflareDeleteAccessPolicyParams extends CloudflareBaseParams { + accountId: string + appId: string + policyId: string +} + +export interface CloudflareListAccessGroupsParams extends CloudflareBaseParams { + accountId: string + name?: string + search?: string + page?: number + per_page?: number +} + +export interface CloudflareListAccessGroupsResponse extends ToolResponse { + output: { + groups: Array<{ + id: string + name: string | null + is_default: unknown[] | null + include: unknown[] | null + exclude: unknown[] | null + require: unknown[] | null + created_at: string | null + updated_at: string | null + }> + total_count: number + } +} + +export interface CloudflareListAccessIdentityProvidersParams extends CloudflareBaseParams { + accountId: string +} + +export interface CloudflareListAccessIdentityProvidersResponse extends ToolResponse { + output: { + identity_providers: Array<{ + id: string + name: string | null + type: string | null + read_only: boolean | null + config: Record | null + scim_config: Record | null + }> + total_count: number + } +} + +export interface CloudflareListAccessServiceTokensParams extends CloudflareBaseParams { + accountId: string + name?: string + search?: string + page?: number + per_page?: number +} + +interface CloudflareAccessServiceToken { + id: string + name: string | null + client_id: string | null + duration: string | null + enabled: boolean | null + expires_at: string | null + last_seen_at: string | null + created_at: string | null + updated_at: string | null +} + +export interface CloudflareListAccessServiceTokensResponse extends ToolResponse { + output: { + service_tokens: CloudflareAccessServiceToken[] + total_count: number + } +} + +export interface CloudflareCreateAccessServiceTokenParams extends CloudflareBaseParams { + accountId: string + name: string + duration?: string +} + +export interface CloudflareCreateAccessServiceTokenResponse extends ToolResponse { + output: CloudflareAccessServiceToken & { + client_secret: string | null + } +} + +export interface CloudflareRevokeAccessServiceTokenParams extends CloudflareBaseParams { + accountId: string + serviceTokenId: string +} + +export interface CloudflareAccessServiceTokenResponse extends ToolResponse { + output: CloudflareAccessServiceToken +} + +interface CloudflareR2Bucket { + name: string + creation_date: string | null + location: string | null + storage_class: string | null + jurisdiction: string | null +} + +export interface CloudflareListR2BucketsParams extends CloudflareBaseParams { + accountId: string + name_contains?: string + start_after?: string + cursor?: string + direction?: string + per_page?: number + jurisdiction?: string +} + +export interface CloudflareListR2BucketsResponse extends ToolResponse { + output: { + buckets: CloudflareR2Bucket[] + cursor: string | null + } +} + +export interface CloudflareGetR2BucketParams extends CloudflareBaseParams { + accountId: string + bucketName: string + jurisdiction?: string +} + +export interface CloudflareCreateR2BucketParams extends CloudflareBaseParams { + accountId: string + bucketName: string + locationHint?: string + storageClass?: string + jurisdiction?: string +} + +export interface CloudflareR2BucketResponse extends ToolResponse { + output: CloudflareR2Bucket +} + +export interface CloudflareDeleteR2BucketParams extends CloudflareBaseParams { + accountId: string + bucketName: string + jurisdiction?: string +} + +export interface CloudflareDeleteR2BucketResponse extends ToolResponse { + output: { + name: string + } +} + +export interface CloudflareListWorkerScriptsParams extends CloudflareBaseParams { + accountId: string + tags?: string +} + +export interface CloudflareListWorkerScriptsResponse extends ToolResponse { + output: { + scripts: Array<{ + id: string + tag: string | null + etag: string | null + created_on: string | null + modified_on: string | null + usage_model: string | null + placement_mode: string | null + logpush: boolean | null + has_assets: boolean | null + has_modules: boolean | null + compatibility_date: string | null + compatibility_flags: string[] | null + routes: unknown[] | null + tail_consumers: unknown[] | null + }> + total_count: number + } +} + +export interface CloudflareGetWorkerScriptSettingsParams extends CloudflareBaseParams { + accountId: string + scriptName: string +} + +export interface CloudflareGetWorkerScriptSettingsResponse extends ToolResponse { + output: { + bindings: unknown[] | null + compatibility_date: string | null + compatibility_flags: string[] | null + limits: Record | null + logpush: boolean | null + migrations: Record | null + observability: Record | null + placement: Record | null + tags: string[] | null + tail_consumers: unknown[] | null + usage_model: string | null + } +} + +export interface CloudflareListWorkerRoutesParams extends CloudflareBaseParams { + zoneId: string +} + +export interface CloudflareListWorkerRoutesResponse extends ToolResponse { + output: { + routes: Array<{ + id: string + pattern: string + script: string | null + }> + total_count: number + } +} + +interface CloudflareTunnel { + id: string + name: string | null + account_tag: string | null + config_src: string | null + status: string | null + tun_type: string | null + remote_config: boolean | null + metadata: Record | null + created_at: string | null + deleted_at: string | null + conns_active_at: string | null + conns_inactive_at: string | null + connections: unknown[] | null +} + +export interface CloudflareListTunnelsParams extends CloudflareBaseParams { + accountId: string + name?: string + status?: string + uuid?: string + is_deleted?: boolean + include_prefix?: string + exclude_prefix?: string + existed_at?: string + was_active_at?: string + was_inactive_at?: string + page?: number + per_page?: number +} + +export interface CloudflareListTunnelsResponse extends ToolResponse { + output: { + tunnels: CloudflareTunnel[] + total_count: number + } +} + +export interface CloudflareGetTunnelParams extends CloudflareBaseParams { + accountId: string + tunnelId: string +} + +export interface CloudflareTunnelResponse extends ToolResponse { + output: CloudflareTunnel +} + +export interface CloudflareGetTunnelConfigurationParams extends CloudflareBaseParams { + accountId: string + tunnelId: string +} + +export interface CloudflareGetTunnelConfigurationResponse extends ToolResponse { + output: { + tunnel_id: string + account_id: string + version: number | null + source: string | null + created_at: string | null + config: Record | null + } +} + export type CloudflareResponse = + | CloudflareListRulesetsResponse + | CloudflareRulesetResponse + | CloudflareListManagedRulesetOverridesResponse + | CloudflareListAccessApplicationsResponse + | CloudflareAccessApplicationResponse + | CloudflareListAccessPoliciesResponse + | CloudflareAccessPolicyResponse + | CloudflareListAccessGroupsResponse + | CloudflareListAccessIdentityProvidersResponse + | CloudflareListAccessServiceTokensResponse + | CloudflareCreateAccessServiceTokenResponse + | CloudflareAccessServiceTokenResponse + | CloudflareDeletedIdResponse + | CloudflareListR2BucketsResponse + | CloudflareR2BucketResponse + | CloudflareDeleteR2BucketResponse + | CloudflareListWorkerScriptsResponse + | CloudflareGetWorkerScriptSettingsResponse + | CloudflareListWorkerRoutesResponse + | CloudflareListTunnelsResponse + | CloudflareTunnelResponse + | CloudflareGetTunnelConfigurationResponse | CloudflareListZonesResponse | CloudflareGetZoneResponse | CloudflareCreateZoneResponse diff --git a/apps/sim/tools/cloudflare/update_access_application.ts b/apps/sim/tools/cloudflare/update_access_application.ts new file mode 100644 index 00000000000..d314e9aeca1 --- /dev/null +++ b/apps/sim/tools/cloudflare/update_access_application.ts @@ -0,0 +1,241 @@ +import type { + CloudflareAccessApplicationResponse, + CloudflareUpdateAccessApplicationParams, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyAccessApplication, + mapAccessApplication, + parseCsvParam, + parseJsonArrayParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const updateAccessApplicationTool: ToolConfig< + CloudflareUpdateAccessApplicationParams, + CloudflareAccessApplicationResponse +> = { + id: 'cloudflare_update_access_application', + name: 'Cloudflare Update Access Application', + description: + 'Updates a Cloudflare Access (Zero Trust) application. This replaces the application definition rather than merging it, so send every field the application should keep — anything you omit reverts to its default, which can widen or break access. Read the current configuration with "Get Access Application" first. Requires an API token with Account Access: Apps and Policies Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + appId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access application ID to update', + }, + type: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Application type: self_hosted, saas, ssh, vnc, app_launcher, warp, biso, bookmark, dash_sso, infrastructure, rdp, mcp, mcp_portal, or proxy_endpoint', + }, + domain: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'The primary hostname and path secured by Access. Required for the self_hosted, ssh, vnc, rdp, and bookmark types; the saas, app_launcher, warp, biso, dash_sso, infrastructure, mcp, mcp_portal, and proxy_endpoint types do not accept it', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Friendly name shown in the dashboard and App Launcher', + }, + sessionDuration: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'How long an Access session stays valid, e.g. 24h or 30m', + }, + allowedIdps: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated identity provider IDs users may authenticate with', + }, + appLauncherVisible: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the application is shown in the App Launcher', + }, + autoRedirectToIdentity: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether users skip the identity provider picker', + }, + customDenyMessage: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Message shown to users who are denied access', + }, + customDenyUrl: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'URL denied users are redirected to', + }, + logoUrl: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Logo image URL shown in the dashboard and App Launcher', + }, + tags: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Comma-separated tag names categorizing the application', + }, + policies: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON array of policies to attach. Entries may be reusable policy IDs or inline policy objects', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps/${params.appId.trim()}`, + method: 'PUT', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const body: Record = { type: params.type } + /** + * `domain` exists only on the self_hosted, ssh, vnc, rdp, and bookmark + * request variants; the saas, app_launcher, warp, biso, dash_sso, + * infrastructure, mcp, mcp_portal, and proxy_endpoint variants have no + * such field, so sending a blank one makes those app types unbuildable. + */ + if (params.domain) body.domain = params.domain + if (params.name) body.name = params.name + if (params.sessionDuration) body.session_duration = params.sessionDuration + + const allowedIdps = parseCsvParam(params.allowedIdps) + if (allowedIdps) body.allowed_idps = allowedIdps + + if (params.appLauncherVisible !== undefined) { + body.app_launcher_visible = params.appLauncherVisible + } + if (params.autoRedirectToIdentity !== undefined) { + body.auto_redirect_to_identity = params.autoRedirectToIdentity + } + if (params.customDenyMessage) body.custom_deny_message = params.customDenyMessage + if (params.customDenyUrl) body.custom_deny_url = params.customDenyUrl + if (params.logoUrl) body.logo_url = params.logoUrl + + const tags = parseCsvParam(params.tags) + if (tags) body.tags = tags + + const policies = parseJsonArrayParam(params.policies, 'Policies') + if (policies) body.policies = policies + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyAccessApplication(), + error: cloudflareErrorMessage(data, 'Failed to update Access application'), + } + } + + return { success: true, output: mapAccessApplication(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Access application identifier' }, + name: { type: 'string', description: 'Application name', optional: true }, + domain: { + type: 'string', + description: 'Primary hostname and path secured by Access', + optional: true, + }, + type: { type: 'string', description: 'Application type', optional: true }, + aud: { type: 'string', description: 'Audience tag used to verify Access JWTs', optional: true }, + session_duration: { + type: 'string', + description: 'How long an Access session stays valid', + optional: true, + }, + allowed_idps: { + type: 'array', + description: 'Identity provider IDs users may authenticate with', + items: { type: 'string', description: 'Identity provider ID' }, + optional: true, + }, + app_launcher_visible: { + type: 'boolean', + description: 'Whether the app appears in the App Launcher', + optional: true, + }, + auto_redirect_to_identity: { + type: 'boolean', + description: 'Whether users skip the identity provider picker', + optional: true, + }, + custom_deny_message: { + type: 'string', + description: 'Message shown when access is denied', + optional: true, + }, + custom_deny_url: { + type: 'string', + description: 'URL users are redirected to when access is denied', + optional: true, + }, + logo_url: { type: 'string', description: 'Logo image URL', optional: true }, + self_hosted_domains: { + type: 'array', + description: + 'Additional hostnames and paths secured by the application. Cloudflare deprecated this field in favour of destinations, which is the one to read on a current application', + items: { type: 'string', description: 'Hostname and path' }, + optional: true, + }, + destinations: { + type: 'json', + description: 'Public and private destinations secured by the application', + optional: true, + }, + tags: { + type: 'array', + description: 'Tags categorizing the application', + items: { type: 'string', description: 'Tag name' }, + optional: true, + }, + policies: { + type: 'json', + description: 'Access policies attached to the application', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/update_access_policy.ts b/apps/sim/tools/cloudflare/update_access_policy.ts new file mode 100644 index 00000000000..3cb47d20636 --- /dev/null +++ b/apps/sim/tools/cloudflare/update_access_policy.ts @@ -0,0 +1,215 @@ +import type { + CloudflareAccessPolicyResponse, + CloudflareUpdateAccessPolicyParams, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyAccessPolicy, + mapAccessPolicy, + parseJsonArrayParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const updateAccessPolicyTool: ToolConfig< + CloudflareUpdateAccessPolicyParams, + CloudflareAccessPolicyResponse +> = { + id: 'cloudflare_update_access_policy', + name: 'Cloudflare Update Access Policy', + description: + 'Updates a Cloudflare Access (Zero Trust) policy on an application. This replaces the policy definition rather than merging it, so send every rule the policy should keep — omitted exclude or require rules are dropped, which can widen who gets in. The change applies to live traffic immediately. Read the current policy with "List Access Policies" first. Requires an API token with Account Access: Apps and Policies Edit.', + version: '1.0.0', + + params: { + accountId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Cloudflare account ID. Access applications are account-scoped', + }, + appId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access application ID that owns the policy', + }, + policyId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Access policy ID to update', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name of the policy', + }, + decision: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'What the policy does when it matches: allow, deny, non_identity, or bypass (skip Access entirely)', + }, + include: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'JSON array of Access rules evaluated with OR logic. Example: [{"email_domain":{"domain":"example.com"}}]', + }, + exclude: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'JSON array of Access rules evaluated with NOT logic', + }, + require: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'JSON array of Access rules evaluated with AND logic', + }, + precedence: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Evaluation order of the policy within the application', + }, + sessionDuration: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'How long a session granted by this policy stays valid, e.g. 24h', + }, + approvalRequired: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether an approver must grant each access request', + }, + isolationRequired: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the session must run in a remote isolated browser', + }, + purposeJustificationRequired: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether users must state a reason for access', + }, + purposeJustificationPrompt: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Prompt shown when a justification is required', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/accounts/${params.accountId.trim()}/access/apps/${params.appId.trim()}/policies/${params.policyId.trim()}`, + method: 'PUT', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const include = parseJsonArrayParam(params.include, 'Include Rules') + if (!include || include.length === 0) { + throw new Error('Include Rules must contain at least one Access rule') + } + + const body: Record = { + name: params.name, + decision: params.decision, + include, + } + + const exclude = parseJsonArrayParam(params.exclude, 'Exclude Rules') + if (exclude) body.exclude = exclude + + const require = parseJsonArrayParam(params.require, 'Require Rules') + if (require) body.require = require + + if (params.precedence !== undefined) body.precedence = params.precedence + if (params.sessionDuration) body.session_duration = params.sessionDuration + if (params.approvalRequired !== undefined) body.approval_required = params.approvalRequired + if (params.isolationRequired !== undefined) body.isolation_required = params.isolationRequired + if (params.purposeJustificationRequired !== undefined) { + body.purpose_justification_required = params.purposeJustificationRequired + } + if (params.purposeJustificationPrompt) { + body.purpose_justification_prompt = params.purposeJustificationPrompt + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyAccessPolicy(), + error: cloudflareErrorMessage(data, 'Failed to update Access policy'), + } + } + + return { success: true, output: mapAccessPolicy(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Policy identifier' }, + name: { type: 'string', description: 'Policy name', optional: true }, + decision: { + type: 'string', + description: 'Decision the policy applies: allow, deny, non_identity, or bypass', + optional: true, + }, + precedence: { + type: 'number', + description: 'Evaluation order of the policy within the application', + optional: true, + }, + include: { type: 'json', description: 'Rules evaluated with OR logic', optional: true }, + exclude: { type: 'json', description: 'Rules evaluated with NOT logic', optional: true }, + require: { type: 'json', description: 'Rules evaluated with AND logic', optional: true }, + session_duration: { + type: 'string', + description: 'How long a session granted by this policy stays valid', + optional: true, + }, + approval_required: { + type: 'boolean', + description: 'Whether an approver must grant each access request', + optional: true, + }, + isolation_required: { + type: 'boolean', + description: 'Whether the session must run in a remote browser', + optional: true, + }, + purpose_justification_required: { + type: 'boolean', + description: 'Whether users must state a reason for access', + optional: true, + }, + purpose_justification_prompt: { + type: 'string', + description: 'Prompt shown when a justification is required', + optional: true, + }, + created_at: { type: 'string', description: 'Creation timestamp', optional: true }, + updated_at: { type: 'string', description: 'Last update timestamp', optional: true }, + }, +} diff --git a/apps/sim/tools/cloudflare/update_dns_record.ts b/apps/sim/tools/cloudflare/update_dns_record.ts index 7b51dbbfc1a..36c21df8e7b 100644 --- a/apps/sim/tools/cloudflare/update_dns_record.ts +++ b/apps/sim/tools/cloudflare/update_dns_record.ts @@ -84,17 +84,24 @@ export const updateDnsRecordTool: ToolConfig< request: { url: (params) => - `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/dns_records/${params.recordId}`, + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/dns_records/${params.recordId.trim()}`, method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, 'Content-Type': 'application/json', }), body: (params) => { - const body: Record = {} - if (params.type !== undefined) body.type = params.type - if (params.name !== undefined) body.name = params.name - if (params.content !== undefined) body.content = params.content + const body: Record = {} + /** + * Cloudflare rejects an empty type, name, or content, so a blank field + * means "leave this alone" rather than "clear it" — the block already + * strips those, and this guard makes a direct tool call behave the same. + * `comment` is deliberately not guarded: an empty comment is how the API + * clears a stored comment, which is a real thing a caller asks for. + */ + if (params.type !== undefined && params.type !== '') body.type = params.type + if (params.name !== undefined && params.name !== '') body.name = params.name + if (params.content !== undefined && params.content !== '') body.content = params.content if (params.ttl !== undefined) body.ttl = Number(params.ttl) if (params.proxied !== undefined) body.proxied = params.proxied if (params.priority !== undefined) body.priority = Number(params.priority) diff --git a/apps/sim/tools/cloudflare/update_rate_limit_rule.ts b/apps/sim/tools/cloudflare/update_rate_limit_rule.ts new file mode 100644 index 00000000000..495cc5f3804 --- /dev/null +++ b/apps/sim/tools/cloudflare/update_rate_limit_rule.ts @@ -0,0 +1,216 @@ +import type { + CloudflareRulesetResponse, + CloudflareUpdateRateLimitRuleParams, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, + parseCsvParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const updateRateLimitRuleTool: ToolConfig< + CloudflareUpdateRateLimitRuleParams, + CloudflareRulesetResponse +> = { + id: 'cloudflare_update_rate_limit_rule', + name: 'Cloudflare Update Rate Limiting Rule', + description: + 'Updates a rate limiting rule in the http_ratelimit phase entry point ruleset of a zone, using the current Rulesets-based rate limiting API. Cloudflare replaces the rule definition rather than merging it, so send the complete rule — every field you omit is reset. Run "List Rate Limiting Rules" first to read the current definition and get the ruleset ID. Requires an API token with Zone WAF Edit.', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID that owns the rule', + }, + rulesetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The http_ratelimit entry point ruleset ID, as returned by "List Rate Limiting Rules"', + }, + ruleId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The rate limiting rule ID to update', + }, + expression: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Cloudflare filter expression selecting the requests the rule applies to', + }, + characteristics: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Comma-separated counting characteristics. cf.colo.id is mandatory, plus exactly one of ip.src or cf.unique_visitor_id', + }, + period: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: + 'Counting window in seconds. Cloudflare accepts only 10, 60, 120, 300, 600, or 3600', + }, + requestsPerPeriod: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'Number of requests allowed within the counting period before the action fires', + }, + action: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Action applied once the limit is exceeded: block, managed_challenge, js_challenge, challenge, or log. Required because this endpoint replaces the rule rather than merging into it — a defaulted action would silently convert an existing log or challenge rule into a hard block', + }, + mitigationTimeout: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: + 'Seconds the action stays applied. Cloudflare accepts only 0, 10, 60, 120, 300, 600, 3600, or 86400', + }, + counting_expression: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional expression defining which requests are counted', + }, + requestsToOrigin: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'When true, only requests that reach the origin are counted', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Human-readable description of the rule', + }, + enabled: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the rule is enabled', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/${params.rulesetId.trim()}/rules/${params.ruleId.trim()}`, + method: 'PATCH', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const characteristics = parseCsvParam(params.characteristics) + if (!characteristics) { + throw new Error('Characteristics must list at least one counting characteristic') + } + + const ratelimit: Record = { + characteristics, + period: params.period, + requests_per_period: params.requestsPerPeriod, + } + if (params.mitigationTimeout !== undefined) { + ratelimit.mitigation_timeout = params.mitigationTimeout + } + if (params.counting_expression) ratelimit.counting_expression = params.counting_expression + if (params.requestsToOrigin !== undefined) { + ratelimit.requests_to_origin = params.requestsToOrigin + } + + const body: Record = { + action: params.action, + expression: params.expression, + ratelimit, + } + if (params.description !== undefined) body.description = params.description + if (params.enabled !== undefined) body.enabled = params.enabled + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to update rate limiting rule'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Ruleset ID of the http_ratelimit entry point' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind' }, + phase: { type: 'string', description: 'Phase the ruleset runs in (http_ratelimit)' }, + version: { type: 'string', description: 'Ruleset version after the change', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rate limiting rules after the change, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { type: 'string', description: 'Action applied once the limit is exceeded' }, + action_parameters: { + type: 'json', + description: 'Action-specific parameters', + optional: true, + }, + expression: { type: 'string', description: 'Filter expression' }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { type: 'string', description: 'Rule reference tag', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { + type: 'json', + description: 'Rate limiting configuration applied to the rule', + optional: true, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/update_ruleset_rule.ts b/apps/sim/tools/cloudflare/update_ruleset_rule.ts new file mode 100644 index 00000000000..f94113c008a --- /dev/null +++ b/apps/sim/tools/cloudflare/update_ruleset_rule.ts @@ -0,0 +1,191 @@ +import type { + CloudflareRulesetResponse, + CloudflareUpdateRulesetRuleParams, +} from '@/tools/cloudflare/types' +import { + cloudflareErrorMessage, + cloudflareHeaders, + emptyRuleset, + mapRuleset, + parseJsonObjectParam, +} from '@/tools/cloudflare/utils' +import type { ToolConfig } from '@/tools/types' + +export const updateRulesetRuleTool: ToolConfig< + CloudflareUpdateRulesetRuleParams, + CloudflareRulesetResponse +> = { + id: 'cloudflare_update_ruleset_rule', + name: 'Cloudflare Update Ruleset Rule', + description: + 'Updates a rule in a zone ruleset. Cloudflare replaces the rule definition rather than merging it, so you must send every field you want the rule to keep — any field you omit is reset to its default. Read the current rule with "Get Ruleset" first. Requires an API token with Zone WAF Edit (or another matching ruleset Write permission).', + version: '1.0.0', + + params: { + zoneId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The zone ID that owns the ruleset', + }, + rulesetId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The ruleset ID containing the rule', + }, + ruleId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The rule ID to update', + }, + action: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The action the rule performs, e.g. block, challenge, js_challenge, managed_challenge, log, skip, or execute. Required because this endpoint replaces the rule definition — omitting it resets the stored action', + }, + expression: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Cloudflare filter expression selecting matching requests. Required because this endpoint replaces the rule definition — omitting it resets the stored expression', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Human-readable description of the rule', + }, + enabled: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: 'Whether the rule is enabled', + }, + ref: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Reference tag that stays stable across rule updates', + }, + actionParameters: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON object of action-specific parameters, e.g. {"id":"","overrides":{"rules":[{"id":"","action":"log","enabled":true,"score_threshold":40}]}}', + }, + ratelimit: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON rate limiting configuration to preserve on a rule in the http_ratelimit phase, e.g. {"characteristics":["cf.colo.id","ip.src"],"period":60,"requests_per_period":100}. Because the update replaces the rule, omitting this on a rate limiting rule stops it rate limiting', + }, + logging: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'JSON logging configuration to preserve, e.g. {"enabled":true}. Omitting it on a rule that had logging configured resets it to the default', + }, + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Cloudflare API Token', + }, + }, + + request: { + url: (params) => + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/rulesets/${params.rulesetId.trim()}/rules/${params.ruleId.trim()}`, + method: 'PATCH', + headers: (params) => cloudflareHeaders(params.apiKey), + body: (params) => { + const body: Record = { + action: params.action, + expression: params.expression, + } + if (params.description !== undefined) body.description = params.description + if (params.enabled !== undefined) body.enabled = params.enabled + if (params.ref) body.ref = params.ref + + const actionParameters = parseJsonObjectParam(params.actionParameters, 'Action Parameters') + if (actionParameters) body.action_parameters = actionParameters + + const ratelimit = parseJsonObjectParam(params.ratelimit, 'Rate Limiting Configuration') + if (ratelimit) body.ratelimit = ratelimit + + const logging = parseJsonObjectParam(params.logging, 'Logging Configuration') + if (logging) body.logging = logging + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!data.success) { + return { + success: false, + output: emptyRuleset(), + error: cloudflareErrorMessage(data, 'Failed to update ruleset rule'), + } + } + + return { success: true, output: mapRuleset(data.result) } + }, + + outputs: { + id: { type: 'string', description: 'Ruleset identifier' }, + name: { type: 'string', description: 'Ruleset name' }, + description: { type: 'string', description: 'Ruleset description' }, + kind: { type: 'string', description: 'Ruleset kind (managed, custom, root, or zone)' }, + phase: { type: 'string', description: 'Phase the ruleset runs in' }, + version: { type: 'string', description: 'Ruleset version after the change', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + rules: { + type: 'array', + description: 'Rules in the ruleset after the change, in evaluation order', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Rule identifier' }, + version: { type: 'string', description: 'Rule version', optional: true }, + action: { type: 'string', description: 'Action the rule performs' }, + action_parameters: { + type: 'json', + description: 'Action-specific parameters', + optional: true, + }, + expression: { type: 'string', description: 'Filter expression' }, + description: { type: 'string', description: 'Rule description' }, + enabled: { type: 'boolean', description: 'Whether the rule is enabled' }, + ref: { type: 'string', description: 'Rule reference tag', optional: true }, + last_updated: { + type: 'string', + description: 'RFC 3339 timestamp of the last change', + optional: true, + }, + categories: { + type: 'array', + description: 'Managed-rule categories', + items: { type: 'string', description: 'Category tag' }, + }, + logging: { type: 'json', description: 'Logging configuration', optional: true }, + ratelimit: { type: 'json', description: 'Rate limiting configuration', optional: true }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cloudflare/update_zone_setting.ts b/apps/sim/tools/cloudflare/update_zone_setting.ts index 60fddb11c68..daac2b6c724 100644 --- a/apps/sim/tools/cloudflare/update_zone_setting.ts +++ b/apps/sim/tools/cloudflare/update_zone_setting.ts @@ -32,8 +32,7 @@ export const updateZoneSettingTool: ToolConfig< type: 'string', required: true, visibility: 'user-or-llm', - description: - 'New value for the setting as a string or JSON string for complex values (e.g., "full" for SSL, "medium" for security_level, "aggressive" for cache_level, \'["ECDHE-RSA-AES128-GCM-SHA256"]\' for ciphers)', + description: `New value for the setting as a string, or a JSON string for complex values (e.g., "full" for SSL, "medium" for security_level, "aggressive" for cache_level, ["ECDHE-RSA-AES128-GCM-SHA256"] for ciphers)`, }, apiKey: { type: 'string', @@ -45,7 +44,7 @@ export const updateZoneSettingTool: ToolConfig< request: { url: (params) => - `https://api.cloudflare.com/client/v4/zones/${params.zoneId}/settings/${params.settingId}`, + `https://api.cloudflare.com/client/v4/zones/${params.zoneId.trim()}/settings/${params.settingId.trim()}`, method: 'PATCH', headers: (params) => ({ Authorization: `Bearer ${params.apiKey}`, diff --git a/apps/sim/tools/cloudflare/utils.ts b/apps/sim/tools/cloudflare/utils.ts new file mode 100644 index 00000000000..e9b5678311d --- /dev/null +++ b/apps/sim/tools/cloudflare/utils.ts @@ -0,0 +1,223 @@ +/** + * Shared request/response helpers for the Cloudflare API tools. + * + * Every Cloudflare v4 endpoint answers with the same envelope: + * `{ success, errors, messages, result }`. A `200 OK` carrying + * `success: false` is a failure, so callers must always branch on + * `data.success` rather than on the HTTP status. + */ + +import type { + CloudflareEnvelope, + CloudflareRawAccessApplication, + CloudflareRawAccessPolicy, + CloudflareRawRuleset, +} from '@/tools/cloudflare/types' + +/** + * Reads a Cloudflare v4 response body into the shared envelope shape, so the + * caller branches on a typed `success` flag and reads `result` through a checked + * payload type instead of an implicitly-`any` `response.json()`. Used by the + * tools whose `result` has a payload type in `types.ts`. + */ +export async function readCloudflareResponse( + response: Response +): Promise> { + return (await response.json()) as CloudflareEnvelope +} + +/** Standard bearer-token headers for the Cloudflare v4 API. */ +export function cloudflareHeaders(apiKey: string): Record { + return { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json', + } +} + +/** Extracts the first error message from a Cloudflare envelope. */ +export function cloudflareErrorMessage(data: CloudflareEnvelope, fallback: string): string { + const message = data.errors?.[0]?.message + return typeof message === 'string' && message.length > 0 ? message : fallback +} + +/** + * Parses a param that may arrive either as a JSON string (typed into a block + * field) or as an already-structured value (piped from an upstream block). + */ +export function parseJsonParam(value: unknown, fieldName: string): unknown { + if (value === undefined || value === null || value === '') return undefined + if (typeof value !== 'string') return value + try { + return JSON.parse(value) + } catch { + throw new Error(`${fieldName} must be valid JSON`) + } +} + +/** Parses a param that must resolve to a JSON array. */ +export function parseJsonArrayParam(value: unknown, fieldName: string): unknown[] | undefined { + const parsed = parseJsonParam(value, fieldName) + if (parsed === undefined) return undefined + if (!Array.isArray(parsed)) throw new Error(`${fieldName} must be a JSON array`) + return parsed +} + +/** Parses a param that must resolve to a JSON object. */ +export function parseJsonObjectParam( + value: unknown, + fieldName: string +): Record | undefined { + const parsed = parseJsonParam(value, fieldName) + if (parsed === undefined) return undefined + if (typeof parsed !== 'object' || Array.isArray(parsed)) { + throw new Error(`${fieldName} must be a JSON object`) + } + return parsed as Record +} + +/** Splits a comma-separated string param into a trimmed, non-empty list. */ +export function parseCsvParam(value: unknown): string[] | undefined { + if (typeof value !== 'string' || value.trim() === '') return undefined + const items = value + .split(',') + .map((item) => item.trim()) + .filter(Boolean) + return items.length > 0 ? items : undefined +} + +/** + * Maps a Cloudflare ruleset `result` payload onto the flat ruleset output shape + * shared by the get-ruleset, phase-entrypoint, and rule mutation tools — every + * one of those endpoints answers with the full ruleset object. + */ +export function mapRuleset(ruleset: CloudflareRawRuleset | undefined) { + return { + id: ruleset?.id ?? '', + name: ruleset?.name ?? '', + description: ruleset?.description ?? '', + kind: ruleset?.kind ?? '', + phase: ruleset?.phase ?? '', + version: ruleset?.version ?? null, + last_updated: ruleset?.last_updated ?? null, + rules: Array.isArray(ruleset?.rules) + ? ruleset.rules.map((rule) => ({ + id: rule.id ?? '', + version: rule.version ?? null, + action: rule.action ?? '', + action_parameters: rule.action_parameters ?? null, + expression: rule.expression ?? '', + description: rule.description ?? '', + enabled: rule.enabled ?? false, + ref: rule.ref ?? null, + last_updated: rule.last_updated ?? null, + categories: rule.categories ?? [], + logging: rule.logging ?? null, + ratelimit: rule.ratelimit ?? null, + })) + : [], + } +} + +/** The empty ruleset payload returned alongside an error. */ +export function emptyRuleset() { + return { + id: '', + name: '', + description: '', + kind: '', + phase: '', + version: null, + last_updated: null, + rules: [], + } +} + +/** Maps a Cloudflare Access application `result` payload onto the flat output shape. */ +export function mapAccessApplication(app: CloudflareRawAccessApplication | undefined) { + return { + id: app?.id ?? '', + name: app?.name ?? null, + domain: app?.domain ?? null, + type: app?.type ?? null, + aud: app?.aud ?? null, + session_duration: app?.session_duration ?? null, + allowed_idps: app?.allowed_idps ?? null, + app_launcher_visible: app?.app_launcher_visible ?? null, + auto_redirect_to_identity: app?.auto_redirect_to_identity ?? null, + custom_deny_message: app?.custom_deny_message ?? null, + custom_deny_url: app?.custom_deny_url ?? null, + logo_url: app?.logo_url ?? null, + self_hosted_domains: app?.self_hosted_domains ?? null, + destinations: app?.destinations ?? null, + tags: app?.tags ?? null, + policies: app?.policies ?? null, + } +} + +/** The empty Access application payload returned alongside an error. */ +export function emptyAccessApplication() { + return { + id: '', + name: null, + domain: null, + type: null, + aud: null, + session_duration: null, + allowed_idps: null, + app_launcher_visible: null, + auto_redirect_to_identity: null, + custom_deny_message: null, + custom_deny_url: null, + logo_url: null, + self_hosted_domains: null, + destinations: null, + tags: null, + policies: null, + } +} + +/** Maps a Cloudflare Access policy `result` payload onto the flat output shape. */ +export function mapAccessPolicy(policy: CloudflareRawAccessPolicy | undefined) { + return { + id: policy?.id ?? '', + name: policy?.name ?? null, + decision: policy?.decision ?? null, + precedence: policy?.precedence ?? null, + include: policy?.include ?? null, + exclude: policy?.exclude ?? null, + require: policy?.require ?? null, + session_duration: policy?.session_duration ?? null, + approval_required: policy?.approval_required ?? null, + isolation_required: policy?.isolation_required ?? null, + purpose_justification_required: policy?.purpose_justification_required ?? null, + purpose_justification_prompt: policy?.purpose_justification_prompt ?? null, + created_at: policy?.created_at ?? null, + updated_at: policy?.updated_at ?? null, + } +} + +/** The empty Access policy payload returned alongside an error. */ +export function emptyAccessPolicy() { + return { + id: '', + name: null, + decision: null, + precedence: null, + include: null, + exclude: null, + require: null, + session_duration: null, + approval_required: null, + isolation_required: null, + purpose_justification_required: null, + purpose_justification_prompt: null, + created_at: null, + updated_at: null, + } +} + +/** Appends a query param when the value is present and non-empty. */ +export function appendParam(url: URL, key: string, value: unknown): void { + if (value === undefined || value === null || value === '') return + url.searchParams.append(key, String(value)) +} diff --git a/apps/sim/tools/generated/tool-ids.ts b/apps/sim/tools/generated/tool-ids.ts index c14c7474cdd..70c79765691 100644 --- a/apps/sim/tools/generated/tool-ids.ts +++ b/apps/sim/tools/generated/tool-ids.ts @@ -3,7 +3,7 @@ /** Every registered tool id, including versioned variants. */ const toolIds: string[] = JSON.parse( - '["a2a_cancel_task","a2a_get_agent_card","a2a_get_task","a2a_send_message","agentmail_create_draft","agentmail_create_inbox","agentmail_delete_draft","agentmail_delete_inbox","agentmail_delete_thread","agentmail_forward_message","agentmail_get_draft","agentmail_get_inbox","agentmail_get_message","agentmail_get_thread","agentmail_list_drafts","agentmail_list_inboxes","agentmail_list_messages","agentmail_list_threads","agentmail_reply_message","agentmail_send_draft","agentmail_send_message","agentmail_update_draft","agentmail_update_inbox","agentmail_update_message","agentmail_update_thread","agentphone_create_call","agentphone_create_contact","agentphone_create_number","agentphone_delete_contact","agentphone_get_call","agentphone_get_call_transcript","agentphone_get_contact","agentphone_get_conversation","agentphone_get_conversation_messages","agentphone_get_number_messages","agentphone_get_usage","agentphone_get_usage_daily","agentphone_get_usage_monthly","agentphone_list_calls","agentphone_list_contacts","agentphone_list_conversations","agentphone_list_numbers","agentphone_react_to_message","agentphone_release_number","agentphone_send_message","agentphone_update_contact","agentphone_update_conversation","agiloft_async_status","agiloft_attach_file","agiloft_attachment_info","agiloft_create_record","agiloft_delete_record","agiloft_get_choice_line_id","agiloft_list_tables","agiloft_lock_record","agiloft_nlp_search","agiloft_read_record","agiloft_remove_attachment","agiloft_retrieve_attachment","agiloft_run_action_button","agiloft_saved_search","agiloft_search_records","agiloft_select_records","agiloft_update_record","agiloft_upsert_record","ahrefs_anchors","ahrefs_backlinks","ahrefs_backlinks_stats","ahrefs_batch_analysis","ahrefs_broken_backlinks","ahrefs_domain_rating","ahrefs_domain_rating_history","ahrefs_keyword_overview","ahrefs_keywords_history","ahrefs_metrics","ahrefs_metrics_history","ahrefs_organic_competitors","ahrefs_organic_keywords","ahrefs_paid_pages","ahrefs_rank_tracker_competitors_overview","ahrefs_rank_tracker_competitors_stats","ahrefs_rank_tracker_overview","ahrefs_rank_tracker_serp_overview","ahrefs_refdomains_history","ahrefs_referring_domains","ahrefs_related_terms","ahrefs_site_audit_page_explorer","ahrefs_top_pages","airtable_create_records","airtable_delete_records","airtable_get_base_schema","airtable_get_record","airtable_list_bases","airtable_list_records","airtable_list_tables","airtable_update_multiple_records","airtable_update_record","airtable_upsert_records","airweave_search","algolia_add_record","algolia_batch_operations","algolia_browse_records","algolia_clear_records","algolia_copy_move_index","algolia_delete_by_filter","algolia_delete_index","algolia_delete_record","algolia_get_record","algolia_get_records","algolia_get_settings","algolia_get_task_status","algolia_list_indices","algolia_partial_update_record","algolia_search","algolia_update_settings","amplitude_event_segmentation","amplitude_funnels","amplitude_get_active_users","amplitude_get_revenue","amplitude_group_identify","amplitude_identify_user","amplitude_list_events","amplitude_realtime_active_users","amplitude_retention","amplitude_send_event","amplitude_user_activity","amplitude_user_profile","amplitude_user_search","apify_get_dataset_items","apify_get_run","apify_run_actor_async","apify_run_actor_sync","apify_run_task","apollo_account_bulk_create","apollo_account_bulk_update","apollo_account_create","apollo_account_search","apollo_account_update","apollo_contact_bulk_create","apollo_contact_bulk_update","apollo_contact_create","apollo_contact_search","apollo_contact_update","apollo_email_accounts","apollo_opportunity_create","apollo_opportunity_get","apollo_opportunity_search","apollo_opportunity_update","apollo_organization_bulk_enrich","apollo_organization_enrich","apollo_organization_search","apollo_people_bulk_enrich","apollo_people_enrich","apollo_people_search","apollo_sequence_add_contacts","apollo_sequence_search","apollo_task_create","apollo_task_search","appconfig_create_application","appconfig_create_configuration_profile","appconfig_create_environment","appconfig_create_hosted_configuration_version","appconfig_delete_application","appconfig_delete_configuration_profile","appconfig_delete_environment","appconfig_delete_hosted_configuration_version","appconfig_get_application","appconfig_get_configuration","appconfig_get_configuration_profile","appconfig_get_deployment","appconfig_get_environment","appconfig_get_hosted_configuration_version","appconfig_list_applications","appconfig_list_configuration_profiles","appconfig_list_deployment_strategies","appconfig_list_deployments","appconfig_list_environments","appconfig_list_hosted_configuration_versions","appconfig_start_deployment","appconfig_stop_deployment","appconfig_update_application","appconfig_update_configuration_profile","appconfig_update_environment","arxiv_get_author_papers","arxiv_get_paper","arxiv_search","asana_add_comment","asana_add_followers","asana_create_project","asana_create_section","asana_create_subtask","asana_create_task","asana_delete_task","asana_get_project","asana_get_projects","asana_get_task","asana_list_sections","asana_list_workspaces","asana_search_tasks","asana_update_task","ashby_add_candidate_tag","ashby_anonymize_candidate","ashby_change_application_source","ashby_change_application_stage","ashby_create_application","ashby_create_candidate","ashby_create_note","ashby_delete_application","ashby_get_application","ashby_get_candidate","ashby_get_job","ashby_get_job_posting","ashby_get_offer","ashby_list_applications","ashby_list_archive_reasons","ashby_list_candidate_tags","ashby_list_candidates","ashby_list_custom_fields","ashby_list_departments","ashby_list_interviews","ashby_list_job_postings","ashby_list_jobs","ashby_list_locations","ashby_list_notes","ashby_list_offers","ashby_list_openings","ashby_list_sources","ashby_list_users","ashby_remove_candidate_tag","ashby_search_candidates","ashby_set_custom_field_value","ashby_set_custom_field_values","ashby_update_candidate","athena_batch_get_query_execution","athena_create_named_query","athena_delete_named_query","athena_get_named_query","athena_get_query_execution","athena_get_query_results","athena_list_databases","athena_list_named_queries","athena_list_query_executions","athena_list_table_metadata","athena_start_query","athena_stop_query","attio_assert_record","attio_create_attribute","attio_create_comment","attio_create_list","attio_create_list_entry","attio_create_note","attio_create_object","attio_create_record","attio_create_task","attio_create_webhook","attio_delete_comment","attio_delete_list_entry","attio_delete_note","attio_delete_record","attio_delete_task","attio_delete_webhook","attio_get_attribute","attio_get_comment","attio_get_list","attio_get_list_entry","attio_get_member","attio_get_note","attio_get_object","attio_get_record","attio_get_task","attio_get_thread","attio_get_webhook","attio_list_attributes","attio_list_lists","attio_list_members","attio_list_notes","attio_list_objects","attio_list_records","attio_list_tasks","attio_list_threads","attio_list_webhooks","attio_query_list_entries","attio_search_records","attio_update_attribute","attio_update_list","attio_update_list_entry","attio_update_object","attio_update_record","attio_update_task","attio_update_webhook","azure_data_explorer_create_table","azure_data_explorer_drop_table","azure_data_explorer_ingest_from_query","azure_data_explorer_ingest_inline","azure_data_explorer_list_databases","azure_data_explorer_list_functions","azure_data_explorer_list_tables","azure_data_explorer_management","azure_data_explorer_query","azure_data_explorer_show_database_schema","azure_data_explorer_show_ingestion_failures","azure_data_explorer_show_operations","azure_data_explorer_show_table_details","azure_data_explorer_show_table_schema","azure_devops_add_comment","azure_devops_create_work_item","azure_devops_get_build_log","azure_devops_get_build_timeline","azure_devops_get_comments","azure_devops_get_pipeline","azure_devops_get_pipeline_run","azure_devops_get_work_item","azure_devops_get_work_items_batch","azure_devops_get_work_items_between_builds","azure_devops_list_build_logs","azure_devops_list_builds","azure_devops_list_pipeline_runs","azure_devops_list_pipelines","azure_devops_query_work_items","azure_devops_update_work_item","box_copy_file","box_create_folder","box_delete_file","box_delete_folder","box_download_file","box_get_file_info","box_list_folder_items","box_search","box_sign_cancel_request","box_sign_create_request","box_sign_get_request","box_sign_list_requests","box_sign_resend_request","box_update_file","box_upload_file","brandfetch_get_brand","brandfetch_search","brex_archive_budget","brex_create_budget","brex_create_spend_limit","brex_create_transfer","brex_create_vendor","brex_get_budget","brex_get_cash_account","brex_get_company","brex_get_current_user","brex_get_expense","brex_get_spend_limit","brex_get_transfer","brex_get_user","brex_get_vendor","brex_list_budgets","brex_list_card_accounts","brex_list_card_statements","brex_list_card_transactions","brex_list_cards","brex_list_cash_accounts","brex_list_cash_statements","brex_list_cash_transactions","brex_list_departments","brex_list_expenses","brex_list_locations","brex_list_spend_limits","brex_list_titles","brex_list_transfers","brex_list_users","brex_list_vendors","brex_match_receipt","brex_update_expense","brex_update_vendor","brex_upload_receipt","brightdata_cancel_snapshot","brightdata_discover","brightdata_download_snapshot","brightdata_scrape_dataset","brightdata_scrape_url","brightdata_serp_search","brightdata_snapshot_status","brightdata_sync_scrape","browser_use_run_task","buffer_create_idea","buffer_create_post","buffer_delete_post","buffer_edit_post","buffer_get_account","buffer_get_channels","buffer_get_idea_groups","buffer_get_ideas","buffer_get_post","buffer_get_posts","calcom_cancel_booking","calcom_confirm_booking","calcom_create_booking","calcom_create_event_type","calcom_create_schedule","calcom_decline_booking","calcom_delete_event_type","calcom_delete_schedule","calcom_get_booking","calcom_get_default_schedule","calcom_get_event_type","calcom_get_schedule","calcom_get_slots","calcom_list_bookings","calcom_list_event_types","calcom_list_schedules","calcom_reschedule_booking","calcom_update_event_type","calcom_update_schedule","calendly_cancel_event","calendly_create_event_invitee","calendly_create_invitee_no_show","calendly_create_scheduling_link","calendly_create_webhook","calendly_delete_invitee_no_show","calendly_delete_webhook","calendly_get_current_user","calendly_get_event_invitee","calendly_get_event_type","calendly_get_scheduled_event","calendly_get_user","calendly_list_event_invitees","calendly_list_event_type_available_times","calendly_list_event_types","calendly_list_organization_memberships","calendly_list_routing_form_submissions","calendly_list_routing_forms","calendly_list_scheduled_events","calendly_list_user_availability_schedules","calendly_list_user_busy_times","calendly_list_webhooks","clay_populate","clerk_add_organization_member","clerk_ban_user","clerk_create_actor_token","clerk_create_allowlist_identifier","clerk_create_blocklist_identifier","clerk_create_organization","clerk_create_organization_invitation","clerk_create_user","clerk_delete_allowlist_identifier","clerk_delete_blocklist_identifier","clerk_delete_organization","clerk_delete_user","clerk_get_jwt_template","clerk_get_organization","clerk_get_session","clerk_get_user","clerk_get_user_oauth_token","clerk_list_allowlist_identifiers","clerk_list_blocklist_identifiers","clerk_list_jwt_templates","clerk_list_organization_invitations","clerk_list_organization_memberships","clerk_list_organizations","clerk_list_sessions","clerk_list_users","clerk_lock_user","clerk_remove_organization_member","clerk_revoke_actor_token","clerk_revoke_session","clerk_unban_user","clerk_unlock_user","clerk_update_organization","clerk_update_organization_membership","clerk_update_user","clickhouse_count_rows","clickhouse_create_database","clickhouse_create_table","clickhouse_delete","clickhouse_describe_table","clickhouse_drop_database","clickhouse_drop_partition","clickhouse_drop_table","clickhouse_execute","clickhouse_insert","clickhouse_insert_rows","clickhouse_introspect","clickhouse_kill_query","clickhouse_list_clusters","clickhouse_list_databases","clickhouse_list_mutations","clickhouse_list_partitions","clickhouse_list_running_queries","clickhouse_list_tables","clickhouse_optimize_table","clickhouse_query","clickhouse_rename_table","clickhouse_show_create_table","clickhouse_table_stats","clickhouse_truncate_table","clickhouse_update","clickup_add_tag_to_task","clickup_create_checklist","clickup_create_checklist_item","clickup_create_comment","clickup_create_folder","clickup_create_list","clickup_create_task","clickup_create_time_entry","clickup_delete_checklist","clickup_delete_checklist_item","clickup_delete_comment","clickup_delete_task","clickup_delete_time_entry","clickup_get_comments","clickup_get_custom_fields","clickup_get_folders","clickup_get_list_members","clickup_get_lists","clickup_get_running_timer","clickup_get_space_tags","clickup_get_spaces","clickup_get_task","clickup_get_task_members","clickup_get_tasks","clickup_get_time_entries","clickup_get_workspaces","clickup_remove_custom_field_value","clickup_remove_tag_from_task","clickup_search_tasks","clickup_set_custom_field_value","clickup_start_timer","clickup_stop_timer","clickup_update_checklist","clickup_update_checklist_item","clickup_update_comment","clickup_update_task","clickup_update_time_entry","clickup_upload_attachment","cloudflare_create_dns_record","cloudflare_create_zone","cloudflare_delete_dns_record","cloudflare_delete_zone","cloudflare_dns_analytics","cloudflare_get_zone","cloudflare_get_zone_settings","cloudflare_list_certificates","cloudflare_list_dns_records","cloudflare_list_zones","cloudflare_purge_cache","cloudflare_update_dns_record","cloudflare_update_zone_setting","cloudformation_cancel_update_stack","cloudformation_create_change_set","cloudformation_create_stack","cloudformation_delete_stack","cloudformation_describe_change_set","cloudformation_describe_stack_drift_detection_status","cloudformation_describe_stack_events","cloudformation_describe_stacks","cloudformation_detect_stack_drift","cloudformation_execute_change_set","cloudformation_get_template","cloudformation_get_template_summary","cloudformation_list_stack_resources","cloudformation_update_stack","cloudformation_validate_template","cloudwatch_describe_alarm_history","cloudwatch_describe_alarms","cloudwatch_describe_log_groups","cloudwatch_describe_log_streams","cloudwatch_filter_log_events","cloudwatch_get_log_events","cloudwatch_get_metric_statistics","cloudwatch_list_metrics","cloudwatch_mute_alarm","cloudwatch_put_log_group_retention","cloudwatch_put_metric_data","cloudwatch_query_logs","cloudwatch_unmute_alarm","codepipeline_disable_stage_transition","codepipeline_enable_stage_transition","codepipeline_get_pipeline","codepipeline_get_pipeline_execution","codepipeline_get_pipeline_state","codepipeline_list_action_executions","codepipeline_list_pipeline_executions","codepipeline_list_pipelines","codepipeline_put_approval_result","codepipeline_retry_stage_execution","codepipeline_start_execution","codepipeline_stop_execution","confluence_add_label","confluence_create_blogpost","confluence_create_comment","confluence_create_page","confluence_create_page_property","confluence_create_space","confluence_create_space_property","confluence_delete_attachment","confluence_delete_blogpost","confluence_delete_comment","confluence_delete_label","confluence_delete_page","confluence_delete_page_property","confluence_delete_space","confluence_delete_space_property","confluence_get_blogpost","confluence_get_page_ancestors","confluence_get_page_children","confluence_get_page_descendants","confluence_get_page_version","confluence_get_pages_by_label","confluence_get_space","confluence_get_task","confluence_get_user","confluence_list_attachments","confluence_list_blogposts","confluence_list_blogposts_in_space","confluence_list_comments","confluence_list_labels","confluence_list_page_properties","confluence_list_page_versions","confluence_list_pages_in_space","confluence_list_space_labels","confluence_list_space_permissions","confluence_list_space_properties","confluence_list_spaces","confluence_list_tasks","confluence_retrieve","confluence_search","confluence_search_in_space","confluence_update","confluence_update_blogpost","confluence_update_comment","confluence_update_space","confluence_update_task","confluence_upload_attachment","context_dev_classify_naics","context_dev_classify_sic","context_dev_crawl","context_dev_extract","context_dev_extract_product","context_dev_extract_products","context_dev_get_brand","context_dev_get_brand_by_email","context_dev_get_brand_by_name","context_dev_get_brand_by_ticker","context_dev_identify_transaction","context_dev_map","context_dev_scrape_fonts","context_dev_scrape_html","context_dev_scrape_images","context_dev_scrape_markdown","context_dev_scrape_styleguide","context_dev_screenshot","context_dev_search","convex_action","convex_document_deltas","convex_list_documents","convex_list_tables","convex_mutation","convex_query","convex_run_function","crowdstrike_create_indicators","crowdstrike_delete_indicators","crowdstrike_delete_rtr_session","crowdstrike_execute_rtr_command","crowdstrike_get_alert_details","crowdstrike_get_case_details","crowdstrike_get_host_group_details","crowdstrike_get_indicator_details","crowdstrike_get_rtr_command_status","crowdstrike_get_sensor_aggregates","crowdstrike_get_sensor_details","crowdstrike_get_vulnerability_details","crowdstrike_init_rtr_session","crowdstrike_perform_host_action","crowdstrike_perform_host_group_action","crowdstrike_query_alerts","crowdstrike_query_cases","crowdstrike_query_host_groups","crowdstrike_query_indicators","crowdstrike_query_sensors","crowdstrike_query_vulnerabilities","crowdstrike_update_alerts","crowdstrike_update_indicators","cursor_add_followup","cursor_add_followup_v2","cursor_delete_agent","cursor_delete_agent_v2","cursor_download_artifact","cursor_download_artifact_v2","cursor_get_agent","cursor_get_agent_v2","cursor_get_api_key_info","cursor_get_api_key_info_v2","cursor_get_conversation","cursor_get_conversation_v2","cursor_launch_agent","cursor_launch_agent_v2","cursor_list_agents","cursor_list_agents_v2","cursor_list_artifacts","cursor_list_artifacts_v2","cursor_list_models","cursor_list_models_v2","cursor_list_repositories","cursor_list_repositories_v2","cursor_stop_agent","cursor_stop_agent_v2","dagster_delete_run","dagster_get_asset","dagster_get_run","dagster_get_run_logs","dagster_launch_run","dagster_list_assets","dagster_list_jobs","dagster_list_runs","dagster_list_schedules","dagster_list_sensors","dagster_materialize_assets","dagster_reexecute_run","dagster_report_asset_materialization","dagster_start_schedule","dagster_start_sensor","dagster_stop_schedule","dagster_stop_sensor","dagster_terminate_run","dagster_wipe_asset","databricks_cancel_run","databricks_execute_sql","databricks_get_cluster","databricks_get_job","databricks_get_run","databricks_get_run_output","databricks_get_statement","databricks_list_clusters","databricks_list_jobs","databricks_list_runs","databricks_list_warehouses","databricks_run_job","datadog_add_incident_todo","datadog_cancel_downtime","datadog_create_dashboard","datadog_create_downtime","datadog_create_event","datadog_create_incident","datadog_create_monitor","datadog_create_slo","datadog_delete_dashboard","datadog_delete_slo","datadog_get_browser_synthetics_results","datadog_get_dashboard","datadog_get_incident","datadog_get_monitor","datadog_get_security_signal","datadog_get_slo","datadog_get_slo_history","datadog_get_synthetics_results","datadog_get_synthetics_test","datadog_list_dashboards","datadog_list_downtimes","datadog_list_incidents","datadog_list_monitors","datadog_list_security_rules","datadog_list_security_signals","datadog_list_services","datadog_list_slos","datadog_list_synthetics_tests","datadog_mute_monitor","datadog_query_logs","datadog_query_timeseries","datadog_search_spans","datadog_send_logs","datadog_submit_metrics","datadog_trigger_synthetics_tests","datadog_unmute_monitor","datadog_update_incident","datadog_update_security_signal_assignee","datadog_update_security_signal_state","datadog_update_slo","datadog_update_synthetics_status","datagma_enrich_company","datagma_enrich_person","datagma_find_email","datagma_find_phone","datagma_get_credits","daytona_create_sandbox","daytona_delete_sandbox","daytona_download_file","daytona_execute_command","daytona_get_sandbox","daytona_git_clone","daytona_list_files","daytona_list_sandboxes","daytona_run_code","daytona_start_sandbox","daytona_stop_sandbox","daytona_upload_file","deployed_block_executor","deployments_deploy","deployments_get_version","deployments_list_versions","deployments_promote","deployments_undeploy","devin_append_session_tags","devin_archive_session","devin_create_session","devin_get_session","devin_get_session_tags","devin_list_session_attachments","devin_list_session_messages","devin_list_sessions","devin_replace_session_tags","devin_send_message","devin_terminate_session","discord_add_reaction","discord_archive_thread","discord_assign_role","discord_ban_member","discord_bulk_delete_messages","discord_create_channel","discord_create_invite","discord_create_role","discord_create_thread","discord_create_webhook","discord_delete_channel","discord_delete_invite","discord_delete_message","discord_delete_role","discord_delete_webhook","discord_edit_message","discord_execute_webhook","discord_get_channel","discord_get_invite","discord_get_member","discord_get_messages","discord_get_pinned_messages","discord_get_server","discord_get_user","discord_get_webhook","discord_join_thread","discord_kick_member","discord_leave_thread","discord_list_channels","discord_list_roles","discord_pin_message","discord_remove_reaction","discord_remove_role","discord_send_message","discord_unban_member","discord_unpin_message","discord_update_channel","discord_update_member","discord_update_role","docusign_create_from_template","docusign_download_document","docusign_get_envelope","docusign_list_envelopes","docusign_list_recipients","docusign_list_templates","docusign_send_envelope","docusign_void_envelope","downdetector_get_company","downdetector_get_company_attribution","downdetector_get_company_baseline","downdetector_get_company_events","downdetector_get_company_incidents","downdetector_get_company_indicators","downdetector_get_company_last_15","downdetector_get_company_status","downdetector_get_provider","downdetector_get_reports","downdetector_get_site_companies","downdetector_list_categories","downdetector_list_incidents","downdetector_list_sites","downdetector_search_companies","dropbox_copy","dropbox_create_folder","dropbox_create_shared_link","dropbox_delete","dropbox_download","dropbox_get_metadata","dropbox_list_folder","dropbox_list_revisions","dropbox_list_shared_links","dropbox_move","dropbox_restore","dropbox_search","dropbox_upload","dropcontact_enrich_contact","dspy_chain_of_thought","dspy_predict","dspy_react","dub_bulk_create_links","dub_bulk_delete_links","dub_bulk_update_links","dub_create_link","dub_create_tag","dub_delete_link","dub_get_analytics","dub_get_events","dub_get_link","dub_get_links_count","dub_get_qr_code","dub_list_domains","dub_list_folders","dub_list_links","dub_list_tags","dub_update_link","dub_upsert_link","duckduckgo_search","dynamodb_delete","dynamodb_get","dynamodb_introspect","dynamodb_put","dynamodb_query","dynamodb_scan","dynamodb_update","dynatrace_add_problem_comment","dynatrace_add_tags","dynatrace_close_problem","dynatrace_create_settings_object","dynatrace_create_slo","dynatrace_delete_problem_comment","dynatrace_delete_settings_object","dynatrace_delete_slo","dynatrace_delete_tag","dynatrace_execute_synthetic_monitors","dynatrace_get_attack","dynatrace_get_audit_logs","dynatrace_get_entity","dynatrace_get_event","dynatrace_get_metric","dynatrace_get_problem","dynatrace_get_problem_comment","dynatrace_get_security_problem","dynatrace_get_settings_object","dynatrace_get_slo","dynatrace_get_synthetic_batch","dynatrace_ingest_event","dynatrace_ingest_logs","dynatrace_ingest_metrics","dynatrace_list_attacks","dynatrace_list_entities","dynatrace_list_entity_types","dynatrace_list_events","dynatrace_list_metrics","dynatrace_list_problem_comments","dynatrace_list_problems","dynatrace_list_remediation_items","dynatrace_list_security_problems","dynatrace_list_settings_objects","dynatrace_list_settings_schemas","dynatrace_list_slos","dynatrace_list_synthetic_monitors","dynatrace_list_tags","dynatrace_mute_security_problem","dynatrace_mute_security_problems","dynatrace_query_metrics","dynatrace_search_logs","dynatrace_unmute_security_problem","dynatrace_unmute_security_problems","dynatrace_update_problem_comment","dynatrace_update_settings_object","dynatrace_update_slo","elasticsearch_bulk","elasticsearch_cluster_health","elasticsearch_cluster_stats","elasticsearch_count","elasticsearch_create_index","elasticsearch_delete_document","elasticsearch_delete_index","elasticsearch_get_document","elasticsearch_get_index","elasticsearch_index_document","elasticsearch_list_indices","elasticsearch_search","elasticsearch_update_document","elevenlabs_audio_isolation","elevenlabs_edit_voice_settings","elevenlabs_get_user","elevenlabs_get_voice","elevenlabs_get_voice_settings","elevenlabs_list_models","elevenlabs_list_voices","elevenlabs_sound_effects","elevenlabs_speech_to_speech","elevenlabs_tts","emailbison_attach_leads_to_campaign","emailbison_attach_tags_to_leads","emailbison_create_campaign","emailbison_create_lead","emailbison_create_tag","emailbison_get_lead","emailbison_list_campaigns","emailbison_list_leads","emailbison_list_replies","emailbison_list_tags","emailbison_update_campaign","emailbison_update_campaign_status","emailbison_update_lead","embeddings_cohere","embeddings_gemini","embeddings_mistral","embeddings_openai","embeddings_openrouter","enrich_check_credits","enrich_company_funding","enrich_company_lookup","enrich_company_revenue","enrich_disposable_email_check","enrich_email_to_ip","enrich_email_to_person_lite","enrich_email_to_phone","enrich_email_to_profile","enrich_find_email","enrich_get_post_details","enrich_ip_to_company","enrich_linkedin_profile","enrich_linkedin_to_personal_email","enrich_linkedin_to_work_email","enrich_phone_finder","enrich_reverse_hash_lookup","enrich_sales_pointer_people","enrich_search_company","enrich_search_company_activities","enrich_search_company_employees","enrich_search_jobs","enrich_search_logo","enrich_search_people","enrich_search_people_activities","enrich_search_post_comments","enrich_search_post_comments_by_url","enrich_search_post_reactions","enrich_search_post_reactions_by_url","enrich_search_posts","enrich_search_similar_companies","enrich_verify_email","enrichment_run","enrow_find_email","enrow_verify_email","evernote_copy_note","evernote_create_note","evernote_create_notebook","evernote_create_tag","evernote_delete_note","evernote_get_note","evernote_get_notebook","evernote_list_notebooks","evernote_list_tags","evernote_search_notes","evernote_update_note","exa_agent","exa_answer","exa_find_similar_links","exa_get_contents","exa_search","extend_parser","extend_parser_v2","fathom_get_summary","fathom_get_transcript","fathom_list_meeting_types","fathom_list_meetings","fathom_list_team_members","fathom_list_teams","file_append","file_compress","file_decompress","file_fetch","file_get","file_get_content","file_manage_sharing","file_parser","file_parser_v2","file_parser_v3","file_read","file_write","findymail_find_email_from_linkedin","findymail_find_email_from_name","findymail_find_emails_by_domain","findymail_find_employees","findymail_find_phone","findymail_get_company","findymail_get_credits","findymail_lookup_technologies","findymail_reverse_email_lookup","findymail_search_technologies","findymail_verify_email","firecrawl_agent","firecrawl_batch_scrape","firecrawl_batch_scrape_status","firecrawl_cancel_crawl","firecrawl_crawl","firecrawl_crawl_status","firecrawl_credit_usage","firecrawl_extract","firecrawl_extract_status","firecrawl_map","firecrawl_parse","firecrawl_scrape","firecrawl_search","fireflies_add_to_live_meeting","fireflies_create_bite","fireflies_delete_transcript","fireflies_get_transcript","fireflies_get_user","fireflies_list_bites","fireflies_list_contacts","fireflies_list_transcripts","fireflies_list_users","fireflies_upload_audio","flint_create_task","flint_generate_pages","flint_get_task","function_execute","gamma_check_status","gamma_generate","gamma_generate_from_template","gamma_list_folders","gamma_list_themes","github_add_assignees","github_add_assignees_v2","github_add_labels","github_add_labels_v2","github_cancel_workflow_run","github_cancel_workflow_run_v2","github_check_star","github_check_star_v2","github_close_issue","github_close_issue_v2","github_close_pr","github_close_pr_v2","github_comment","github_comment_v2","github_compare_commits","github_compare_commits_v2","github_create_branch","github_create_branch_v2","github_create_comment_reaction","github_create_comment_reaction_v2","github_create_file","github_create_file_v2","github_create_gist","github_create_gist_v2","github_create_issue","github_create_issue_reaction","github_create_issue_reaction_v2","github_create_issue_v2","github_create_milestone","github_create_milestone_v2","github_create_pr","github_create_pr_review","github_create_pr_review_v2","github_create_pr_v2","github_create_project","github_create_project_v2","github_create_release","github_create_release_v2","github_delete_branch","github_delete_branch_v2","github_delete_comment","github_delete_comment_reaction","github_delete_comment_reaction_v2","github_delete_comment_v2","github_delete_file","github_delete_file_v2","github_delete_gist","github_delete_gist_v2","github_delete_issue_reaction","github_delete_issue_reaction_v2","github_delete_milestone","github_delete_milestone_v2","github_delete_project","github_delete_project_v2","github_delete_release","github_delete_release_v2","github_fork_gist","github_fork_gist_v2","github_fork_repo","github_fork_repo_v2","github_get_branch","github_get_branch_protection","github_get_branch_protection_v2","github_get_branch_v2","github_get_commit","github_get_commit_v2","github_get_file_content","github_get_file_content_v2","github_get_gist","github_get_gist_v2","github_get_issue","github_get_issue_v2","github_get_latest_release","github_get_latest_release_v2","github_get_milestone","github_get_milestone_v2","github_get_pr_files","github_get_pr_files_v2","github_get_project","github_get_project_v2","github_get_readme","github_get_readme_v2","github_get_release","github_get_release_v2","github_get_tree","github_get_tree_v2","github_get_workflow","github_get_workflow_run","github_get_workflow_run_v2","github_get_workflow_v2","github_issue_comment","github_issue_comment_v2","github_job_logs","github_latest_commit","github_latest_commit_v2","github_list_branches","github_list_branches_v2","github_list_commits","github_list_commits_v2","github_list_forks","github_list_forks_v2","github_list_gists","github_list_gists_v2","github_list_issue_comments","github_list_issue_comments_v2","github_list_issues","github_list_issues_v2","github_list_milestones","github_list_milestones_v2","github_list_pr_comments","github_list_pr_comments_v2","github_list_projects","github_list_projects_v2","github_list_prs","github_list_prs_v2","github_list_releases","github_list_releases_v2","github_list_review_threads","github_list_stargazers","github_list_stargazers_v2","github_list_tags","github_list_tags_v2","github_list_workflow_runs","github_list_workflow_runs_v2","github_list_workflows","github_list_workflows_v2","github_merge_pr","github_merge_pr_v2","github_pr","github_pr_v2","github_remove_label","github_remove_label_v2","github_reply_review_thread","github_repo_info","github_repo_info_v2","github_request_reviewers","github_request_reviewers_v2","github_rerun_workflow","github_rerun_workflow_v2","github_resolve_review_thread","github_search_code","github_search_code_v2","github_search_commits","github_search_commits_v2","github_search_issues","github_search_issues_v2","github_search_repos","github_search_repos_v2","github_search_users","github_search_users_v2","github_star_gist","github_star_gist_v2","github_star_repo","github_star_repo_v2","github_status_check_rollup","github_trigger_workflow","github_trigger_workflow_v2","github_unstar_gist","github_unstar_gist_v2","github_unstar_repo","github_unstar_repo_v2","github_update_branch_protection","github_update_branch_protection_v2","github_update_comment","github_update_comment_v2","github_update_file","github_update_file_v2","github_update_gist","github_update_gist_v2","github_update_issue","github_update_issue_v2","github_update_milestone","github_update_milestone_v2","github_update_pr","github_update_pr_v2","github_update_project","github_update_project_v2","github_update_release","github_update_release_v2","gitlab_activate_user","gitlab_add_member","gitlab_add_saml_group_link","gitlab_approve_access_request","gitlab_approve_merge_request","gitlab_approve_user","gitlab_ban_user","gitlab_block_user","gitlab_cancel_pipeline","gitlab_compare_branches","gitlab_create_branch","gitlab_create_file","gitlab_create_issue","gitlab_create_issue_note","gitlab_create_merge_request","gitlab_create_merge_request_note","gitlab_create_pipeline","gitlab_create_release","gitlab_create_user","gitlab_deactivate_user","gitlab_delete_branch","gitlab_delete_issue","gitlab_delete_saml_group_link","gitlab_delete_user","gitlab_delete_user_identity","gitlab_deny_access_request","gitlab_get_file","gitlab_get_group","gitlab_get_issue","gitlab_get_job_log","gitlab_get_merge_request","gitlab_get_merge_request_changes","gitlab_get_pipeline","gitlab_get_project","gitlab_invite_member","gitlab_list_access_requests","gitlab_list_branches","gitlab_list_commits","gitlab_list_groups","gitlab_list_invitations","gitlab_list_issues","gitlab_list_members","gitlab_list_merge_requests","gitlab_list_pipeline_jobs","gitlab_list_pipelines","gitlab_list_projects","gitlab_list_releases","gitlab_list_repository_tree","gitlab_list_saml_group_links","gitlab_list_user_memberships","gitlab_merge_merge_request","gitlab_play_job","gitlab_reject_user","gitlab_remove_member","gitlab_retry_pipeline","gitlab_revoke_invitation","gitlab_search_users","gitlab_unban_user","gitlab_unblock_user","gitlab_update_file","gitlab_update_invitation","gitlab_update_issue","gitlab_update_member","gitlab_update_merge_request","gitlab_update_user","gmail_add_label","gmail_add_label_v2","gmail_archive","gmail_archive_v2","gmail_create_label_v2","gmail_delete","gmail_delete_draft_v2","gmail_delete_label_v2","gmail_delete_v2","gmail_draft","gmail_draft_v2","gmail_edit_draft_v2","gmail_get_draft_v2","gmail_get_thread_v2","gmail_list_drafts_v2","gmail_list_labels_v2","gmail_list_threads_v2","gmail_mark_read","gmail_mark_read_v2","gmail_mark_unread","gmail_mark_unread_v2","gmail_move","gmail_move_v2","gmail_read","gmail_read_v2","gmail_remove_label","gmail_remove_label_v2","gmail_search","gmail_search_v2","gmail_send","gmail_send_v2","gmail_trash_thread_v2","gmail_unarchive","gmail_unarchive_v2","gmail_untrash_thread_v2","gmail_update_label_v2","gong_aggregate_activity","gong_aggregate_by_period","gong_answered_scorecards","gong_ask_anything","gong_assign_flow_prospects","gong_create_call","gong_day_by_day_activity","gong_get_brief","gong_get_call","gong_get_call_transcript","gong_get_coaching","gong_get_extensive_calls","gong_get_folder_content","gong_get_logs","gong_get_prospect_flows","gong_get_user","gong_interaction_stats","gong_list_calls","gong_list_flows","gong_list_library_folders","gong_list_scorecards","gong_list_trackers","gong_list_users","gong_list_workspaces","gong_lookup_email","gong_lookup_phone","gong_purge_email_address","gong_purge_phone_number","gong_unassign_flow_prospects","google_ads_ad_performance","google_ads_campaign_performance","google_ads_list_ad_groups","google_ads_list_campaigns","google_ads_list_customers","google_ads_search","google_appsheet_add_rows","google_appsheet_delete_rows","google_appsheet_edit_rows","google_appsheet_find_rows","google_bigquery_create_dataset","google_bigquery_create_table","google_bigquery_delete_dataset","google_bigquery_delete_table","google_bigquery_get_query_results","google_bigquery_get_table","google_bigquery_insert_rows","google_bigquery_list_datasets","google_bigquery_list_table_data","google_bigquery_list_tables","google_bigquery_query","google_books_volume_details","google_books_volume_search","google_calendar_create","google_calendar_create_calendar","google_calendar_create_calendar_v2","google_calendar_create_v2","google_calendar_delete","google_calendar_delete_calendar","google_calendar_delete_calendar_v2","google_calendar_delete_v2","google_calendar_freebusy","google_calendar_freebusy_v2","google_calendar_get","google_calendar_get_v2","google_calendar_instances","google_calendar_instances_v2","google_calendar_invite","google_calendar_invite_v2","google_calendar_list","google_calendar_list_acl","google_calendar_list_acl_v2","google_calendar_list_calendars","google_calendar_list_calendars_v2","google_calendar_list_v2","google_calendar_move","google_calendar_move_v2","google_calendar_quick_add","google_calendar_quick_add_v2","google_calendar_share_calendar","google_calendar_share_calendar_v2","google_calendar_unshare_calendar","google_calendar_unshare_calendar_v2","google_calendar_update","google_calendar_update_acl","google_calendar_update_acl_v2","google_calendar_update_calendar","google_calendar_update_calendar_v2","google_calendar_update_v2","google_contacts_create","google_contacts_delete","google_contacts_get","google_contacts_list","google_contacts_search","google_contacts_update","google_docs_create","google_docs_create_named_range","google_docs_create_paragraph_bullets","google_docs_delete_content_range","google_docs_delete_named_range","google_docs_delete_paragraph_bullets","google_docs_insert_image","google_docs_insert_page_break","google_docs_insert_table","google_docs_insert_text","google_docs_read","google_docs_replace_text","google_docs_update_paragraph_style","google_docs_update_text_style","google_docs_write","google_drive_copy","google_drive_create_comment","google_drive_create_folder","google_drive_delete","google_drive_delete_comment","google_drive_download","google_drive_export","google_drive_get_about","google_drive_get_content","google_drive_get_file","google_drive_get_revision","google_drive_list","google_drive_list_comments","google_drive_list_permissions","google_drive_list_revisions","google_drive_move","google_drive_search","google_drive_share","google_drive_trash","google_drive_unshare","google_drive_untrash","google_drive_update","google_drive_upload","google_forms_batch_update","google_forms_create_form","google_forms_create_watch","google_forms_delete_watch","google_forms_get_form","google_forms_get_responses","google_forms_list_watches","google_forms_renew_watch","google_forms_set_publish_settings","google_groups_add_alias","google_groups_add_member","google_groups_create_group","google_groups_delete_group","google_groups_get_group","google_groups_get_member","google_groups_get_settings","google_groups_has_member","google_groups_list_aliases","google_groups_list_groups","google_groups_list_members","google_groups_remove_alias","google_groups_remove_member","google_groups_update_group","google_groups_update_member","google_groups_update_settings","google_maps_air_quality","google_maps_directions","google_maps_distance_matrix","google_maps_elevation","google_maps_geocode","google_maps_geolocate","google_maps_place_details","google_maps_places_nearby","google_maps_places_search","google_maps_pollen","google_maps_reverse_geocode","google_maps_snap_to_roads","google_maps_solar","google_maps_speed_limits","google_maps_timezone","google_maps_validate_address","google_meet_create_space","google_meet_end_conference","google_meet_get_conference_record","google_meet_get_space","google_meet_list_conference_records","google_meet_list_participants","google_pagespeed_analyze","google_search","google_sheets_append","google_sheets_append_v2","google_sheets_batch_clear_v2","google_sheets_batch_get_v2","google_sheets_batch_update_v2","google_sheets_clear_v2","google_sheets_copy_sheet_v2","google_sheets_create_spreadsheet_v2","google_sheets_delete_rows_v2","google_sheets_delete_sheet_v2","google_sheets_delete_spreadsheet_v2","google_sheets_get_spreadsheet_v2","google_sheets_read","google_sheets_read_v2","google_sheets_update","google_sheets_update_v2","google_sheets_write","google_sheets_write_v2","google_slides_add_image","google_slides_add_slide","google_slides_batch_update","google_slides_copy_presentation","google_slides_create","google_slides_create_line","google_slides_create_paragraph_bullets","google_slides_create_shape","google_slides_create_sheets_chart","google_slides_create_table","google_slides_create_video","google_slides_delete_object","google_slides_delete_paragraph_bullets","google_slides_delete_table_column","google_slides_delete_table_row","google_slides_delete_text","google_slides_duplicate_object","google_slides_export_presentation","google_slides_get_page","google_slides_get_thumbnail","google_slides_group_objects","google_slides_insert_table_columns","google_slides_insert_table_rows","google_slides_insert_text","google_slides_merge_table_cells","google_slides_read","google_slides_refresh_sheets_chart","google_slides_replace_all_shapes_with_image","google_slides_replace_all_shapes_with_sheets_chart","google_slides_replace_all_text","google_slides_replace_image","google_slides_reroute_line","google_slides_ungroup_objects","google_slides_unmerge_table_cells","google_slides_update_image_properties","google_slides_update_line_category","google_slides_update_line_properties","google_slides_update_page_element_alt_text","google_slides_update_page_element_transform","google_slides_update_page_elements_z_order","google_slides_update_page_properties","google_slides_update_paragraph_style","google_slides_update_shape_properties","google_slides_update_slide_properties","google_slides_update_slides_position","google_slides_update_table_border_properties","google_slides_update_table_cell_properties","google_slides_update_table_column_properties","google_slides_update_table_row_properties","google_slides_update_text_style","google_slides_update_video_properties","google_slides_write","google_tasks_create","google_tasks_delete","google_tasks_get","google_tasks_list","google_tasks_list_task_lists","google_tasks_update","google_translate_detect","google_translate_text","google_vault_add_held_accounts","google_vault_add_matters_permissions","google_vault_close_matters","google_vault_create_matters","google_vault_create_matters_export","google_vault_create_matters_holds","google_vault_create_saved_query","google_vault_delete_matters","google_vault_delete_matters_export","google_vault_delete_matters_holds","google_vault_delete_saved_query","google_vault_download_export_file","google_vault_list_matters","google_vault_list_matters_export","google_vault_list_matters_holds","google_vault_list_saved_queries","google_vault_remove_held_accounts","google_vault_remove_matters_permissions","google_vault_reopen_matters","google_vault_undelete_matters","google_vault_update_matters","google_vault_update_matters_holds","grafana_check_data_source_health","grafana_create_alert_rule","grafana_create_annotation","grafana_create_contact_point","grafana_create_dashboard","grafana_create_folder","grafana_delete_alert_rule","grafana_delete_annotation","grafana_delete_contact_point","grafana_delete_dashboard","grafana_delete_folder","grafana_get_alert_rule","grafana_get_alert_rule_group","grafana_get_dashboard","grafana_get_data_source","grafana_get_folder","grafana_get_health","grafana_list_alert_rules","grafana_list_annotations","grafana_list_contact_points","grafana_list_dashboards","grafana_list_data_sources","grafana_list_folders","grafana_move_folder","grafana_query_data_source","grafana_update_alert_rule","grafana_update_annotation","grafana_update_contact_point","grafana_update_dashboard","grafana_update_folder","grain_create_hook","grain_create_hook_v2","grain_delete_hook","grain_delete_hook_v2","grain_get_recording","grain_get_transcript","grain_list_hooks","grain_list_hooks_v2","grain_list_meeting_types","grain_list_recordings","grain_list_teams","grain_list_views","granola_get_note","granola_list_folders","granola_list_notes","greenhouse_get_application","greenhouse_get_candidate","greenhouse_get_job","greenhouse_get_user","greenhouse_list_applications","greenhouse_list_candidates","greenhouse_list_departments","greenhouse_list_job_stages","greenhouse_list_jobs","greenhouse_list_offices","greenhouse_list_users","greptile_index_repo","greptile_query","greptile_search","greptile_status","guardrails_validate","hex_cancel_run","hex_create_collection","hex_create_group","hex_deactivate_user","hex_delete_group","hex_get_collection","hex_get_data_connection","hex_get_group","hex_get_project","hex_get_project_runs","hex_get_queried_tables","hex_get_run_status","hex_list_collections","hex_list_data_connections","hex_list_groups","hex_list_projects","hex_list_users","hex_run_project","hex_update_collection","hex_update_group","hex_update_project","http_request","hubspot_add_list_memberships","hubspot_create_appointment","hubspot_create_association","hubspot_create_company","hubspot_create_contact","hubspot_create_deal","hubspot_create_email","hubspot_create_line_item","hubspot_create_list","hubspot_create_note","hubspot_create_ticket","hubspot_delete_association","hubspot_delete_company","hubspot_delete_contact","hubspot_delete_deal","hubspot_delete_line_item","hubspot_delete_ticket","hubspot_get_appointment","hubspot_get_association_labels","hubspot_get_cart","hubspot_get_company","hubspot_get_contact","hubspot_get_deal","hubspot_get_email","hubspot_get_line_item","hubspot_get_list","hubspot_get_list_memberships","hubspot_get_marketing_event","hubspot_get_note","hubspot_get_properties","hubspot_get_quote","hubspot_get_ticket","hubspot_get_users","hubspot_list_appointments","hubspot_list_associations","hubspot_list_carts","hubspot_list_companies","hubspot_list_contacts","hubspot_list_deals","hubspot_list_emails","hubspot_list_line_items","hubspot_list_lists","hubspot_list_marketing_events","hubspot_list_notes","hubspot_list_owners","hubspot_list_quotes","hubspot_list_tickets","hubspot_remove_list_memberships","hubspot_search_companies","hubspot_search_contacts","hubspot_search_deals","hubspot_search_emails","hubspot_search_line_items","hubspot_search_notes","hubspot_search_quotes","hubspot_search_tickets","hubspot_update_appointment","hubspot_update_company","hubspot_update_contact","hubspot_update_deal","hubspot_update_line_item","hubspot_update_ticket","huggingface_chat","hunter_companies_find","hunter_discover","hunter_domain_search","hunter_email_count","hunter_email_finder","hunter_email_verifier","iam_add_user_to_group","iam_attach_role_policy","iam_attach_user_policy","iam_create_access_key","iam_create_role","iam_create_user","iam_delete_access_key","iam_delete_role","iam_delete_user","iam_detach_role_policy","iam_detach_user_policy","iam_get_role","iam_get_user","iam_list_attached_role_policies","iam_list_attached_user_policies","iam_list_groups","iam_list_policies","iam_list_roles","iam_list_users","iam_remove_user_from_group","iam_simulate_principal_policy","icypeas_find_email","icypeas_verify_email","identity_center_check_assignment_deletion_status","identity_center_check_assignment_status","identity_center_create_account_assignment","identity_center_delete_account_assignment","identity_center_describe_account","identity_center_get_group","identity_center_get_user","identity_center_list_account_assignments","identity_center_list_accounts","identity_center_list_groups","identity_center_list_instances","identity_center_list_permission_sets","image_generate","incidentio_actions_create","incidentio_actions_list","incidentio_actions_show","incidentio_actions_update","incidentio_alert_events_create","incidentio_alerts_list","incidentio_alerts_resolve","incidentio_alerts_show","incidentio_catalog_entries_list","incidentio_catalog_types_list","incidentio_custom_fields_create","incidentio_custom_fields_delete","incidentio_custom_fields_list","incidentio_custom_fields_show","incidentio_custom_fields_update","incidentio_escalation_paths_create","incidentio_escalation_paths_delete","incidentio_escalation_paths_list","incidentio_escalation_paths_show","incidentio_escalation_paths_update","incidentio_escalations_cancel","incidentio_escalations_create","incidentio_escalations_list","incidentio_escalations_show","incidentio_follow_ups_create","incidentio_follow_ups_list","incidentio_follow_ups_show","incidentio_follow_ups_update","incidentio_incident_alerts_list","incidentio_incident_memberships_create","incidentio_incident_memberships_revoke","incidentio_incident_participants_list","incidentio_incident_roles_create","incidentio_incident_roles_delete","incidentio_incident_roles_list","incidentio_incident_roles_show","incidentio_incident_roles_update","incidentio_incident_statuses_list","incidentio_incident_timestamps_list","incidentio_incident_timestamps_show","incidentio_incident_types_list","incidentio_incident_updates_list","incidentio_incidents_create","incidentio_incidents_list","incidentio_incidents_show","incidentio_incidents_update","incidentio_on_call_now","incidentio_schedule_entries_list","incidentio_schedule_overrides_create","incidentio_schedule_overrides_list","incidentio_schedules_create","incidentio_schedules_delete","incidentio_schedules_list","incidentio_schedules_show","incidentio_schedules_update","incidentio_severities_list","incidentio_teams_list","incidentio_teams_show","incidentio_users_list","incidentio_users_show","incidentio_workflows_create","incidentio_workflows_delete","incidentio_workflows_list","incidentio_workflows_show","incidentio_workflows_update","infisical_create_secret","infisical_delete_secret","infisical_get_secret","infisical_list_secrets","infisical_update_secret","instagram_delete_comment","instagram_download_media","instagram_get_account_insights","instagram_get_container_status","instagram_get_conversation_messages","instagram_get_media","instagram_get_media_insights","instagram_get_message","instagram_get_profile","instagram_get_publishing_limit","instagram_hide_comment","instagram_list_comments","instagram_list_conversations","instagram_list_media","instagram_list_stories","instagram_private_reply","instagram_publish_carousel","instagram_publish_image","instagram_publish_reel","instagram_publish_story","instagram_publish_video","instagram_reply_to_comment","instagram_send_text_message","instagram_set_comments_enabled","instantly_activate_campaign","instantly_create_campaign","instantly_create_lead","instantly_create_lead_list","instantly_delete_campaign","instantly_delete_leads","instantly_get_lead","instantly_list_campaigns","instantly_list_emails","instantly_list_lead_lists","instantly_list_leads","instantly_patch_campaign","instantly_patch_lead","instantly_pause_campaign","instantly_reply_to_email","instantly_update_lead_interest_status","intercom_assign_conversation_v2","intercom_attach_contact_to_company_v2","intercom_close_conversation_v2","intercom_create_company","intercom_create_company_v2","intercom_create_contact","intercom_create_contact_v2","intercom_create_event_v2","intercom_create_message","intercom_create_message_v2","intercom_create_note_v2","intercom_create_tag_v2","intercom_create_ticket","intercom_create_ticket_v2","intercom_delete_contact","intercom_delete_contact_v2","intercom_detach_contact_from_company_v2","intercom_get_company","intercom_get_company_v2","intercom_get_contact","intercom_get_contact_v2","intercom_get_conversation","intercom_get_conversation_v2","intercom_get_ticket","intercom_get_ticket_v2","intercom_list_admins_v2","intercom_list_companies","intercom_list_companies_v2","intercom_list_contacts","intercom_list_contacts_v2","intercom_list_conversations","intercom_list_conversations_v2","intercom_list_tags_v2","intercom_open_conversation_v2","intercom_reply_conversation","intercom_reply_conversation_v2","intercom_search_contacts","intercom_search_contacts_v2","intercom_search_conversations","intercom_search_conversations_v2","intercom_snooze_conversation_v2","intercom_tag_contact_v2","intercom_tag_conversation_v2","intercom_untag_contact_v2","intercom_update_contact","intercom_update_contact_v2","intercom_update_ticket_v2","jina_read_url","jina_search","jira_add_attachment","jira_add_comment","jira_add_watcher","jira_add_worklog","jira_assign_issue","jira_bulk_read","jira_create_issue_link","jira_delete_attachment","jira_delete_comment","jira_delete_issue","jira_delete_issue_link","jira_delete_worklog","jira_get_attachments","jira_get_comments","jira_get_fields","jira_get_project","jira_get_transitions","jira_get_users","jira_get_worklogs","jira_list_issue_types","jira_list_projects","jira_remove_watcher","jira_retrieve","jira_search_issues","jira_search_users","jira_transition_issue","jira_update","jira_update_comment","jira_update_worklog","jira_write","jsm_add_comment","jsm_add_customer","jsm_add_organization","jsm_add_participants","jsm_answer_approval","jsm_attach_form","jsm_copy_forms","jsm_create_object","jsm_create_organization","jsm_create_request","jsm_delete_form","jsm_delete_object","jsm_externalise_form","jsm_get_approvals","jsm_get_comments","jsm_get_customers","jsm_get_form","jsm_get_form_answers","jsm_get_form_structure","jsm_get_form_templates","jsm_get_issue_forms","jsm_get_object","jsm_get_object_schema","jsm_get_object_type_attributes","jsm_get_organizations","jsm_get_participants","jsm_get_queues","jsm_get_request","jsm_get_request_type_fields","jsm_get_request_types","jsm_get_requests","jsm_get_service_desks","jsm_get_sla","jsm_get_transitions","jsm_internalise_form","jsm_list_object_schemas","jsm_list_object_types","jsm_reopen_form","jsm_save_form_answers","jsm_search_objects_aql","jsm_submit_form","jsm_transition_request","jsm_update_object","jupyter_copy_content","jupyter_create_file","jupyter_create_session","jupyter_delete_content","jupyter_delete_session","jupyter_get_content","jupyter_interrupt_kernel","jupyter_list_contents","jupyter_list_kernels","jupyter_list_kernelspecs","jupyter_list_sessions","jupyter_rename_content","jupyter_restart_kernel","jupyter_start_kernel","jupyter_stop_kernel","jupyter_upload_file","kalshi_amend_order","kalshi_amend_order_v2","kalshi_cancel_order","kalshi_cancel_order_v2","kalshi_create_order","kalshi_create_order_v2","kalshi_get_balance","kalshi_get_balance_v2","kalshi_get_candlesticks","kalshi_get_candlesticks_v2","kalshi_get_event","kalshi_get_event_candlesticks","kalshi_get_event_candlesticks_v2","kalshi_get_event_v2","kalshi_get_events","kalshi_get_events_v2","kalshi_get_exchange_announcements","kalshi_get_exchange_announcements_v2","kalshi_get_exchange_schedule","kalshi_get_exchange_schedule_v2","kalshi_get_exchange_status","kalshi_get_exchange_status_v2","kalshi_get_fills","kalshi_get_fills_v2","kalshi_get_market","kalshi_get_market_v2","kalshi_get_markets","kalshi_get_markets_v2","kalshi_get_order","kalshi_get_order_v2","kalshi_get_orderbook","kalshi_get_orderbook_v2","kalshi_get_orders","kalshi_get_orders_v2","kalshi_get_positions","kalshi_get_positions_v2","kalshi_get_series_by_ticker","kalshi_get_series_by_ticker_v2","kalshi_get_series_list","kalshi_get_series_list_v2","kalshi_get_settlements","kalshi_get_settlements_v2","kalshi_get_trades","kalshi_get_trades_v2","ketch_get_consent","ketch_get_subscriptions","ketch_invoke_right","ketch_set_consent","ketch_set_subscriptions","knowledge_create_document","knowledge_delete_chunk","knowledge_delete_document","knowledge_get_connector","knowledge_get_document","knowledge_list_chunks","knowledge_list_connectors","knowledge_list_documents","knowledge_list_tags","knowledge_search","knowledge_trigger_sync","knowledge_update_chunk","knowledge_upload_chunk","knowledge_upsert_document","langsmith_create_feedback","langsmith_create_run","langsmith_create_runs_batch","langsmith_get_run","langsmith_update_run","latex_compile","latex_get_package","latex_list_fonts","latex_search_packages","launchdarkly_create_flag","launchdarkly_delete_flag","launchdarkly_get_audit_log","launchdarkly_get_flag","launchdarkly_get_flag_status","launchdarkly_list_environments","launchdarkly_list_flags","launchdarkly_list_members","launchdarkly_list_projects","launchdarkly_list_segments","launchdarkly_toggle_flag","launchdarkly_update_flag","leadmagic_company_search","leadmagic_email_to_profile","leadmagic_find_email","leadmagic_find_mobile","leadmagic_get_credits","leadmagic_profile_search","leadmagic_profile_to_email","leadmagic_role_finder","leadmagic_validate_email","lemlist_get_activities","lemlist_get_lead","lemlist_send_email","linear_add_label_to_issue","linear_add_label_to_project","linear_archive_issue","linear_archive_label","linear_archive_project","linear_create_attachment","linear_create_comment","linear_create_customer","linear_create_customer_request","linear_create_customer_status","linear_create_customer_tier","linear_create_cycle","linear_create_favorite","linear_create_issue","linear_create_issue_relation","linear_create_label","linear_create_project","linear_create_project_label","linear_create_project_milestone","linear_create_project_status","linear_create_project_update","linear_create_workflow_state","linear_delete_attachment","linear_delete_comment","linear_delete_customer","linear_delete_customer_status","linear_delete_customer_tier","linear_delete_issue","linear_delete_issue_relation","linear_delete_project","linear_delete_project_label","linear_delete_project_milestone","linear_delete_project_status","linear_get_active_cycle","linear_get_customer","linear_get_cycle","linear_get_issue","linear_get_project","linear_get_viewer","linear_list_attachments","linear_list_comments","linear_list_customer_requests","linear_list_customer_statuses","linear_list_customer_tiers","linear_list_customers","linear_list_cycles","linear_list_favorites","linear_list_issue_relations","linear_list_labels","linear_list_notifications","linear_list_project_labels","linear_list_project_milestones","linear_list_project_statuses","linear_list_project_updates","linear_list_projects","linear_list_teams","linear_list_users","linear_list_workflow_states","linear_merge_customers","linear_read_issues","linear_remove_label_from_issue","linear_remove_label_from_project","linear_search_issues","linear_unarchive_issue","linear_update_attachment","linear_update_comment","linear_update_customer","linear_update_customer_request","linear_update_customer_status","linear_update_customer_tier","linear_update_issue","linear_update_label","linear_update_notification","linear_update_project","linear_update_project_label","linear_update_project_milestone","linear_update_project_status","linear_update_workflow_state","linkedin_get_profile","linkedin_share_post","linkup_search","linq_add_participant","linq_check_imessage","linq_check_rcs","linq_create_attachment","linq_create_chat","linq_create_contact_card","linq_create_webhook_subscription","linq_delete_attachment","linq_delete_message","linq_delete_webhook_subscription","linq_edit_message","linq_get_attachment","linq_get_chat","linq_get_contact_card","linq_get_message","linq_get_webhook_subscription","linq_leave_chat","linq_list_chats","linq_list_messages","linq_list_phone_numbers","linq_list_thread","linq_list_webhook_events","linq_list_webhook_subscriptions","linq_mark_chat_read","linq_react_to_message","linq_remove_participant","linq_send_message","linq_send_voice_memo","linq_share_contact_card","linq_start_typing","linq_stop_typing","linq_update_chat","linq_update_contact_card","linq_update_webhook_subscription","llm_chat","logfire_get_token_info","logfire_get_trace","logfire_query","logfire_search_records","logrocket_create_release","logrocket_get_audit_logs","logrocket_get_highlights","logrocket_identify_user","logrocket_list_exported_sessions","logrocket_request_highlights","logs_get","logs_get_execution","logs_get_run_details","logs_query","logs_query_runs","loops_check_contact_suppression","loops_create_contact","loops_create_contact_property","loops_delete_contact","loops_find_contact","loops_get_transactional_email","loops_list_contact_properties","loops_list_mailing_lists","loops_list_transactional_emails","loops_remove_contact_suppression","loops_send_event","loops_send_transactional_email","loops_update_contact","luma_add_guests","luma_cancel_event","luma_create_event","luma_get_event","luma_get_guest","luma_get_guests","luma_list_events","luma_lookup_event","luma_send_invites","luma_update_event","luma_update_guest_status","mailchimp_add_member","mailchimp_add_member_tags","mailchimp_add_or_update_member","mailchimp_add_segment_member","mailchimp_add_subscriber_to_automation","mailchimp_archive_member","mailchimp_create_audience","mailchimp_create_batch_operation","mailchimp_create_campaign","mailchimp_create_interest","mailchimp_create_interest_category","mailchimp_create_landing_page","mailchimp_create_merge_field","mailchimp_create_segment","mailchimp_create_template","mailchimp_delete_audience","mailchimp_delete_batch_operation","mailchimp_delete_campaign","mailchimp_delete_interest","mailchimp_delete_interest_category","mailchimp_delete_landing_page","mailchimp_delete_member","mailchimp_delete_merge_field","mailchimp_delete_segment","mailchimp_delete_template","mailchimp_get_audience","mailchimp_get_audiences","mailchimp_get_automation","mailchimp_get_automations","mailchimp_get_batch_operation","mailchimp_get_batch_operations","mailchimp_get_campaign","mailchimp_get_campaign_content","mailchimp_get_campaign_report","mailchimp_get_campaign_reports","mailchimp_get_campaigns","mailchimp_get_interest","mailchimp_get_interest_categories","mailchimp_get_interest_category","mailchimp_get_interests","mailchimp_get_landing_page","mailchimp_get_landing_pages","mailchimp_get_member","mailchimp_get_member_tags","mailchimp_get_members","mailchimp_get_merge_field","mailchimp_get_merge_fields","mailchimp_get_segment","mailchimp_get_segment_members","mailchimp_get_segments","mailchimp_get_template","mailchimp_get_templates","mailchimp_pause_automation","mailchimp_publish_landing_page","mailchimp_remove_member_tags","mailchimp_remove_segment_member","mailchimp_replicate_campaign","mailchimp_schedule_campaign","mailchimp_send_campaign","mailchimp_set_campaign_content","mailchimp_start_automation","mailchimp_unarchive_member","mailchimp_unpublish_landing_page","mailchimp_unschedule_campaign","mailchimp_update_audience","mailchimp_update_campaign","mailchimp_update_interest","mailchimp_update_interest_category","mailchimp_update_landing_page","mailchimp_update_member","mailchimp_update_merge_field","mailchimp_update_segment","mailchimp_update_template","mailgun_add_list_member","mailgun_create_mailing_list","mailgun_get_domain","mailgun_get_mailing_list","mailgun_get_message","mailgun_list_domains","mailgun_list_messages","mailgun_send_message","managed_agent_archive_session","managed_agent_create_session","managed_agent_delete_session","managed_agent_get_session","managed_agent_interrupt_session","managed_agent_list_events","managed_agent_respond_custom_tool","managed_agent_respond_tool_confirmation","managed_agent_run_session","managed_agent_send_message","managed_agent_update_session","mem0_add_memories","mem0_get_memories","mem0_search_memories","memory_add","memory_delete","memory_get","memory_get_all","microsoft_ad_add_group_member","microsoft_ad_create_group","microsoft_ad_create_user","microsoft_ad_delete_group","microsoft_ad_delete_user","microsoft_ad_get_group","microsoft_ad_get_user","microsoft_ad_list_group_members","microsoft_ad_list_groups","microsoft_ad_list_users","microsoft_ad_remove_group_member","microsoft_ad_update_group","microsoft_ad_update_user","microsoft_dataverse_associate","microsoft_dataverse_create_multiple","microsoft_dataverse_create_record","microsoft_dataverse_delete_record","microsoft_dataverse_disassociate","microsoft_dataverse_download_file","microsoft_dataverse_execute_action","microsoft_dataverse_execute_function","microsoft_dataverse_fetchxml_query","microsoft_dataverse_get_entity_metadata","microsoft_dataverse_get_record","microsoft_dataverse_list_records","microsoft_dataverse_search","microsoft_dataverse_update_multiple","microsoft_dataverse_update_record","microsoft_dataverse_upload_file","microsoft_dataverse_upsert_record","microsoft_dataverse_whoami","microsoft_excel_clear_range","microsoft_excel_create_table","microsoft_excel_delete_worksheet","microsoft_excel_format_range","microsoft_excel_read","microsoft_excel_read_v2","microsoft_excel_sort_range","microsoft_excel_table_add","microsoft_excel_worksheet_add","microsoft_excel_write","microsoft_excel_write_v2","microsoft_planner_create_bucket","microsoft_planner_create_plan","microsoft_planner_create_task","microsoft_planner_delete_bucket","microsoft_planner_delete_plan","microsoft_planner_delete_task","microsoft_planner_get_plan_details","microsoft_planner_get_task_details","microsoft_planner_list_buckets","microsoft_planner_list_plans","microsoft_planner_read_bucket","microsoft_planner_read_plan","microsoft_planner_read_task","microsoft_planner_update_bucket","microsoft_planner_update_plan","microsoft_planner_update_plan_details","microsoft_planner_update_task","microsoft_planner_update_task_details","microsoft_teams_delete_channel_message","microsoft_teams_delete_chat_message","microsoft_teams_get_message","microsoft_teams_list_channel_members","microsoft_teams_list_channels","microsoft_teams_list_chat_members","microsoft_teams_list_chats","microsoft_teams_list_team_members","microsoft_teams_list_teams","microsoft_teams_read_channel","microsoft_teams_read_chat","microsoft_teams_reply_to_message","microsoft_teams_set_reaction","microsoft_teams_unset_reaction","microsoft_teams_update_channel_message","microsoft_teams_update_chat_message","microsoft_teams_write_channel","microsoft_teams_write_chat","millionverifier_get_credits","millionverifier_verify_email","mintlify_create_agent_job","mintlify_create_assistant_message","mintlify_detect_ai_prose","mintlify_get_agent_job","mintlify_get_assistant_caller_stats","mintlify_get_assistant_conversations","mintlify_get_feedback","mintlify_get_feedback_by_page","mintlify_get_page_content","mintlify_get_searches","mintlify_get_update_status","mintlify_get_views","mintlify_get_visitors","mintlify_search","mintlify_send_agent_message","mintlify_trigger_automation","mintlify_trigger_preview","mintlify_trigger_update","mistral_parser","mistral_parser_v2","mistral_parser_v3","monday_archive_item","monday_change_column_value","monday_create_board","monday_create_column","monday_create_group","monday_create_item","monday_create_subitem","monday_create_update","monday_delete_item","monday_duplicate_item","monday_get_board","monday_get_groups","monday_get_item","monday_get_items","monday_list_boards","monday_move_item_to_group","monday_search_items","monday_update_item","mongodb_delete","mongodb_execute","mongodb_insert","mongodb_introspect","mongodb_query","mongodb_update","mysql_delete","mysql_execute","mysql_insert","mysql_introspect","mysql_query","mysql_update","neo4j_create","neo4j_delete","neo4j_execute","neo4j_introspect","neo4j_merge","neo4j_query","neo4j_update","netsuite_attach_record","netsuite_batch_create_records","netsuite_batch_delete_records","netsuite_batch_get_records","netsuite_batch_update_records","netsuite_batch_upsert_records","netsuite_create_record","netsuite_delete_record","netsuite_detach_record","netsuite_execute_action","netsuite_execute_dataset","netsuite_execute_suiteql","netsuite_get_async_result","netsuite_get_async_status","netsuite_get_governance_limits","netsuite_get_record","netsuite_get_record_form","netsuite_get_record_metadata","netsuite_get_select_options","netsuite_get_server_time","netsuite_get_subresource","netsuite_list_datasets","netsuite_list_record_types","netsuite_list_records","netsuite_transform_record","netsuite_update_record","netsuite_upsert_record","neverbounce_get_credits","neverbounce_verify_email","new_relic_create_deployment_event","new_relic_get_entity","new_relic_nrql_query","new_relic_search_entities","notion_add_database_row","notion_add_database_row_v2","notion_append_blocks","notion_append_blocks_v2","notion_create_comment","notion_create_comment_v2","notion_create_database","notion_create_database_v2","notion_create_page","notion_create_page_v2","notion_delete_block","notion_delete_block_v2","notion_list_comments","notion_list_comments_v2","notion_list_users","notion_list_users_v2","notion_query_database","notion_query_database_v2","notion_read","notion_read_database","notion_read_database_v2","notion_read_v2","notion_retrieve_block","notion_retrieve_block_children","notion_retrieve_block_children_v2","notion_retrieve_block_v2","notion_retrieve_user","notion_retrieve_user_v2","notion_search","notion_search_v2","notion_update_block","notion_update_block_v2","notion_update_page","notion_update_page_v2","notion_write","notion_write_v2","obsidian_append_active","obsidian_append_note","obsidian_append_periodic_note","obsidian_create_note","obsidian_delete_note","obsidian_execute_command","obsidian_get_active","obsidian_get_note","obsidian_get_periodic_note","obsidian_list_commands","obsidian_list_files","obsidian_open_file","obsidian_patch_active","obsidian_patch_note","obsidian_search","okta_activate_group_rule","okta_activate_user","okta_add_user_to_group","okta_assign_group_to_app","okta_assign_user_role","okta_assign_user_to_app","okta_clear_user_sessions","okta_create_group","okta_create_group_rule","okta_create_user","okta_deactivate_group_rule","okta_deactivate_user","okta_delete_group","okta_delete_group_rule","okta_delete_user","okta_enroll_factor","okta_get_app","okta_get_factor","okta_get_group","okta_get_group_rule","okta_get_logs","okta_get_session","okta_get_user","okta_list_app_groups","okta_list_app_users","okta_list_apps","okta_list_factors","okta_list_group_members","okta_list_group_rules","okta_list_groups","okta_list_user_roles","okta_list_users","okta_remove_group_from_app","okta_remove_user_from_app","okta_remove_user_from_group","okta_remove_user_role","okta_reset_all_factors","okta_reset_factor","okta_reset_password","okta_revoke_session","okta_suspend_user","okta_unsuspend_user","okta_update_group","okta_update_user","onedrive_copy","onedrive_create_folder","onedrive_create_share_link","onedrive_delete","onedrive_download","onedrive_get_drive_info","onedrive_get_item","onedrive_list","onedrive_move","onedrive_search","onedrive_upload","onepassword_create_item","onepassword_delete_item","onepassword_get_item","onepassword_get_item_file","onepassword_get_vault","onepassword_list_items","onepassword_list_vaults","onepassword_replace_item","onepassword_resolve_secret","onepassword_update_item","openai_embeddings","openai_image","outlook_calendar_create_event","outlook_calendar_delete_event","outlook_calendar_get_event","outlook_calendar_list_events","outlook_calendar_respond","outlook_calendar_update_event","outlook_copy","outlook_create_folder","outlook_delete","outlook_draft","outlook_forward","outlook_get_attachment","outlook_list_attachments","outlook_list_folders","outlook_mark_read","outlook_mark_unread","outlook_move","outlook_read","outlook_reply","outlook_reply_all","outlook_search","outlook_send","outlook_update_message","pagerduty_add_note","pagerduty_create_incident","pagerduty_get_incident","pagerduty_get_service","pagerduty_list_escalation_policies","pagerduty_list_incident_alerts","pagerduty_list_incidents","pagerduty_list_oncalls","pagerduty_list_schedules","pagerduty_list_services","pagerduty_list_users","pagerduty_merge_incidents","pagerduty_send_event","pagerduty_snooze_incident","pagerduty_update_incident","parallel_deep_research","parallel_extract","parallel_search","pdl_autocomplete","pdl_bulk_company_enrich","pdl_bulk_person_enrich","pdl_clean_company","pdl_clean_location","pdl_clean_school","pdl_company_enrich","pdl_company_search","pdl_person_enrich","pdl_person_identify","pdl_person_search","perplexity_chat","perplexity_search","persona_approve_inquiry","persona_create_account","persona_create_inquiry","persona_create_report","persona_decline_inquiry","persona_expire_inquiry","persona_generate_inquiry_link","persona_get_account","persona_get_case","persona_get_document","persona_get_inquiry","persona_get_report","persona_get_verification","persona_import_accounts","persona_list_accounts","persona_list_cases","persona_list_inquiries","persona_list_inquiry_templates","persona_list_reports","persona_mark_inquiry_for_review","persona_print_inquiry_pdf","persona_redact_account","persona_redact_inquiry","persona_resume_inquiry","persona_update_account","persona_update_inquiry","pinecone_delete_vectors","pinecone_describe_index","pinecone_describe_index_stats","pinecone_fetch","pinecone_generate_embeddings","pinecone_list_indexes","pinecone_list_vector_ids","pinecone_search_text","pinecone_search_vector","pinecone_update_vector","pinecone_upsert_text","pipedrive_create_activity","pipedrive_create_deal","pipedrive_create_lead","pipedrive_create_project","pipedrive_delete_lead","pipedrive_get_activities","pipedrive_get_all_deals","pipedrive_get_deal","pipedrive_get_files","pipedrive_get_leads","pipedrive_get_mail_messages","pipedrive_get_mail_thread","pipedrive_get_pipeline_deals","pipedrive_get_pipelines","pipedrive_get_projects","pipedrive_update_activity","pipedrive_update_deal","pipedrive_update_lead","polymarket_get_activity","polymarket_get_event","polymarket_get_events","polymarket_get_holders","polymarket_get_last_trade_price","polymarket_get_leaderboard","polymarket_get_market","polymarket_get_markets","polymarket_get_midpoint","polymarket_get_orderbook","polymarket_get_positions","polymarket_get_price","polymarket_get_price_history","polymarket_get_series","polymarket_get_series_by_id","polymarket_get_spread","polymarket_get_tags","polymarket_get_tick_size","polymarket_get_trades","polymarket_search","postgresql_delete","postgresql_execute","postgresql_insert","postgresql_introspect","postgresql_query","postgresql_update","posthog_batch_events","posthog_capture_event","posthog_create_annotation","posthog_create_cohort","posthog_create_dashboard","posthog_create_experiment","posthog_create_feature_flag","posthog_create_insight","posthog_create_survey","posthog_delete_feature_flag","posthog_delete_person","posthog_delete_survey","posthog_evaluate_flags","posthog_get_cohort","posthog_get_dashboard","posthog_get_event_definition","posthog_get_experiment","posthog_get_feature_flag","posthog_get_insight","posthog_get_organization","posthog_get_person","posthog_get_project","posthog_get_property_definition","posthog_get_session_recording","posthog_get_survey","posthog_list_actions","posthog_list_annotations","posthog_list_cohorts","posthog_list_dashboards","posthog_list_event_definitions","posthog_list_experiments","posthog_list_feature_flags","posthog_list_insights","posthog_list_organizations","posthog_list_persons","posthog_list_projects","posthog_list_property_definitions","posthog_list_recording_playlists","posthog_list_session_recordings","posthog_list_surveys","posthog_query","posthog_update_cohort","posthog_update_event_definition","posthog_update_experiment","posthog_update_feature_flag","posthog_update_insight","posthog_update_property_definition","posthog_update_survey","profound_bot_logs","profound_bots_report","profound_category_assets","profound_category_personas","profound_category_prompts","profound_category_tags","profound_category_topics","profound_citation_prompts","profound_citations_report","profound_list_assets","profound_list_categories","profound_list_domains","profound_list_models","profound_list_optimizations","profound_list_personas","profound_list_regions","profound_optimization_analysis","profound_prompt_answers","profound_prompt_volume","profound_query_fanouts","profound_raw_logs","profound_referrals_report","profound_sentiment_report","profound_visibility_report","prospeo_account_information","prospeo_bulk_enrich_company","prospeo_bulk_enrich_person","prospeo_enrich_company","prospeo_enrich_person","prospeo_search_company","prospeo_search_person","prospeo_search_suggestions","pulse_parser","pulse_parser_v2","qdrant_fetch_points","qdrant_search_vector","qdrant_upsert_points","quartr_get_audio","quartr_get_company","quartr_get_event","quartr_get_event_summary","quartr_get_report","quartr_get_slide_deck","quartr_get_transcript","quartr_list_audio","quartr_list_companies","quartr_list_document_types","quartr_list_documents","quartr_list_event_types","quartr_list_events","quartr_list_live_events","quartr_list_reports","quartr_list_slide_decks","quartr_list_transcripts","quiver_image_to_svg","quiver_list_models","quiver_text_to_svg","rabbitmq_create_binding","rabbitmq_create_exchange","rabbitmq_create_policy","rabbitmq_create_queue","rabbitmq_delete_binding","rabbitmq_delete_exchange","rabbitmq_delete_policy","rabbitmq_delete_queue","rabbitmq_get_exchange","rabbitmq_get_messages","rabbitmq_get_overview","rabbitmq_get_queue","rabbitmq_health_check","rabbitmq_list_bindings","rabbitmq_list_channels","rabbitmq_list_connections","rabbitmq_list_consumers","rabbitmq_list_exchange_bindings","rabbitmq_list_exchanges","rabbitmq_list_nodes","rabbitmq_list_policies","rabbitmq_list_queues","rabbitmq_list_vhosts","rabbitmq_publish_message","rabbitmq_purge_queue","railway_create_environment","railway_create_project","railway_create_service","railway_delete_environment","railway_delete_project","railway_delete_service","railway_delete_variable","railway_deploy_service","railway_get_deployment","railway_get_deployment_logs","railway_get_project","railway_list_deployments","railway_list_project_members","railway_list_projects","railway_list_variables","railway_restart_deployment","railway_rollback_deployment","railway_transfer_project","railway_update_project","railway_upsert_variable","rb2b_credit_check","rb2b_email_to_activity","rb2b_hem_to_best_linkedin","rb2b_hem_to_business_profile","rb2b_hem_to_linkedin","rb2b_hem_to_maid","rb2b_ip_to_company","rb2b_ip_to_hem","rb2b_ip_to_maid","rb2b_linkedin_slug_search","rb2b_linkedin_to_best_personal_email","rb2b_linkedin_to_business_profile","rb2b_linkedin_to_hashed_emails","rb2b_linkedin_to_mobile_phone","rb2b_linkedin_to_personal_email","rds_delete","rds_execute","rds_insert","rds_introspect","rds_query","rds_update","reddit_delete","reddit_edit","reddit_get_comments","reddit_get_controversial","reddit_get_info","reddit_get_me","reddit_get_messages","reddit_get_posts","reddit_get_saved","reddit_get_subreddit_info","reddit_get_subreddit_rules","reddit_get_user","reddit_get_user_comments","reddit_get_user_posts","reddit_hide","reddit_hot_posts","reddit_list_my_subreddits","reddit_lock","reddit_mark_all_read","reddit_mark_read","reddit_marknsfw","reddit_mod_approve","reddit_mod_distinguish","reddit_mod_remove","reddit_mod_sticky","reddit_reply","reddit_report","reddit_save","reddit_search","reddit_search_subreddits","reddit_send_message","reddit_submit_post","reddit_subscribe","reddit_unhide","reddit_unlock","reddit_unmarknsfw","reddit_unsave","reddit_vote","redis_command","redis_delete","redis_exists","redis_expire","redis_get","redis_hdel","redis_hget","redis_hgetall","redis_hset","redis_incr","redis_incrby","redis_keys","redis_llen","redis_lpop","redis_lpush","redis_lrange","redis_persist","redis_rpop","redis_rpush","redis_set","redis_setnx","redis_ttl","reducto_parser","reducto_parser_v2","resend_cancel_email","resend_create_audience","resend_create_broadcast","resend_create_contact","resend_delete_audience","resend_delete_contact","resend_get_audience","resend_get_broadcast","resend_get_contact","resend_get_email","resend_list_audiences","resend_list_contacts","resend_list_domains","resend_send","resend_send_broadcast","resend_update_contact","revenuecat_create_purchase","revenuecat_defer_google_subscription","revenuecat_delete_customer","revenuecat_get_customer","revenuecat_grant_entitlement","revenuecat_list_offerings","revenuecat_refund_google_subscription","revenuecat_revoke_entitlement","revenuecat_revoke_google_subscription","revenuecat_update_subscriber_attributes","rippling_bulk_create_custom_object_records","rippling_bulk_delete_custom_object_records","rippling_bulk_update_custom_object_records","rippling_create_business_partner","rippling_create_business_partner_group","rippling_create_custom_app","rippling_create_custom_object","rippling_create_custom_object_field","rippling_create_custom_object_record","rippling_create_custom_page","rippling_create_custom_setting","rippling_create_department","rippling_create_draft_hires","rippling_create_object_category","rippling_create_title","rippling_create_work_location","rippling_delete_business_partner","rippling_delete_business_partner_group","rippling_delete_custom_app","rippling_delete_custom_object","rippling_delete_custom_object_field","rippling_delete_custom_object_record","rippling_delete_custom_page","rippling_delete_custom_setting","rippling_delete_object_category","rippling_delete_title","rippling_delete_work_location","rippling_get_business_partner","rippling_get_business_partner_group","rippling_get_current_user","rippling_get_custom_app","rippling_get_custom_object","rippling_get_custom_object_field","rippling_get_custom_object_record","rippling_get_custom_object_record_by_external_id","rippling_get_custom_page","rippling_get_custom_setting","rippling_get_department","rippling_get_employment_type","rippling_get_job_function","rippling_get_object_category","rippling_get_report_run","rippling_get_supergroup","rippling_get_team","rippling_get_title","rippling_get_user","rippling_get_work_location","rippling_get_worker","rippling_list_business_partner_groups","rippling_list_business_partners","rippling_list_companies","rippling_list_custom_apps","rippling_list_custom_fields","rippling_list_custom_object_fields","rippling_list_custom_object_records","rippling_list_custom_objects","rippling_list_custom_pages","rippling_list_custom_settings","rippling_list_departments","rippling_list_employment_types","rippling_list_entitlements","rippling_list_job_functions","rippling_list_object_categories","rippling_list_supergroup_exclusion_members","rippling_list_supergroup_inclusion_members","rippling_list_supergroup_members","rippling_list_supergroups","rippling_list_teams","rippling_list_titles","rippling_list_users","rippling_list_work_locations","rippling_list_workers","rippling_query_custom_object_records","rippling_trigger_report_run","rippling_update_custom_app","rippling_update_custom_object","rippling_update_custom_object_field","rippling_update_custom_object_record","rippling_update_custom_page","rippling_update_custom_setting","rippling_update_department","rippling_update_object_category","rippling_update_supergroup_exclusion_members","rippling_update_supergroup_inclusion_members","rippling_update_title","rippling_update_work_location","rocketlane_add_field_option","rocketlane_add_project_members","rocketlane_add_task_assignees","rocketlane_add_task_dependencies","rocketlane_add_task_followers","rocketlane_archive_project","rocketlane_assign_placeholders","rocketlane_create_field","rocketlane_create_phase","rocketlane_create_project","rocketlane_create_space","rocketlane_create_space_document","rocketlane_create_task","rocketlane_create_time_entry","rocketlane_create_time_off","rocketlane_delete_field","rocketlane_delete_phase","rocketlane_delete_project","rocketlane_delete_space","rocketlane_delete_space_document","rocketlane_delete_task","rocketlane_delete_time_entry","rocketlane_delete_time_off","rocketlane_get_field","rocketlane_get_invoice","rocketlane_get_invoice_line_items","rocketlane_get_invoice_payments","rocketlane_get_phase","rocketlane_get_project","rocketlane_get_space","rocketlane_get_space_document","rocketlane_get_task","rocketlane_get_time_entry","rocketlane_get_time_off","rocketlane_get_user","rocketlane_import_template","rocketlane_list_fields","rocketlane_list_invoices","rocketlane_list_phases","rocketlane_list_placeholders","rocketlane_list_projects","rocketlane_list_resource_allocations","rocketlane_list_space_documents","rocketlane_list_spaces","rocketlane_list_tasks","rocketlane_list_time_entries","rocketlane_list_time_entry_categories","rocketlane_list_time_offs","rocketlane_list_users","rocketlane_move_task_to_phase","rocketlane_remove_project_members","rocketlane_remove_task_assignees","rocketlane_remove_task_dependencies","rocketlane_remove_task_followers","rocketlane_search_time_entries","rocketlane_unassign_placeholders","rocketlane_update_field","rocketlane_update_field_option","rocketlane_update_phase","rocketlane_update_project","rocketlane_update_space","rocketlane_update_space_document","rocketlane_update_task","rocketlane_update_time_entry","rootly_acknowledge_alert","rootly_add_incident_event","rootly_add_subscribers","rootly_assign_incident_role","rootly_create_action_item","rootly_create_alert","rootly_create_incident","rootly_create_status_page_event","rootly_delete_action_item","rootly_delete_incident","rootly_escalate_alert","rootly_get_alert","rootly_get_incident","rootly_list_action_items","rootly_list_alerts","rootly_list_causes","rootly_list_environments","rootly_list_escalation_policies","rootly_list_functionalities","rootly_list_incident_events","rootly_list_incident_roles","rootly_list_incident_types","rootly_list_incidents","rootly_list_on_calls","rootly_list_playbooks","rootly_list_retrospectives","rootly_list_schedules","rootly_list_services","rootly_list_severities","rootly_list_teams","rootly_list_users","rootly_mitigate_incident","rootly_remove_subscribers","rootly_resolve_alert","rootly_resolve_incident","rootly_run_workflow","rootly_snooze_alert","rootly_unassign_incident_role","rootly_update_action_item","rootly_update_alert","rootly_update_incident","s3_copy_object","s3_create_bucket","s3_delete_bucket","s3_delete_object","s3_delete_objects","s3_get_object","s3_head_object","s3_list_buckets","s3_list_objects","s3_presigned_url","s3_put_object","salesforce_create_account","salesforce_create_case","salesforce_create_contact","salesforce_create_custom_field","salesforce_create_custom_object","salesforce_create_lead","salesforce_create_opportunity","salesforce_create_task","salesforce_delete_account","salesforce_delete_case","salesforce_delete_contact","salesforce_delete_custom_field","salesforce_delete_lead","salesforce_delete_opportunity","salesforce_delete_task","salesforce_describe_object","salesforce_get_accounts","salesforce_get_cases","salesforce_get_contacts","salesforce_get_dashboard","salesforce_get_leads","salesforce_get_opportunities","salesforce_get_report","salesforce_get_tasks","salesforce_list_dashboards","salesforce_list_objects","salesforce_list_report_types","salesforce_list_reports","salesforce_query","salesforce_query_more","salesforce_refresh_dashboard","salesforce_run_report","salesforce_tooling_query","salesforce_update_account","salesforce_update_case","salesforce_update_contact","salesforce_update_custom_field","salesforce_update_lead","salesforce_update_opportunity","salesforce_update_task","sap_concur_approve_expense_report","sap_concur_associate_attendees","sap_concur_create_cash_advance","sap_concur_create_expected_expense","sap_concur_create_expense_report","sap_concur_create_list_item","sap_concur_create_purchase_request","sap_concur_create_quick_expense","sap_concur_create_quick_expense_with_image","sap_concur_create_report_comment","sap_concur_create_travel_request","sap_concur_create_user","sap_concur_delete_expected_expense","sap_concur_delete_expense","sap_concur_delete_expense_report","sap_concur_delete_list_item","sap_concur_delete_travel_request","sap_concur_delete_user","sap_concur_get_allocation","sap_concur_get_budget","sap_concur_get_cash_advance","sap_concur_get_expected_expense","sap_concur_get_expense","sap_concur_get_expense_report","sap_concur_get_itemizations","sap_concur_get_itinerary","sap_concur_get_list","sap_concur_get_list_item","sap_concur_get_purchase_request","sap_concur_get_receipt","sap_concur_get_receipt_status","sap_concur_get_request_cash_advance","sap_concur_get_travel_profile","sap_concur_get_travel_request","sap_concur_get_user","sap_concur_issue_cash_advance","sap_concur_list_allocations","sap_concur_list_attendee_associations","sap_concur_list_budget_categories","sap_concur_list_budgets","sap_concur_list_exceptions","sap_concur_list_expected_expenses","sap_concur_list_expense_reports","sap_concur_list_expenses","sap_concur_list_itineraries","sap_concur_list_list_items","sap_concur_list_lists","sap_concur_list_receipts","sap_concur_list_report_comments","sap_concur_list_reports_to_approve","sap_concur_list_travel_profiles_summary","sap_concur_list_travel_request_comments","sap_concur_list_travel_requests","sap_concur_list_users","sap_concur_move_travel_request","sap_concur_recall_expense_report","sap_concur_remove_all_attendees","sap_concur_search_locations","sap_concur_search_users","sap_concur_send_back_expense_report","sap_concur_submit_expense_report","sap_concur_update_allocation","sap_concur_update_expected_expense","sap_concur_update_expense","sap_concur_update_expense_report","sap_concur_update_list_item","sap_concur_update_travel_request","sap_concur_update_user","sap_concur_upload_exchange_rates","sap_concur_upload_receipt_image","sap_s4hana_create_business_partner","sap_s4hana_create_purchase_order","sap_s4hana_create_purchase_requisition","sap_s4hana_create_sales_order","sap_s4hana_delete_sales_order","sap_s4hana_get_billing_document","sap_s4hana_get_business_partner","sap_s4hana_get_customer","sap_s4hana_get_inbound_delivery","sap_s4hana_get_material_document","sap_s4hana_get_outbound_delivery","sap_s4hana_get_product","sap_s4hana_get_purchase_order","sap_s4hana_get_purchase_requisition","sap_s4hana_get_sales_order","sap_s4hana_get_supplier","sap_s4hana_get_supplier_invoice","sap_s4hana_list_billing_documents","sap_s4hana_list_business_partners","sap_s4hana_list_customers","sap_s4hana_list_inbound_deliveries","sap_s4hana_list_material_documents","sap_s4hana_list_material_stock","sap_s4hana_list_outbound_deliveries","sap_s4hana_list_products","sap_s4hana_list_purchase_orders","sap_s4hana_list_purchase_requisitions","sap_s4hana_list_sales_orders","sap_s4hana_list_supplier_invoices","sap_s4hana_list_suppliers","sap_s4hana_odata_query","sap_s4hana_update_business_partner","sap_s4hana_update_customer","sap_s4hana_update_product","sap_s4hana_update_purchase_order","sap_s4hana_update_purchase_requisition","sap_s4hana_update_sales_order","sap_s4hana_update_supplier","search_tool","secrets_manager_create_secret","secrets_manager_delete_secret","secrets_manager_describe_secret","secrets_manager_get_secret","secrets_manager_list_secrets","secrets_manager_restore_secret","secrets_manager_rotate_secret","secrets_manager_tag_resource","secrets_manager_untag_resource","secrets_manager_update_secret","sendblue_evaluate_service","sendblue_get_message","sendblue_send_group_message","sendblue_send_message","sendblue_send_typing_indicator","sendgrid_add_contact","sendgrid_add_contacts_to_list","sendgrid_create_list","sendgrid_create_template","sendgrid_create_template_version","sendgrid_delete_contacts","sendgrid_delete_list","sendgrid_delete_template","sendgrid_get_contact","sendgrid_get_list","sendgrid_get_template","sendgrid_list_all_lists","sendgrid_list_templates","sendgrid_remove_contacts_from_list","sendgrid_search_contacts","sendgrid_send_mail","sentry_events_get","sentry_events_list","sentry_issues_get","sentry_issues_list","sentry_issues_update","sentry_projects_create","sentry_projects_get","sentry_projects_list","sentry_projects_update","sentry_releases_create","sentry_releases_deploy","sentry_releases_list","sentry_teams_list","serper_search","servicenow_add_incident_comment","servicenow_aggregate","servicenow_close_incident","servicenow_create_change_request","servicenow_create_incident","servicenow_create_record","servicenow_delete_record","servicenow_download_attachment","servicenow_find_user","servicenow_get_change_next_states","servicenow_get_change_request","servicenow_get_ci","servicenow_get_incident","servicenow_get_knowledge_article","servicenow_get_requested_item","servicenow_list_approvals","servicenow_list_attachments","servicenow_list_catalog_items","servicenow_list_change_requests","servicenow_list_change_tasks","servicenow_list_ci_relationships","servicenow_list_group_members","servicenow_list_incidents","servicenow_list_requested_items","servicenow_order_catalog_item","servicenow_read_record","servicenow_resolve_incident","servicenow_search_cis","servicenow_search_knowledge","servicenow_update_approval","servicenow_update_change_request","servicenow_update_change_state","servicenow_update_incident","servicenow_update_record","servicenow_upload_attachment","ses_create_configuration_set","ses_create_email_identity","ses_create_template","ses_delete_email_identity","ses_delete_suppressed_destination","ses_delete_template","ses_get_account","ses_get_email_identity","ses_get_suppressed_destination","ses_get_template","ses_list_identities","ses_list_suppressed_destinations","ses_list_templates","ses_put_suppressed_destination","ses_send_bulk_email","ses_send_custom_verification_email","ses_send_email","ses_send_templated_email","ses_update_template","sftp_delete","sftp_download","sftp_list","sftp_mkdir","sftp_upload","sharepoint_add_list_items","sharepoint_create_list","sharepoint_create_page","sharepoint_delete_file","sharepoint_delete_list_item","sharepoint_delete_page","sharepoint_download_file","sharepoint_get_drive_item","sharepoint_get_list","sharepoint_get_list_item","sharepoint_list_sites","sharepoint_publish_page","sharepoint_read_page","sharepoint_update_list","sharepoint_update_page","sharepoint_upload_file","shopify_adjust_inventory","shopify_cancel_order","shopify_create_customer","shopify_create_fulfillment","shopify_create_product","shopify_delete_customer","shopify_delete_product","shopify_get_collection","shopify_get_customer","shopify_get_inventory_level","shopify_get_order","shopify_get_product","shopify_list_collections","shopify_list_customers","shopify_list_inventory_items","shopify_list_locations","shopify_list_orders","shopify_list_products","shopify_update_customer","shopify_update_order","shopify_update_product","similarweb_bounce_rate","similarweb_page_views","similarweb_pages_per_visit","similarweb_traffic_visits","similarweb_visit_duration","similarweb_website_overview","sixtyfour_enrich_company","sixtyfour_enrich_lead","sixtyfour_find_email","sixtyfour_find_phone","slack_add_reaction","slack_archive_conversation","slack_canvas","slack_create_channel_canvas","slack_create_conversation","slack_delete_canvas","slack_delete_message","slack_delete_scheduled_message","slack_download","slack_edit_canvas","slack_ephemeral_message","slack_get_canvas","slack_get_channel_history","slack_get_channel_info","slack_get_message","slack_get_permalink","slack_get_thread","slack_get_thread_replies","slack_get_user","slack_get_user_presence","slack_invite_to_conversation","slack_list_canvases","slack_list_channels","slack_list_members","slack_list_scheduled_messages","slack_list_users","slack_lookup_canvas_sections","slack_message","slack_message_reader","slack_open_view","slack_publish_view","slack_push_view","slack_remove_reaction","slack_rename_conversation","slack_schedule_message","slack_set_conversation_purpose","slack_set_conversation_topic","slack_set_status","slack_set_suggested_prompts","slack_set_title","slack_update_message","slack_update_view","smartlead_add_email_accounts_to_campaign","smartlead_add_leads_to_campaign","smartlead_create_campaign","smartlead_create_lead_list","smartlead_delete_campaign","smartlead_delete_campaign_webhook","smartlead_delete_lead_from_campaign","smartlead_delete_lead_list","smartlead_duplicate_campaign","smartlead_export_campaign_leads","smartlead_get_campaign","smartlead_get_campaign_analytics","smartlead_get_campaign_analytics_by_date","smartlead_get_campaign_lead_statistics","smartlead_get_campaign_mailbox_statistics","smartlead_get_campaign_sequences","smartlead_get_campaign_statistics","smartlead_get_campaign_top_level_analytics_by_date","smartlead_get_campaign_webhook_summary","smartlead_get_lead_by_email","smartlead_get_lead_by_id","smartlead_get_lead_list","smartlead_get_lead_message_history","smartlead_list_campaign_email_accounts","smartlead_list_campaign_leads","smartlead_list_campaign_webhooks","smartlead_list_campaigns","smartlead_list_clients","smartlead_list_email_accounts","smartlead_list_inbox_replies","smartlead_list_lead_activities","smartlead_list_lead_categories","smartlead_list_lead_lists","smartlead_mark_lead_complete","smartlead_pause_lead","smartlead_remove_email_accounts_from_campaign","smartlead_resume_lead","smartlead_save_campaign_sequences","smartlead_unsubscribe_lead_from_campaign","smartlead_unsubscribe_lead_globally","smartlead_update_campaign_schedule","smartlead_update_campaign_settings","smartlead_update_campaign_status","smartlead_update_lead","smartlead_update_lead_category","smartlead_update_lead_list","smartlead_upsert_campaign_webhook","sms_send","smtp_send_mail","snowflake_alter_warehouse","snowflake_call_procedure","snowflake_cancel_statement","snowflake_cancel_task_run","snowflake_delete_rows","snowflake_execute_sql","snowflake_get_statement","snowflake_get_task","snowflake_get_task_run","snowflake_get_task_run_output","snowflake_get_warehouse","snowflake_insert_rows","snowflake_introspect_schema","snowflake_list_copy_history","snowflake_list_databases","snowflake_list_query_history","snowflake_list_schemas","snowflake_list_tables","snowflake_list_task_runs","snowflake_list_tasks","snowflake_list_warehouses","snowflake_load_data","snowflake_resume_task","snowflake_resume_warehouse","snowflake_run_task","snowflake_suspend_task","snowflake_suspend_warehouse","snowflake_unload_data","snowflake_update_rows","snowflake_upsert_rows","splunk_cancel_search_job","splunk_create_search_job","splunk_dispatch_saved_search","splunk_get_fired_alerts","splunk_get_saved_search","splunk_get_search_job","splunk_get_search_results","splunk_list_apps","splunk_list_fired_alerts","splunk_list_indexes","splunk_list_saved_searches","splunk_run_search","sportmonks_core_get_cities","sportmonks_core_get_city","sportmonks_core_get_continent","sportmonks_core_get_continents","sportmonks_core_get_countries","sportmonks_core_get_country","sportmonks_core_get_entity_filters","sportmonks_core_get_my_usage","sportmonks_core_get_region","sportmonks_core_get_regions","sportmonks_core_get_timezones","sportmonks_core_get_type","sportmonks_core_get_type_by_entity","sportmonks_core_get_types","sportmonks_core_search_cities","sportmonks_core_search_countries","sportmonks_core_search_regions","sportmonks_football_expected_by_player","sportmonks_football_expected_by_team","sportmonks_football_get_all_commentaries","sportmonks_football_get_all_fixtures","sportmonks_football_get_all_players","sportmonks_football_get_all_rivals","sportmonks_football_get_all_teams","sportmonks_football_get_all_transfer_rumours","sportmonks_football_get_all_transfers","sportmonks_football_get_brackets_by_season","sportmonks_football_get_coach","sportmonks_football_get_coaches","sportmonks_football_get_coaches_by_country","sportmonks_football_get_commentaries_by_fixture","sportmonks_football_get_current_leagues_by_team","sportmonks_football_get_expected_lineups_by_player","sportmonks_football_get_expected_lineups_by_team","sportmonks_football_get_extended_team_squad","sportmonks_football_get_fixture","sportmonks_football_get_fixtures_by_date","sportmonks_football_get_fixtures_by_date_range","sportmonks_football_get_fixtures_by_date_range_for_team","sportmonks_football_get_fixtures_by_ids","sportmonks_football_get_grouped_standings_by_round","sportmonks_football_get_head_to_head","sportmonks_football_get_inplay_livescores","sportmonks_football_get_latest_coaches","sportmonks_football_get_latest_fixtures","sportmonks_football_get_latest_livescores","sportmonks_football_get_latest_players","sportmonks_football_get_latest_totw","sportmonks_football_get_latest_transfers","sportmonks_football_get_league","sportmonks_football_get_leagues","sportmonks_football_get_leagues_by_country","sportmonks_football_get_leagues_by_date","sportmonks_football_get_leagues_by_team","sportmonks_football_get_live_leagues","sportmonks_football_get_live_probabilities","sportmonks_football_get_live_probabilities_by_fixture","sportmonks_football_get_live_standings_by_league","sportmonks_football_get_livescores","sportmonks_football_get_match_facts","sportmonks_football_get_match_facts_by_date_range","sportmonks_football_get_match_facts_by_fixture","sportmonks_football_get_match_facts_by_league","sportmonks_football_get_past_fixtures_by_tv_station","sportmonks_football_get_player","sportmonks_football_get_players_by_country","sportmonks_football_get_postmatch_news","sportmonks_football_get_postmatch_news_by_season","sportmonks_football_get_predictability_by_league","sportmonks_football_get_prematch_news","sportmonks_football_get_prematch_news_by_season","sportmonks_football_get_prematch_news_upcoming","sportmonks_football_get_probabilities","sportmonks_football_get_probabilities_by_fixture","sportmonks_football_get_referee","sportmonks_football_get_referees","sportmonks_football_get_referees_by_country","sportmonks_football_get_referees_by_season","sportmonks_football_get_rivals_by_team","sportmonks_football_get_round","sportmonks_football_get_round_statistics","sportmonks_football_get_rounds","sportmonks_football_get_rounds_by_season","sportmonks_football_get_schedules_by_season","sportmonks_football_get_schedules_by_season_and_team","sportmonks_football_get_schedules_by_team","sportmonks_football_get_season","sportmonks_football_get_seasons","sportmonks_football_get_seasons_by_team","sportmonks_football_get_stage","sportmonks_football_get_stage_statistics","sportmonks_football_get_stages","sportmonks_football_get_stages_by_season","sportmonks_football_get_standing_corrections_by_season","sportmonks_football_get_standings","sportmonks_football_get_standings_by_round","sportmonks_football_get_standings_by_season","sportmonks_football_get_state","sportmonks_football_get_states","sportmonks_football_get_team","sportmonks_football_get_team_rankings","sportmonks_football_get_team_rankings_by_date","sportmonks_football_get_team_rankings_by_team","sportmonks_football_get_team_squad","sportmonks_football_get_team_squad_by_season","sportmonks_football_get_teams_by_country","sportmonks_football_get_teams_by_season","sportmonks_football_get_topscorers_by_season","sportmonks_football_get_topscorers_by_stage","sportmonks_football_get_totw","sportmonks_football_get_totw_by_round","sportmonks_football_get_transfer","sportmonks_football_get_transfer_rumour","sportmonks_football_get_transfer_rumours_between_dates","sportmonks_football_get_transfer_rumours_by_player","sportmonks_football_get_transfer_rumours_by_team","sportmonks_football_get_transfers_between_dates","sportmonks_football_get_transfers_by_player","sportmonks_football_get_transfers_by_team","sportmonks_football_get_tv_station","sportmonks_football_get_tv_stations","sportmonks_football_get_tv_stations_by_fixture","sportmonks_football_get_upcoming_fixtures_by_market","sportmonks_football_get_upcoming_fixtures_by_tv_station","sportmonks_football_get_value_bets","sportmonks_football_get_value_bets_by_fixture","sportmonks_football_get_venue","sportmonks_football_get_venues","sportmonks_football_get_venues_by_season","sportmonks_football_search_coaches","sportmonks_football_search_fixtures","sportmonks_football_search_leagues","sportmonks_football_search_players","sportmonks_football_search_referees","sportmonks_football_search_rounds","sportmonks_football_search_seasons","sportmonks_football_search_stages","sportmonks_football_search_teams","sportmonks_football_search_venues","sportmonks_motorsport_get_all_fixtures","sportmonks_motorsport_get_current_leagues_by_team","sportmonks_motorsport_get_driver","sportmonks_motorsport_get_driver_standings","sportmonks_motorsport_get_driver_standings_by_season","sportmonks_motorsport_get_drivers","sportmonks_motorsport_get_drivers_by_country","sportmonks_motorsport_get_drivers_by_season","sportmonks_motorsport_get_fixture","sportmonks_motorsport_get_fixtures_by_date","sportmonks_motorsport_get_fixtures_by_date_range","sportmonks_motorsport_get_fixtures_by_ids","sportmonks_motorsport_get_laps_by_fixture","sportmonks_motorsport_get_laps_by_fixture_and_driver","sportmonks_motorsport_get_laps_by_fixture_and_lap","sportmonks_motorsport_get_latest_laps_by_fixture","sportmonks_motorsport_get_latest_pitstops_by_fixture","sportmonks_motorsport_get_latest_stints_by_fixture","sportmonks_motorsport_get_latest_updated_drivers","sportmonks_motorsport_get_latest_updated_fixtures","sportmonks_motorsport_get_league","sportmonks_motorsport_get_leagues","sportmonks_motorsport_get_leagues_by_country","sportmonks_motorsport_get_leagues_by_date","sportmonks_motorsport_get_leagues_by_live","sportmonks_motorsport_get_leagues_by_team","sportmonks_motorsport_get_livescores","sportmonks_motorsport_get_pitstops_by_fixture","sportmonks_motorsport_get_pitstops_by_fixture_and_driver","sportmonks_motorsport_get_pitstops_by_fixture_and_lap","sportmonks_motorsport_get_race_results_by_season_and_driver","sportmonks_motorsport_get_race_results_by_season_and_team","sportmonks_motorsport_get_schedules_by_season","sportmonks_motorsport_get_season","sportmonks_motorsport_get_seasons","sportmonks_motorsport_get_stage","sportmonks_motorsport_get_stages","sportmonks_motorsport_get_stages_by_season","sportmonks_motorsport_get_state","sportmonks_motorsport_get_states","sportmonks_motorsport_get_stints_by_fixture","sportmonks_motorsport_get_stints_by_fixture_and_driver","sportmonks_motorsport_get_stints_by_fixture_and_stint","sportmonks_motorsport_get_team","sportmonks_motorsport_get_team_standings","sportmonks_motorsport_get_team_standings_by_season","sportmonks_motorsport_get_teams","sportmonks_motorsport_get_teams_by_country","sportmonks_motorsport_get_teams_by_season","sportmonks_motorsport_get_venue","sportmonks_motorsport_get_venues","sportmonks_motorsport_get_venues_by_season","sportmonks_motorsport_search_drivers","sportmonks_motorsport_search_leagues","sportmonks_motorsport_search_stages","sportmonks_motorsport_search_teams","sportmonks_motorsport_search_venues","sportmonks_odds_get_all_historical_odds","sportmonks_odds_get_all_inplay_odds","sportmonks_odds_get_all_pre_match_odds","sportmonks_odds_get_all_premium_odds","sportmonks_odds_get_bookmaker","sportmonks_odds_get_bookmaker_event_ids_by_fixture","sportmonks_odds_get_bookmakers","sportmonks_odds_get_bookmakers_by_fixture","sportmonks_odds_get_inplay_odds_by_fixture","sportmonks_odds_get_inplay_odds_by_fixture_and_bookmaker","sportmonks_odds_get_inplay_odds_by_fixture_and_market","sportmonks_odds_get_last_updated_inplay_odds","sportmonks_odds_get_last_updated_pre_match_odds","sportmonks_odds_get_market","sportmonks_odds_get_markets","sportmonks_odds_get_pre_match_odds_by_fixture","sportmonks_odds_get_pre_match_odds_by_fixture_and_bookmaker","sportmonks_odds_get_pre_match_odds_by_fixture_and_market","sportmonks_odds_get_premium_odds_by_fixture","sportmonks_odds_get_premium_odds_by_fixture_and_bookmaker","sportmonks_odds_get_premium_odds_by_fixture_and_market","sportmonks_odds_get_updated_historical_odds_between","sportmonks_odds_get_updated_premium_odds_between","sportmonks_odds_search_bookmakers","sportmonks_odds_search_markets","spotify_add_playlist_cover","spotify_add_to_queue","spotify_add_tracks_to_playlist","spotify_check_following","spotify_check_playlist_followers","spotify_check_saved_albums","spotify_check_saved_audiobooks","spotify_check_saved_episodes","spotify_check_saved_shows","spotify_check_saved_tracks","spotify_create_playlist","spotify_follow_artists","spotify_follow_playlist","spotify_get_album","spotify_get_album_tracks","spotify_get_albums","spotify_get_artist","spotify_get_artist_albums","spotify_get_artist_top_tracks","spotify_get_artists","spotify_get_audiobook","spotify_get_audiobook_chapters","spotify_get_audiobooks","spotify_get_categories","spotify_get_current_user","spotify_get_currently_playing","spotify_get_devices","spotify_get_episode","spotify_get_episodes","spotify_get_followed_artists","spotify_get_markets","spotify_get_new_releases","spotify_get_playback_state","spotify_get_playlist","spotify_get_playlist_cover","spotify_get_playlist_tracks","spotify_get_queue","spotify_get_recently_played","spotify_get_saved_albums","spotify_get_saved_audiobooks","spotify_get_saved_episodes","spotify_get_saved_shows","spotify_get_saved_tracks","spotify_get_show","spotify_get_show_episodes","spotify_get_shows","spotify_get_top_artists","spotify_get_top_tracks","spotify_get_track","spotify_get_tracks","spotify_get_user_playlists","spotify_get_user_profile","spotify_pause","spotify_play","spotify_remove_saved_albums","spotify_remove_saved_audiobooks","spotify_remove_saved_episodes","spotify_remove_saved_shows","spotify_remove_saved_tracks","spotify_remove_tracks_from_playlist","spotify_reorder_playlist_items","spotify_replace_playlist_items","spotify_save_albums","spotify_save_audiobooks","spotify_save_episodes","spotify_save_shows","spotify_save_tracks","spotify_search","spotify_seek","spotify_set_repeat","spotify_set_shuffle","spotify_set_volume","spotify_skip_next","spotify_skip_previous","spotify_transfer_playback","spotify_unfollow_artists","spotify_unfollow_playlist","spotify_update_playlist","sqs_send","square_batch_retrieve_inventory_counts","square_cancel_invoice","square_cancel_payment","square_complete_payment","square_create_catalog_image","square_create_customer","square_create_invoice","square_create_order","square_create_payment","square_delete_catalog_object","square_delete_customer","square_delete_invoice","square_get_catalog_object","square_get_customer","square_get_invoice","square_get_location","square_get_order","square_get_payment","square_get_refund","square_list_catalog","square_list_customers","square_list_invoices","square_list_locations","square_list_payments","square_list_refunds","square_pay_order","square_publish_invoice","square_refund_payment","square_search_catalog_objects","square_search_customers","square_search_invoices","square_search_orders","square_update_customer","square_upsert_catalog_object","ssh_check_command_exists","ssh_check_file_exists","ssh_create_directory","ssh_delete_file","ssh_download_file","ssh_execute_command","ssh_execute_script","ssh_get_system_info","ssh_list_directory","ssh_move_rename","ssh_read_file_content","ssh_upload_file","ssh_write_file_content","stagehand_agent","stagehand_extract","stripe_cancel_payment_intent","stripe_cancel_subscription","stripe_capture_charge","stripe_capture_payment_intent","stripe_confirm_payment_intent","stripe_create_charge","stripe_create_customer","stripe_create_invoice","stripe_create_payment_intent","stripe_create_price","stripe_create_product","stripe_create_subscription","stripe_delete_customer","stripe_delete_invoice","stripe_delete_product","stripe_finalize_invoice","stripe_list_charges","stripe_list_customers","stripe_list_events","stripe_list_invoices","stripe_list_payment_intents","stripe_list_prices","stripe_list_products","stripe_list_subscriptions","stripe_pay_invoice","stripe_resume_subscription","stripe_retrieve_charge","stripe_retrieve_customer","stripe_retrieve_event","stripe_retrieve_invoice","stripe_retrieve_payment_intent","stripe_retrieve_price","stripe_retrieve_product","stripe_retrieve_subscription","stripe_search_charges","stripe_search_customers","stripe_search_invoices","stripe_search_payment_intents","stripe_search_prices","stripe_search_products","stripe_search_subscriptions","stripe_send_invoice","stripe_update_charge","stripe_update_customer","stripe_update_invoice","stripe_update_payment_intent","stripe_update_price","stripe_update_product","stripe_update_subscription","stripe_void_invoice","sts_assume_role","sts_assume_role_with_saml","sts_assume_role_with_web_identity","sts_get_access_key_info","sts_get_caller_identity","sts_get_session_token","stt_assemblyai","stt_assemblyai_v2","stt_deepgram","stt_deepgram_v2","stt_elevenlabs","stt_elevenlabs_v2","stt_gemini","stt_gemini_v2","stt_whisper","stt_whisper_v2","supabase_count","supabase_delete","supabase_get_row","supabase_insert","supabase_introspect","supabase_invoke_function","supabase_query","supabase_rpc","supabase_storage_copy","supabase_storage_create_bucket","supabase_storage_create_signed_upload_url","supabase_storage_create_signed_url","supabase_storage_delete","supabase_storage_delete_bucket","supabase_storage_download","supabase_storage_empty_bucket","supabase_storage_get_public_url","supabase_storage_list","supabase_storage_list_buckets","supabase_storage_move","supabase_storage_update_bucket","supabase_storage_upload","supabase_text_search","supabase_update","supabase_upsert","supabase_vector_search","table_batch_insert_rows","table_create","table_delete_row","table_delete_rows_by_filter","table_get_row","table_get_schema","table_insert_row","table_list","table_query_rows","table_query_rows_v2","table_update_row","table_update_rows_by_filter","table_upsert_row","tailscale_authorize_device","tailscale_create_auth_key","tailscale_delete_auth_key","tailscale_delete_device","tailscale_delete_user","tailscale_expire_device_key","tailscale_get_acl","tailscale_get_auth_key","tailscale_get_device","tailscale_get_device_routes","tailscale_get_dns_preferences","tailscale_get_dns_searchpaths","tailscale_list_auth_keys","tailscale_list_devices","tailscale_list_dns_nameservers","tailscale_list_users","tailscale_set_acl","tailscale_set_device_routes","tailscale_set_device_tags","tailscale_set_dns_nameservers","tailscale_set_dns_preferences","tailscale_set_dns_searchpaths","tailscale_suspend_user","tailscale_update_device_key","tavily_crawl","tavily_extract","tavily_map","tavily_search","telegram_copy_message","telegram_delete_message","telegram_edit_message_text","telegram_forward_message","telegram_get_chat","telegram_get_chat_member","telegram_message","telegram_pin_message","telegram_send_animation","telegram_send_audio","telegram_send_chat_action","telegram_send_contact","telegram_send_document","telegram_send_location","telegram_send_photo","telegram_send_poll","telegram_send_video","telegram_set_message_reaction","telegram_unpin_message","temporal_cancel_workflow","temporal_count_workflows","temporal_create_schedule","temporal_delete_schedule","temporal_describe_schedule","temporal_describe_task_queue","temporal_describe_workflow","temporal_get_workflow_history","temporal_list_schedules","temporal_list_workflows","temporal_pause_schedule","temporal_query_workflow","temporal_reset_workflow","temporal_signal_with_start","temporal_signal_workflow","temporal_start_workflow","temporal_terminate_workflow","temporal_trigger_schedule","temporal_unpause_schedule","temporal_update_workflow","textract_analyze_expense","textract_analyze_id","textract_parser","textract_parser_v2","thinking_tool","thrive_add_audience_managers","thrive_add_audience_members","thrive_add_user_tags","thrive_create_assignment","thrive_create_audience","thrive_create_completion","thrive_create_user","thrive_delete_assignment","thrive_delete_audience","thrive_delete_user","thrive_get_activity","thrive_get_assignment","thrive_get_audience","thrive_get_completion","thrive_get_content","thrive_get_cpd_category","thrive_get_cpd_entry","thrive_get_cpd_requirement","thrive_get_enrolment","thrive_get_skill_levels","thrive_get_tag","thrive_get_user_by_id","thrive_get_user_by_ref","thrive_list_assignments","thrive_list_audience_managers","thrive_list_audience_members","thrive_list_audiences","thrive_list_completions","thrive_list_enrolments","thrive_list_tags","thrive_query_activities","thrive_query_content","thrive_query_cpd_categories","thrive_query_cpd_entries","thrive_query_cpd_requirements","thrive_query_cpd_user_summaries","thrive_remove_audience_manager","thrive_remove_audience_member","thrive_remove_user_tags","thrive_replace_audience_managers","thrive_replace_audience_members","thrive_search_users","thrive_suspend_user","thrive_update_assignment","thrive_update_audience","thrive_update_user","thrive_update_user_skills","tiktok_get_post_status","tiktok_get_user","tiktok_list_videos","tiktok_query_videos","tiktok_upload_video_draft","tinybird_append_datasource","tinybird_delete_datasource_rows","tinybird_events","tinybird_get_job","tinybird_query","tinybird_query_pipe","tinybird_truncate_datasource","trello_add_checklist","trello_add_checklist_item","trello_add_comment","trello_add_label","trello_add_member","trello_create_board","trello_create_card","trello_create_list","trello_delete_card","trello_get_actions","trello_get_board","trello_get_card","trello_list_cards","trello_list_lists","trello_list_members","trello_remove_label","trello_remove_member","trello_search","trello_update_card","trello_update_checklist_item","trello_update_list","trigger_dev_activate_schedule","trigger_dev_add_run_tags","trigger_dev_batch_trigger_task","trigger_dev_cancel_run","trigger_dev_complete_waitpoint_token","trigger_dev_create_env_var","trigger_dev_create_schedule","trigger_dev_create_waitpoint_token","trigger_dev_deactivate_schedule","trigger_dev_delete_env_var","trigger_dev_delete_schedule","trigger_dev_execute_query","trigger_dev_get_batch","trigger_dev_get_batch_results","trigger_dev_get_deployment","trigger_dev_get_env_var","trigger_dev_get_latest_deployment","trigger_dev_get_query_schema","trigger_dev_get_queue","trigger_dev_get_run","trigger_dev_get_run_events","trigger_dev_get_run_result","trigger_dev_get_run_trace","trigger_dev_get_schedule","trigger_dev_get_waitpoint_token","trigger_dev_import_env_vars","trigger_dev_list_deployments","trigger_dev_list_env_vars","trigger_dev_list_queues","trigger_dev_list_runs","trigger_dev_list_schedules","trigger_dev_list_timezones","trigger_dev_list_waitpoint_tokens","trigger_dev_override_queue_concurrency","trigger_dev_pause_queue","trigger_dev_promote_deployment","trigger_dev_replay_run","trigger_dev_reschedule_run","trigger_dev_reset_queue_concurrency","trigger_dev_resume_queue","trigger_dev_trigger_task","trigger_dev_update_env_var","trigger_dev_update_run_metadata","trigger_dev_update_schedule","tts_azure","tts_cartesia","tts_deepgram","tts_elevenlabs","tts_google","tts_openai","tts_playht","twilio_send_sms","twilio_voice_get_recording","twilio_voice_list_calls","twilio_voice_make_call","typeform_create_form","typeform_delete_form","typeform_files","typeform_get_form","typeform_insights","typeform_list_forms","typeform_responses","typeform_update_form","upstash_redis_command","upstash_redis_delete","upstash_redis_exists","upstash_redis_expire","upstash_redis_get","upstash_redis_hget","upstash_redis_hgetall","upstash_redis_hset","upstash_redis_incr","upstash_redis_incrby","upstash_redis_keys","upstash_redis_lpush","upstash_redis_lrange","upstash_redis_set","upstash_redis_setnx","upstash_redis_ttl","uptimerobot_create_alert_contact","uptimerobot_create_maintenance_window","uptimerobot_create_monitor","uptimerobot_create_psp","uptimerobot_delete_alert_contact","uptimerobot_delete_maintenance_window","uptimerobot_delete_monitor","uptimerobot_delete_psp","uptimerobot_get_account","uptimerobot_get_alert_contact","uptimerobot_get_incident","uptimerobot_get_maintenance_window","uptimerobot_get_monitor","uptimerobot_get_psp","uptimerobot_list_alert_contacts","uptimerobot_list_incidents","uptimerobot_list_maintenance_windows","uptimerobot_list_monitors","uptimerobot_list_psps","uptimerobot_pause_monitor","uptimerobot_start_monitor","uptimerobot_update_maintenance_window","uptimerobot_update_monitor","uptimerobot_update_psp","vanta_download_document_file","vanta_get_control","vanta_get_document","vanta_get_framework","vanta_get_person","vanta_get_policy","vanta_get_risk_scenario","vanta_get_test","vanta_get_vendor","vanta_get_vulnerable_asset","vanta_list_control_documents","vanta_list_control_tests","vanta_list_controls","vanta_list_document_uploads","vanta_list_documents","vanta_list_framework_controls","vanta_list_frameworks","vanta_list_monitored_computers","vanta_list_people","vanta_list_policies","vanta_list_risk_scenarios","vanta_list_test_entities","vanta_list_tests","vanta_list_vendors","vanta_list_vulnerabilities","vanta_list_vulnerability_remediations","vanta_list_vulnerable_assets","vanta_submit_document","vanta_upload_document_file","vercel_add_domain","vercel_add_project_domain","vercel_cancel_deployment","vercel_create_alias","vercel_create_check","vercel_create_deployment","vercel_create_dns_record","vercel_create_edge_config","vercel_create_env_var","vercel_create_project","vercel_create_webhook","vercel_delete_alias","vercel_delete_deployment","vercel_delete_dns_record","vercel_delete_domain","vercel_delete_edge_config","vercel_delete_env_var","vercel_delete_project","vercel_delete_webhook","vercel_get_alias","vercel_get_check","vercel_get_deployment","vercel_get_deployment_events","vercel_get_domain","vercel_get_domain_config","vercel_get_edge_config","vercel_get_edge_config_items","vercel_get_env_vars","vercel_get_project","vercel_get_team","vercel_get_user","vercel_get_webhook","vercel_list_aliases","vercel_list_checks","vercel_list_deployment_files","vercel_list_deployments","vercel_list_dns_records","vercel_list_domains","vercel_list_edge_configs","vercel_list_project_domains","vercel_list_projects","vercel_list_team_members","vercel_list_teams","vercel_list_webhooks","vercel_pause_project","vercel_promote_deployment","vercel_remove_project_domain","vercel_rerequest_check","vercel_unpause_project","vercel_update_check","vercel_update_dns_record","vercel_update_edge_config_items","vercel_update_env_var","vercel_update_project","vercel_update_project_domain","vercel_verify_project_domain","video_falai","video_luma","video_minimax","video_runway","video_veo","vision_tool","vision_tool_v2","wealthbox_read_contact","wealthbox_read_note","wealthbox_read_task","wealthbox_write_contact","wealthbox_write_note","wealthbox_write_task","webflow_create_item","webflow_delete_item","webflow_get_item","webflow_list_items","webflow_update_item","webhook_request","whatsapp_get_media","whatsapp_mark_read","whatsapp_send_interactive","whatsapp_send_media","whatsapp_send_message","whatsapp_send_reaction","whatsapp_send_template","whatsapp_upload_media","wikipedia_content","wikipedia_random","wikipedia_search","wikipedia_summary","windchill_check_in_document","windchill_check_in_documents","windchill_check_out_document","windchill_check_out_documents","windchill_create_document","windchill_create_documents","windchill_delete_document","windchill_delete_documents","windchill_download_attachment","windchill_download_primary_content","windchill_get_document","windchill_get_document_structure","windchill_get_primary_content","windchill_get_valid_state_transitions","windchill_list_attachments","windchill_list_documents","windchill_revise_document","windchill_revise_documents","windchill_set_lifecycle_state","windchill_undo_check_out_document","windchill_undo_check_out_documents","windchill_update_common_properties","windchill_update_document","windchill_update_document_security_labels","windchill_update_documents","windchill_upload_attachments","windchill_upload_primary_content","wiza_company_enrichment","wiza_get_credits","wiza_individual_reveal","wiza_prospect_search","wordpress_create_category","wordpress_create_comment","wordpress_create_page","wordpress_create_post","wordpress_create_tag","wordpress_delete_category","wordpress_delete_comment","wordpress_delete_media","wordpress_delete_page","wordpress_delete_post","wordpress_delete_tag","wordpress_get_category","wordpress_get_current_user","wordpress_get_media","wordpress_get_page","wordpress_get_post","wordpress_get_tag","wordpress_get_user","wordpress_list_categories","wordpress_list_comments","wordpress_list_media","wordpress_list_pages","wordpress_list_posts","wordpress_list_tags","wordpress_list_users","wordpress_search_content","wordpress_update_category","wordpress_update_comment","wordpress_update_page","wordpress_update_post","wordpress_update_tag","wordpress_upload_media","workday_assign_onboarding","workday_change_job","workday_create_prehire","workday_get_compensation","workday_get_organizations","workday_get_worker","workday_hire_employee","workday_list_workers","workday_terminate_worker","workday_update_worker","workflow_executor","x_create_bookmark","x_create_tweet","x_delete_bookmark","x_delete_tweet","x_get_blocking","x_get_bookmarks","x_get_followers","x_get_following","x_get_liked_tweets","x_get_liking_users","x_get_me","x_get_personalized_trends","x_get_quote_tweets","x_get_retweeted_by","x_get_trends_by_woeid","x_get_tweets_by_ids","x_get_usage","x_get_user_mentions","x_get_user_timeline","x_get_user_tweets","x_hide_reply","x_manage_block","x_manage_follow","x_manage_like","x_manage_mute","x_manage_retweet","x_read","x_search","x_search_tweets","x_search_users","x_user","x_write","youtube_channel_info","youtube_channel_playlists","youtube_channel_videos","youtube_comments","youtube_playlist_items","youtube_search","youtube_trending","youtube_video_categories","youtube_video_details","zendesk_autocomplete_organizations","zendesk_create_organization","zendesk_create_organizations_bulk","zendesk_create_ticket","zendesk_create_tickets_bulk","zendesk_create_user","zendesk_create_users_bulk","zendesk_delete_organization","zendesk_delete_ticket","zendesk_delete_user","zendesk_get_current_user","zendesk_get_organization","zendesk_get_organizations","zendesk_get_ticket","zendesk_get_tickets","zendesk_get_user","zendesk_get_users","zendesk_merge_tickets","zendesk_search","zendesk_search_count","zendesk_search_users","zendesk_update_organization","zendesk_update_ticket","zendesk_update_tickets_bulk","zendesk_update_user","zendesk_update_users_bulk","zep_add_messages","zep_add_user","zep_create_thread","zep_delete_thread","zep_get_context","zep_get_messages","zep_get_threads","zep_get_user","zep_get_user_threads","zerobounce_get_credits","zerobounce_verify_email","zoho_desk_add_comment","zoho_desk_get_attachment","zoho_desk_get_contact","zoho_desk_get_thread","zoho_desk_get_ticket","zoho_desk_list_comments","zoho_desk_list_organizations","zoho_desk_list_threads","zoho_desk_list_tickets","zoho_desk_update_ticket","zoom_create_meeting","zoom_delete_meeting","zoom_delete_recording","zoom_get_meeting","zoom_get_meeting_invitation","zoom_get_meeting_recordings","zoom_list_meetings","zoom_list_past_participants","zoom_list_recordings","zoom_update_meeting","zoominfo_enrich_companies","zoominfo_enrich_contacts","zoominfo_search_companies","zoominfo_search_contacts","zoominfo_search_intent","zoominfo_search_news"]' + '["a2a_cancel_task","a2a_get_agent_card","a2a_get_task","a2a_send_message","agentmail_create_draft","agentmail_create_inbox","agentmail_delete_draft","agentmail_delete_inbox","agentmail_delete_thread","agentmail_forward_message","agentmail_get_draft","agentmail_get_inbox","agentmail_get_message","agentmail_get_thread","agentmail_list_drafts","agentmail_list_inboxes","agentmail_list_messages","agentmail_list_threads","agentmail_reply_message","agentmail_send_draft","agentmail_send_message","agentmail_update_draft","agentmail_update_inbox","agentmail_update_message","agentmail_update_thread","agentphone_create_call","agentphone_create_contact","agentphone_create_number","agentphone_delete_contact","agentphone_get_call","agentphone_get_call_transcript","agentphone_get_contact","agentphone_get_conversation","agentphone_get_conversation_messages","agentphone_get_number_messages","agentphone_get_usage","agentphone_get_usage_daily","agentphone_get_usage_monthly","agentphone_list_calls","agentphone_list_contacts","agentphone_list_conversations","agentphone_list_numbers","agentphone_react_to_message","agentphone_release_number","agentphone_send_message","agentphone_update_contact","agentphone_update_conversation","agiloft_async_status","agiloft_attach_file","agiloft_attachment_info","agiloft_create_record","agiloft_delete_record","agiloft_get_choice_line_id","agiloft_list_tables","agiloft_lock_record","agiloft_nlp_search","agiloft_read_record","agiloft_remove_attachment","agiloft_retrieve_attachment","agiloft_run_action_button","agiloft_saved_search","agiloft_search_records","agiloft_select_records","agiloft_update_record","agiloft_upsert_record","ahrefs_anchors","ahrefs_backlinks","ahrefs_backlinks_stats","ahrefs_batch_analysis","ahrefs_broken_backlinks","ahrefs_domain_rating","ahrefs_domain_rating_history","ahrefs_keyword_overview","ahrefs_keywords_history","ahrefs_metrics","ahrefs_metrics_history","ahrefs_organic_competitors","ahrefs_organic_keywords","ahrefs_paid_pages","ahrefs_rank_tracker_competitors_overview","ahrefs_rank_tracker_competitors_stats","ahrefs_rank_tracker_overview","ahrefs_rank_tracker_serp_overview","ahrefs_refdomains_history","ahrefs_referring_domains","ahrefs_related_terms","ahrefs_site_audit_page_explorer","ahrefs_top_pages","airtable_create_records","airtable_delete_records","airtable_get_base_schema","airtable_get_record","airtable_list_bases","airtable_list_records","airtable_list_tables","airtable_update_multiple_records","airtable_update_record","airtable_upsert_records","airweave_search","algolia_add_record","algolia_batch_operations","algolia_browse_records","algolia_clear_records","algolia_copy_move_index","algolia_delete_by_filter","algolia_delete_index","algolia_delete_record","algolia_get_record","algolia_get_records","algolia_get_settings","algolia_get_task_status","algolia_list_indices","algolia_partial_update_record","algolia_search","algolia_update_settings","amplitude_event_segmentation","amplitude_funnels","amplitude_get_active_users","amplitude_get_revenue","amplitude_group_identify","amplitude_identify_user","amplitude_list_events","amplitude_realtime_active_users","amplitude_retention","amplitude_send_event","amplitude_user_activity","amplitude_user_profile","amplitude_user_search","apify_get_dataset_items","apify_get_run","apify_run_actor_async","apify_run_actor_sync","apify_run_task","apollo_account_bulk_create","apollo_account_bulk_update","apollo_account_create","apollo_account_search","apollo_account_update","apollo_contact_bulk_create","apollo_contact_bulk_update","apollo_contact_create","apollo_contact_search","apollo_contact_update","apollo_email_accounts","apollo_opportunity_create","apollo_opportunity_get","apollo_opportunity_search","apollo_opportunity_update","apollo_organization_bulk_enrich","apollo_organization_enrich","apollo_organization_search","apollo_people_bulk_enrich","apollo_people_enrich","apollo_people_search","apollo_sequence_add_contacts","apollo_sequence_search","apollo_task_create","apollo_task_search","appconfig_create_application","appconfig_create_configuration_profile","appconfig_create_environment","appconfig_create_hosted_configuration_version","appconfig_delete_application","appconfig_delete_configuration_profile","appconfig_delete_environment","appconfig_delete_hosted_configuration_version","appconfig_get_application","appconfig_get_configuration","appconfig_get_configuration_profile","appconfig_get_deployment","appconfig_get_environment","appconfig_get_hosted_configuration_version","appconfig_list_applications","appconfig_list_configuration_profiles","appconfig_list_deployment_strategies","appconfig_list_deployments","appconfig_list_environments","appconfig_list_hosted_configuration_versions","appconfig_start_deployment","appconfig_stop_deployment","appconfig_update_application","appconfig_update_configuration_profile","appconfig_update_environment","arxiv_get_author_papers","arxiv_get_paper","arxiv_search","asana_add_comment","asana_add_followers","asana_create_project","asana_create_section","asana_create_subtask","asana_create_task","asana_delete_task","asana_get_project","asana_get_projects","asana_get_task","asana_list_sections","asana_list_workspaces","asana_search_tasks","asana_update_task","ashby_add_candidate_tag","ashby_anonymize_candidate","ashby_change_application_source","ashby_change_application_stage","ashby_create_application","ashby_create_candidate","ashby_create_note","ashby_delete_application","ashby_get_application","ashby_get_candidate","ashby_get_job","ashby_get_job_posting","ashby_get_offer","ashby_list_applications","ashby_list_archive_reasons","ashby_list_candidate_tags","ashby_list_candidates","ashby_list_custom_fields","ashby_list_departments","ashby_list_interviews","ashby_list_job_postings","ashby_list_jobs","ashby_list_locations","ashby_list_notes","ashby_list_offers","ashby_list_openings","ashby_list_sources","ashby_list_users","ashby_remove_candidate_tag","ashby_search_candidates","ashby_set_custom_field_value","ashby_set_custom_field_values","ashby_update_candidate","athena_batch_get_query_execution","athena_create_named_query","athena_delete_named_query","athena_get_named_query","athena_get_query_execution","athena_get_query_results","athena_list_databases","athena_list_named_queries","athena_list_query_executions","athena_list_table_metadata","athena_start_query","athena_stop_query","attio_assert_record","attio_create_attribute","attio_create_comment","attio_create_list","attio_create_list_entry","attio_create_note","attio_create_object","attio_create_record","attio_create_task","attio_create_webhook","attio_delete_comment","attio_delete_list_entry","attio_delete_note","attio_delete_record","attio_delete_task","attio_delete_webhook","attio_get_attribute","attio_get_comment","attio_get_list","attio_get_list_entry","attio_get_member","attio_get_note","attio_get_object","attio_get_record","attio_get_task","attio_get_thread","attio_get_webhook","attio_list_attributes","attio_list_lists","attio_list_members","attio_list_notes","attio_list_objects","attio_list_records","attio_list_tasks","attio_list_threads","attio_list_webhooks","attio_query_list_entries","attio_search_records","attio_update_attribute","attio_update_list","attio_update_list_entry","attio_update_object","attio_update_record","attio_update_task","attio_update_webhook","azure_data_explorer_create_table","azure_data_explorer_drop_table","azure_data_explorer_ingest_from_query","azure_data_explorer_ingest_inline","azure_data_explorer_list_databases","azure_data_explorer_list_functions","azure_data_explorer_list_tables","azure_data_explorer_management","azure_data_explorer_query","azure_data_explorer_show_database_schema","azure_data_explorer_show_ingestion_failures","azure_data_explorer_show_operations","azure_data_explorer_show_table_details","azure_data_explorer_show_table_schema","azure_devops_add_comment","azure_devops_create_work_item","azure_devops_get_build_log","azure_devops_get_build_timeline","azure_devops_get_comments","azure_devops_get_pipeline","azure_devops_get_pipeline_run","azure_devops_get_work_item","azure_devops_get_work_items_batch","azure_devops_get_work_items_between_builds","azure_devops_list_build_logs","azure_devops_list_builds","azure_devops_list_pipeline_runs","azure_devops_list_pipelines","azure_devops_query_work_items","azure_devops_update_work_item","box_copy_file","box_create_folder","box_delete_file","box_delete_folder","box_download_file","box_get_file_info","box_list_folder_items","box_search","box_sign_cancel_request","box_sign_create_request","box_sign_get_request","box_sign_list_requests","box_sign_resend_request","box_update_file","box_upload_file","brandfetch_get_brand","brandfetch_search","brex_archive_budget","brex_create_budget","brex_create_spend_limit","brex_create_transfer","brex_create_vendor","brex_get_budget","brex_get_cash_account","brex_get_company","brex_get_current_user","brex_get_expense","brex_get_spend_limit","brex_get_transfer","brex_get_user","brex_get_vendor","brex_list_budgets","brex_list_card_accounts","brex_list_card_statements","brex_list_card_transactions","brex_list_cards","brex_list_cash_accounts","brex_list_cash_statements","brex_list_cash_transactions","brex_list_departments","brex_list_expenses","brex_list_locations","brex_list_spend_limits","brex_list_titles","brex_list_transfers","brex_list_users","brex_list_vendors","brex_match_receipt","brex_update_expense","brex_update_vendor","brex_upload_receipt","brightdata_cancel_snapshot","brightdata_discover","brightdata_download_snapshot","brightdata_scrape_dataset","brightdata_scrape_url","brightdata_serp_search","brightdata_snapshot_status","brightdata_sync_scrape","browser_use_run_task","buffer_create_idea","buffer_create_post","buffer_delete_post","buffer_edit_post","buffer_get_account","buffer_get_channels","buffer_get_idea_groups","buffer_get_ideas","buffer_get_post","buffer_get_posts","calcom_cancel_booking","calcom_confirm_booking","calcom_create_booking","calcom_create_event_type","calcom_create_schedule","calcom_decline_booking","calcom_delete_event_type","calcom_delete_schedule","calcom_get_booking","calcom_get_default_schedule","calcom_get_event_type","calcom_get_schedule","calcom_get_slots","calcom_list_bookings","calcom_list_event_types","calcom_list_schedules","calcom_reschedule_booking","calcom_update_event_type","calcom_update_schedule","calendly_cancel_event","calendly_create_event_invitee","calendly_create_invitee_no_show","calendly_create_scheduling_link","calendly_create_webhook","calendly_delete_invitee_no_show","calendly_delete_webhook","calendly_get_current_user","calendly_get_event_invitee","calendly_get_event_type","calendly_get_scheduled_event","calendly_get_user","calendly_list_event_invitees","calendly_list_event_type_available_times","calendly_list_event_types","calendly_list_organization_memberships","calendly_list_routing_form_submissions","calendly_list_routing_forms","calendly_list_scheduled_events","calendly_list_user_availability_schedules","calendly_list_user_busy_times","calendly_list_webhooks","clay_populate","clerk_add_organization_member","clerk_ban_user","clerk_create_actor_token","clerk_create_allowlist_identifier","clerk_create_blocklist_identifier","clerk_create_organization","clerk_create_organization_invitation","clerk_create_user","clerk_delete_allowlist_identifier","clerk_delete_blocklist_identifier","clerk_delete_organization","clerk_delete_user","clerk_get_jwt_template","clerk_get_organization","clerk_get_session","clerk_get_user","clerk_get_user_oauth_token","clerk_list_allowlist_identifiers","clerk_list_blocklist_identifiers","clerk_list_jwt_templates","clerk_list_organization_invitations","clerk_list_organization_memberships","clerk_list_organizations","clerk_list_sessions","clerk_list_users","clerk_lock_user","clerk_remove_organization_member","clerk_revoke_actor_token","clerk_revoke_session","clerk_unban_user","clerk_unlock_user","clerk_update_organization","clerk_update_organization_membership","clerk_update_user","clickhouse_count_rows","clickhouse_create_database","clickhouse_create_table","clickhouse_delete","clickhouse_describe_table","clickhouse_drop_database","clickhouse_drop_partition","clickhouse_drop_table","clickhouse_execute","clickhouse_insert","clickhouse_insert_rows","clickhouse_introspect","clickhouse_kill_query","clickhouse_list_clusters","clickhouse_list_databases","clickhouse_list_mutations","clickhouse_list_partitions","clickhouse_list_running_queries","clickhouse_list_tables","clickhouse_optimize_table","clickhouse_query","clickhouse_rename_table","clickhouse_show_create_table","clickhouse_table_stats","clickhouse_truncate_table","clickhouse_update","clickup_add_tag_to_task","clickup_create_checklist","clickup_create_checklist_item","clickup_create_comment","clickup_create_folder","clickup_create_list","clickup_create_task","clickup_create_time_entry","clickup_delete_checklist","clickup_delete_checklist_item","clickup_delete_comment","clickup_delete_task","clickup_delete_time_entry","clickup_get_comments","clickup_get_custom_fields","clickup_get_folders","clickup_get_list_members","clickup_get_lists","clickup_get_running_timer","clickup_get_space_tags","clickup_get_spaces","clickup_get_task","clickup_get_task_members","clickup_get_tasks","clickup_get_time_entries","clickup_get_workspaces","clickup_remove_custom_field_value","clickup_remove_tag_from_task","clickup_search_tasks","clickup_set_custom_field_value","clickup_start_timer","clickup_stop_timer","clickup_update_checklist","clickup_update_checklist_item","clickup_update_comment","clickup_update_task","clickup_update_time_entry","clickup_upload_attachment","cloudflare_create_access_application","cloudflare_create_access_policy","cloudflare_create_access_service_token","cloudflare_create_dns_record","cloudflare_create_r2_bucket","cloudflare_create_rate_limit_rule","cloudflare_create_ruleset","cloudflare_create_ruleset_rule","cloudflare_create_zone","cloudflare_delete_access_application","cloudflare_delete_access_policy","cloudflare_delete_dns_record","cloudflare_delete_r2_bucket","cloudflare_delete_ruleset_rule","cloudflare_delete_zone","cloudflare_dns_analytics","cloudflare_get_access_application","cloudflare_get_r2_bucket","cloudflare_get_ruleset","cloudflare_get_ruleset_entrypoint","cloudflare_get_tunnel","cloudflare_get_tunnel_configuration","cloudflare_get_worker_script_settings","cloudflare_get_zone","cloudflare_get_zone_settings","cloudflare_list_access_applications","cloudflare_list_access_groups","cloudflare_list_access_identity_providers","cloudflare_list_access_policies","cloudflare_list_access_service_tokens","cloudflare_list_certificates","cloudflare_list_dns_records","cloudflare_list_managed_ruleset_overrides","cloudflare_list_r2_buckets","cloudflare_list_rate_limit_rules","cloudflare_list_rulesets","cloudflare_list_tunnels","cloudflare_list_worker_routes","cloudflare_list_worker_scripts","cloudflare_list_zones","cloudflare_purge_cache","cloudflare_revoke_access_service_token","cloudflare_update_access_application","cloudflare_update_access_policy","cloudflare_update_dns_record","cloudflare_update_rate_limit_rule","cloudflare_update_ruleset_rule","cloudflare_update_zone_setting","cloudformation_cancel_update_stack","cloudformation_create_change_set","cloudformation_create_stack","cloudformation_delete_stack","cloudformation_describe_change_set","cloudformation_describe_stack_drift_detection_status","cloudformation_describe_stack_events","cloudformation_describe_stacks","cloudformation_detect_stack_drift","cloudformation_execute_change_set","cloudformation_get_template","cloudformation_get_template_summary","cloudformation_list_stack_resources","cloudformation_update_stack","cloudformation_validate_template","cloudwatch_describe_alarm_history","cloudwatch_describe_alarms","cloudwatch_describe_log_groups","cloudwatch_describe_log_streams","cloudwatch_filter_log_events","cloudwatch_get_log_events","cloudwatch_get_metric_statistics","cloudwatch_list_metrics","cloudwatch_mute_alarm","cloudwatch_put_log_group_retention","cloudwatch_put_metric_data","cloudwatch_query_logs","cloudwatch_unmute_alarm","codepipeline_disable_stage_transition","codepipeline_enable_stage_transition","codepipeline_get_pipeline","codepipeline_get_pipeline_execution","codepipeline_get_pipeline_state","codepipeline_list_action_executions","codepipeline_list_pipeline_executions","codepipeline_list_pipelines","codepipeline_put_approval_result","codepipeline_retry_stage_execution","codepipeline_start_execution","codepipeline_stop_execution","confluence_add_label","confluence_create_blogpost","confluence_create_comment","confluence_create_page","confluence_create_page_property","confluence_create_space","confluence_create_space_property","confluence_delete_attachment","confluence_delete_blogpost","confluence_delete_comment","confluence_delete_label","confluence_delete_page","confluence_delete_page_property","confluence_delete_space","confluence_delete_space_property","confluence_get_blogpost","confluence_get_page_ancestors","confluence_get_page_children","confluence_get_page_descendants","confluence_get_page_version","confluence_get_pages_by_label","confluence_get_space","confluence_get_task","confluence_get_user","confluence_list_attachments","confluence_list_blogposts","confluence_list_blogposts_in_space","confluence_list_comments","confluence_list_labels","confluence_list_page_properties","confluence_list_page_versions","confluence_list_pages_in_space","confluence_list_space_labels","confluence_list_space_permissions","confluence_list_space_properties","confluence_list_spaces","confluence_list_tasks","confluence_retrieve","confluence_search","confluence_search_in_space","confluence_update","confluence_update_blogpost","confluence_update_comment","confluence_update_space","confluence_update_task","confluence_upload_attachment","context_dev_classify_naics","context_dev_classify_sic","context_dev_crawl","context_dev_extract","context_dev_extract_product","context_dev_extract_products","context_dev_get_brand","context_dev_get_brand_by_email","context_dev_get_brand_by_name","context_dev_get_brand_by_ticker","context_dev_identify_transaction","context_dev_map","context_dev_scrape_fonts","context_dev_scrape_html","context_dev_scrape_images","context_dev_scrape_markdown","context_dev_scrape_styleguide","context_dev_screenshot","context_dev_search","convex_action","convex_document_deltas","convex_list_documents","convex_list_tables","convex_mutation","convex_query","convex_run_function","crowdstrike_create_indicators","crowdstrike_delete_indicators","crowdstrike_delete_rtr_session","crowdstrike_execute_rtr_command","crowdstrike_get_alert_details","crowdstrike_get_case_details","crowdstrike_get_host_group_details","crowdstrike_get_indicator_details","crowdstrike_get_rtr_command_status","crowdstrike_get_sensor_aggregates","crowdstrike_get_sensor_details","crowdstrike_get_vulnerability_details","crowdstrike_init_rtr_session","crowdstrike_perform_host_action","crowdstrike_perform_host_group_action","crowdstrike_query_alerts","crowdstrike_query_cases","crowdstrike_query_host_groups","crowdstrike_query_indicators","crowdstrike_query_sensors","crowdstrike_query_vulnerabilities","crowdstrike_update_alerts","crowdstrike_update_indicators","cursor_add_followup","cursor_add_followup_v2","cursor_delete_agent","cursor_delete_agent_v2","cursor_download_artifact","cursor_download_artifact_v2","cursor_get_agent","cursor_get_agent_v2","cursor_get_api_key_info","cursor_get_api_key_info_v2","cursor_get_conversation","cursor_get_conversation_v2","cursor_launch_agent","cursor_launch_agent_v2","cursor_list_agents","cursor_list_agents_v2","cursor_list_artifacts","cursor_list_artifacts_v2","cursor_list_models","cursor_list_models_v2","cursor_list_repositories","cursor_list_repositories_v2","cursor_stop_agent","cursor_stop_agent_v2","dagster_delete_run","dagster_get_asset","dagster_get_run","dagster_get_run_logs","dagster_launch_run","dagster_list_assets","dagster_list_jobs","dagster_list_runs","dagster_list_schedules","dagster_list_sensors","dagster_materialize_assets","dagster_reexecute_run","dagster_report_asset_materialization","dagster_start_schedule","dagster_start_sensor","dagster_stop_schedule","dagster_stop_sensor","dagster_terminate_run","dagster_wipe_asset","databricks_cancel_run","databricks_execute_sql","databricks_get_cluster","databricks_get_job","databricks_get_run","databricks_get_run_output","databricks_get_statement","databricks_list_clusters","databricks_list_jobs","databricks_list_runs","databricks_list_warehouses","databricks_run_job","datadog_add_incident_todo","datadog_cancel_downtime","datadog_create_dashboard","datadog_create_downtime","datadog_create_event","datadog_create_incident","datadog_create_monitor","datadog_create_slo","datadog_delete_dashboard","datadog_delete_slo","datadog_get_browser_synthetics_results","datadog_get_dashboard","datadog_get_incident","datadog_get_monitor","datadog_get_security_signal","datadog_get_slo","datadog_get_slo_history","datadog_get_synthetics_results","datadog_get_synthetics_test","datadog_list_dashboards","datadog_list_downtimes","datadog_list_incidents","datadog_list_monitors","datadog_list_security_rules","datadog_list_security_signals","datadog_list_services","datadog_list_slos","datadog_list_synthetics_tests","datadog_mute_monitor","datadog_query_logs","datadog_query_timeseries","datadog_search_spans","datadog_send_logs","datadog_submit_metrics","datadog_trigger_synthetics_tests","datadog_unmute_monitor","datadog_update_incident","datadog_update_security_signal_assignee","datadog_update_security_signal_state","datadog_update_slo","datadog_update_synthetics_status","datagma_enrich_company","datagma_enrich_person","datagma_find_email","datagma_find_phone","datagma_get_credits","daytona_create_sandbox","daytona_delete_sandbox","daytona_download_file","daytona_execute_command","daytona_get_sandbox","daytona_git_clone","daytona_list_files","daytona_list_sandboxes","daytona_run_code","daytona_start_sandbox","daytona_stop_sandbox","daytona_upload_file","deployed_block_executor","deployments_deploy","deployments_get_version","deployments_list_versions","deployments_promote","deployments_undeploy","devin_append_session_tags","devin_archive_session","devin_create_session","devin_get_session","devin_get_session_tags","devin_list_session_attachments","devin_list_session_messages","devin_list_sessions","devin_replace_session_tags","devin_send_message","devin_terminate_session","discord_add_reaction","discord_archive_thread","discord_assign_role","discord_ban_member","discord_bulk_delete_messages","discord_create_channel","discord_create_invite","discord_create_role","discord_create_thread","discord_create_webhook","discord_delete_channel","discord_delete_invite","discord_delete_message","discord_delete_role","discord_delete_webhook","discord_edit_message","discord_execute_webhook","discord_get_channel","discord_get_invite","discord_get_member","discord_get_messages","discord_get_pinned_messages","discord_get_server","discord_get_user","discord_get_webhook","discord_join_thread","discord_kick_member","discord_leave_thread","discord_list_channels","discord_list_roles","discord_pin_message","discord_remove_reaction","discord_remove_role","discord_send_message","discord_unban_member","discord_unpin_message","discord_update_channel","discord_update_member","discord_update_role","docusign_create_from_template","docusign_download_document","docusign_get_envelope","docusign_list_envelopes","docusign_list_recipients","docusign_list_templates","docusign_send_envelope","docusign_void_envelope","downdetector_get_company","downdetector_get_company_attribution","downdetector_get_company_baseline","downdetector_get_company_events","downdetector_get_company_incidents","downdetector_get_company_indicators","downdetector_get_company_last_15","downdetector_get_company_status","downdetector_get_provider","downdetector_get_reports","downdetector_get_site_companies","downdetector_list_categories","downdetector_list_incidents","downdetector_list_sites","downdetector_search_companies","dropbox_copy","dropbox_create_folder","dropbox_create_shared_link","dropbox_delete","dropbox_download","dropbox_get_metadata","dropbox_list_folder","dropbox_list_revisions","dropbox_list_shared_links","dropbox_move","dropbox_restore","dropbox_search","dropbox_upload","dropcontact_enrich_contact","dspy_chain_of_thought","dspy_predict","dspy_react","dub_bulk_create_links","dub_bulk_delete_links","dub_bulk_update_links","dub_create_link","dub_create_tag","dub_delete_link","dub_get_analytics","dub_get_events","dub_get_link","dub_get_links_count","dub_get_qr_code","dub_list_domains","dub_list_folders","dub_list_links","dub_list_tags","dub_update_link","dub_upsert_link","duckduckgo_search","dynamodb_delete","dynamodb_get","dynamodb_introspect","dynamodb_put","dynamodb_query","dynamodb_scan","dynamodb_update","dynatrace_add_problem_comment","dynatrace_add_tags","dynatrace_close_problem","dynatrace_create_settings_object","dynatrace_create_slo","dynatrace_delete_problem_comment","dynatrace_delete_settings_object","dynatrace_delete_slo","dynatrace_delete_tag","dynatrace_execute_synthetic_monitors","dynatrace_get_attack","dynatrace_get_audit_logs","dynatrace_get_entity","dynatrace_get_event","dynatrace_get_metric","dynatrace_get_problem","dynatrace_get_problem_comment","dynatrace_get_security_problem","dynatrace_get_settings_object","dynatrace_get_slo","dynatrace_get_synthetic_batch","dynatrace_ingest_event","dynatrace_ingest_logs","dynatrace_ingest_metrics","dynatrace_list_attacks","dynatrace_list_entities","dynatrace_list_entity_types","dynatrace_list_events","dynatrace_list_metrics","dynatrace_list_problem_comments","dynatrace_list_problems","dynatrace_list_remediation_items","dynatrace_list_security_problems","dynatrace_list_settings_objects","dynatrace_list_settings_schemas","dynatrace_list_slos","dynatrace_list_synthetic_monitors","dynatrace_list_tags","dynatrace_mute_security_problem","dynatrace_mute_security_problems","dynatrace_query_metrics","dynatrace_search_logs","dynatrace_unmute_security_problem","dynatrace_unmute_security_problems","dynatrace_update_problem_comment","dynatrace_update_settings_object","dynatrace_update_slo","elasticsearch_bulk","elasticsearch_cluster_health","elasticsearch_cluster_stats","elasticsearch_count","elasticsearch_create_index","elasticsearch_delete_document","elasticsearch_delete_index","elasticsearch_get_document","elasticsearch_get_index","elasticsearch_index_document","elasticsearch_list_indices","elasticsearch_search","elasticsearch_update_document","elevenlabs_audio_isolation","elevenlabs_edit_voice_settings","elevenlabs_get_user","elevenlabs_get_voice","elevenlabs_get_voice_settings","elevenlabs_list_models","elevenlabs_list_voices","elevenlabs_sound_effects","elevenlabs_speech_to_speech","elevenlabs_tts","emailbison_attach_leads_to_campaign","emailbison_attach_tags_to_leads","emailbison_create_campaign","emailbison_create_lead","emailbison_create_tag","emailbison_get_lead","emailbison_list_campaigns","emailbison_list_leads","emailbison_list_replies","emailbison_list_tags","emailbison_update_campaign","emailbison_update_campaign_status","emailbison_update_lead","embeddings_cohere","embeddings_gemini","embeddings_mistral","embeddings_openai","embeddings_openrouter","enrich_check_credits","enrich_company_funding","enrich_company_lookup","enrich_company_revenue","enrich_disposable_email_check","enrich_email_to_ip","enrich_email_to_person_lite","enrich_email_to_phone","enrich_email_to_profile","enrich_find_email","enrich_get_post_details","enrich_ip_to_company","enrich_linkedin_profile","enrich_linkedin_to_personal_email","enrich_linkedin_to_work_email","enrich_phone_finder","enrich_reverse_hash_lookup","enrich_sales_pointer_people","enrich_search_company","enrich_search_company_activities","enrich_search_company_employees","enrich_search_jobs","enrich_search_logo","enrich_search_people","enrich_search_people_activities","enrich_search_post_comments","enrich_search_post_comments_by_url","enrich_search_post_reactions","enrich_search_post_reactions_by_url","enrich_search_posts","enrich_search_similar_companies","enrich_verify_email","enrichment_run","enrow_find_email","enrow_verify_email","evernote_copy_note","evernote_create_note","evernote_create_notebook","evernote_create_tag","evernote_delete_note","evernote_get_note","evernote_get_notebook","evernote_list_notebooks","evernote_list_tags","evernote_search_notes","evernote_update_note","exa_agent","exa_answer","exa_find_similar_links","exa_get_contents","exa_search","extend_parser","extend_parser_v2","fathom_get_summary","fathom_get_transcript","fathom_list_meeting_types","fathom_list_meetings","fathom_list_team_members","fathom_list_teams","file_append","file_compress","file_decompress","file_fetch","file_get","file_get_content","file_manage_sharing","file_parser","file_parser_v2","file_parser_v3","file_read","file_write","findymail_find_email_from_linkedin","findymail_find_email_from_name","findymail_find_emails_by_domain","findymail_find_employees","findymail_find_phone","findymail_get_company","findymail_get_credits","findymail_lookup_technologies","findymail_reverse_email_lookup","findymail_search_technologies","findymail_verify_email","firecrawl_agent","firecrawl_batch_scrape","firecrawl_batch_scrape_status","firecrawl_cancel_crawl","firecrawl_crawl","firecrawl_crawl_status","firecrawl_credit_usage","firecrawl_extract","firecrawl_extract_status","firecrawl_map","firecrawl_parse","firecrawl_scrape","firecrawl_search","fireflies_add_to_live_meeting","fireflies_create_bite","fireflies_delete_transcript","fireflies_get_transcript","fireflies_get_user","fireflies_list_bites","fireflies_list_contacts","fireflies_list_transcripts","fireflies_list_users","fireflies_upload_audio","flint_create_task","flint_generate_pages","flint_get_task","function_execute","gamma_check_status","gamma_generate","gamma_generate_from_template","gamma_list_folders","gamma_list_themes","github_add_assignees","github_add_assignees_v2","github_add_labels","github_add_labels_v2","github_cancel_workflow_run","github_cancel_workflow_run_v2","github_check_star","github_check_star_v2","github_close_issue","github_close_issue_v2","github_close_pr","github_close_pr_v2","github_comment","github_comment_v2","github_compare_commits","github_compare_commits_v2","github_create_branch","github_create_branch_v2","github_create_comment_reaction","github_create_comment_reaction_v2","github_create_file","github_create_file_v2","github_create_gist","github_create_gist_v2","github_create_issue","github_create_issue_reaction","github_create_issue_reaction_v2","github_create_issue_v2","github_create_milestone","github_create_milestone_v2","github_create_pr","github_create_pr_review","github_create_pr_review_v2","github_create_pr_v2","github_create_project","github_create_project_v2","github_create_release","github_create_release_v2","github_delete_branch","github_delete_branch_v2","github_delete_comment","github_delete_comment_reaction","github_delete_comment_reaction_v2","github_delete_comment_v2","github_delete_file","github_delete_file_v2","github_delete_gist","github_delete_gist_v2","github_delete_issue_reaction","github_delete_issue_reaction_v2","github_delete_milestone","github_delete_milestone_v2","github_delete_project","github_delete_project_v2","github_delete_release","github_delete_release_v2","github_fork_gist","github_fork_gist_v2","github_fork_repo","github_fork_repo_v2","github_get_branch","github_get_branch_protection","github_get_branch_protection_v2","github_get_branch_v2","github_get_commit","github_get_commit_v2","github_get_file_content","github_get_file_content_v2","github_get_gist","github_get_gist_v2","github_get_issue","github_get_issue_v2","github_get_latest_release","github_get_latest_release_v2","github_get_milestone","github_get_milestone_v2","github_get_pr_files","github_get_pr_files_v2","github_get_project","github_get_project_v2","github_get_readme","github_get_readme_v2","github_get_release","github_get_release_v2","github_get_tree","github_get_tree_v2","github_get_workflow","github_get_workflow_run","github_get_workflow_run_v2","github_get_workflow_v2","github_issue_comment","github_issue_comment_v2","github_job_logs","github_latest_commit","github_latest_commit_v2","github_list_branches","github_list_branches_v2","github_list_commits","github_list_commits_v2","github_list_forks","github_list_forks_v2","github_list_gists","github_list_gists_v2","github_list_issue_comments","github_list_issue_comments_v2","github_list_issues","github_list_issues_v2","github_list_milestones","github_list_milestones_v2","github_list_pr_comments","github_list_pr_comments_v2","github_list_projects","github_list_projects_v2","github_list_prs","github_list_prs_v2","github_list_releases","github_list_releases_v2","github_list_review_threads","github_list_stargazers","github_list_stargazers_v2","github_list_tags","github_list_tags_v2","github_list_workflow_runs","github_list_workflow_runs_v2","github_list_workflows","github_list_workflows_v2","github_merge_pr","github_merge_pr_v2","github_pr","github_pr_v2","github_remove_label","github_remove_label_v2","github_reply_review_thread","github_repo_info","github_repo_info_v2","github_request_reviewers","github_request_reviewers_v2","github_rerun_workflow","github_rerun_workflow_v2","github_resolve_review_thread","github_search_code","github_search_code_v2","github_search_commits","github_search_commits_v2","github_search_issues","github_search_issues_v2","github_search_repos","github_search_repos_v2","github_search_users","github_search_users_v2","github_star_gist","github_star_gist_v2","github_star_repo","github_star_repo_v2","github_status_check_rollup","github_trigger_workflow","github_trigger_workflow_v2","github_unstar_gist","github_unstar_gist_v2","github_unstar_repo","github_unstar_repo_v2","github_update_branch_protection","github_update_branch_protection_v2","github_update_comment","github_update_comment_v2","github_update_file","github_update_file_v2","github_update_gist","github_update_gist_v2","github_update_issue","github_update_issue_v2","github_update_milestone","github_update_milestone_v2","github_update_pr","github_update_pr_v2","github_update_project","github_update_project_v2","github_update_release","github_update_release_v2","gitlab_activate_user","gitlab_add_member","gitlab_add_saml_group_link","gitlab_approve_access_request","gitlab_approve_merge_request","gitlab_approve_user","gitlab_ban_user","gitlab_block_user","gitlab_cancel_pipeline","gitlab_compare_branches","gitlab_create_branch","gitlab_create_file","gitlab_create_issue","gitlab_create_issue_note","gitlab_create_merge_request","gitlab_create_merge_request_note","gitlab_create_pipeline","gitlab_create_release","gitlab_create_user","gitlab_deactivate_user","gitlab_delete_branch","gitlab_delete_issue","gitlab_delete_saml_group_link","gitlab_delete_user","gitlab_delete_user_identity","gitlab_deny_access_request","gitlab_get_file","gitlab_get_group","gitlab_get_issue","gitlab_get_job_log","gitlab_get_merge_request","gitlab_get_merge_request_changes","gitlab_get_pipeline","gitlab_get_project","gitlab_invite_member","gitlab_list_access_requests","gitlab_list_branches","gitlab_list_commits","gitlab_list_groups","gitlab_list_invitations","gitlab_list_issues","gitlab_list_members","gitlab_list_merge_requests","gitlab_list_pipeline_jobs","gitlab_list_pipelines","gitlab_list_projects","gitlab_list_releases","gitlab_list_repository_tree","gitlab_list_saml_group_links","gitlab_list_user_memberships","gitlab_merge_merge_request","gitlab_play_job","gitlab_reject_user","gitlab_remove_member","gitlab_retry_pipeline","gitlab_revoke_invitation","gitlab_search_users","gitlab_unban_user","gitlab_unblock_user","gitlab_update_file","gitlab_update_invitation","gitlab_update_issue","gitlab_update_member","gitlab_update_merge_request","gitlab_update_user","gmail_add_label","gmail_add_label_v2","gmail_archive","gmail_archive_v2","gmail_create_label_v2","gmail_delete","gmail_delete_draft_v2","gmail_delete_label_v2","gmail_delete_v2","gmail_draft","gmail_draft_v2","gmail_edit_draft_v2","gmail_get_draft_v2","gmail_get_thread_v2","gmail_list_drafts_v2","gmail_list_labels_v2","gmail_list_threads_v2","gmail_mark_read","gmail_mark_read_v2","gmail_mark_unread","gmail_mark_unread_v2","gmail_move","gmail_move_v2","gmail_read","gmail_read_v2","gmail_remove_label","gmail_remove_label_v2","gmail_search","gmail_search_v2","gmail_send","gmail_send_v2","gmail_trash_thread_v2","gmail_unarchive","gmail_unarchive_v2","gmail_untrash_thread_v2","gmail_update_label_v2","gong_aggregate_activity","gong_aggregate_by_period","gong_answered_scorecards","gong_ask_anything","gong_assign_flow_prospects","gong_create_call","gong_day_by_day_activity","gong_get_brief","gong_get_call","gong_get_call_transcript","gong_get_coaching","gong_get_extensive_calls","gong_get_folder_content","gong_get_logs","gong_get_prospect_flows","gong_get_user","gong_interaction_stats","gong_list_calls","gong_list_flows","gong_list_library_folders","gong_list_scorecards","gong_list_trackers","gong_list_users","gong_list_workspaces","gong_lookup_email","gong_lookup_phone","gong_purge_email_address","gong_purge_phone_number","gong_unassign_flow_prospects","google_ads_ad_performance","google_ads_campaign_performance","google_ads_list_ad_groups","google_ads_list_campaigns","google_ads_list_customers","google_ads_search","google_appsheet_add_rows","google_appsheet_delete_rows","google_appsheet_edit_rows","google_appsheet_find_rows","google_bigquery_create_dataset","google_bigquery_create_table","google_bigquery_delete_dataset","google_bigquery_delete_table","google_bigquery_get_query_results","google_bigquery_get_table","google_bigquery_insert_rows","google_bigquery_list_datasets","google_bigquery_list_table_data","google_bigquery_list_tables","google_bigquery_query","google_books_volume_details","google_books_volume_search","google_calendar_create","google_calendar_create_calendar","google_calendar_create_calendar_v2","google_calendar_create_v2","google_calendar_delete","google_calendar_delete_calendar","google_calendar_delete_calendar_v2","google_calendar_delete_v2","google_calendar_freebusy","google_calendar_freebusy_v2","google_calendar_get","google_calendar_get_v2","google_calendar_instances","google_calendar_instances_v2","google_calendar_invite","google_calendar_invite_v2","google_calendar_list","google_calendar_list_acl","google_calendar_list_acl_v2","google_calendar_list_calendars","google_calendar_list_calendars_v2","google_calendar_list_v2","google_calendar_move","google_calendar_move_v2","google_calendar_quick_add","google_calendar_quick_add_v2","google_calendar_share_calendar","google_calendar_share_calendar_v2","google_calendar_unshare_calendar","google_calendar_unshare_calendar_v2","google_calendar_update","google_calendar_update_acl","google_calendar_update_acl_v2","google_calendar_update_calendar","google_calendar_update_calendar_v2","google_calendar_update_v2","google_contacts_create","google_contacts_delete","google_contacts_get","google_contacts_list","google_contacts_search","google_contacts_update","google_docs_create","google_docs_create_named_range","google_docs_create_paragraph_bullets","google_docs_delete_content_range","google_docs_delete_named_range","google_docs_delete_paragraph_bullets","google_docs_insert_image","google_docs_insert_page_break","google_docs_insert_table","google_docs_insert_text","google_docs_read","google_docs_replace_text","google_docs_update_paragraph_style","google_docs_update_text_style","google_docs_write","google_drive_copy","google_drive_create_comment","google_drive_create_folder","google_drive_delete","google_drive_delete_comment","google_drive_download","google_drive_export","google_drive_get_about","google_drive_get_content","google_drive_get_file","google_drive_get_revision","google_drive_list","google_drive_list_comments","google_drive_list_permissions","google_drive_list_revisions","google_drive_move","google_drive_search","google_drive_share","google_drive_trash","google_drive_unshare","google_drive_untrash","google_drive_update","google_drive_upload","google_forms_batch_update","google_forms_create_form","google_forms_create_watch","google_forms_delete_watch","google_forms_get_form","google_forms_get_responses","google_forms_list_watches","google_forms_renew_watch","google_forms_set_publish_settings","google_groups_add_alias","google_groups_add_member","google_groups_create_group","google_groups_delete_group","google_groups_get_group","google_groups_get_member","google_groups_get_settings","google_groups_has_member","google_groups_list_aliases","google_groups_list_groups","google_groups_list_members","google_groups_remove_alias","google_groups_remove_member","google_groups_update_group","google_groups_update_member","google_groups_update_settings","google_maps_air_quality","google_maps_directions","google_maps_distance_matrix","google_maps_elevation","google_maps_geocode","google_maps_geolocate","google_maps_place_details","google_maps_places_nearby","google_maps_places_search","google_maps_pollen","google_maps_reverse_geocode","google_maps_snap_to_roads","google_maps_solar","google_maps_speed_limits","google_maps_timezone","google_maps_validate_address","google_meet_create_space","google_meet_end_conference","google_meet_get_conference_record","google_meet_get_space","google_meet_list_conference_records","google_meet_list_participants","google_pagespeed_analyze","google_search","google_sheets_append","google_sheets_append_v2","google_sheets_batch_clear_v2","google_sheets_batch_get_v2","google_sheets_batch_update_v2","google_sheets_clear_v2","google_sheets_copy_sheet_v2","google_sheets_create_spreadsheet_v2","google_sheets_delete_rows_v2","google_sheets_delete_sheet_v2","google_sheets_delete_spreadsheet_v2","google_sheets_get_spreadsheet_v2","google_sheets_read","google_sheets_read_v2","google_sheets_update","google_sheets_update_v2","google_sheets_write","google_sheets_write_v2","google_slides_add_image","google_slides_add_slide","google_slides_batch_update","google_slides_copy_presentation","google_slides_create","google_slides_create_line","google_slides_create_paragraph_bullets","google_slides_create_shape","google_slides_create_sheets_chart","google_slides_create_table","google_slides_create_video","google_slides_delete_object","google_slides_delete_paragraph_bullets","google_slides_delete_table_column","google_slides_delete_table_row","google_slides_delete_text","google_slides_duplicate_object","google_slides_export_presentation","google_slides_get_page","google_slides_get_thumbnail","google_slides_group_objects","google_slides_insert_table_columns","google_slides_insert_table_rows","google_slides_insert_text","google_slides_merge_table_cells","google_slides_read","google_slides_refresh_sheets_chart","google_slides_replace_all_shapes_with_image","google_slides_replace_all_shapes_with_sheets_chart","google_slides_replace_all_text","google_slides_replace_image","google_slides_reroute_line","google_slides_ungroup_objects","google_slides_unmerge_table_cells","google_slides_update_image_properties","google_slides_update_line_category","google_slides_update_line_properties","google_slides_update_page_element_alt_text","google_slides_update_page_element_transform","google_slides_update_page_elements_z_order","google_slides_update_page_properties","google_slides_update_paragraph_style","google_slides_update_shape_properties","google_slides_update_slide_properties","google_slides_update_slides_position","google_slides_update_table_border_properties","google_slides_update_table_cell_properties","google_slides_update_table_column_properties","google_slides_update_table_row_properties","google_slides_update_text_style","google_slides_update_video_properties","google_slides_write","google_tasks_create","google_tasks_delete","google_tasks_get","google_tasks_list","google_tasks_list_task_lists","google_tasks_update","google_translate_detect","google_translate_text","google_vault_add_held_accounts","google_vault_add_matters_permissions","google_vault_close_matters","google_vault_create_matters","google_vault_create_matters_export","google_vault_create_matters_holds","google_vault_create_saved_query","google_vault_delete_matters","google_vault_delete_matters_export","google_vault_delete_matters_holds","google_vault_delete_saved_query","google_vault_download_export_file","google_vault_list_matters","google_vault_list_matters_export","google_vault_list_matters_holds","google_vault_list_saved_queries","google_vault_remove_held_accounts","google_vault_remove_matters_permissions","google_vault_reopen_matters","google_vault_undelete_matters","google_vault_update_matters","google_vault_update_matters_holds","grafana_check_data_source_health","grafana_create_alert_rule","grafana_create_annotation","grafana_create_contact_point","grafana_create_dashboard","grafana_create_folder","grafana_delete_alert_rule","grafana_delete_annotation","grafana_delete_contact_point","grafana_delete_dashboard","grafana_delete_folder","grafana_get_alert_rule","grafana_get_alert_rule_group","grafana_get_dashboard","grafana_get_data_source","grafana_get_folder","grafana_get_health","grafana_list_alert_rules","grafana_list_annotations","grafana_list_contact_points","grafana_list_dashboards","grafana_list_data_sources","grafana_list_folders","grafana_move_folder","grafana_query_data_source","grafana_update_alert_rule","grafana_update_annotation","grafana_update_contact_point","grafana_update_dashboard","grafana_update_folder","grain_create_hook","grain_create_hook_v2","grain_delete_hook","grain_delete_hook_v2","grain_get_recording","grain_get_transcript","grain_list_hooks","grain_list_hooks_v2","grain_list_meeting_types","grain_list_recordings","grain_list_teams","grain_list_views","granola_get_note","granola_list_folders","granola_list_notes","greenhouse_get_application","greenhouse_get_candidate","greenhouse_get_job","greenhouse_get_user","greenhouse_list_applications","greenhouse_list_candidates","greenhouse_list_departments","greenhouse_list_job_stages","greenhouse_list_jobs","greenhouse_list_offices","greenhouse_list_users","greptile_index_repo","greptile_query","greptile_search","greptile_status","guardrails_validate","hex_cancel_run","hex_create_collection","hex_create_group","hex_deactivate_user","hex_delete_group","hex_get_collection","hex_get_data_connection","hex_get_group","hex_get_project","hex_get_project_runs","hex_get_queried_tables","hex_get_run_status","hex_list_collections","hex_list_data_connections","hex_list_groups","hex_list_projects","hex_list_users","hex_run_project","hex_update_collection","hex_update_group","hex_update_project","http_request","hubspot_add_list_memberships","hubspot_create_appointment","hubspot_create_association","hubspot_create_company","hubspot_create_contact","hubspot_create_deal","hubspot_create_email","hubspot_create_line_item","hubspot_create_list","hubspot_create_note","hubspot_create_ticket","hubspot_delete_association","hubspot_delete_company","hubspot_delete_contact","hubspot_delete_deal","hubspot_delete_line_item","hubspot_delete_ticket","hubspot_get_appointment","hubspot_get_association_labels","hubspot_get_cart","hubspot_get_company","hubspot_get_contact","hubspot_get_deal","hubspot_get_email","hubspot_get_line_item","hubspot_get_list","hubspot_get_list_memberships","hubspot_get_marketing_event","hubspot_get_note","hubspot_get_properties","hubspot_get_quote","hubspot_get_ticket","hubspot_get_users","hubspot_list_appointments","hubspot_list_associations","hubspot_list_carts","hubspot_list_companies","hubspot_list_contacts","hubspot_list_deals","hubspot_list_emails","hubspot_list_line_items","hubspot_list_lists","hubspot_list_marketing_events","hubspot_list_notes","hubspot_list_owners","hubspot_list_quotes","hubspot_list_tickets","hubspot_remove_list_memberships","hubspot_search_companies","hubspot_search_contacts","hubspot_search_deals","hubspot_search_emails","hubspot_search_line_items","hubspot_search_notes","hubspot_search_quotes","hubspot_search_tickets","hubspot_update_appointment","hubspot_update_company","hubspot_update_contact","hubspot_update_deal","hubspot_update_line_item","hubspot_update_ticket","huggingface_chat","hunter_companies_find","hunter_discover","hunter_domain_search","hunter_email_count","hunter_email_finder","hunter_email_verifier","iam_add_user_to_group","iam_attach_role_policy","iam_attach_user_policy","iam_create_access_key","iam_create_role","iam_create_user","iam_delete_access_key","iam_delete_role","iam_delete_user","iam_detach_role_policy","iam_detach_user_policy","iam_get_role","iam_get_user","iam_list_attached_role_policies","iam_list_attached_user_policies","iam_list_groups","iam_list_policies","iam_list_roles","iam_list_users","iam_remove_user_from_group","iam_simulate_principal_policy","icypeas_find_email","icypeas_verify_email","identity_center_check_assignment_deletion_status","identity_center_check_assignment_status","identity_center_create_account_assignment","identity_center_delete_account_assignment","identity_center_describe_account","identity_center_get_group","identity_center_get_user","identity_center_list_account_assignments","identity_center_list_accounts","identity_center_list_groups","identity_center_list_instances","identity_center_list_permission_sets","image_generate","incidentio_actions_create","incidentio_actions_list","incidentio_actions_show","incidentio_actions_update","incidentio_alert_events_create","incidentio_alerts_list","incidentio_alerts_resolve","incidentio_alerts_show","incidentio_catalog_entries_list","incidentio_catalog_types_list","incidentio_custom_fields_create","incidentio_custom_fields_delete","incidentio_custom_fields_list","incidentio_custom_fields_show","incidentio_custom_fields_update","incidentio_escalation_paths_create","incidentio_escalation_paths_delete","incidentio_escalation_paths_list","incidentio_escalation_paths_show","incidentio_escalation_paths_update","incidentio_escalations_cancel","incidentio_escalations_create","incidentio_escalations_list","incidentio_escalations_show","incidentio_follow_ups_create","incidentio_follow_ups_list","incidentio_follow_ups_show","incidentio_follow_ups_update","incidentio_incident_alerts_list","incidentio_incident_memberships_create","incidentio_incident_memberships_revoke","incidentio_incident_participants_list","incidentio_incident_roles_create","incidentio_incident_roles_delete","incidentio_incident_roles_list","incidentio_incident_roles_show","incidentio_incident_roles_update","incidentio_incident_statuses_list","incidentio_incident_timestamps_list","incidentio_incident_timestamps_show","incidentio_incident_types_list","incidentio_incident_updates_list","incidentio_incidents_create","incidentio_incidents_list","incidentio_incidents_show","incidentio_incidents_update","incidentio_on_call_now","incidentio_schedule_entries_list","incidentio_schedule_overrides_create","incidentio_schedule_overrides_list","incidentio_schedules_create","incidentio_schedules_delete","incidentio_schedules_list","incidentio_schedules_show","incidentio_schedules_update","incidentio_severities_list","incidentio_teams_list","incidentio_teams_show","incidentio_users_list","incidentio_users_show","incidentio_workflows_create","incidentio_workflows_delete","incidentio_workflows_list","incidentio_workflows_show","incidentio_workflows_update","infisical_create_secret","infisical_delete_secret","infisical_get_secret","infisical_list_secrets","infisical_update_secret","instagram_delete_comment","instagram_download_media","instagram_get_account_insights","instagram_get_container_status","instagram_get_conversation_messages","instagram_get_media","instagram_get_media_insights","instagram_get_message","instagram_get_profile","instagram_get_publishing_limit","instagram_hide_comment","instagram_list_comments","instagram_list_conversations","instagram_list_media","instagram_list_stories","instagram_private_reply","instagram_publish_carousel","instagram_publish_image","instagram_publish_reel","instagram_publish_story","instagram_publish_video","instagram_reply_to_comment","instagram_send_text_message","instagram_set_comments_enabled","instantly_activate_campaign","instantly_create_campaign","instantly_create_lead","instantly_create_lead_list","instantly_delete_campaign","instantly_delete_leads","instantly_get_lead","instantly_list_campaigns","instantly_list_emails","instantly_list_lead_lists","instantly_list_leads","instantly_patch_campaign","instantly_patch_lead","instantly_pause_campaign","instantly_reply_to_email","instantly_update_lead_interest_status","intercom_assign_conversation_v2","intercom_attach_contact_to_company_v2","intercom_close_conversation_v2","intercom_create_company","intercom_create_company_v2","intercom_create_contact","intercom_create_contact_v2","intercom_create_event_v2","intercom_create_message","intercom_create_message_v2","intercom_create_note_v2","intercom_create_tag_v2","intercom_create_ticket","intercom_create_ticket_v2","intercom_delete_contact","intercom_delete_contact_v2","intercom_detach_contact_from_company_v2","intercom_get_company","intercom_get_company_v2","intercom_get_contact","intercom_get_contact_v2","intercom_get_conversation","intercom_get_conversation_v2","intercom_get_ticket","intercom_get_ticket_v2","intercom_list_admins_v2","intercom_list_companies","intercom_list_companies_v2","intercom_list_contacts","intercom_list_contacts_v2","intercom_list_conversations","intercom_list_conversations_v2","intercom_list_tags_v2","intercom_open_conversation_v2","intercom_reply_conversation","intercom_reply_conversation_v2","intercom_search_contacts","intercom_search_contacts_v2","intercom_search_conversations","intercom_search_conversations_v2","intercom_snooze_conversation_v2","intercom_tag_contact_v2","intercom_tag_conversation_v2","intercom_untag_contact_v2","intercom_update_contact","intercom_update_contact_v2","intercom_update_ticket_v2","jina_read_url","jina_search","jira_add_attachment","jira_add_comment","jira_add_watcher","jira_add_worklog","jira_assign_issue","jira_bulk_read","jira_create_issue_link","jira_delete_attachment","jira_delete_comment","jira_delete_issue","jira_delete_issue_link","jira_delete_worklog","jira_get_attachments","jira_get_comments","jira_get_fields","jira_get_project","jira_get_transitions","jira_get_users","jira_get_worklogs","jira_list_issue_types","jira_list_projects","jira_remove_watcher","jira_retrieve","jira_search_issues","jira_search_users","jira_transition_issue","jira_update","jira_update_comment","jira_update_worklog","jira_write","jsm_add_comment","jsm_add_customer","jsm_add_organization","jsm_add_participants","jsm_answer_approval","jsm_attach_form","jsm_copy_forms","jsm_create_object","jsm_create_organization","jsm_create_request","jsm_delete_form","jsm_delete_object","jsm_externalise_form","jsm_get_approvals","jsm_get_comments","jsm_get_customers","jsm_get_form","jsm_get_form_answers","jsm_get_form_structure","jsm_get_form_templates","jsm_get_issue_forms","jsm_get_object","jsm_get_object_schema","jsm_get_object_type_attributes","jsm_get_organizations","jsm_get_participants","jsm_get_queues","jsm_get_request","jsm_get_request_type_fields","jsm_get_request_types","jsm_get_requests","jsm_get_service_desks","jsm_get_sla","jsm_get_transitions","jsm_internalise_form","jsm_list_object_schemas","jsm_list_object_types","jsm_reopen_form","jsm_save_form_answers","jsm_search_objects_aql","jsm_submit_form","jsm_transition_request","jsm_update_object","jupyter_copy_content","jupyter_create_file","jupyter_create_session","jupyter_delete_content","jupyter_delete_session","jupyter_get_content","jupyter_interrupt_kernel","jupyter_list_contents","jupyter_list_kernels","jupyter_list_kernelspecs","jupyter_list_sessions","jupyter_rename_content","jupyter_restart_kernel","jupyter_start_kernel","jupyter_stop_kernel","jupyter_upload_file","kalshi_amend_order","kalshi_amend_order_v2","kalshi_cancel_order","kalshi_cancel_order_v2","kalshi_create_order","kalshi_create_order_v2","kalshi_get_balance","kalshi_get_balance_v2","kalshi_get_candlesticks","kalshi_get_candlesticks_v2","kalshi_get_event","kalshi_get_event_candlesticks","kalshi_get_event_candlesticks_v2","kalshi_get_event_v2","kalshi_get_events","kalshi_get_events_v2","kalshi_get_exchange_announcements","kalshi_get_exchange_announcements_v2","kalshi_get_exchange_schedule","kalshi_get_exchange_schedule_v2","kalshi_get_exchange_status","kalshi_get_exchange_status_v2","kalshi_get_fills","kalshi_get_fills_v2","kalshi_get_market","kalshi_get_market_v2","kalshi_get_markets","kalshi_get_markets_v2","kalshi_get_order","kalshi_get_order_v2","kalshi_get_orderbook","kalshi_get_orderbook_v2","kalshi_get_orders","kalshi_get_orders_v2","kalshi_get_positions","kalshi_get_positions_v2","kalshi_get_series_by_ticker","kalshi_get_series_by_ticker_v2","kalshi_get_series_list","kalshi_get_series_list_v2","kalshi_get_settlements","kalshi_get_settlements_v2","kalshi_get_trades","kalshi_get_trades_v2","ketch_get_consent","ketch_get_subscriptions","ketch_invoke_right","ketch_set_consent","ketch_set_subscriptions","knowledge_create_document","knowledge_delete_chunk","knowledge_delete_document","knowledge_get_connector","knowledge_get_document","knowledge_list_chunks","knowledge_list_connectors","knowledge_list_documents","knowledge_list_tags","knowledge_search","knowledge_trigger_sync","knowledge_update_chunk","knowledge_upload_chunk","knowledge_upsert_document","langsmith_create_feedback","langsmith_create_run","langsmith_create_runs_batch","langsmith_get_run","langsmith_update_run","latex_compile","latex_get_package","latex_list_fonts","latex_search_packages","launchdarkly_create_flag","launchdarkly_delete_flag","launchdarkly_get_audit_log","launchdarkly_get_flag","launchdarkly_get_flag_status","launchdarkly_list_environments","launchdarkly_list_flags","launchdarkly_list_members","launchdarkly_list_projects","launchdarkly_list_segments","launchdarkly_toggle_flag","launchdarkly_update_flag","leadmagic_company_search","leadmagic_email_to_profile","leadmagic_find_email","leadmagic_find_mobile","leadmagic_get_credits","leadmagic_profile_search","leadmagic_profile_to_email","leadmagic_role_finder","leadmagic_validate_email","lemlist_get_activities","lemlist_get_lead","lemlist_send_email","linear_add_label_to_issue","linear_add_label_to_project","linear_archive_issue","linear_archive_label","linear_archive_project","linear_create_attachment","linear_create_comment","linear_create_customer","linear_create_customer_request","linear_create_customer_status","linear_create_customer_tier","linear_create_cycle","linear_create_favorite","linear_create_issue","linear_create_issue_relation","linear_create_label","linear_create_project","linear_create_project_label","linear_create_project_milestone","linear_create_project_status","linear_create_project_update","linear_create_workflow_state","linear_delete_attachment","linear_delete_comment","linear_delete_customer","linear_delete_customer_status","linear_delete_customer_tier","linear_delete_issue","linear_delete_issue_relation","linear_delete_project","linear_delete_project_label","linear_delete_project_milestone","linear_delete_project_status","linear_get_active_cycle","linear_get_customer","linear_get_cycle","linear_get_issue","linear_get_project","linear_get_viewer","linear_list_attachments","linear_list_comments","linear_list_customer_requests","linear_list_customer_statuses","linear_list_customer_tiers","linear_list_customers","linear_list_cycles","linear_list_favorites","linear_list_issue_relations","linear_list_labels","linear_list_notifications","linear_list_project_labels","linear_list_project_milestones","linear_list_project_statuses","linear_list_project_updates","linear_list_projects","linear_list_teams","linear_list_users","linear_list_workflow_states","linear_merge_customers","linear_read_issues","linear_remove_label_from_issue","linear_remove_label_from_project","linear_search_issues","linear_unarchive_issue","linear_update_attachment","linear_update_comment","linear_update_customer","linear_update_customer_request","linear_update_customer_status","linear_update_customer_tier","linear_update_issue","linear_update_label","linear_update_notification","linear_update_project","linear_update_project_label","linear_update_project_milestone","linear_update_project_status","linear_update_workflow_state","linkedin_get_profile","linkedin_share_post","linkup_search","linq_add_participant","linq_check_imessage","linq_check_rcs","linq_create_attachment","linq_create_chat","linq_create_contact_card","linq_create_webhook_subscription","linq_delete_attachment","linq_delete_message","linq_delete_webhook_subscription","linq_edit_message","linq_get_attachment","linq_get_chat","linq_get_contact_card","linq_get_message","linq_get_webhook_subscription","linq_leave_chat","linq_list_chats","linq_list_messages","linq_list_phone_numbers","linq_list_thread","linq_list_webhook_events","linq_list_webhook_subscriptions","linq_mark_chat_read","linq_react_to_message","linq_remove_participant","linq_send_message","linq_send_voice_memo","linq_share_contact_card","linq_start_typing","linq_stop_typing","linq_update_chat","linq_update_contact_card","linq_update_webhook_subscription","llm_chat","logfire_get_token_info","logfire_get_trace","logfire_query","logfire_search_records","logrocket_create_release","logrocket_get_audit_logs","logrocket_get_highlights","logrocket_identify_user","logrocket_list_exported_sessions","logrocket_request_highlights","logs_get","logs_get_execution","logs_get_run_details","logs_query","logs_query_runs","loops_check_contact_suppression","loops_create_contact","loops_create_contact_property","loops_delete_contact","loops_find_contact","loops_get_transactional_email","loops_list_contact_properties","loops_list_mailing_lists","loops_list_transactional_emails","loops_remove_contact_suppression","loops_send_event","loops_send_transactional_email","loops_update_contact","luma_add_guests","luma_cancel_event","luma_create_event","luma_get_event","luma_get_guest","luma_get_guests","luma_list_events","luma_lookup_event","luma_send_invites","luma_update_event","luma_update_guest_status","mailchimp_add_member","mailchimp_add_member_tags","mailchimp_add_or_update_member","mailchimp_add_segment_member","mailchimp_add_subscriber_to_automation","mailchimp_archive_member","mailchimp_create_audience","mailchimp_create_batch_operation","mailchimp_create_campaign","mailchimp_create_interest","mailchimp_create_interest_category","mailchimp_create_landing_page","mailchimp_create_merge_field","mailchimp_create_segment","mailchimp_create_template","mailchimp_delete_audience","mailchimp_delete_batch_operation","mailchimp_delete_campaign","mailchimp_delete_interest","mailchimp_delete_interest_category","mailchimp_delete_landing_page","mailchimp_delete_member","mailchimp_delete_merge_field","mailchimp_delete_segment","mailchimp_delete_template","mailchimp_get_audience","mailchimp_get_audiences","mailchimp_get_automation","mailchimp_get_automations","mailchimp_get_batch_operation","mailchimp_get_batch_operations","mailchimp_get_campaign","mailchimp_get_campaign_content","mailchimp_get_campaign_report","mailchimp_get_campaign_reports","mailchimp_get_campaigns","mailchimp_get_interest","mailchimp_get_interest_categories","mailchimp_get_interest_category","mailchimp_get_interests","mailchimp_get_landing_page","mailchimp_get_landing_pages","mailchimp_get_member","mailchimp_get_member_tags","mailchimp_get_members","mailchimp_get_merge_field","mailchimp_get_merge_fields","mailchimp_get_segment","mailchimp_get_segment_members","mailchimp_get_segments","mailchimp_get_template","mailchimp_get_templates","mailchimp_pause_automation","mailchimp_publish_landing_page","mailchimp_remove_member_tags","mailchimp_remove_segment_member","mailchimp_replicate_campaign","mailchimp_schedule_campaign","mailchimp_send_campaign","mailchimp_set_campaign_content","mailchimp_start_automation","mailchimp_unarchive_member","mailchimp_unpublish_landing_page","mailchimp_unschedule_campaign","mailchimp_update_audience","mailchimp_update_campaign","mailchimp_update_interest","mailchimp_update_interest_category","mailchimp_update_landing_page","mailchimp_update_member","mailchimp_update_merge_field","mailchimp_update_segment","mailchimp_update_template","mailgun_add_list_member","mailgun_create_mailing_list","mailgun_get_domain","mailgun_get_mailing_list","mailgun_get_message","mailgun_list_domains","mailgun_list_messages","mailgun_send_message","managed_agent_archive_session","managed_agent_create_session","managed_agent_delete_session","managed_agent_get_session","managed_agent_interrupt_session","managed_agent_list_events","managed_agent_respond_custom_tool","managed_agent_respond_tool_confirmation","managed_agent_run_session","managed_agent_send_message","managed_agent_update_session","mem0_add_memories","mem0_get_memories","mem0_search_memories","memory_add","memory_delete","memory_get","memory_get_all","microsoft_ad_add_group_member","microsoft_ad_create_group","microsoft_ad_create_user","microsoft_ad_delete_group","microsoft_ad_delete_user","microsoft_ad_get_group","microsoft_ad_get_user","microsoft_ad_list_group_members","microsoft_ad_list_groups","microsoft_ad_list_users","microsoft_ad_remove_group_member","microsoft_ad_update_group","microsoft_ad_update_user","microsoft_dataverse_associate","microsoft_dataverse_create_multiple","microsoft_dataverse_create_record","microsoft_dataverse_delete_record","microsoft_dataverse_disassociate","microsoft_dataverse_download_file","microsoft_dataverse_execute_action","microsoft_dataverse_execute_function","microsoft_dataverse_fetchxml_query","microsoft_dataverse_get_entity_metadata","microsoft_dataverse_get_record","microsoft_dataverse_list_records","microsoft_dataverse_search","microsoft_dataverse_update_multiple","microsoft_dataverse_update_record","microsoft_dataverse_upload_file","microsoft_dataverse_upsert_record","microsoft_dataverse_whoami","microsoft_excel_clear_range","microsoft_excel_create_table","microsoft_excel_delete_worksheet","microsoft_excel_format_range","microsoft_excel_read","microsoft_excel_read_v2","microsoft_excel_sort_range","microsoft_excel_table_add","microsoft_excel_worksheet_add","microsoft_excel_write","microsoft_excel_write_v2","microsoft_planner_create_bucket","microsoft_planner_create_plan","microsoft_planner_create_task","microsoft_planner_delete_bucket","microsoft_planner_delete_plan","microsoft_planner_delete_task","microsoft_planner_get_plan_details","microsoft_planner_get_task_details","microsoft_planner_list_buckets","microsoft_planner_list_plans","microsoft_planner_read_bucket","microsoft_planner_read_plan","microsoft_planner_read_task","microsoft_planner_update_bucket","microsoft_planner_update_plan","microsoft_planner_update_plan_details","microsoft_planner_update_task","microsoft_planner_update_task_details","microsoft_teams_delete_channel_message","microsoft_teams_delete_chat_message","microsoft_teams_get_message","microsoft_teams_list_channel_members","microsoft_teams_list_channels","microsoft_teams_list_chat_members","microsoft_teams_list_chats","microsoft_teams_list_team_members","microsoft_teams_list_teams","microsoft_teams_read_channel","microsoft_teams_read_chat","microsoft_teams_reply_to_message","microsoft_teams_set_reaction","microsoft_teams_unset_reaction","microsoft_teams_update_channel_message","microsoft_teams_update_chat_message","microsoft_teams_write_channel","microsoft_teams_write_chat","millionverifier_get_credits","millionverifier_verify_email","mintlify_create_agent_job","mintlify_create_assistant_message","mintlify_detect_ai_prose","mintlify_get_agent_job","mintlify_get_assistant_caller_stats","mintlify_get_assistant_conversations","mintlify_get_feedback","mintlify_get_feedback_by_page","mintlify_get_page_content","mintlify_get_searches","mintlify_get_update_status","mintlify_get_views","mintlify_get_visitors","mintlify_search","mintlify_send_agent_message","mintlify_trigger_automation","mintlify_trigger_preview","mintlify_trigger_update","mistral_parser","mistral_parser_v2","mistral_parser_v3","monday_archive_item","monday_change_column_value","monday_create_board","monday_create_column","monday_create_group","monday_create_item","monday_create_subitem","monday_create_update","monday_delete_item","monday_duplicate_item","monday_get_board","monday_get_groups","monday_get_item","monday_get_items","monday_list_boards","monday_move_item_to_group","monday_search_items","monday_update_item","mongodb_delete","mongodb_execute","mongodb_insert","mongodb_introspect","mongodb_query","mongodb_update","mysql_delete","mysql_execute","mysql_insert","mysql_introspect","mysql_query","mysql_update","neo4j_create","neo4j_delete","neo4j_execute","neo4j_introspect","neo4j_merge","neo4j_query","neo4j_update","netsuite_attach_record","netsuite_batch_create_records","netsuite_batch_delete_records","netsuite_batch_get_records","netsuite_batch_update_records","netsuite_batch_upsert_records","netsuite_create_record","netsuite_delete_record","netsuite_detach_record","netsuite_execute_action","netsuite_execute_dataset","netsuite_execute_suiteql","netsuite_get_async_result","netsuite_get_async_status","netsuite_get_governance_limits","netsuite_get_record","netsuite_get_record_form","netsuite_get_record_metadata","netsuite_get_select_options","netsuite_get_server_time","netsuite_get_subresource","netsuite_list_datasets","netsuite_list_record_types","netsuite_list_records","netsuite_transform_record","netsuite_update_record","netsuite_upsert_record","neverbounce_get_credits","neverbounce_verify_email","new_relic_create_deployment_event","new_relic_get_entity","new_relic_nrql_query","new_relic_search_entities","notion_add_database_row","notion_add_database_row_v2","notion_append_blocks","notion_append_blocks_v2","notion_create_comment","notion_create_comment_v2","notion_create_database","notion_create_database_v2","notion_create_page","notion_create_page_v2","notion_delete_block","notion_delete_block_v2","notion_list_comments","notion_list_comments_v2","notion_list_users","notion_list_users_v2","notion_query_database","notion_query_database_v2","notion_read","notion_read_database","notion_read_database_v2","notion_read_v2","notion_retrieve_block","notion_retrieve_block_children","notion_retrieve_block_children_v2","notion_retrieve_block_v2","notion_retrieve_user","notion_retrieve_user_v2","notion_search","notion_search_v2","notion_update_block","notion_update_block_v2","notion_update_page","notion_update_page_v2","notion_write","notion_write_v2","obsidian_append_active","obsidian_append_note","obsidian_append_periodic_note","obsidian_create_note","obsidian_delete_note","obsidian_execute_command","obsidian_get_active","obsidian_get_note","obsidian_get_periodic_note","obsidian_list_commands","obsidian_list_files","obsidian_open_file","obsidian_patch_active","obsidian_patch_note","obsidian_search","okta_activate_group_rule","okta_activate_user","okta_add_user_to_group","okta_assign_group_to_app","okta_assign_user_role","okta_assign_user_to_app","okta_clear_user_sessions","okta_create_group","okta_create_group_rule","okta_create_user","okta_deactivate_group_rule","okta_deactivate_user","okta_delete_group","okta_delete_group_rule","okta_delete_user","okta_enroll_factor","okta_get_app","okta_get_factor","okta_get_group","okta_get_group_rule","okta_get_logs","okta_get_session","okta_get_user","okta_list_app_groups","okta_list_app_users","okta_list_apps","okta_list_factors","okta_list_group_members","okta_list_group_rules","okta_list_groups","okta_list_user_roles","okta_list_users","okta_remove_group_from_app","okta_remove_user_from_app","okta_remove_user_from_group","okta_remove_user_role","okta_reset_all_factors","okta_reset_factor","okta_reset_password","okta_revoke_session","okta_suspend_user","okta_unsuspend_user","okta_update_group","okta_update_user","onedrive_copy","onedrive_create_folder","onedrive_create_share_link","onedrive_delete","onedrive_download","onedrive_get_drive_info","onedrive_get_item","onedrive_list","onedrive_move","onedrive_search","onedrive_upload","onepassword_create_item","onepassword_delete_item","onepassword_get_item","onepassword_get_item_file","onepassword_get_vault","onepassword_list_items","onepassword_list_vaults","onepassword_replace_item","onepassword_resolve_secret","onepassword_update_item","openai_embeddings","openai_image","outlook_calendar_create_event","outlook_calendar_delete_event","outlook_calendar_get_event","outlook_calendar_list_events","outlook_calendar_respond","outlook_calendar_update_event","outlook_copy","outlook_create_folder","outlook_delete","outlook_draft","outlook_forward","outlook_get_attachment","outlook_list_attachments","outlook_list_folders","outlook_mark_read","outlook_mark_unread","outlook_move","outlook_read","outlook_reply","outlook_reply_all","outlook_search","outlook_send","outlook_update_message","pagerduty_add_note","pagerduty_create_incident","pagerduty_get_incident","pagerduty_get_service","pagerduty_list_escalation_policies","pagerduty_list_incident_alerts","pagerduty_list_incidents","pagerduty_list_oncalls","pagerduty_list_schedules","pagerduty_list_services","pagerduty_list_users","pagerduty_merge_incidents","pagerduty_send_event","pagerduty_snooze_incident","pagerduty_update_incident","parallel_deep_research","parallel_extract","parallel_search","pdl_autocomplete","pdl_bulk_company_enrich","pdl_bulk_person_enrich","pdl_clean_company","pdl_clean_location","pdl_clean_school","pdl_company_enrich","pdl_company_search","pdl_person_enrich","pdl_person_identify","pdl_person_search","perplexity_chat","perplexity_search","persona_approve_inquiry","persona_create_account","persona_create_inquiry","persona_create_report","persona_decline_inquiry","persona_expire_inquiry","persona_generate_inquiry_link","persona_get_account","persona_get_case","persona_get_document","persona_get_inquiry","persona_get_report","persona_get_verification","persona_import_accounts","persona_list_accounts","persona_list_cases","persona_list_inquiries","persona_list_inquiry_templates","persona_list_reports","persona_mark_inquiry_for_review","persona_print_inquiry_pdf","persona_redact_account","persona_redact_inquiry","persona_resume_inquiry","persona_update_account","persona_update_inquiry","pinecone_delete_vectors","pinecone_describe_index","pinecone_describe_index_stats","pinecone_fetch","pinecone_generate_embeddings","pinecone_list_indexes","pinecone_list_vector_ids","pinecone_search_text","pinecone_search_vector","pinecone_update_vector","pinecone_upsert_text","pipedrive_create_activity","pipedrive_create_deal","pipedrive_create_lead","pipedrive_create_project","pipedrive_delete_lead","pipedrive_get_activities","pipedrive_get_all_deals","pipedrive_get_deal","pipedrive_get_files","pipedrive_get_leads","pipedrive_get_mail_messages","pipedrive_get_mail_thread","pipedrive_get_pipeline_deals","pipedrive_get_pipelines","pipedrive_get_projects","pipedrive_update_activity","pipedrive_update_deal","pipedrive_update_lead","polymarket_get_activity","polymarket_get_event","polymarket_get_events","polymarket_get_holders","polymarket_get_last_trade_price","polymarket_get_leaderboard","polymarket_get_market","polymarket_get_markets","polymarket_get_midpoint","polymarket_get_orderbook","polymarket_get_positions","polymarket_get_price","polymarket_get_price_history","polymarket_get_series","polymarket_get_series_by_id","polymarket_get_spread","polymarket_get_tags","polymarket_get_tick_size","polymarket_get_trades","polymarket_search","postgresql_delete","postgresql_execute","postgresql_insert","postgresql_introspect","postgresql_query","postgresql_update","posthog_batch_events","posthog_capture_event","posthog_create_annotation","posthog_create_cohort","posthog_create_dashboard","posthog_create_experiment","posthog_create_feature_flag","posthog_create_insight","posthog_create_survey","posthog_delete_feature_flag","posthog_delete_person","posthog_delete_survey","posthog_evaluate_flags","posthog_get_cohort","posthog_get_dashboard","posthog_get_event_definition","posthog_get_experiment","posthog_get_feature_flag","posthog_get_insight","posthog_get_organization","posthog_get_person","posthog_get_project","posthog_get_property_definition","posthog_get_session_recording","posthog_get_survey","posthog_list_actions","posthog_list_annotations","posthog_list_cohorts","posthog_list_dashboards","posthog_list_event_definitions","posthog_list_experiments","posthog_list_feature_flags","posthog_list_insights","posthog_list_organizations","posthog_list_persons","posthog_list_projects","posthog_list_property_definitions","posthog_list_recording_playlists","posthog_list_session_recordings","posthog_list_surveys","posthog_query","posthog_update_cohort","posthog_update_event_definition","posthog_update_experiment","posthog_update_feature_flag","posthog_update_insight","posthog_update_property_definition","posthog_update_survey","profound_bot_logs","profound_bots_report","profound_category_assets","profound_category_personas","profound_category_prompts","profound_category_tags","profound_category_topics","profound_citation_prompts","profound_citations_report","profound_list_assets","profound_list_categories","profound_list_domains","profound_list_models","profound_list_optimizations","profound_list_personas","profound_list_regions","profound_optimization_analysis","profound_prompt_answers","profound_prompt_volume","profound_query_fanouts","profound_raw_logs","profound_referrals_report","profound_sentiment_report","profound_visibility_report","prospeo_account_information","prospeo_bulk_enrich_company","prospeo_bulk_enrich_person","prospeo_enrich_company","prospeo_enrich_person","prospeo_search_company","prospeo_search_person","prospeo_search_suggestions","pulse_parser","pulse_parser_v2","qdrant_fetch_points","qdrant_search_vector","qdrant_upsert_points","quartr_get_audio","quartr_get_company","quartr_get_event","quartr_get_event_summary","quartr_get_report","quartr_get_slide_deck","quartr_get_transcript","quartr_list_audio","quartr_list_companies","quartr_list_document_types","quartr_list_documents","quartr_list_event_types","quartr_list_events","quartr_list_live_events","quartr_list_reports","quartr_list_slide_decks","quartr_list_transcripts","quiver_image_to_svg","quiver_list_models","quiver_text_to_svg","rabbitmq_create_binding","rabbitmq_create_exchange","rabbitmq_create_policy","rabbitmq_create_queue","rabbitmq_delete_binding","rabbitmq_delete_exchange","rabbitmq_delete_policy","rabbitmq_delete_queue","rabbitmq_get_exchange","rabbitmq_get_messages","rabbitmq_get_overview","rabbitmq_get_queue","rabbitmq_health_check","rabbitmq_list_bindings","rabbitmq_list_channels","rabbitmq_list_connections","rabbitmq_list_consumers","rabbitmq_list_exchange_bindings","rabbitmq_list_exchanges","rabbitmq_list_nodes","rabbitmq_list_policies","rabbitmq_list_queues","rabbitmq_list_vhosts","rabbitmq_publish_message","rabbitmq_purge_queue","railway_create_environment","railway_create_project","railway_create_service","railway_delete_environment","railway_delete_project","railway_delete_service","railway_delete_variable","railway_deploy_service","railway_get_deployment","railway_get_deployment_logs","railway_get_project","railway_list_deployments","railway_list_project_members","railway_list_projects","railway_list_variables","railway_restart_deployment","railway_rollback_deployment","railway_transfer_project","railway_update_project","railway_upsert_variable","rb2b_credit_check","rb2b_email_to_activity","rb2b_hem_to_best_linkedin","rb2b_hem_to_business_profile","rb2b_hem_to_linkedin","rb2b_hem_to_maid","rb2b_ip_to_company","rb2b_ip_to_hem","rb2b_ip_to_maid","rb2b_linkedin_slug_search","rb2b_linkedin_to_best_personal_email","rb2b_linkedin_to_business_profile","rb2b_linkedin_to_hashed_emails","rb2b_linkedin_to_mobile_phone","rb2b_linkedin_to_personal_email","rds_delete","rds_execute","rds_insert","rds_introspect","rds_query","rds_update","reddit_delete","reddit_edit","reddit_get_comments","reddit_get_controversial","reddit_get_info","reddit_get_me","reddit_get_messages","reddit_get_posts","reddit_get_saved","reddit_get_subreddit_info","reddit_get_subreddit_rules","reddit_get_user","reddit_get_user_comments","reddit_get_user_posts","reddit_hide","reddit_hot_posts","reddit_list_my_subreddits","reddit_lock","reddit_mark_all_read","reddit_mark_read","reddit_marknsfw","reddit_mod_approve","reddit_mod_distinguish","reddit_mod_remove","reddit_mod_sticky","reddit_reply","reddit_report","reddit_save","reddit_search","reddit_search_subreddits","reddit_send_message","reddit_submit_post","reddit_subscribe","reddit_unhide","reddit_unlock","reddit_unmarknsfw","reddit_unsave","reddit_vote","redis_command","redis_delete","redis_exists","redis_expire","redis_get","redis_hdel","redis_hget","redis_hgetall","redis_hset","redis_incr","redis_incrby","redis_keys","redis_llen","redis_lpop","redis_lpush","redis_lrange","redis_persist","redis_rpop","redis_rpush","redis_set","redis_setnx","redis_ttl","reducto_parser","reducto_parser_v2","resend_cancel_email","resend_create_audience","resend_create_broadcast","resend_create_contact","resend_delete_audience","resend_delete_contact","resend_get_audience","resend_get_broadcast","resend_get_contact","resend_get_email","resend_list_audiences","resend_list_contacts","resend_list_domains","resend_send","resend_send_broadcast","resend_update_contact","revenuecat_create_purchase","revenuecat_defer_google_subscription","revenuecat_delete_customer","revenuecat_get_customer","revenuecat_grant_entitlement","revenuecat_list_offerings","revenuecat_refund_google_subscription","revenuecat_revoke_entitlement","revenuecat_revoke_google_subscription","revenuecat_update_subscriber_attributes","rippling_bulk_create_custom_object_records","rippling_bulk_delete_custom_object_records","rippling_bulk_update_custom_object_records","rippling_create_business_partner","rippling_create_business_partner_group","rippling_create_custom_app","rippling_create_custom_object","rippling_create_custom_object_field","rippling_create_custom_object_record","rippling_create_custom_page","rippling_create_custom_setting","rippling_create_department","rippling_create_draft_hires","rippling_create_object_category","rippling_create_title","rippling_create_work_location","rippling_delete_business_partner","rippling_delete_business_partner_group","rippling_delete_custom_app","rippling_delete_custom_object","rippling_delete_custom_object_field","rippling_delete_custom_object_record","rippling_delete_custom_page","rippling_delete_custom_setting","rippling_delete_object_category","rippling_delete_title","rippling_delete_work_location","rippling_get_business_partner","rippling_get_business_partner_group","rippling_get_current_user","rippling_get_custom_app","rippling_get_custom_object","rippling_get_custom_object_field","rippling_get_custom_object_record","rippling_get_custom_object_record_by_external_id","rippling_get_custom_page","rippling_get_custom_setting","rippling_get_department","rippling_get_employment_type","rippling_get_job_function","rippling_get_object_category","rippling_get_report_run","rippling_get_supergroup","rippling_get_team","rippling_get_title","rippling_get_user","rippling_get_work_location","rippling_get_worker","rippling_list_business_partner_groups","rippling_list_business_partners","rippling_list_companies","rippling_list_custom_apps","rippling_list_custom_fields","rippling_list_custom_object_fields","rippling_list_custom_object_records","rippling_list_custom_objects","rippling_list_custom_pages","rippling_list_custom_settings","rippling_list_departments","rippling_list_employment_types","rippling_list_entitlements","rippling_list_job_functions","rippling_list_object_categories","rippling_list_supergroup_exclusion_members","rippling_list_supergroup_inclusion_members","rippling_list_supergroup_members","rippling_list_supergroups","rippling_list_teams","rippling_list_titles","rippling_list_users","rippling_list_work_locations","rippling_list_workers","rippling_query_custom_object_records","rippling_trigger_report_run","rippling_update_custom_app","rippling_update_custom_object","rippling_update_custom_object_field","rippling_update_custom_object_record","rippling_update_custom_page","rippling_update_custom_setting","rippling_update_department","rippling_update_object_category","rippling_update_supergroup_exclusion_members","rippling_update_supergroup_inclusion_members","rippling_update_title","rippling_update_work_location","rocketlane_add_field_option","rocketlane_add_project_members","rocketlane_add_task_assignees","rocketlane_add_task_dependencies","rocketlane_add_task_followers","rocketlane_archive_project","rocketlane_assign_placeholders","rocketlane_create_field","rocketlane_create_phase","rocketlane_create_project","rocketlane_create_space","rocketlane_create_space_document","rocketlane_create_task","rocketlane_create_time_entry","rocketlane_create_time_off","rocketlane_delete_field","rocketlane_delete_phase","rocketlane_delete_project","rocketlane_delete_space","rocketlane_delete_space_document","rocketlane_delete_task","rocketlane_delete_time_entry","rocketlane_delete_time_off","rocketlane_get_field","rocketlane_get_invoice","rocketlane_get_invoice_line_items","rocketlane_get_invoice_payments","rocketlane_get_phase","rocketlane_get_project","rocketlane_get_space","rocketlane_get_space_document","rocketlane_get_task","rocketlane_get_time_entry","rocketlane_get_time_off","rocketlane_get_user","rocketlane_import_template","rocketlane_list_fields","rocketlane_list_invoices","rocketlane_list_phases","rocketlane_list_placeholders","rocketlane_list_projects","rocketlane_list_resource_allocations","rocketlane_list_space_documents","rocketlane_list_spaces","rocketlane_list_tasks","rocketlane_list_time_entries","rocketlane_list_time_entry_categories","rocketlane_list_time_offs","rocketlane_list_users","rocketlane_move_task_to_phase","rocketlane_remove_project_members","rocketlane_remove_task_assignees","rocketlane_remove_task_dependencies","rocketlane_remove_task_followers","rocketlane_search_time_entries","rocketlane_unassign_placeholders","rocketlane_update_field","rocketlane_update_field_option","rocketlane_update_phase","rocketlane_update_project","rocketlane_update_space","rocketlane_update_space_document","rocketlane_update_task","rocketlane_update_time_entry","rootly_acknowledge_alert","rootly_add_incident_event","rootly_add_subscribers","rootly_assign_incident_role","rootly_create_action_item","rootly_create_alert","rootly_create_incident","rootly_create_status_page_event","rootly_delete_action_item","rootly_delete_incident","rootly_escalate_alert","rootly_get_alert","rootly_get_incident","rootly_list_action_items","rootly_list_alerts","rootly_list_causes","rootly_list_environments","rootly_list_escalation_policies","rootly_list_functionalities","rootly_list_incident_events","rootly_list_incident_roles","rootly_list_incident_types","rootly_list_incidents","rootly_list_on_calls","rootly_list_playbooks","rootly_list_retrospectives","rootly_list_schedules","rootly_list_services","rootly_list_severities","rootly_list_teams","rootly_list_users","rootly_mitigate_incident","rootly_remove_subscribers","rootly_resolve_alert","rootly_resolve_incident","rootly_run_workflow","rootly_snooze_alert","rootly_unassign_incident_role","rootly_update_action_item","rootly_update_alert","rootly_update_incident","s3_copy_object","s3_create_bucket","s3_delete_bucket","s3_delete_object","s3_delete_objects","s3_get_object","s3_head_object","s3_list_buckets","s3_list_objects","s3_presigned_url","s3_put_object","salesforce_create_account","salesforce_create_case","salesforce_create_contact","salesforce_create_custom_field","salesforce_create_custom_object","salesforce_create_lead","salesforce_create_opportunity","salesforce_create_task","salesforce_delete_account","salesforce_delete_case","salesforce_delete_contact","salesforce_delete_custom_field","salesforce_delete_lead","salesforce_delete_opportunity","salesforce_delete_task","salesforce_describe_object","salesforce_get_accounts","salesforce_get_cases","salesforce_get_contacts","salesforce_get_dashboard","salesforce_get_leads","salesforce_get_opportunities","salesforce_get_report","salesforce_get_tasks","salesforce_list_dashboards","salesforce_list_objects","salesforce_list_report_types","salesforce_list_reports","salesforce_query","salesforce_query_more","salesforce_refresh_dashboard","salesforce_run_report","salesforce_tooling_query","salesforce_update_account","salesforce_update_case","salesforce_update_contact","salesforce_update_custom_field","salesforce_update_lead","salesforce_update_opportunity","salesforce_update_task","sap_concur_approve_expense_report","sap_concur_associate_attendees","sap_concur_create_cash_advance","sap_concur_create_expected_expense","sap_concur_create_expense_report","sap_concur_create_list_item","sap_concur_create_purchase_request","sap_concur_create_quick_expense","sap_concur_create_quick_expense_with_image","sap_concur_create_report_comment","sap_concur_create_travel_request","sap_concur_create_user","sap_concur_delete_expected_expense","sap_concur_delete_expense","sap_concur_delete_expense_report","sap_concur_delete_list_item","sap_concur_delete_travel_request","sap_concur_delete_user","sap_concur_get_allocation","sap_concur_get_budget","sap_concur_get_cash_advance","sap_concur_get_expected_expense","sap_concur_get_expense","sap_concur_get_expense_report","sap_concur_get_itemizations","sap_concur_get_itinerary","sap_concur_get_list","sap_concur_get_list_item","sap_concur_get_purchase_request","sap_concur_get_receipt","sap_concur_get_receipt_status","sap_concur_get_request_cash_advance","sap_concur_get_travel_profile","sap_concur_get_travel_request","sap_concur_get_user","sap_concur_issue_cash_advance","sap_concur_list_allocations","sap_concur_list_attendee_associations","sap_concur_list_budget_categories","sap_concur_list_budgets","sap_concur_list_exceptions","sap_concur_list_expected_expenses","sap_concur_list_expense_reports","sap_concur_list_expenses","sap_concur_list_itineraries","sap_concur_list_list_items","sap_concur_list_lists","sap_concur_list_receipts","sap_concur_list_report_comments","sap_concur_list_reports_to_approve","sap_concur_list_travel_profiles_summary","sap_concur_list_travel_request_comments","sap_concur_list_travel_requests","sap_concur_list_users","sap_concur_move_travel_request","sap_concur_recall_expense_report","sap_concur_remove_all_attendees","sap_concur_search_locations","sap_concur_search_users","sap_concur_send_back_expense_report","sap_concur_submit_expense_report","sap_concur_update_allocation","sap_concur_update_expected_expense","sap_concur_update_expense","sap_concur_update_expense_report","sap_concur_update_list_item","sap_concur_update_travel_request","sap_concur_update_user","sap_concur_upload_exchange_rates","sap_concur_upload_receipt_image","sap_s4hana_create_business_partner","sap_s4hana_create_purchase_order","sap_s4hana_create_purchase_requisition","sap_s4hana_create_sales_order","sap_s4hana_delete_sales_order","sap_s4hana_get_billing_document","sap_s4hana_get_business_partner","sap_s4hana_get_customer","sap_s4hana_get_inbound_delivery","sap_s4hana_get_material_document","sap_s4hana_get_outbound_delivery","sap_s4hana_get_product","sap_s4hana_get_purchase_order","sap_s4hana_get_purchase_requisition","sap_s4hana_get_sales_order","sap_s4hana_get_supplier","sap_s4hana_get_supplier_invoice","sap_s4hana_list_billing_documents","sap_s4hana_list_business_partners","sap_s4hana_list_customers","sap_s4hana_list_inbound_deliveries","sap_s4hana_list_material_documents","sap_s4hana_list_material_stock","sap_s4hana_list_outbound_deliveries","sap_s4hana_list_products","sap_s4hana_list_purchase_orders","sap_s4hana_list_purchase_requisitions","sap_s4hana_list_sales_orders","sap_s4hana_list_supplier_invoices","sap_s4hana_list_suppliers","sap_s4hana_odata_query","sap_s4hana_update_business_partner","sap_s4hana_update_customer","sap_s4hana_update_product","sap_s4hana_update_purchase_order","sap_s4hana_update_purchase_requisition","sap_s4hana_update_sales_order","sap_s4hana_update_supplier","search_tool","secrets_manager_create_secret","secrets_manager_delete_secret","secrets_manager_describe_secret","secrets_manager_get_secret","secrets_manager_list_secrets","secrets_manager_restore_secret","secrets_manager_rotate_secret","secrets_manager_tag_resource","secrets_manager_untag_resource","secrets_manager_update_secret","sendblue_evaluate_service","sendblue_get_message","sendblue_send_group_message","sendblue_send_message","sendblue_send_typing_indicator","sendgrid_add_contact","sendgrid_add_contacts_to_list","sendgrid_create_list","sendgrid_create_template","sendgrid_create_template_version","sendgrid_delete_contacts","sendgrid_delete_list","sendgrid_delete_template","sendgrid_get_contact","sendgrid_get_list","sendgrid_get_template","sendgrid_list_all_lists","sendgrid_list_templates","sendgrid_remove_contacts_from_list","sendgrid_search_contacts","sendgrid_send_mail","sentry_events_get","sentry_events_list","sentry_issues_get","sentry_issues_list","sentry_issues_update","sentry_projects_create","sentry_projects_get","sentry_projects_list","sentry_projects_update","sentry_releases_create","sentry_releases_deploy","sentry_releases_list","sentry_teams_list","serper_search","servicenow_add_incident_comment","servicenow_aggregate","servicenow_close_incident","servicenow_create_change_request","servicenow_create_incident","servicenow_create_record","servicenow_delete_record","servicenow_download_attachment","servicenow_find_user","servicenow_get_change_next_states","servicenow_get_change_request","servicenow_get_ci","servicenow_get_incident","servicenow_get_knowledge_article","servicenow_get_requested_item","servicenow_list_approvals","servicenow_list_attachments","servicenow_list_catalog_items","servicenow_list_change_requests","servicenow_list_change_tasks","servicenow_list_ci_relationships","servicenow_list_group_members","servicenow_list_incidents","servicenow_list_requested_items","servicenow_order_catalog_item","servicenow_read_record","servicenow_resolve_incident","servicenow_search_cis","servicenow_search_knowledge","servicenow_update_approval","servicenow_update_change_request","servicenow_update_change_state","servicenow_update_incident","servicenow_update_record","servicenow_upload_attachment","ses_create_configuration_set","ses_create_email_identity","ses_create_template","ses_delete_email_identity","ses_delete_suppressed_destination","ses_delete_template","ses_get_account","ses_get_email_identity","ses_get_suppressed_destination","ses_get_template","ses_list_identities","ses_list_suppressed_destinations","ses_list_templates","ses_put_suppressed_destination","ses_send_bulk_email","ses_send_custom_verification_email","ses_send_email","ses_send_templated_email","ses_update_template","sftp_delete","sftp_download","sftp_list","sftp_mkdir","sftp_upload","sharepoint_add_list_items","sharepoint_create_list","sharepoint_create_page","sharepoint_delete_file","sharepoint_delete_list_item","sharepoint_delete_page","sharepoint_download_file","sharepoint_get_drive_item","sharepoint_get_list","sharepoint_get_list_item","sharepoint_list_sites","sharepoint_publish_page","sharepoint_read_page","sharepoint_update_list","sharepoint_update_page","sharepoint_upload_file","shopify_adjust_inventory","shopify_cancel_order","shopify_create_customer","shopify_create_fulfillment","shopify_create_product","shopify_delete_customer","shopify_delete_product","shopify_get_collection","shopify_get_customer","shopify_get_inventory_level","shopify_get_order","shopify_get_product","shopify_list_collections","shopify_list_customers","shopify_list_inventory_items","shopify_list_locations","shopify_list_orders","shopify_list_products","shopify_update_customer","shopify_update_order","shopify_update_product","similarweb_bounce_rate","similarweb_page_views","similarweb_pages_per_visit","similarweb_traffic_visits","similarweb_visit_duration","similarweb_website_overview","sixtyfour_enrich_company","sixtyfour_enrich_lead","sixtyfour_find_email","sixtyfour_find_phone","slack_add_reaction","slack_archive_conversation","slack_canvas","slack_create_channel_canvas","slack_create_conversation","slack_delete_canvas","slack_delete_message","slack_delete_scheduled_message","slack_download","slack_edit_canvas","slack_ephemeral_message","slack_get_canvas","slack_get_channel_history","slack_get_channel_info","slack_get_message","slack_get_permalink","slack_get_thread","slack_get_thread_replies","slack_get_user","slack_get_user_presence","slack_invite_to_conversation","slack_list_canvases","slack_list_channels","slack_list_members","slack_list_scheduled_messages","slack_list_users","slack_lookup_canvas_sections","slack_message","slack_message_reader","slack_open_view","slack_publish_view","slack_push_view","slack_remove_reaction","slack_rename_conversation","slack_schedule_message","slack_set_conversation_purpose","slack_set_conversation_topic","slack_set_status","slack_set_suggested_prompts","slack_set_title","slack_update_message","slack_update_view","smartlead_add_email_accounts_to_campaign","smartlead_add_leads_to_campaign","smartlead_create_campaign","smartlead_create_lead_list","smartlead_delete_campaign","smartlead_delete_campaign_webhook","smartlead_delete_lead_from_campaign","smartlead_delete_lead_list","smartlead_duplicate_campaign","smartlead_export_campaign_leads","smartlead_get_campaign","smartlead_get_campaign_analytics","smartlead_get_campaign_analytics_by_date","smartlead_get_campaign_lead_statistics","smartlead_get_campaign_mailbox_statistics","smartlead_get_campaign_sequences","smartlead_get_campaign_statistics","smartlead_get_campaign_top_level_analytics_by_date","smartlead_get_campaign_webhook_summary","smartlead_get_lead_by_email","smartlead_get_lead_by_id","smartlead_get_lead_list","smartlead_get_lead_message_history","smartlead_list_campaign_email_accounts","smartlead_list_campaign_leads","smartlead_list_campaign_webhooks","smartlead_list_campaigns","smartlead_list_clients","smartlead_list_email_accounts","smartlead_list_inbox_replies","smartlead_list_lead_activities","smartlead_list_lead_categories","smartlead_list_lead_lists","smartlead_mark_lead_complete","smartlead_pause_lead","smartlead_remove_email_accounts_from_campaign","smartlead_resume_lead","smartlead_save_campaign_sequences","smartlead_unsubscribe_lead_from_campaign","smartlead_unsubscribe_lead_globally","smartlead_update_campaign_schedule","smartlead_update_campaign_settings","smartlead_update_campaign_status","smartlead_update_lead","smartlead_update_lead_category","smartlead_update_lead_list","smartlead_upsert_campaign_webhook","sms_send","smtp_send_mail","snowflake_alter_warehouse","snowflake_call_procedure","snowflake_cancel_statement","snowflake_cancel_task_run","snowflake_delete_rows","snowflake_execute_sql","snowflake_get_statement","snowflake_get_task","snowflake_get_task_run","snowflake_get_task_run_output","snowflake_get_warehouse","snowflake_insert_rows","snowflake_introspect_schema","snowflake_list_copy_history","snowflake_list_databases","snowflake_list_query_history","snowflake_list_schemas","snowflake_list_tables","snowflake_list_task_runs","snowflake_list_tasks","snowflake_list_warehouses","snowflake_load_data","snowflake_resume_task","snowflake_resume_warehouse","snowflake_run_task","snowflake_suspend_task","snowflake_suspend_warehouse","snowflake_unload_data","snowflake_update_rows","snowflake_upsert_rows","splunk_cancel_search_job","splunk_create_search_job","splunk_dispatch_saved_search","splunk_get_fired_alerts","splunk_get_saved_search","splunk_get_search_job","splunk_get_search_results","splunk_list_apps","splunk_list_fired_alerts","splunk_list_indexes","splunk_list_saved_searches","splunk_run_search","sportmonks_core_get_cities","sportmonks_core_get_city","sportmonks_core_get_continent","sportmonks_core_get_continents","sportmonks_core_get_countries","sportmonks_core_get_country","sportmonks_core_get_entity_filters","sportmonks_core_get_my_usage","sportmonks_core_get_region","sportmonks_core_get_regions","sportmonks_core_get_timezones","sportmonks_core_get_type","sportmonks_core_get_type_by_entity","sportmonks_core_get_types","sportmonks_core_search_cities","sportmonks_core_search_countries","sportmonks_core_search_regions","sportmonks_football_expected_by_player","sportmonks_football_expected_by_team","sportmonks_football_get_all_commentaries","sportmonks_football_get_all_fixtures","sportmonks_football_get_all_players","sportmonks_football_get_all_rivals","sportmonks_football_get_all_teams","sportmonks_football_get_all_transfer_rumours","sportmonks_football_get_all_transfers","sportmonks_football_get_brackets_by_season","sportmonks_football_get_coach","sportmonks_football_get_coaches","sportmonks_football_get_coaches_by_country","sportmonks_football_get_commentaries_by_fixture","sportmonks_football_get_current_leagues_by_team","sportmonks_football_get_expected_lineups_by_player","sportmonks_football_get_expected_lineups_by_team","sportmonks_football_get_extended_team_squad","sportmonks_football_get_fixture","sportmonks_football_get_fixtures_by_date","sportmonks_football_get_fixtures_by_date_range","sportmonks_football_get_fixtures_by_date_range_for_team","sportmonks_football_get_fixtures_by_ids","sportmonks_football_get_grouped_standings_by_round","sportmonks_football_get_head_to_head","sportmonks_football_get_inplay_livescores","sportmonks_football_get_latest_coaches","sportmonks_football_get_latest_fixtures","sportmonks_football_get_latest_livescores","sportmonks_football_get_latest_players","sportmonks_football_get_latest_totw","sportmonks_football_get_latest_transfers","sportmonks_football_get_league","sportmonks_football_get_leagues","sportmonks_football_get_leagues_by_country","sportmonks_football_get_leagues_by_date","sportmonks_football_get_leagues_by_team","sportmonks_football_get_live_leagues","sportmonks_football_get_live_probabilities","sportmonks_football_get_live_probabilities_by_fixture","sportmonks_football_get_live_standings_by_league","sportmonks_football_get_livescores","sportmonks_football_get_match_facts","sportmonks_football_get_match_facts_by_date_range","sportmonks_football_get_match_facts_by_fixture","sportmonks_football_get_match_facts_by_league","sportmonks_football_get_past_fixtures_by_tv_station","sportmonks_football_get_player","sportmonks_football_get_players_by_country","sportmonks_football_get_postmatch_news","sportmonks_football_get_postmatch_news_by_season","sportmonks_football_get_predictability_by_league","sportmonks_football_get_prematch_news","sportmonks_football_get_prematch_news_by_season","sportmonks_football_get_prematch_news_upcoming","sportmonks_football_get_probabilities","sportmonks_football_get_probabilities_by_fixture","sportmonks_football_get_referee","sportmonks_football_get_referees","sportmonks_football_get_referees_by_country","sportmonks_football_get_referees_by_season","sportmonks_football_get_rivals_by_team","sportmonks_football_get_round","sportmonks_football_get_round_statistics","sportmonks_football_get_rounds","sportmonks_football_get_rounds_by_season","sportmonks_football_get_schedules_by_season","sportmonks_football_get_schedules_by_season_and_team","sportmonks_football_get_schedules_by_team","sportmonks_football_get_season","sportmonks_football_get_seasons","sportmonks_football_get_seasons_by_team","sportmonks_football_get_stage","sportmonks_football_get_stage_statistics","sportmonks_football_get_stages","sportmonks_football_get_stages_by_season","sportmonks_football_get_standing_corrections_by_season","sportmonks_football_get_standings","sportmonks_football_get_standings_by_round","sportmonks_football_get_standings_by_season","sportmonks_football_get_state","sportmonks_football_get_states","sportmonks_football_get_team","sportmonks_football_get_team_rankings","sportmonks_football_get_team_rankings_by_date","sportmonks_football_get_team_rankings_by_team","sportmonks_football_get_team_squad","sportmonks_football_get_team_squad_by_season","sportmonks_football_get_teams_by_country","sportmonks_football_get_teams_by_season","sportmonks_football_get_topscorers_by_season","sportmonks_football_get_topscorers_by_stage","sportmonks_football_get_totw","sportmonks_football_get_totw_by_round","sportmonks_football_get_transfer","sportmonks_football_get_transfer_rumour","sportmonks_football_get_transfer_rumours_between_dates","sportmonks_football_get_transfer_rumours_by_player","sportmonks_football_get_transfer_rumours_by_team","sportmonks_football_get_transfers_between_dates","sportmonks_football_get_transfers_by_player","sportmonks_football_get_transfers_by_team","sportmonks_football_get_tv_station","sportmonks_football_get_tv_stations","sportmonks_football_get_tv_stations_by_fixture","sportmonks_football_get_upcoming_fixtures_by_market","sportmonks_football_get_upcoming_fixtures_by_tv_station","sportmonks_football_get_value_bets","sportmonks_football_get_value_bets_by_fixture","sportmonks_football_get_venue","sportmonks_football_get_venues","sportmonks_football_get_venues_by_season","sportmonks_football_search_coaches","sportmonks_football_search_fixtures","sportmonks_football_search_leagues","sportmonks_football_search_players","sportmonks_football_search_referees","sportmonks_football_search_rounds","sportmonks_football_search_seasons","sportmonks_football_search_stages","sportmonks_football_search_teams","sportmonks_football_search_venues","sportmonks_motorsport_get_all_fixtures","sportmonks_motorsport_get_current_leagues_by_team","sportmonks_motorsport_get_driver","sportmonks_motorsport_get_driver_standings","sportmonks_motorsport_get_driver_standings_by_season","sportmonks_motorsport_get_drivers","sportmonks_motorsport_get_drivers_by_country","sportmonks_motorsport_get_drivers_by_season","sportmonks_motorsport_get_fixture","sportmonks_motorsport_get_fixtures_by_date","sportmonks_motorsport_get_fixtures_by_date_range","sportmonks_motorsport_get_fixtures_by_ids","sportmonks_motorsport_get_laps_by_fixture","sportmonks_motorsport_get_laps_by_fixture_and_driver","sportmonks_motorsport_get_laps_by_fixture_and_lap","sportmonks_motorsport_get_latest_laps_by_fixture","sportmonks_motorsport_get_latest_pitstops_by_fixture","sportmonks_motorsport_get_latest_stints_by_fixture","sportmonks_motorsport_get_latest_updated_drivers","sportmonks_motorsport_get_latest_updated_fixtures","sportmonks_motorsport_get_league","sportmonks_motorsport_get_leagues","sportmonks_motorsport_get_leagues_by_country","sportmonks_motorsport_get_leagues_by_date","sportmonks_motorsport_get_leagues_by_live","sportmonks_motorsport_get_leagues_by_team","sportmonks_motorsport_get_livescores","sportmonks_motorsport_get_pitstops_by_fixture","sportmonks_motorsport_get_pitstops_by_fixture_and_driver","sportmonks_motorsport_get_pitstops_by_fixture_and_lap","sportmonks_motorsport_get_race_results_by_season_and_driver","sportmonks_motorsport_get_race_results_by_season_and_team","sportmonks_motorsport_get_schedules_by_season","sportmonks_motorsport_get_season","sportmonks_motorsport_get_seasons","sportmonks_motorsport_get_stage","sportmonks_motorsport_get_stages","sportmonks_motorsport_get_stages_by_season","sportmonks_motorsport_get_state","sportmonks_motorsport_get_states","sportmonks_motorsport_get_stints_by_fixture","sportmonks_motorsport_get_stints_by_fixture_and_driver","sportmonks_motorsport_get_stints_by_fixture_and_stint","sportmonks_motorsport_get_team","sportmonks_motorsport_get_team_standings","sportmonks_motorsport_get_team_standings_by_season","sportmonks_motorsport_get_teams","sportmonks_motorsport_get_teams_by_country","sportmonks_motorsport_get_teams_by_season","sportmonks_motorsport_get_venue","sportmonks_motorsport_get_venues","sportmonks_motorsport_get_venues_by_season","sportmonks_motorsport_search_drivers","sportmonks_motorsport_search_leagues","sportmonks_motorsport_search_stages","sportmonks_motorsport_search_teams","sportmonks_motorsport_search_venues","sportmonks_odds_get_all_historical_odds","sportmonks_odds_get_all_inplay_odds","sportmonks_odds_get_all_pre_match_odds","sportmonks_odds_get_all_premium_odds","sportmonks_odds_get_bookmaker","sportmonks_odds_get_bookmaker_event_ids_by_fixture","sportmonks_odds_get_bookmakers","sportmonks_odds_get_bookmakers_by_fixture","sportmonks_odds_get_inplay_odds_by_fixture","sportmonks_odds_get_inplay_odds_by_fixture_and_bookmaker","sportmonks_odds_get_inplay_odds_by_fixture_and_market","sportmonks_odds_get_last_updated_inplay_odds","sportmonks_odds_get_last_updated_pre_match_odds","sportmonks_odds_get_market","sportmonks_odds_get_markets","sportmonks_odds_get_pre_match_odds_by_fixture","sportmonks_odds_get_pre_match_odds_by_fixture_and_bookmaker","sportmonks_odds_get_pre_match_odds_by_fixture_and_market","sportmonks_odds_get_premium_odds_by_fixture","sportmonks_odds_get_premium_odds_by_fixture_and_bookmaker","sportmonks_odds_get_premium_odds_by_fixture_and_market","sportmonks_odds_get_updated_historical_odds_between","sportmonks_odds_get_updated_premium_odds_between","sportmonks_odds_search_bookmakers","sportmonks_odds_search_markets","spotify_add_playlist_cover","spotify_add_to_queue","spotify_add_tracks_to_playlist","spotify_check_following","spotify_check_playlist_followers","spotify_check_saved_albums","spotify_check_saved_audiobooks","spotify_check_saved_episodes","spotify_check_saved_shows","spotify_check_saved_tracks","spotify_create_playlist","spotify_follow_artists","spotify_follow_playlist","spotify_get_album","spotify_get_album_tracks","spotify_get_albums","spotify_get_artist","spotify_get_artist_albums","spotify_get_artist_top_tracks","spotify_get_artists","spotify_get_audiobook","spotify_get_audiobook_chapters","spotify_get_audiobooks","spotify_get_categories","spotify_get_current_user","spotify_get_currently_playing","spotify_get_devices","spotify_get_episode","spotify_get_episodes","spotify_get_followed_artists","spotify_get_markets","spotify_get_new_releases","spotify_get_playback_state","spotify_get_playlist","spotify_get_playlist_cover","spotify_get_playlist_tracks","spotify_get_queue","spotify_get_recently_played","spotify_get_saved_albums","spotify_get_saved_audiobooks","spotify_get_saved_episodes","spotify_get_saved_shows","spotify_get_saved_tracks","spotify_get_show","spotify_get_show_episodes","spotify_get_shows","spotify_get_top_artists","spotify_get_top_tracks","spotify_get_track","spotify_get_tracks","spotify_get_user_playlists","spotify_get_user_profile","spotify_pause","spotify_play","spotify_remove_saved_albums","spotify_remove_saved_audiobooks","spotify_remove_saved_episodes","spotify_remove_saved_shows","spotify_remove_saved_tracks","spotify_remove_tracks_from_playlist","spotify_reorder_playlist_items","spotify_replace_playlist_items","spotify_save_albums","spotify_save_audiobooks","spotify_save_episodes","spotify_save_shows","spotify_save_tracks","spotify_search","spotify_seek","spotify_set_repeat","spotify_set_shuffle","spotify_set_volume","spotify_skip_next","spotify_skip_previous","spotify_transfer_playback","spotify_unfollow_artists","spotify_unfollow_playlist","spotify_update_playlist","sqs_send","square_batch_retrieve_inventory_counts","square_cancel_invoice","square_cancel_payment","square_complete_payment","square_create_catalog_image","square_create_customer","square_create_invoice","square_create_order","square_create_payment","square_delete_catalog_object","square_delete_customer","square_delete_invoice","square_get_catalog_object","square_get_customer","square_get_invoice","square_get_location","square_get_order","square_get_payment","square_get_refund","square_list_catalog","square_list_customers","square_list_invoices","square_list_locations","square_list_payments","square_list_refunds","square_pay_order","square_publish_invoice","square_refund_payment","square_search_catalog_objects","square_search_customers","square_search_invoices","square_search_orders","square_update_customer","square_upsert_catalog_object","ssh_check_command_exists","ssh_check_file_exists","ssh_create_directory","ssh_delete_file","ssh_download_file","ssh_execute_command","ssh_execute_script","ssh_get_system_info","ssh_list_directory","ssh_move_rename","ssh_read_file_content","ssh_upload_file","ssh_write_file_content","stagehand_agent","stagehand_extract","stripe_cancel_payment_intent","stripe_cancel_subscription","stripe_capture_charge","stripe_capture_payment_intent","stripe_confirm_payment_intent","stripe_create_charge","stripe_create_customer","stripe_create_invoice","stripe_create_payment_intent","stripe_create_price","stripe_create_product","stripe_create_subscription","stripe_delete_customer","stripe_delete_invoice","stripe_delete_product","stripe_finalize_invoice","stripe_list_charges","stripe_list_customers","stripe_list_events","stripe_list_invoices","stripe_list_payment_intents","stripe_list_prices","stripe_list_products","stripe_list_subscriptions","stripe_pay_invoice","stripe_resume_subscription","stripe_retrieve_charge","stripe_retrieve_customer","stripe_retrieve_event","stripe_retrieve_invoice","stripe_retrieve_payment_intent","stripe_retrieve_price","stripe_retrieve_product","stripe_retrieve_subscription","stripe_search_charges","stripe_search_customers","stripe_search_invoices","stripe_search_payment_intents","stripe_search_prices","stripe_search_products","stripe_search_subscriptions","stripe_send_invoice","stripe_update_charge","stripe_update_customer","stripe_update_invoice","stripe_update_payment_intent","stripe_update_price","stripe_update_product","stripe_update_subscription","stripe_void_invoice","sts_assume_role","sts_assume_role_with_saml","sts_assume_role_with_web_identity","sts_get_access_key_info","sts_get_caller_identity","sts_get_session_token","stt_assemblyai","stt_assemblyai_v2","stt_deepgram","stt_deepgram_v2","stt_elevenlabs","stt_elevenlabs_v2","stt_gemini","stt_gemini_v2","stt_whisper","stt_whisper_v2","supabase_count","supabase_delete","supabase_get_row","supabase_insert","supabase_introspect","supabase_invoke_function","supabase_query","supabase_rpc","supabase_storage_copy","supabase_storage_create_bucket","supabase_storage_create_signed_upload_url","supabase_storage_create_signed_url","supabase_storage_delete","supabase_storage_delete_bucket","supabase_storage_download","supabase_storage_empty_bucket","supabase_storage_get_public_url","supabase_storage_list","supabase_storage_list_buckets","supabase_storage_move","supabase_storage_update_bucket","supabase_storage_upload","supabase_text_search","supabase_update","supabase_upsert","supabase_vector_search","table_batch_insert_rows","table_create","table_delete_row","table_delete_rows_by_filter","table_get_row","table_get_schema","table_insert_row","table_list","table_query_rows","table_query_rows_v2","table_update_row","table_update_rows_by_filter","table_upsert_row","tailscale_authorize_device","tailscale_create_auth_key","tailscale_delete_auth_key","tailscale_delete_device","tailscale_delete_user","tailscale_expire_device_key","tailscale_get_acl","tailscale_get_auth_key","tailscale_get_device","tailscale_get_device_routes","tailscale_get_dns_preferences","tailscale_get_dns_searchpaths","tailscale_list_auth_keys","tailscale_list_devices","tailscale_list_dns_nameservers","tailscale_list_users","tailscale_set_acl","tailscale_set_device_routes","tailscale_set_device_tags","tailscale_set_dns_nameservers","tailscale_set_dns_preferences","tailscale_set_dns_searchpaths","tailscale_suspend_user","tailscale_update_device_key","tavily_crawl","tavily_extract","tavily_map","tavily_search","telegram_copy_message","telegram_delete_message","telegram_edit_message_text","telegram_forward_message","telegram_get_chat","telegram_get_chat_member","telegram_message","telegram_pin_message","telegram_send_animation","telegram_send_audio","telegram_send_chat_action","telegram_send_contact","telegram_send_document","telegram_send_location","telegram_send_photo","telegram_send_poll","telegram_send_video","telegram_set_message_reaction","telegram_unpin_message","temporal_cancel_workflow","temporal_count_workflows","temporal_create_schedule","temporal_delete_schedule","temporal_describe_schedule","temporal_describe_task_queue","temporal_describe_workflow","temporal_get_workflow_history","temporal_list_schedules","temporal_list_workflows","temporal_pause_schedule","temporal_query_workflow","temporal_reset_workflow","temporal_signal_with_start","temporal_signal_workflow","temporal_start_workflow","temporal_terminate_workflow","temporal_trigger_schedule","temporal_unpause_schedule","temporal_update_workflow","textract_analyze_expense","textract_analyze_id","textract_parser","textract_parser_v2","thinking_tool","thrive_add_audience_managers","thrive_add_audience_members","thrive_add_user_tags","thrive_create_assignment","thrive_create_audience","thrive_create_completion","thrive_create_user","thrive_delete_assignment","thrive_delete_audience","thrive_delete_user","thrive_get_activity","thrive_get_assignment","thrive_get_audience","thrive_get_completion","thrive_get_content","thrive_get_cpd_category","thrive_get_cpd_entry","thrive_get_cpd_requirement","thrive_get_enrolment","thrive_get_skill_levels","thrive_get_tag","thrive_get_user_by_id","thrive_get_user_by_ref","thrive_list_assignments","thrive_list_audience_managers","thrive_list_audience_members","thrive_list_audiences","thrive_list_completions","thrive_list_enrolments","thrive_list_tags","thrive_query_activities","thrive_query_content","thrive_query_cpd_categories","thrive_query_cpd_entries","thrive_query_cpd_requirements","thrive_query_cpd_user_summaries","thrive_remove_audience_manager","thrive_remove_audience_member","thrive_remove_user_tags","thrive_replace_audience_managers","thrive_replace_audience_members","thrive_search_users","thrive_suspend_user","thrive_update_assignment","thrive_update_audience","thrive_update_user","thrive_update_user_skills","tiktok_get_post_status","tiktok_get_user","tiktok_list_videos","tiktok_query_videos","tiktok_upload_video_draft","tinybird_append_datasource","tinybird_delete_datasource_rows","tinybird_events","tinybird_get_job","tinybird_query","tinybird_query_pipe","tinybird_truncate_datasource","trello_add_checklist","trello_add_checklist_item","trello_add_comment","trello_add_label","trello_add_member","trello_create_board","trello_create_card","trello_create_list","trello_delete_card","trello_get_actions","trello_get_board","trello_get_card","trello_list_cards","trello_list_lists","trello_list_members","trello_remove_label","trello_remove_member","trello_search","trello_update_card","trello_update_checklist_item","trello_update_list","trigger_dev_activate_schedule","trigger_dev_add_run_tags","trigger_dev_batch_trigger_task","trigger_dev_cancel_run","trigger_dev_complete_waitpoint_token","trigger_dev_create_env_var","trigger_dev_create_schedule","trigger_dev_create_waitpoint_token","trigger_dev_deactivate_schedule","trigger_dev_delete_env_var","trigger_dev_delete_schedule","trigger_dev_execute_query","trigger_dev_get_batch","trigger_dev_get_batch_results","trigger_dev_get_deployment","trigger_dev_get_env_var","trigger_dev_get_latest_deployment","trigger_dev_get_query_schema","trigger_dev_get_queue","trigger_dev_get_run","trigger_dev_get_run_events","trigger_dev_get_run_result","trigger_dev_get_run_trace","trigger_dev_get_schedule","trigger_dev_get_waitpoint_token","trigger_dev_import_env_vars","trigger_dev_list_deployments","trigger_dev_list_env_vars","trigger_dev_list_queues","trigger_dev_list_runs","trigger_dev_list_schedules","trigger_dev_list_timezones","trigger_dev_list_waitpoint_tokens","trigger_dev_override_queue_concurrency","trigger_dev_pause_queue","trigger_dev_promote_deployment","trigger_dev_replay_run","trigger_dev_reschedule_run","trigger_dev_reset_queue_concurrency","trigger_dev_resume_queue","trigger_dev_trigger_task","trigger_dev_update_env_var","trigger_dev_update_run_metadata","trigger_dev_update_schedule","tts_azure","tts_cartesia","tts_deepgram","tts_elevenlabs","tts_google","tts_openai","tts_playht","twilio_send_sms","twilio_voice_get_recording","twilio_voice_list_calls","twilio_voice_make_call","typeform_create_form","typeform_delete_form","typeform_files","typeform_get_form","typeform_insights","typeform_list_forms","typeform_responses","typeform_update_form","upstash_redis_command","upstash_redis_delete","upstash_redis_exists","upstash_redis_expire","upstash_redis_get","upstash_redis_hget","upstash_redis_hgetall","upstash_redis_hset","upstash_redis_incr","upstash_redis_incrby","upstash_redis_keys","upstash_redis_lpush","upstash_redis_lrange","upstash_redis_set","upstash_redis_setnx","upstash_redis_ttl","uptimerobot_create_alert_contact","uptimerobot_create_maintenance_window","uptimerobot_create_monitor","uptimerobot_create_psp","uptimerobot_delete_alert_contact","uptimerobot_delete_maintenance_window","uptimerobot_delete_monitor","uptimerobot_delete_psp","uptimerobot_get_account","uptimerobot_get_alert_contact","uptimerobot_get_incident","uptimerobot_get_maintenance_window","uptimerobot_get_monitor","uptimerobot_get_psp","uptimerobot_list_alert_contacts","uptimerobot_list_incidents","uptimerobot_list_maintenance_windows","uptimerobot_list_monitors","uptimerobot_list_psps","uptimerobot_pause_monitor","uptimerobot_start_monitor","uptimerobot_update_maintenance_window","uptimerobot_update_monitor","uptimerobot_update_psp","vanta_download_document_file","vanta_get_control","vanta_get_document","vanta_get_framework","vanta_get_person","vanta_get_policy","vanta_get_risk_scenario","vanta_get_test","vanta_get_vendor","vanta_get_vulnerable_asset","vanta_list_control_documents","vanta_list_control_tests","vanta_list_controls","vanta_list_document_uploads","vanta_list_documents","vanta_list_framework_controls","vanta_list_frameworks","vanta_list_monitored_computers","vanta_list_people","vanta_list_policies","vanta_list_risk_scenarios","vanta_list_test_entities","vanta_list_tests","vanta_list_vendors","vanta_list_vulnerabilities","vanta_list_vulnerability_remediations","vanta_list_vulnerable_assets","vanta_submit_document","vanta_upload_document_file","vercel_add_domain","vercel_add_project_domain","vercel_cancel_deployment","vercel_create_alias","vercel_create_check","vercel_create_deployment","vercel_create_dns_record","vercel_create_edge_config","vercel_create_env_var","vercel_create_project","vercel_create_webhook","vercel_delete_alias","vercel_delete_deployment","vercel_delete_dns_record","vercel_delete_domain","vercel_delete_edge_config","vercel_delete_env_var","vercel_delete_project","vercel_delete_webhook","vercel_get_alias","vercel_get_check","vercel_get_deployment","vercel_get_deployment_events","vercel_get_domain","vercel_get_domain_config","vercel_get_edge_config","vercel_get_edge_config_items","vercel_get_env_vars","vercel_get_project","vercel_get_team","vercel_get_user","vercel_get_webhook","vercel_list_aliases","vercel_list_checks","vercel_list_deployment_files","vercel_list_deployments","vercel_list_dns_records","vercel_list_domains","vercel_list_edge_configs","vercel_list_project_domains","vercel_list_projects","vercel_list_team_members","vercel_list_teams","vercel_list_webhooks","vercel_pause_project","vercel_promote_deployment","vercel_remove_project_domain","vercel_rerequest_check","vercel_unpause_project","vercel_update_check","vercel_update_dns_record","vercel_update_edge_config_items","vercel_update_env_var","vercel_update_project","vercel_update_project_domain","vercel_verify_project_domain","video_falai","video_luma","video_minimax","video_runway","video_veo","vision_tool","vision_tool_v2","wealthbox_read_contact","wealthbox_read_note","wealthbox_read_task","wealthbox_write_contact","wealthbox_write_note","wealthbox_write_task","webflow_create_item","webflow_delete_item","webflow_get_item","webflow_list_items","webflow_update_item","webhook_request","whatsapp_get_media","whatsapp_mark_read","whatsapp_send_interactive","whatsapp_send_media","whatsapp_send_message","whatsapp_send_reaction","whatsapp_send_template","whatsapp_upload_media","wikipedia_content","wikipedia_random","wikipedia_search","wikipedia_summary","windchill_check_in_document","windchill_check_in_documents","windchill_check_out_document","windchill_check_out_documents","windchill_create_document","windchill_create_documents","windchill_delete_document","windchill_delete_documents","windchill_download_attachment","windchill_download_primary_content","windchill_get_document","windchill_get_document_structure","windchill_get_primary_content","windchill_get_valid_state_transitions","windchill_list_attachments","windchill_list_documents","windchill_revise_document","windchill_revise_documents","windchill_set_lifecycle_state","windchill_undo_check_out_document","windchill_undo_check_out_documents","windchill_update_common_properties","windchill_update_document","windchill_update_document_security_labels","windchill_update_documents","windchill_upload_attachments","windchill_upload_primary_content","wiza_company_enrichment","wiza_get_credits","wiza_individual_reveal","wiza_prospect_search","wordpress_create_category","wordpress_create_comment","wordpress_create_page","wordpress_create_post","wordpress_create_tag","wordpress_delete_category","wordpress_delete_comment","wordpress_delete_media","wordpress_delete_page","wordpress_delete_post","wordpress_delete_tag","wordpress_get_category","wordpress_get_current_user","wordpress_get_media","wordpress_get_page","wordpress_get_post","wordpress_get_tag","wordpress_get_user","wordpress_list_categories","wordpress_list_comments","wordpress_list_media","wordpress_list_pages","wordpress_list_posts","wordpress_list_tags","wordpress_list_users","wordpress_search_content","wordpress_update_category","wordpress_update_comment","wordpress_update_page","wordpress_update_post","wordpress_update_tag","wordpress_upload_media","workday_assign_onboarding","workday_change_job","workday_create_prehire","workday_get_compensation","workday_get_organizations","workday_get_worker","workday_hire_employee","workday_list_workers","workday_terminate_worker","workday_update_worker","workflow_executor","x_create_bookmark","x_create_tweet","x_delete_bookmark","x_delete_tweet","x_get_blocking","x_get_bookmarks","x_get_followers","x_get_following","x_get_liked_tweets","x_get_liking_users","x_get_me","x_get_personalized_trends","x_get_quote_tweets","x_get_retweeted_by","x_get_trends_by_woeid","x_get_tweets_by_ids","x_get_usage","x_get_user_mentions","x_get_user_timeline","x_get_user_tweets","x_hide_reply","x_manage_block","x_manage_follow","x_manage_like","x_manage_mute","x_manage_retweet","x_read","x_search","x_search_tweets","x_search_users","x_user","x_write","youtube_channel_info","youtube_channel_playlists","youtube_channel_videos","youtube_comments","youtube_playlist_items","youtube_search","youtube_trending","youtube_video_categories","youtube_video_details","zendesk_autocomplete_organizations","zendesk_create_organization","zendesk_create_organizations_bulk","zendesk_create_ticket","zendesk_create_tickets_bulk","zendesk_create_user","zendesk_create_users_bulk","zendesk_delete_organization","zendesk_delete_ticket","zendesk_delete_user","zendesk_get_current_user","zendesk_get_organization","zendesk_get_organizations","zendesk_get_ticket","zendesk_get_tickets","zendesk_get_user","zendesk_get_users","zendesk_merge_tickets","zendesk_search","zendesk_search_count","zendesk_search_users","zendesk_update_organization","zendesk_update_ticket","zendesk_update_tickets_bulk","zendesk_update_user","zendesk_update_users_bulk","zep_add_messages","zep_add_user","zep_create_thread","zep_delete_thread","zep_get_context","zep_get_messages","zep_get_threads","zep_get_user","zep_get_user_threads","zerobounce_get_credits","zerobounce_verify_email","zoho_desk_add_comment","zoho_desk_get_attachment","zoho_desk_get_contact","zoho_desk_get_thread","zoho_desk_get_ticket","zoho_desk_list_comments","zoho_desk_list_organizations","zoho_desk_list_threads","zoho_desk_list_tickets","zoho_desk_update_ticket","zoom_create_meeting","zoom_delete_meeting","zoom_delete_recording","zoom_get_meeting","zoom_get_meeting_invitation","zoom_get_meeting_recordings","zoom_list_meetings","zoom_list_past_participants","zoom_list_recordings","zoom_update_meeting","zoominfo_enrich_companies","zoominfo_enrich_contacts","zoominfo_search_companies","zoominfo_search_contacts","zoominfo_search_intent","zoominfo_search_news"]' ) export default toolIds diff --git a/apps/sim/tools/generated/tool-metadata.ts b/apps/sim/tools/generated/tool-metadata.ts index 832cd44cc31..0a3af36b822 100644 --- a/apps/sim/tools/generated/tool-metadata.ts +++ b/apps/sim/tools/generated/tool-metadata.ts @@ -3,7 +3,7 @@ /** Serializable metadata for every built-in tool, keyed by tool id. */ const toolMetadata: Record = JSON.parse( - '{"a2a_cancel_task":{"id":"a2a_cancel_task","name":"A2A Cancel Task","description":"Request cancellation of an in-progress A2A task.","version":"1.0.0","params":{"agentUrl":{"type":"string","required":true,"visibility":"user-only","description":"The A2A agent endpoint URL"},"taskId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The task ID to cancel"},"apiKey":{"type":"string","required":false,"visibility":"user-only","description":"API key for authentication (if required)"}}},"a2a_get_agent_card":{"id":"a2a_get_agent_card","name":"A2A Get Agent Card","description":"Fetch the Agent Card (discovery document) for an external A2A agent.","version":"1.0.0","params":{"agentUrl":{"type":"string","required":true,"visibility":"user-only","description":"The A2A agent endpoint URL"},"apiKey":{"type":"string","required":false,"visibility":"user-only","description":"API key for authentication (if required)"}}},"a2a_get_task":{"id":"a2a_get_task","name":"A2A Get Task","description":"Retrieve the current state and result of an A2A task.","version":"1.0.0","params":{"agentUrl":{"type":"string","required":true,"visibility":"user-only","description":"The A2A agent endpoint URL"},"taskId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The task ID to retrieve"},"historyLength":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of history messages to include"},"apiKey":{"type":"string","required":false,"visibility":"user-only","description":"API key for authentication (if required)"}}},"a2a_send_message":{"id":"a2a_send_message","name":"A2A Send Message","description":"Send a message to an external A2A agent and return its response.","version":"1.0.0","params":{"agentUrl":{"type":"string","required":true,"visibility":"user-only","description":"The A2A agent endpoint URL"},"message":{"type":"string","required":true,"visibility":"user-or-llm","description":"The message text to send"},"data":{"type":"json","required":false,"visibility":"user-or-llm","description":"Optional structured JSON data to attach"},"files":{"type":"json","required":false,"visibility":"user-or-llm","description":"Optional files to attach"},"taskId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Existing task ID to continue"},"contextId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Conversation context ID to continue"},"apiKey":{"type":"string","required":false,"visibility":"user-only","description":"API key for authentication (if required)"}}},"agentmail_create_draft":{"id":"agentmail_create_draft","name":"Create Draft","description":"Create a new email draft in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to create the draft in"},"to":{"type":"string","required":false,"visibility":"user-or-llm","description":"Recipient email addresses (comma-separated)"},"subject":{"type":"string","required":false,"visibility":"user-or-llm","description":"Draft subject line"},"text":{"type":"string","required":false,"visibility":"user-or-llm","description":"Plain text draft body"},"html":{"type":"string","required":false,"visibility":"user-or-llm","description":"HTML draft body"},"cc":{"type":"string","required":false,"visibility":"user-or-llm","description":"CC recipient email addresses (comma-separated)"},"bcc":{"type":"string","required":false,"visibility":"user-or-llm","description":"BCC recipient email addresses (comma-separated)"},"inReplyTo":{"type":"string","required":false,"visibility":"user-or-llm","description":"ID of message being replied to"},"sendAt":{"type":"string","required":false,"visibility":"user-or-llm","description":"ISO 8601 timestamp to schedule sending"}}},"agentmail_create_inbox":{"id":"agentmail_create_inbox","name":"Create Inbox","description":"Create a new email inbox with AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"username":{"type":"string","required":false,"visibility":"user-or-llm","description":"Username for the inbox email address"},"domain":{"type":"string","required":false,"visibility":"user-or-llm","description":"Domain for the inbox email address"},"displayName":{"type":"string","required":false,"visibility":"user-or-llm","description":"Display name for the inbox"}}},"agentmail_delete_draft":{"id":"agentmail_delete_draft","name":"Delete Draft","description":"Delete an email draft in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the draft"},"draftId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the draft to delete"}}},"agentmail_delete_inbox":{"id":"agentmail_delete_inbox","name":"Delete Inbox","description":"Delete an email inbox in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to delete"}}},"agentmail_delete_thread":{"id":"agentmail_delete_thread","name":"Delete Thread","description":"Delete an email thread in AgentMail (moves to trash, or permanently deletes if already in trash)","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the thread"},"threadId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the thread to delete"},"permanent":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Force permanent deletion instead of moving to trash"}}},"agentmail_forward_message":{"id":"agentmail_forward_message","name":"Forward Message","description":"Forward an email message to new recipients in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the message"},"messageId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the message to forward"},"to":{"type":"string","required":true,"visibility":"user-or-llm","description":"Recipient email addresses (comma-separated)"},"subject":{"type":"string","required":false,"visibility":"user-or-llm","description":"Override subject line"},"text":{"type":"string","required":false,"visibility":"user-or-llm","description":"Additional plain text to prepend"},"html":{"type":"string","required":false,"visibility":"user-or-llm","description":"Additional HTML to prepend"},"cc":{"type":"string","required":false,"visibility":"user-or-llm","description":"CC recipient email addresses (comma-separated)"},"bcc":{"type":"string","required":false,"visibility":"user-or-llm","description":"BCC recipient email addresses (comma-separated)"}}},"agentmail_get_draft":{"id":"agentmail_get_draft","name":"Get Draft","description":"Get details of a specific email draft in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox the draft belongs to"},"draftId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the draft to retrieve"}}},"agentmail_get_inbox":{"id":"agentmail_get_inbox","name":"Get Inbox","description":"Get details of a specific email inbox in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to retrieve"}}},"agentmail_get_message":{"id":"agentmail_get_message","name":"Get Message","description":"Get details of a specific email message in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the message"},"messageId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the message to retrieve"}}},"agentmail_get_thread":{"id":"agentmail_get_thread","name":"Get Thread","description":"Get details of a specific email thread including messages in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the thread"},"threadId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the thread to retrieve"}}},"agentmail_list_drafts":{"id":"agentmail_list_drafts","name":"List Drafts","description":"List email drafts in an inbox in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to list drafts from"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of drafts to return"},"pageToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token for next page of results"}}},"agentmail_list_inboxes":{"id":"agentmail_list_inboxes","name":"List Inboxes","description":"List all email inboxes in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of inboxes to return"},"pageToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token for next page of results"}}},"agentmail_list_messages":{"id":"agentmail_list_messages","name":"List Messages","description":"List messages in an inbox in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to list messages from"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of messages to return"},"pageToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token for next page of results"}}},"agentmail_list_threads":{"id":"agentmail_list_threads","name":"List Threads","description":"List email threads in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to list threads from"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of threads to return"},"pageToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token for next page of results"},"labels":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated labels to filter threads by"},"before":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter threads before this ISO 8601 timestamp"},"after":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter threads after this ISO 8601 timestamp"}}},"agentmail_reply_message":{"id":"agentmail_reply_message","name":"Reply to Message","description":"Reply to an existing email message in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to reply from"},"messageId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the message to reply to"},"text":{"type":"string","required":false,"visibility":"user-or-llm","description":"Plain text reply body"},"html":{"type":"string","required":false,"visibility":"user-or-llm","description":"HTML reply body"},"to":{"type":"string","required":false,"visibility":"user-or-llm","description":"Override recipient email addresses (comma-separated)"},"cc":{"type":"string","required":false,"visibility":"user-or-llm","description":"CC email addresses (comma-separated)"},"bcc":{"type":"string","required":false,"visibility":"user-or-llm","description":"BCC email addresses (comma-separated)"},"replyAll":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Reply to all recipients of the original message"}}},"agentmail_send_draft":{"id":"agentmail_send_draft","name":"Send Draft","description":"Send an existing email draft in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the draft"},"draftId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the draft to send"}}},"agentmail_send_message":{"id":"agentmail_send_message","name":"Send Message","description":"Send an email message from an AgentMail inbox","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to send from"},"to":{"type":"string","required":true,"visibility":"user-or-llm","description":"Recipient email address (comma-separated for multiple)"},"subject":{"type":"string","required":true,"visibility":"user-or-llm","description":"Email subject line"},"text":{"type":"string","required":false,"visibility":"user-or-llm","description":"Plain text email body"},"html":{"type":"string","required":false,"visibility":"user-or-llm","description":"HTML email body"},"cc":{"type":"string","required":false,"visibility":"user-or-llm","description":"CC recipient email addresses (comma-separated)"},"bcc":{"type":"string","required":false,"visibility":"user-or-llm","description":"BCC recipient email addresses (comma-separated)"}}},"agentmail_update_draft":{"id":"agentmail_update_draft","name":"Update Draft","description":"Update an existing email draft in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the draft"},"draftId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the draft to update"},"to":{"type":"string","required":false,"visibility":"user-or-llm","description":"Recipient email addresses (comma-separated)"},"subject":{"type":"string","required":false,"visibility":"user-or-llm","description":"Draft subject line"},"text":{"type":"string","required":false,"visibility":"user-or-llm","description":"Plain text draft body"},"html":{"type":"string","required":false,"visibility":"user-or-llm","description":"HTML draft body"},"cc":{"type":"string","required":false,"visibility":"user-or-llm","description":"CC recipient email addresses (comma-separated)"},"bcc":{"type":"string","required":false,"visibility":"user-or-llm","description":"BCC recipient email addresses (comma-separated)"},"sendAt":{"type":"string","required":false,"visibility":"user-or-llm","description":"ISO 8601 timestamp to schedule sending"}}},"agentmail_update_inbox":{"id":"agentmail_update_inbox","name":"Update Inbox","description":"Update the display name of an email inbox in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox to update"},"displayName":{"type":"string","required":true,"visibility":"user-or-llm","description":"New display name for the inbox"}}},"agentmail_update_message":{"id":"agentmail_update_message","name":"Update Message","description":"Add or remove labels on an email message in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the message"},"messageId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the message to update"},"addLabels":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated labels to add to the message"},"removeLabels":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated labels to remove from the message"}}},"agentmail_update_thread":{"id":"agentmail_update_thread","name":"Update Thread Labels","description":"Add or remove labels on an email thread in AgentMail","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentMail API key"},"inboxId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the inbox containing the thread"},"threadId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the thread to update"},"addLabels":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated labels to add to the thread"},"removeLabels":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated labels to remove from the thread"}}},"agentphone_create_call":{"id":"agentphone_create_call","name":"Create Outbound Call","description":"Initiate an outbound voice call from an AgentPhone agent","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"agentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Agent that will handle the call"},"toNumber":{"type":"string","required":true,"visibility":"user-or-llm","description":"Phone number to call in E.164 format (e.g. +14155551234)"},"fromNumberId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Phone number ID to use as caller ID. Must belong to the agent. If omitted, the agent\'s first assigned number is used."},"initialGreeting":{"type":"string","required":false,"visibility":"user-or-llm","description":"Optional greeting spoken when the recipient answers"},"voice":{"type":"string","required":false,"visibility":"user-or-llm","description":"Voice ID override for this call (defaults to the agent\'s configured voice)"},"systemPrompt":{"type":"string","required":false,"visibility":"user-or-llm","description":"When provided, uses a built-in LLM for the conversation instead of forwarding to your webhook"}}},"agentphone_create_contact":{"id":"agentphone_create_contact","name":"Create Contact","description":"Create a new contact in AgentPhone","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"phoneNumber":{"type":"string","required":true,"visibility":"user-or-llm","description":"Phone number in E.164 format (e.g. +14155551234)"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Contact\'s full name"},"email":{"type":"string","required":false,"visibility":"user-or-llm","description":"Contact\'s email address"},"notes":{"type":"string","required":false,"visibility":"user-or-llm","description":"Freeform notes stored on the contact"}}},"agentphone_create_number":{"id":"agentphone_create_number","name":"Create Phone Number","description":"Provision a new SMS- and voice-enabled phone number","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Two-letter country code (e.g. US, CA). Defaults to US."},"areaCode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Preferred area code (US/CA only, e.g. \\"415\\"). Best-effort — may be ignored if unavailable."},"agentId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Optionally attach the number to an agent immediately"}}},"agentphone_delete_contact":{"id":"agentphone_delete_contact","name":"Delete Contact","description":"Delete a contact by ID","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"contactId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Contact ID"}}},"agentphone_get_call":{"id":"agentphone_get_call","name":"Get Call","description":"Fetch a call and its full transcript","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"callId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the call to retrieve"}}},"agentphone_get_call_transcript":{"id":"agentphone_get_call_transcript","name":"Get Call Transcript","description":"Get the full ordered transcript for a call","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"callId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the call to retrieve the transcript for"}}},"agentphone_get_contact":{"id":"agentphone_get_contact","name":"Get Contact","description":"Fetch a single contact by ID","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"contactId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Contact ID"}}},"agentphone_get_conversation":{"id":"agentphone_get_conversation","name":"Get Conversation","description":"Get a conversation along with its recent messages","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"conversationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Conversation ID"},"messageLimit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of recent messages to include (default 50, max 100)"}}},"agentphone_get_conversation_messages":{"id":"agentphone_get_conversation_messages","name":"Get Conversation Messages","description":"Get paginated messages for a conversation","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"conversationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Conversation ID"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of messages to return (default 50, max 200)"},"before":{"type":"string","required":false,"visibility":"user-or-llm","description":"Return messages received before this ISO 8601 timestamp"},"after":{"type":"string","required":false,"visibility":"user-or-llm","description":"Return messages received after this ISO 8601 timestamp"}}},"agentphone_get_number_messages":{"id":"agentphone_get_number_messages","name":"Get Phone Number Messages","description":"Fetch messages received on a specific phone number","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"numberId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the phone number"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of messages to return (default 50, max 200)"},"before":{"type":"string","required":false,"visibility":"user-or-llm","description":"Return messages received before this ISO 8601 timestamp"},"after":{"type":"string","required":false,"visibility":"user-or-llm","description":"Return messages received after this ISO 8601 timestamp"}}},"agentphone_get_usage":{"id":"agentphone_get_usage","name":"Get Usage","description":"Retrieve current usage statistics for the AgentPhone account","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"}}},"agentphone_get_usage_daily":{"id":"agentphone_get_usage_daily","name":"Get Daily Usage","description":"Get a daily breakdown of usage (messages, calls, webhooks) for the last N days","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"days":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of days to return (1-365, default 30)"}}},"agentphone_get_usage_monthly":{"id":"agentphone_get_usage_monthly","name":"Get Monthly Usage","description":"Get monthly usage aggregation (messages, calls, webhooks) for the last N months","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"months":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of months to return (1-24, default 6)"}}},"agentphone_list_calls":{"id":"agentphone_list_calls","name":"List Calls","description":"List voice calls for this AgentPhone account","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to return (default 20, max 100)"},"offset":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to skip (min 0)"},"status":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter by status (completed, in-progress, failed)"},"direction":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter by direction (inbound, outbound)"},"type":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter by call type (pstn, web)"},"search":{"type":"string","required":false,"visibility":"user-or-llm","description":"Search by phone number (matches fromNumber or toNumber)"}}},"agentphone_list_contacts":{"id":"agentphone_list_contacts","name":"List Contacts","description":"List contacts for this AgentPhone account","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"search":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter by name or phone number (case-insensitive contains)"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to return (default 50, max 200)"},"offset":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to skip (min 0)"}}},"agentphone_list_conversations":{"id":"agentphone_list_conversations","name":"List Conversations","description":"List conversations (message threads) for this AgentPhone account","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to return (default 20, max 100)"},"offset":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to skip (min 0)"}}},"agentphone_list_numbers":{"id":"agentphone_list_numbers","name":"List Phone Numbers","description":"List all phone numbers provisioned for this AgentPhone account","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to return (default 20, max 100)"},"offset":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to skip (min 0)"}}},"agentphone_react_to_message":{"id":"agentphone_react_to_message","name":"React to Message","description":"Send an iMessage tapback reaction to a message (iMessage only)","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"messageId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the message to react to"},"reaction":{"type":"string","required":true,"visibility":"user-or-llm","description":"Reaction type: love, like, dislike, laugh, emphasize, or question"}}},"agentphone_release_number":{"id":"agentphone_release_number","name":"Release Phone Number","description":"Release (delete) a phone number. This action is irreversible.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"numberId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the phone number to release"}}},"agentphone_send_message":{"id":"agentphone_send_message","name":"Send Message","description":"Send an outbound SMS or iMessage from an AgentPhone agent","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"agentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Agent sending the message"},"toNumber":{"type":"string","required":true,"visibility":"user-or-llm","description":"Recipient phone number in E.164 format (e.g. +14155551234)"},"body":{"type":"string","required":true,"visibility":"user-or-llm","description":"Message text to send"},"mediaUrl":{"type":"string","required":false,"visibility":"user-or-llm","description":"Optional URL of an image, video, or file to attach"},"numberId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Phone number ID to send from. If omitted, the agent\'s first assigned number is used."}}},"agentphone_update_contact":{"id":"agentphone_update_contact","name":"Update Contact","description":"Update a contact\'s fields","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"contactId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Contact ID"},"phoneNumber":{"type":"string","required":false,"visibility":"user-or-llm","description":"New phone number in E.164 format"},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"New contact name"},"email":{"type":"string","required":false,"visibility":"user-or-llm","description":"New email address"},"notes":{"type":"string","required":false,"visibility":"user-or-llm","description":"New freeform notes"}}},"agentphone_update_conversation":{"id":"agentphone_update_conversation","name":"Update Conversation","description":"Update conversation metadata (stored state). Pass null to clear existing metadata.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"AgentPhone API key"},"conversationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Conversation ID"},"metadata":{"type":"json","required":false,"visibility":"user-or-llm","description":"Custom key-value metadata to store on the conversation. Pass null to clear existing metadata."}}},"agiloft_async_status":{"id":"agiloft_async_status","name":"Agiloft Async Status","description":"Check whether an asynchronous Agiloft call, such as a run action button, has completed.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table the asynchronous call was made against"},"callbackId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Callback ID returned by the asynchronous call, e.g. from Run Action Button"}}},"agiloft_attach_file":{"id":"agiloft_attach_file","name":"Agiloft Attach File","description":"Attach a file to a field in an Agiloft record.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record to attach the file to"},"fieldName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the attachment field"},"file":{"type":"file","required":true,"visibility":"user-or-llm","description":"File to attach"},"fileName":{"type":"string","required":false,"visibility":"user-or-llm","description":"Name to assign to the file (defaults to original file name)"},"overwrite":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Replace the contents of the field instead of adding another file to it"}}},"agiloft_attachment_info":{"id":"agiloft_attachment_info","name":"Agiloft Attachment Info","description":"Get information about file attachments on a record field.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record to check attachments on"},"fieldName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the attachment field to inspect"}}},"agiloft_create_record":{"id":"agiloft_create_record","name":"Agiloft Create Record","description":"Create a new record in an Agiloft table.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\", \\"contacts.employees\\")"},"data":{"type":"string","required":true,"visibility":"user-or-llm","description":"Record field values as a JSON object (e.g., {\\"first_name\\": \\"John\\", \\"status\\": \\"Active\\"})"}}},"agiloft_delete_record":{"id":"agiloft_delete_record","name":"Agiloft Delete Record","description":"Delete a record from an Agiloft table.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\", \\"contacts.employees\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record to delete"},"substituteIds":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated IDs of records that adopt the dependants of the deleted record. Read only when the delete rule is REPLACE_WITH_ANOTHER."},"deleteRule":{"type":"string","required":false,"visibility":"user-or-llm","description":"How to treat records that depend on this one: ERROR_IF_DEPENDANTS (default — fails rather than cascading), APPLY_DELETE_WHERE_POSSIBLE, DELETE_WHERE_POSSIBLE_OTHERWISE_UNLINK, APPLY_UNLINK, UNLINK_WHERE_POSSIBLE_OTHERWISE_DELETE, or REPLACE_WITH_ANOTHER"}}},"agiloft_get_choice_line_id":{"id":"agiloft_get_choice_line_id","name":"Agiloft Get Choice Line ID","description":"Resolve the internal numeric ID of a choice-list value, for use in EWSelect WHERE clauses against choice fields.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"case\\", \\"contracts\\")"},"fieldName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Choice field name (e.g., \\"priority\\", \\"status\\")"},"value":{"type":"string","required":true,"visibility":"user-or-llm","description":"Choice display value to resolve (e.g., \\"High\\", \\"Active\\")"}}},"agiloft_list_tables":{"id":"agiloft_list_tables","name":"Agiloft List Tables","description":"List the tables and fields in an Agiloft knowledge base, to discover the logical names other operations need.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":false,"visibility":"user-or-llm","description":"Logical name of a single table to describe (e.g., \\"contacts\\"). Leave empty to list every table in the knowledge base."},"includeLinkedInfo":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Include the source table and column behind each linked field"},"skipColumnsInfo":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Return table names only, omitting field details, for a much smaller response"}}},"agiloft_lock_record":{"id":"agiloft_lock_record","name":"Agiloft Lock Record","description":"Lock, unlock, or check the lock status of an Agiloft record.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record to lock, unlock, or check"},"lockAction":{"type":"string","required":true,"visibility":"user-or-llm","description":"Action to perform: \\"lock\\", \\"unlock\\", or \\"check\\""},"force":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Unlock only: release a lock held by another user."}}},"agiloft_nlp_search":{"id":"agiloft_nlp_search","name":"Agiloft Natural Language Search","description":"Search Agiloft records by describing what you want in plain language, such as \\"active NDAs submitted last month\\".","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"nlpQuery":{"type":"string","required":true,"visibility":"user-or-llm","description":"The request in plain language, e.g. \\"Show me open, high-priority contracts\\". Structured field filters are not accepted — use Search Records for those."},"fields":{"type":"string","required":true,"visibility":"user-or-llm","description":"Comma-separated field names to return, e.g. \\"id, contract_title1, company_name\\""},"page":{"type":"string","required":false,"visibility":"user-or-llm","description":"Page number, starting from 0"},"limit":{"type":"string","required":false,"visibility":"user-or-llm","description":"Records per page"}}},"agiloft_read_record":{"id":"agiloft_read_record","name":"Agiloft Read Record","description":"Read a record by ID from an Agiloft table.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\", \\"contacts.employees\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record to read"},"fields":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated list of field names to include in the response"}}},"agiloft_remove_attachment":{"id":"agiloft_remove_attachment","name":"Agiloft Remove Attachment","description":"Remove an attached file from a field in an Agiloft record.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record containing the attachment"},"fieldName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the attachment field"},"position":{"type":"string","required":true,"visibility":"user-or-llm","description":"Position index of the file to remove (starting from 0)"}}},"agiloft_retrieve_attachment":{"id":"agiloft_retrieve_attachment","name":"Agiloft Retrieve Attachment","description":"Download an attached file from an Agiloft record field.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record containing the attachment"},"fieldName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the attachment field"},"position":{"type":"string","required":true,"visibility":"user-or-llm","description":"Position index of the file in the field (starting from 0)"}}},"agiloft_run_action_button":{"id":"agiloft_run_action_button","name":"Agiloft Run Action Button","description":"Run an action button on an Agiloft record, such as an approval or send-for-signature step.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\", \\"case\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record to run the action button on"},"actionButtonField":{"type":"string","required":true,"visibility":"user-or-llm","description":"Logical name of the field holding the action button (e.g., \\"ab_field\\")"}}},"agiloft_saved_search":{"id":"agiloft_saved_search","name":"Agiloft Saved Search","description":"List the saved searches defined for an Agiloft table.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Logical table name to list saved searches for (e.g., \\"contract\\")"}}},"agiloft_search_records":{"id":"agiloft_search_records","name":"Agiloft Search Records","description":"Search for records in an Agiloft table using a query.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name to search in (e.g., \\"contracts\\", \\"contacts.employees\\")"},"query":{"type":"string","required":false,"visibility":"user-or-llm","description":"Ad hoc EWSearch query. Combine conditions with && (and) or || (or) and quote every value — e.g. \\"summary~=\'test\'&&priority=\'High\'\\". Required unless a saved search is given."},"search":{"type":"string","required":false,"visibility":"user-or-llm","description":"Label of a saved search defined on the table (e.g., \\"C: Status is Closed\\"). Can be combined with a query to narrow it further."},"fields":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated list of field names to include in the results"},"page":{"type":"string","required":false,"visibility":"user-or-llm","description":"Page number for paginated results (starting from 0)"},"limit":{"type":"string","required":false,"visibility":"user-or-llm","description":"Maximum number of records to return per page. Agiloft treats 0 as \\"all records\\", so leave it unset or use a positive value to keep result sizes bounded."}}},"agiloft_select_records":{"id":"agiloft_select_records","name":"Agiloft Select Records","description":"Select record IDs matching a SQL WHERE clause from an Agiloft table.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\", \\"contacts.employees\\")"},"where":{"type":"string","required":true,"visibility":"user-or-llm","description":"SQL WHERE clause using database column names (e.g., \\"summary like \'%new%\'\\" or \\"assigned_person=\'John Doe\'\\"). EWSelect has no page size and returns every matching ID, so append a database limit such as \\"limit 0,200\\" to bound the result."}}},"agiloft_update_record":{"id":"agiloft_update_record","name":"Agiloft Update Record","description":"Update an existing record in an Agiloft table.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\", \\"contacts.employees\\")"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the record to update"},"data":{"type":"string","required":true,"visibility":"user-or-llm","description":"Updated field values as a JSON object (e.g., {\\"status\\": \\"Active\\", \\"priority\\": \\"High\\"})"}}},"agiloft_upsert_record":{"id":"agiloft_upsert_record","name":"Agiloft Upsert Record","description":"Create an Agiloft record, or update it when a record already matches the given fields.","version":"1.0.0","params":{"instanceUrl":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft instance URL (e.g., https://mycompany.agiloft.com)"},"knowledgeBase":{"type":"string","required":true,"visibility":"user-only","description":"Knowledge base name"},"login":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft username"},"password":{"type":"string","required":true,"visibility":"user-only","description":"Agiloft password"},"table":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table name (e.g., \\"contracts\\", \\"contacts.employees\\")"},"match":{"type":"string","required":true,"visibility":"user-or-llm","description":"Field used to find an existing record (e.g., \\"ext_id\\"). Pick something that identifies a record uniquely — if more than one record matches, Agiloft writes nothing and returns a conflict."},"async":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Queue the write instead of waiting for it. Returns a callback ID instead of a record ID; pass that to Async Status to poll the result."},"data":{"type":"string","required":true,"visibility":"user-or-llm","description":"Field values as a JSON object. On create these populate the new record; on update only the supplied fields change."}}},"ahrefs_anchors":{"id":"ahrefs_anchors","name":"Ahrefs Anchors","description":"Get the anchor text distribution for a target domain or URL\'s backlinks, showing how many links and referring domains use each anchor text.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\" or \\"https://example.com/page\\""},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)"},"history":{"type":"string","required":false,"visibility":"user-or-llm","description":"Historical scope: \\"live\\" (currently live), \\"all_time\\" (default, includes lost backlinks), or \\"since:YYYY-MM-DD\\" (backlinks found since a date)"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_backlinks":{"id":"ahrefs_backlinks","name":"Ahrefs Backlinks","description":"Get a list of backlinks pointing to a target domain or URL. Returns details about each backlink including source URL, anchor text, and domain rating.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\" or \\"https://example.com/page\\""},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: \\"domain\\""},"history":{"type":"string","required":false,"visibility":"user-or-llm","description":"Historical scope: \\"live\\" (currently live backlinks), \\"all_time\\" (default, includes lost backlinks), or \\"since:YYYY-MM-DD\\" (backlinks found since a date)."},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_backlinks_stats":{"id":"ahrefs_backlinks_stats","name":"Ahrefs Backlinks Stats","description":"Get backlink and referring domain totals for a target domain or URL, both currently live and across all time.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\" or \\"https://example.com/page\\""},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: \\"domain\\""},"date":{"type":"string","required":false,"visibility":"user-only","description":"Date to report metrics on, in YYYY-MM-DD format (defaults to today)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_batch_analysis":{"id":"ahrefs_batch_analysis","name":"Ahrefs Batch Analysis","description":"Get bulk SEO metrics (Domain Rating, backlinks, referring domains, organic traffic, and more) for multiple domains or URLs in a single request. Useful for comparing many competitors at once.","version":"1.0.0","params":{"targets":{"type":"string","required":true,"visibility":"user-or-llm","description":"Comma-separated list of domains or URLs to analyze. Example: \\"example.com,competitor.com\\""},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode applied to every target: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)"},"protocol":{"type":"string","required":false,"visibility":"user-or-llm","description":"Protocol applied to every target: \\"both\\" (default), \\"http\\", or \\"https\\""},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for traffic data. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"volumeMode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Search volume calculation: \\"monthly\\" or \\"average\\" (default: \\"monthly\\")"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_broken_backlinks":{"id":"ahrefs_broken_backlinks","name":"Ahrefs Broken Backlinks","description":"Get a list of broken backlinks pointing to a target domain or URL. Useful for identifying link reclamation opportunities.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\" or \\"https://example.com/page\\""},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: \\"domain\\""},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_domain_rating":{"id":"ahrefs_domain_rating","name":"Ahrefs Domain Rating","description":"Get the Domain Rating (DR) and Ahrefs Rank for a target domain. Domain Rating shows the strength of a website\'s backlink profile on a scale from 0 to 100.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain to analyze (e.g., example.com)"},"date":{"type":"string","required":false,"visibility":"user-only","description":"Date for historical data in YYYY-MM-DD format (defaults to today)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_domain_rating_history":{"id":"ahrefs_domain_rating_history","name":"Ahrefs Domain Rating History","description":"Get the historical Domain Rating (DR) trend for a target domain or URL over a date range, grouped daily, weekly, or monthly.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\""},"dateFrom":{"type":"string","required":true,"visibility":"user-only","description":"Start date of the historical period, in YYYY-MM-DD format"},"dateTo":{"type":"string","required":false,"visibility":"user-only","description":"End date of the historical period, in YYYY-MM-DD format (defaults to today)"},"historyGrouping":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval for grouping data points: \\"daily\\", \\"weekly\\", or \\"monthly\\" (default: \\"monthly\\")"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_keyword_overview":{"id":"ahrefs_keyword_overview","name":"Ahrefs Keyword Overview","description":"Get detailed metrics for a keyword including search volume, keyword difficulty, CPC, clicks, and traffic potential.","version":"1.0.0","params":{"keyword":{"type":"string","required":true,"visibility":"user-or-llm","description":"The keyword to analyze"},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for keyword data. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_keywords_history":{"id":"ahrefs_keywords_history","name":"Ahrefs Keywords History","description":"Get the historical organic keyword ranking distribution for a target domain or URL over a date range: how many keywords rank in each position bucket at each point in time.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\""},"dateFrom":{"type":"string","required":true,"visibility":"user-only","description":"Start date of the historical period, in YYYY-MM-DD format"},"dateTo":{"type":"string","required":false,"visibility":"user-only","description":"End date of the historical period, in YYYY-MM-DD format (defaults to today)"},"historyGrouping":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval for grouping data points: \\"daily\\", \\"weekly\\", or \\"monthly\\" (default: \\"monthly\\")"},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for search results. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_metrics":{"id":"ahrefs_metrics","name":"Ahrefs Metrics","description":"Get a one-call organic and paid search overview for a target domain or URL: organic traffic, organic keywords, paid traffic, paid keywords, and estimated traffic cost.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\""},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for traffic data. Example: \\"us\\", \\"gb\\", \\"de\\""},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: \\"domain\\""},"date":{"type":"string","required":false,"visibility":"user-only","description":"Date to report metrics on, in YYYY-MM-DD format (defaults to today)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_metrics_history":{"id":"ahrefs_metrics_history","name":"Ahrefs Metrics History","description":"Get the historical organic and paid traffic trend for a target domain or URL over a date range: organic traffic/cost and paid traffic/cost at each point in time.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\""},"dateFrom":{"type":"string","required":true,"visibility":"user-only","description":"Start date of the historical period, in YYYY-MM-DD format"},"dateTo":{"type":"string","required":false,"visibility":"user-only","description":"End date of the historical period, in YYYY-MM-DD format (defaults to today)"},"volumeMode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Search volume calculation: \\"monthly\\" or \\"average\\" (default: \\"monthly\\")"},"historyGrouping":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval for grouping data points: \\"daily\\", \\"weekly\\", or \\"monthly\\" (default: \\"monthly\\")"},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for traffic data. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_organic_competitors":{"id":"ahrefs_organic_competitors","name":"Ahrefs Organic Competitors","description":"Get domains that compete with a target domain or URL for the same organic keywords, ranked by keyword overlap.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\""},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for search results. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: \\"domain\\""},"date":{"type":"string","required":false,"visibility":"user-only","description":"Date to report metrics on, in YYYY-MM-DD format (defaults to today)"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_organic_keywords":{"id":"ahrefs_organic_keywords","name":"Ahrefs Organic Keywords","description":"Get organic keywords that a target domain or URL ranks for in Google search results. Returns keyword details including search volume, ranking position, and estimated traffic.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\" or \\"https://example.com/page\\""},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for search results. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: \\"domain\\""},"date":{"type":"string","required":false,"visibility":"user-only","description":"Date to report metrics on, in YYYY-MM-DD format (defaults to today)"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_paid_pages":{"id":"ahrefs_paid_pages","name":"Ahrefs Paid Pages","description":"Get a target domain\'s pages that receive paid search traffic, sorted by estimated paid traffic. Returns page URLs with their paid traffic, keyword counts, and estimated spend.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\""},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for traffic data. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)"},"date":{"type":"string","required":false,"visibility":"user-only","description":"Date to report metrics on, in YYYY-MM-DD format (defaults to today)"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_rank_tracker_competitors_overview":{"id":"ahrefs_rank_tracker_competitors_overview","name":"Ahrefs Rank Tracker Competitors Overview","description":"Get competitor rankings for the keywords tracked in an Ahrefs Rank Tracker project: each tracked keyword\'s volume and difficulty alongside every competitor\'s position, traffic, and traffic value. This endpoint is free and does not consume API units.","version":"1.0.0","params":{"projectId":{"type":"number","required":true,"visibility":"user-or-llm","description":"The Rank Tracker project ID (found in the project URL in Ahrefs)"},"date":{"type":"string","required":true,"visibility":"user-only","description":"Date to report rankings for, in YYYY-MM-DD format"},"device":{"type":"string","required":true,"visibility":"user-or-llm","description":"Rankings device type: \\"desktop\\" or \\"mobile\\""},"dateCompared":{"type":"string","required":false,"visibility":"user-only","description":"Comparison date in YYYY-MM-DD format, to compute position/traffic deltas"},"volumeMode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Search volume calculation: \\"monthly\\" or \\"average\\" (default: \\"monthly\\")"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_rank_tracker_competitors_stats":{"id":"ahrefs_rank_tracker_competitors_stats","name":"Ahrefs Rank Tracker Competitors Stats","description":"Get aggregate competitor stats for an Ahrefs Rank Tracker project: each competitor\'s traffic, traffic value, average position, and share of voice across all tracked keywords. This endpoint is free and does not consume API units.","version":"1.0.0","params":{"projectId":{"type":"number","required":true,"visibility":"user-or-llm","description":"The Rank Tracker project ID (found in the project URL in Ahrefs)"},"date":{"type":"string","required":true,"visibility":"user-only","description":"Date to report metrics for, in YYYY-MM-DD format"},"device":{"type":"string","required":true,"visibility":"user-or-llm","description":"Rankings device type: \\"desktop\\" or \\"mobile\\""},"volumeMode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Search volume calculation: \\"monthly\\" or \\"average\\" (default: \\"monthly\\")"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_rank_tracker_overview":{"id":"ahrefs_rank_tracker_overview","name":"Ahrefs Rank Tracker Overview","description":"Get ranking overview metrics for the keywords tracked in an Ahrefs Rank Tracker project: position, search volume, keyword difficulty, and estimated traffic. This endpoint is free and does not consume API units.","version":"1.0.0","params":{"projectId":{"type":"number","required":true,"visibility":"user-or-llm","description":"The Rank Tracker project ID (found in the project URL in Ahrefs)"},"date":{"type":"string","required":true,"visibility":"user-only","description":"Date to report rankings for, in YYYY-MM-DD format"},"device":{"type":"string","required":true,"visibility":"user-or-llm","description":"Rankings device type: \\"desktop\\" or \\"mobile\\""},"dateCompared":{"type":"string","required":false,"visibility":"user-only","description":"Comparison date in YYYY-MM-DD format, to compute position/traffic deltas"},"volumeMode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Search volume calculation: \\"monthly\\" or \\"average\\" (default: \\"monthly\\")"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_rank_tracker_serp_overview":{"id":"ahrefs_rank_tracker_serp_overview","name":"Ahrefs Rank Tracker SERP Overview","description":"Get the full SERP (search engine results page) for a keyword tracked in an Ahrefs Rank Tracker project, including every ranking URL with its position, title, and authority metrics. This endpoint is free and does not consume API units.","version":"1.0.0","params":{"projectId":{"type":"number","required":true,"visibility":"user-or-llm","description":"The Rank Tracker project ID (found in the project URL in Ahrefs)"},"keyword":{"type":"string","required":true,"visibility":"user-or-llm","description":"The tracked keyword to retrieve SERP data for"},"country":{"type":"string","required":true,"visibility":"user-or-llm","description":"Country code for the tracked keyword. Example: \\"us\\", \\"gb\\", \\"de\\""},"device":{"type":"string","required":true,"visibility":"user-or-llm","description":"Rankings device type: \\"desktop\\" or \\"mobile\\""},"topPositions":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of top organic positions to return (defaults to all available)"},"date":{"type":"string","required":false,"visibility":"user-only","description":"Timestamp to return the last available SERP Overview at, in YYYY-MM-DDThh:mm:ss format"},"locationId":{"type":"number","required":false,"visibility":"user-or-llm","description":"Location ID of the tracked keyword, if tracked at a specific location"},"languageCode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Language code of the tracked keyword"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_refdomains_history":{"id":"ahrefs_refdomains_history","name":"Ahrefs Referring Domains History","description":"Get the historical referring domains trend for a target domain or URL over a date range, grouped daily, weekly, or monthly.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\""},"dateFrom":{"type":"string","required":true,"visibility":"user-only","description":"Start date of the historical period, in YYYY-MM-DD format"},"dateTo":{"type":"string","required":false,"visibility":"user-only","description":"End date of the historical period, in YYYY-MM-DD format (defaults to today)"},"historyGrouping":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval for grouping data points: \\"daily\\", \\"weekly\\", or \\"monthly\\" (default: \\"monthly\\")"},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_referring_domains":{"id":"ahrefs_referring_domains","name":"Ahrefs Referring Domains","description":"Get a list of domains that link to a target domain or URL. Returns unique referring domains with their domain rating, backlink counts, and discovery dates.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain or URL to analyze. Example: \\"example.com\\" or \\"https://example.com/page\\""},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: \\"domain\\""},"history":{"type":"string","required":false,"visibility":"user-or-llm","description":"Historical scope: \\"live\\" (currently live), \\"all_time\\" (default, includes lost domains), or \\"since:YYYY-MM-DD\\" (domains found since a date)."},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_related_terms":{"id":"ahrefs_related_terms","name":"Ahrefs Related Terms","description":"Get keyword ideas related to a seed keyword: terms the same top-ranking pages also rank for (\\"also rank for\\") or also discuss (\\"also talk about\\"), with volume, difficulty, and CPC.","version":"1.0.0","params":{"keyword":{"type":"string","required":true,"visibility":"user-or-llm","description":"The seed keyword to find related terms for"},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for keyword data. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"terms":{"type":"string","required":false,"visibility":"user-or-llm","description":"Type of related keywords to return: \\"also_rank_for\\", \\"also_talk_about\\", or \\"all\\" (default: \\"all\\")"},"viewFor":{"type":"string","required":false,"visibility":"user-or-llm","description":"Whether to derive related terms from the top 10 or top 100 ranking pages (default: \\"top_10\\")"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_site_audit_page_explorer":{"id":"ahrefs_site_audit_page_explorer","name":"Ahrefs Site Audit Page Explorer","description":"Get crawled pages from an Ahrefs Site Audit project with health and SEO metrics: HTTP status, title, link counts, backlinks, indexability, and traffic. Optionally filter to pages affected by a specific issue.","version":"1.0.0","params":{"projectId":{"type":"number","required":true,"visibility":"user-or-llm","description":"The Site Audit project ID (found in the project URL in Ahrefs)"},"date":{"type":"string","required":false,"visibility":"user-only","description":"Crawl date in YYYY-MM-DDThh:mm:ss format (defaults to the most recent crawl)"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"offset":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of results to skip, for pagination"},"issueId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Only return pages affected by this issue ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"ahrefs_top_pages":{"id":"ahrefs_top_pages","name":"Ahrefs Top Pages","description":"Get the top pages of a target domain sorted by organic traffic. Returns page URLs with their traffic, keyword counts, and estimated traffic value.","version":"1.0.0","params":{"target":{"type":"string","required":true,"visibility":"user-or-llm","description":"The target domain to analyze. Example: \\"example.com\\""},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Country code for traffic data. Example: \\"us\\", \\"gb\\", \\"de\\" (default: \\"us\\")"},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Analysis mode: domain (entire domain), prefix (URL prefix), subdomains (include all subdomains, default), exact (exact URL match). Example: \\"domain\\""},"date":{"type":"string","required":false,"visibility":"user-only","description":"Date to report metrics on, in YYYY-MM-DD format (defaults to today)"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of results to return. Example: 50 (default: 1000)"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ahrefs API Key"}}},"airtable_create_records":{"id":"airtable_create_records","name":"Airtable Create Records","description":"Write new records to an Airtable table","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"},"tableId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table ID (starts with \\"tbl\\") or table name"},"records":{"type":"json","required":true,"visibility":"user-or-llm","description":"Array of records to create, each with a `fields` object"},"typecast":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"When true, Airtable automatically converts string values to the field type"}},"oauth":{"required":true,"provider":"airtable"}},"airtable_delete_records":{"id":"airtable_delete_records","name":"Airtable Delete Records","description":"Delete one or more records from an Airtable table by ID","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"},"tableId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table ID (starts with \\"tbl\\") or table name"},"recordIds":{"type":"json","required":true,"visibility":"user-or-llm","description":"Array of record IDs to delete (each starts with \\"rec\\", e.g., [\\"recXXXXXXXXXXXXXX\\"]). Pass a single-element array to delete one record."}},"oauth":{"required":true,"provider":"airtable"}},"airtable_get_base_schema":{"id":"airtable_get_base_schema","name":"Airtable Get Base Schema","description":"Get the schema of all tables, fields, and views in an Airtable base","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"}},"oauth":{"required":true,"provider":"airtable"}},"airtable_get_record":{"id":"airtable_get_record","name":"Airtable Get Record","description":"Retrieve a single record from an Airtable table by its ID","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"},"tableId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table ID (starts with \\"tbl\\") or table name"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Record ID to retrieve (starts with \\"rec\\", e.g., \\"recXXXXXXXXXXXXXX\\")"}},"oauth":{"required":true,"provider":"airtable"}},"airtable_list_bases":{"id":"airtable_list_bases","name":"Airtable List Bases","description":"List all bases the authenticated user has access to","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"offset":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination offset for retrieving additional bases"}},"oauth":{"required":true,"provider":"airtable"}},"airtable_list_records":{"id":"airtable_list_records","name":"Airtable List Records","description":"Read records from an Airtable table","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"},"tableId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table ID (starts with \\"tbl\\") or table name"},"maxRecords":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of records to return (default: all records)"},"filterFormula":{"type":"string","required":false,"visibility":"user-or-llm","description":"Formula to filter records (e.g., \\"({Field Name} = \'Value\')\\")"}},"oauth":{"required":true,"provider":"airtable"}},"airtable_list_tables":{"id":"airtable_list_tables","name":"Airtable List Tables","description":"List all tables and their schema in an Airtable base","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"}},"oauth":{"required":true,"provider":"airtable"}},"airtable_update_multiple_records":{"id":"airtable_update_multiple_records","name":"Airtable Update Multiple Records","description":"Update multiple existing records in an Airtable table","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"},"tableId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table ID (starts with \\"tbl\\") or table name"},"records":{"type":"json","required":true,"visibility":"user-or-llm","description":"Array of records to update, each with an `id` and a `fields` object"},"typecast":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"When true, Airtable automatically converts string values to the field type"}},"oauth":{"required":true,"provider":"airtable"}},"airtable_update_record":{"id":"airtable_update_record","name":"Airtable Update Record","description":"Update an existing record in an Airtable table by ID","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"},"tableId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table ID (starts with \\"tbl\\") or table name"},"recordId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Record ID to update (starts with \\"rec\\", e.g., \\"recXXXXXXXXXXXXXX\\")"},"fields":{"type":"json","required":true,"visibility":"user-or-llm","description":"An object containing the field names and their new values"},"typecast":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"When true, Airtable automatically converts string values to the field type"}},"oauth":{"required":true,"provider":"airtable"}},"airtable_upsert_records":{"id":"airtable_upsert_records","name":"Airtable Upsert Records","description":"Update existing records or create new ones in an Airtable table, matching on the specified merge fields","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token"},"baseId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Airtable base ID (starts with \\"app\\", e.g., \\"appXXXXXXXXXXXXXX\\")"},"tableId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Table ID (starts with \\"tbl\\") or table name"},"records":{"type":"json","required":true,"visibility":"user-or-llm","description":"Array of records to upsert, each with a `fields` object"},"fieldsToMergeOn":{"type":"json","required":true,"visibility":"user-or-llm","description":"Array of field names used to match existing records (max 3). A record is updated when all merge fields match, otherwise it is created. Example: [\\"Name\\"]"},"typecast":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"When true, Airtable automatically converts string values to the field type"}},"oauth":{"required":true,"provider":"airtable"}},"airweave_search":{"id":"airweave_search","name":"Airweave Search","description":"Search your synced data collections using Airweave. Supports semantic search with hybrid, neural, or keyword retrieval strategies. Optionally generate AI-powered answers from search results.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Airweave API Key for authentication"},"collectionId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The readable ID of the collection to search"},"query":{"type":"string","required":true,"visibility":"user-or-llm","description":"The search query text"},"limit":{"type":"number","required":false,"visibility":"user-only","description":"Maximum number of results to return (default: 100)"},"retrievalStrategy":{"type":"string","required":false,"visibility":"user-or-llm","description":"Retrieval strategy: hybrid (default), neural, or keyword"},"expandQuery":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Generate query variations to improve recall"},"rerank":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Reorder results for improved relevance using LLM"},"generateAnswer":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Generate a natural-language answer to the query"}}},"algolia_add_record":{"id":"algolia_add_record","name":"Algolia Add Record","description":"Add or replace a record in an Algolia index","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index"},"objectID":{"type":"string","required":false,"visibility":"user-or-llm","description":"Object ID for the record (auto-generated if not provided)"},"record":{"type":"json","required":true,"visibility":"user-or-llm","description":"JSON object representing the record to add"}}},"algolia_batch_operations":{"id":"algolia_batch_operations","name":"Algolia Batch Operations","description":"Perform batch add, update, partial update, or delete operations on records in an Algolia index","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index"},"requests":{"type":"json","required":true,"visibility":"user-or-llm","description":"Array of batch operations. Each item has \\"action\\" (addObject, updateObject, partialUpdateObject, partialUpdateObjectNoCreate, deleteObject, delete, clear) and \\"body\\" (the record data; must include objectID for update/delete; use an empty object {} for the index-level delete/clear actions)"}}},"algolia_browse_records":{"id":"algolia_browse_records","name":"Algolia Browse Records","description":"Browse and iterate over all records in an Algolia index using cursor pagination","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia API Key (must have browse ACL)"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index to browse"},"query":{"type":"string","required":false,"visibility":"user-or-llm","description":"Search query to filter browsed records"},"filters":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter string to narrow down results"},"attributesToRetrieve":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated list of attributes to retrieve"},"hitsPerPage":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of hits per page (default: 1000, max: 1000)"},"cursor":{"type":"string","required":false,"visibility":"user-or-llm","description":"Cursor from a previous browse response for pagination"},"aroundLatLng":{"type":"string","required":false,"visibility":"user-or-llm","description":"Coordinates for geo-search (e.g., \\"40.71,-74.01\\")"},"aroundRadius":{"type":"string","required":false,"visibility":"user-or-llm","description":"Maximum radius in meters for geo-search, or \\"all\\" for unlimited"},"insideBoundingBox":{"type":"json","required":false,"visibility":"user-or-llm","description":"Bounding box coordinates as [[lat1, lng1, lat2, lng2]] for geo-search"},"insidePolygon":{"type":"json","required":false,"visibility":"user-or-llm","description":"Polygon coordinates as [[lat1, lng1, lat2, lng2, lat3, lng3, ...]] for geo-search"}}},"algolia_clear_records":{"id":"algolia_clear_records","name":"Algolia Clear Records","description":"Clear all records from an Algolia index while keeping settings, synonyms, and rules","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key (must have deleteIndex ACL)"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index to clear"}}},"algolia_copy_move_index":{"id":"algolia_copy_move_index","name":"Algolia Copy/Move Index","description":"Copy or move an Algolia index to a new destination","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the source index"},"operation":{"type":"string","required":true,"visibility":"user-or-llm","description":"Operation to perform: \\"copy\\" or \\"move\\""},"destination":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the destination index"},"scope":{"type":"json","required":false,"visibility":"user-or-llm","description":"Array of scopes to copy (only for \\"copy\\" operation): [\\"settings\\", \\"synonyms\\", \\"rules\\"]. Omit to copy everything including records."}}},"algolia_delete_by_filter":{"id":"algolia_delete_by_filter","name":"Algolia Delete By Filter","description":"Delete all records matching a filter from an Algolia index","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key (must have deleteIndex ACL)"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index"},"filters":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter expression to match records for deletion (e.g., \\"category:outdated\\")"},"facetFilters":{"type":"json","required":false,"visibility":"user-or-llm","description":"Array of facet filters (e.g., [\\"brand:Acme\\"])"},"numericFilters":{"type":"json","required":false,"visibility":"user-or-llm","description":"Array of numeric filters (e.g., [\\"price > 100\\"])"},"tagFilters":{"type":"json","required":false,"visibility":"user-or-llm","description":"Array of tag filters using the _tags attribute (e.g., [\\"published\\"])"},"aroundLatLng":{"type":"string","required":false,"visibility":"user-or-llm","description":"Coordinates for geo-search filter (e.g., \\"40.71,-74.01\\")"},"aroundRadius":{"type":"string","required":false,"visibility":"user-or-llm","description":"Maximum radius in meters for geo-search, or \\"all\\" for unlimited"},"insideBoundingBox":{"type":"json","required":false,"visibility":"user-or-llm","description":"Bounding box coordinates as [[lat1, lng1, lat2, lng2]] for geo-search filter"},"insidePolygon":{"type":"json","required":false,"visibility":"user-or-llm","description":"Polygon coordinates as [[lat1, lng1, lat2, lng2, lat3, lng3, ...]] for geo-search filter"}}},"algolia_delete_index":{"id":"algolia_delete_index","name":"Algolia Delete Index","description":"Delete an entire Algolia index and all its records","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key (must have deleteIndex ACL)"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index to delete"}}},"algolia_delete_record":{"id":"algolia_delete_record","name":"Algolia Delete Record","description":"Delete a record by objectID from an Algolia index","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index"},"objectID":{"type":"string","required":true,"visibility":"user-or-llm","description":"The objectID of the record to delete"}}},"algolia_get_record":{"id":"algolia_get_record","name":"Algolia Get Record","description":"Get a record by objectID from an Algolia index","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index"},"objectID":{"type":"string","required":true,"visibility":"user-or-llm","description":"The objectID of the record to retrieve"},"attributesToRetrieve":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated list of attributes to retrieve"}}},"algolia_get_records":{"id":"algolia_get_records","name":"Algolia Get Records","description":"Retrieve multiple records by objectID from one or more Algolia indices","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Default index name for all requests"},"requests":{"type":"json","required":true,"visibility":"user-or-llm","description":"Array of objects specifying records to retrieve. Each must have \\"objectID\\" and optionally \\"indexName\\" and \\"attributesToRetrieve\\"."}}},"algolia_get_settings":{"id":"algolia_get_settings","name":"Algolia Get Settings","description":"Retrieve the settings of an Algolia index","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index"}}},"algolia_get_task_status":{"id":"algolia_get_task_status","name":"Algolia Get Task Status","description":"Check whether an Algolia indexing task has finished publishing","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index the task ran against"},"taskID":{"type":"number","required":true,"visibility":"user-or-llm","description":"The taskID returned by a previous write operation"}}},"algolia_list_indices":{"id":"algolia_list_indices","name":"Algolia List Indices","description":"List all indices in an Algolia application","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia API Key"},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number for paginating indices (default: not paginated)"},"hitsPerPage":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of indices per page (default: 100)"}}},"algolia_partial_update_record":{"id":"algolia_partial_update_record","name":"Algolia Partial Update Record","description":"Partially update a record in an Algolia index without replacing it entirely","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index"},"objectID":{"type":"string","required":true,"visibility":"user-or-llm","description":"The objectID of the record to update"},"attributes":{"type":"json","required":true,"visibility":"user-or-llm","description":"JSON object with attributes to update. Supports built-in operations like {\\"stock\\": {\\"_operation\\": \\"Decrement\\", \\"value\\": 1}}"},"createIfNotExists":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Whether to create the record if it does not exist (default: true)"}}},"algolia_search":{"id":"algolia_search","name":"Algolia Search","description":"Search an Algolia index","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia API Key"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index to search"},"query":{"type":"string","required":true,"visibility":"user-or-llm","description":"Search query text"},"hitsPerPage":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of hits per page (default: 20)"},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number to retrieve (default: 0)"},"filters":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter string (e.g., \\"category:electronics AND price < 100\\")"},"attributesToRetrieve":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated list of attributes to retrieve"},"facets":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated list of facet attribute names to retrieve counts for (use \\"*\\" for all)"},"getRankingInfo":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Whether to include detailed ranking information in each hit"},"aroundLatLng":{"type":"string","required":false,"visibility":"user-or-llm","description":"Coordinates for geo-search (e.g., \\"40.71,-74.01\\")"},"aroundRadius":{"type":"string","required":false,"visibility":"user-or-llm","description":"Maximum radius in meters for geo-search, or \\"all\\" for unlimited"},"insideBoundingBox":{"type":"json","required":false,"visibility":"user-or-llm","description":"Bounding box coordinates as [[lat1, lng1, lat2, lng2]] for geo-search"},"insidePolygon":{"type":"json","required":false,"visibility":"user-or-llm","description":"Polygon coordinates as [[lat1, lng1, lat2, lng2, lat3, lng3, ...]] for geo-search"}}},"algolia_update_settings":{"id":"algolia_update_settings","name":"Algolia Update Settings","description":"Update the settings of an Algolia index","version":"1.0","params":{"applicationId":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Application ID"},"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Algolia Admin API Key (must have editSettings ACL)"},"indexName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the Algolia index"},"settings":{"type":"json","required":true,"visibility":"user-or-llm","description":"JSON object with settings to update (e.g., {\\"searchableAttributes\\": [\\"name\\", \\"description\\"], \\"customRanking\\": [\\"desc(popularity)\\"]})"},"forwardToReplicas":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Whether to apply changes to replica indices (default: false)"}}},"amplitude_event_segmentation":{"id":"amplitude_event_segmentation","name":"Amplitude Event Segmentation","description":"Query event analytics data with segmentation. Get event counts, uniques, averages, and more.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"eventType":{"type":"string","required":true,"visibility":"user-or-llm","description":"Event type name to analyze"},"start":{"type":"string","required":true,"visibility":"user-or-llm","description":"Start date in YYYYMMDD format"},"end":{"type":"string","required":true,"visibility":"user-or-llm","description":"End date in YYYYMMDD format"},"metric":{"type":"string","required":false,"visibility":"user-or-llm","description":"Metric type: uniques, totals, pct_dau, average, histogram, sums, value_avg, or formula (default: uniques)"},"interval":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval: 1 (daily), 7 (weekly), or 30 (monthly)"},"groupBy":{"type":"string","required":false,"visibility":"user-or-llm","description":"Property name to group by (prefix custom user properties with \\"gp:\\")"},"groupBy2":{"type":"string","required":false,"visibility":"user-or-llm","description":"Second property name to group by (prefix custom user properties with \\"gp:\\")"},"limit":{"type":"string","required":false,"visibility":"user-or-llm","description":"Maximum number of group-by values (max 1000)"},"filters":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON array of filter objects applied to the event, e.g. [{\\"subprop_type\\":\\"event\\",\\"subprop_key\\":\\"city\\",\\"subprop_op\\":\\"is\\",\\"subprop_value\\":[\\"San Francisco\\"]}]"},"formula":{"type":"string","required":false,"visibility":"user-or-llm","description":"Required when metric is \\"formula\\", e.g. \\"UNIQUES(A)/UNIQUES(B)\\""},"segment":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON segment definition(s) applied to the query"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_funnels":{"id":"amplitude_funnels","name":"Amplitude Funnels","description":"Analyze conversion rates and drop-off between a sequence of events.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"events":{"type":"string","required":true,"visibility":"user-or-llm","description":"JSON array of event objects, one per funnel step in order, e.g. [{\\"event_type\\":\\"signup\\"},{\\"event_type\\":\\"purchase\\"}]"},"start":{"type":"string","required":true,"visibility":"user-or-llm","description":"Start date in YYYYMMDD format"},"end":{"type":"string","required":true,"visibility":"user-or-llm","description":"End date in YYYYMMDD format"},"mode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Funnel ordering: \\"ordered\\", \\"unordered\\", or \\"sequential\\" (default: ordered)"},"userType":{"type":"string","required":false,"visibility":"user-or-llm","description":"User type: \\"new\\" or \\"active\\" (default: active)"},"interval":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval: -300000 (real-time), -3600000 (hourly), 1 (daily), 7 (weekly), or 30 (monthly)"},"conversionWindowSeconds":{"type":"string","required":false,"visibility":"user-or-llm","description":"Conversion window in seconds (default: 2592000, i.e. 30 days)"},"groupBy":{"type":"string","required":false,"visibility":"user-or-llm","description":"Property to group by (limit: one; prefix custom properties with \\"gp:\\")"},"limit":{"type":"string","required":false,"visibility":"user-or-llm","description":"Maximum number of group-by values (default: 100, max: 1000)"},"segment":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON segment definition(s) applied to the query"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_get_active_users":{"id":"amplitude_get_active_users","name":"Amplitude Get Active Users","description":"Get active or new user counts over a date range from the Dashboard REST API.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"start":{"type":"string","required":true,"visibility":"user-or-llm","description":"Start date in YYYYMMDD format"},"end":{"type":"string","required":true,"visibility":"user-or-llm","description":"End date in YYYYMMDD format"},"metric":{"type":"string","required":false,"visibility":"user-or-llm","description":"Metric type: \\"active\\" or \\"new\\" (default: active)"},"interval":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval: 1 (daily), 7 (weekly), or 30 (monthly)"},"groupBy":{"type":"string","required":false,"visibility":"user-or-llm","description":"Property name to group by"},"segment":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON segment definition(s) applied to the query"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_get_revenue":{"id":"amplitude_get_revenue","name":"Amplitude Get Revenue","description":"Get revenue LTV data including ARPU, ARPPU, total revenue, and paying user counts.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"start":{"type":"string","required":true,"visibility":"user-or-llm","description":"Start date in YYYYMMDD format"},"end":{"type":"string","required":true,"visibility":"user-or-llm","description":"End date in YYYYMMDD format"},"metric":{"type":"string","required":false,"visibility":"user-or-llm","description":"Metric: 0 (ARPU), 1 (ARPPU), 2 (Total Revenue), 3 (Paying Users)"},"interval":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval: 1 (daily), 7 (weekly), or 30 (monthly)"},"groupBy":{"type":"string","required":false,"visibility":"user-or-llm","description":"Property name to group by (limit: one)"},"segment":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON segment definition(s) applied to the query"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_group_identify":{"id":"amplitude_group_identify","name":"Amplitude Group Identify","description":"Set group-level properties in Amplitude. Supports $set, $setOnce, $add, $append, $unset operations.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"groupType":{"type":"string","required":true,"visibility":"user-or-llm","description":"Group classification (e.g., \\"company\\", \\"org_id\\")"},"groupValue":{"type":"string","required":true,"visibility":"user-or-llm","description":"Specific group identifier (e.g., \\"Acme Corp\\")"},"groupProperties":{"type":"string","required":true,"visibility":"user-or-llm","description":"JSON object of group properties. Use operations like $set, $setOnce, $add, $append, $unset."},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_identify_user":{"id":"amplitude_identify_user","name":"Amplitude Identify User","description":"Set user properties in Amplitude using the Identify API. Supports $set, $setOnce, $add, $append, $unset operations.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"userId":{"type":"string","required":false,"visibility":"user-or-llm","description":"User ID (required if no device_id)"},"deviceId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Device ID (required if no user_id)"},"userProperties":{"type":"string","required":true,"visibility":"user-or-llm","description":"JSON object of user properties. Use operations like $set, $setOnce, $add, $append, $unset."},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_list_events":{"id":"amplitude_list_events","name":"Amplitude List Events","description":"List all event types in the Amplitude project with their weekly totals and unique counts.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_realtime_active_users":{"id":"amplitude_realtime_active_users","name":"Amplitude Real-time Active Users","description":"Get real-time active user counts at 5-minute granularity for the last 2 days.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_retention":{"id":"amplitude_retention","name":"Amplitude Retention","description":"Measure how many users return to perform an action after a starting action.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"startEvent":{"type":"string","required":true,"visibility":"user-or-llm","description":"JSON starting event object, e.g. {\\"event_type\\":\\"_new\\"} or {\\"event_type\\":\\"_active\\"}"},"returnEvent":{"type":"string","required":true,"visibility":"user-or-llm","description":"JSON returning event object, e.g. {\\"event_type\\":\\"_all\\"} or {\\"event_type\\":\\"_active\\"}"},"start":{"type":"string","required":true,"visibility":"user-or-llm","description":"Start date in YYYYMMDD format"},"end":{"type":"string","required":true,"visibility":"user-or-llm","description":"End date in YYYYMMDD format"},"retentionMode":{"type":"string","required":false,"visibility":"user-or-llm","description":"Retention type: \\"bracket\\", \\"rolling\\", or \\"n-day\\" (default: n-day)"},"retentionBrackets":{"type":"string","required":false,"visibility":"user-or-llm","description":"Required when Retention Mode is \\"bracket\\". Day ranges, e.g. [[0,4]]"},"interval":{"type":"string","required":false,"visibility":"user-or-llm","description":"Time interval: 1 (daily), 7 (weekly), or 30 (monthly)"},"groupBy":{"type":"string","required":false,"visibility":"user-or-llm","description":"Property to group by (limit: one; prefix custom properties with \\"gp:\\")"},"segment":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON segment definition(s) applied to the query"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_send_event":{"id":"amplitude_send_event","name":"Amplitude Send Event","description":"Track an event in Amplitude using the HTTP V2 API.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"userId":{"type":"string","required":false,"visibility":"user-or-llm","description":"User ID (required if no device_id)"},"deviceId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Device ID (required if no user_id)"},"eventType":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the event (e.g., \\"page_view\\", \\"purchase\\")"},"eventProperties":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON object of custom event properties"},"userProperties":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON object of user properties to set (supports $set, $setOnce, $add, $append, $unset)"},"time":{"type":"string","required":false,"visibility":"user-or-llm","description":"Event timestamp in milliseconds since epoch"},"sessionId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Session start time in milliseconds since epoch"},"insertId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Unique ID for deduplication (within 7-day window)"},"appVersion":{"type":"string","required":false,"visibility":"user-or-llm","description":"Application version string"},"platform":{"type":"string","required":false,"visibility":"user-or-llm","description":"Platform (e.g., \\"Web\\", \\"iOS\\", \\"Android\\")"},"country":{"type":"string","required":false,"visibility":"user-or-llm","description":"Two-letter country code"},"language":{"type":"string","required":false,"visibility":"user-or-llm","description":"Language code (e.g., \\"en\\")"},"ip":{"type":"string","required":false,"visibility":"user-or-llm","description":"IP address for geo-location"},"price":{"type":"string","required":false,"visibility":"user-or-llm","description":"Price of the item purchased"},"quantity":{"type":"string","required":false,"visibility":"user-or-llm","description":"Quantity of items purchased"},"revenue":{"type":"string","required":false,"visibility":"user-or-llm","description":"Revenue amount"},"productId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Product identifier"},"revenueType":{"type":"string","required":false,"visibility":"user-or-llm","description":"Revenue type (e.g., \\"purchase\\", \\"refund\\")"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_user_activity":{"id":"amplitude_user_activity","name":"Amplitude User Activity","description":"Get the event stream for a specific user by their Amplitude ID.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"amplitudeId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Amplitude internal user ID"},"offset":{"type":"string","required":false,"visibility":"user-or-llm","description":"Offset for pagination (default 0)"},"limit":{"type":"string","required":false,"visibility":"user-or-llm","description":"Maximum number of events to return (default 1000, max 1000)"},"direction":{"type":"string","required":false,"visibility":"user-or-llm","description":"Sort direction: \\"latest\\" or \\"earliest\\" (default: latest)"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"amplitude_user_profile":{"id":"amplitude_user_profile","name":"Amplitude User Profile","description":"Get a user profile including properties, cohort memberships, and computed properties. Not available for EU data-residency projects.","version":"1.0.0","params":{"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"userId":{"type":"string","required":false,"visibility":"user-or-llm","description":"External user ID (required if no device_id)"},"deviceId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Device ID (required if no user_id)"},"getAmpProps":{"type":"string","required":false,"visibility":"user-or-llm","description":"Include Amplitude user properties (true/false, default: false)"},"getCohortIds":{"type":"string","required":false,"visibility":"user-or-llm","description":"Include cohort IDs the user belongs to (true/false, default: false)"},"getComputations":{"type":"string","required":false,"visibility":"user-or-llm","description":"Include computed user properties (true/false, default: false)"}}},"amplitude_user_search":{"id":"amplitude_user_search","name":"Amplitude User Search","description":"Search for a user by User ID, Device ID, or Amplitude ID using the Dashboard REST API.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude API Key"},"secretKey":{"type":"string","required":true,"visibility":"user-only","description":"Amplitude Secret Key"},"user":{"type":"string","required":true,"visibility":"user-or-llm","description":"User ID, Device ID, or Amplitude ID to search for"},"dataResidency":{"type":"string","required":false,"visibility":"user-or-llm","description":"Data residency region: \\"us\\" (default) or \\"eu\\""}}},"apify_get_dataset_items":{"id":"apify_get_dataset_items","name":"APIFY Get Dataset Items","description":"Retrieve items stored in an APIFY dataset","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"APIFY API token from console.apify.com/account#/integrations"},"datasetId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Dataset ID to read items from. Example: \\"9RnD3Pql2vGZkc5H5\\""},"itemLimit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Max items to return (1-250000). Default: all items. Example: 500"},"offset":{"type":"number","required":false,"visibility":"user-or-llm","description":"Number of items to skip at the start. Default: 0"},"fields":{"type":"string","required":false,"visibility":"user-or-llm","description":"Comma-separated list of fields to include. Example: \\"title,url,price\\""}}},"apify_get_run":{"id":"apify_get_run","name":"APIFY Get Run","description":"Get the status and details of an APIFY actor run","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"APIFY API token from console.apify.com/account#/integrations"},"runId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Actor run ID to fetch. Example: \\"HG7ML7M8z78YcAPEB\\""}}},"apify_run_actor_async":{"id":"apify_run_actor_async","name":"APIFY Run Actor (Async)","description":"Run an APIFY actor asynchronously with polling for long-running tasks","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"APIFY API token from console.apify.com/account#/integrations"},"actorId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Actor ID or username/actor-name. Examples: \\"apify/web-scraper\\", \\"janedoe/my-actor\\", \\"moJRLRc85AitArpNN\\""},"input":{"type":"string","required":false,"visibility":"user-or-llm","description":"Actor input as JSON string. Example: {\\"startUrls\\": [{\\"url\\": \\"https://example.com\\"}], \\"maxPages\\": 10}"},"waitForFinish":{"type":"number","required":false,"visibility":"user-or-llm","description":"Initial wait time in seconds (0-60) before polling starts. Example: 30"},"itemLimit":{"type":"number","required":false,"default":100,"visibility":"user-or-llm","description":"Max dataset items to fetch (1-250000). Default: 100. Example: 500"},"memory":{"type":"number","required":false,"visibility":"user-or-llm","description":"Memory in megabytes allocated for the actor run (128-32768). Example: 1024 for 1GB, 2048 for 2GB"},"timeout":{"type":"number","required":false,"visibility":"user-or-llm","description":"Timeout in seconds for the actor run. Example: 300 for 5 minutes, 3600 for 1 hour"},"build":{"type":"string","required":false,"visibility":"user-or-llm","description":"Actor build to run. Examples: \\"latest\\", \\"beta\\", \\"1.2.3\\", \\"build-tag-name\\""}}},"apify_run_actor_sync":{"id":"apify_run_actor_sync","name":"APIFY Run Actor (Sync)","description":"Run an APIFY actor synchronously and get results (max 5 minutes)","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"APIFY API token from console.apify.com/account#/integrations"},"actorId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Actor ID or username/actor-name. Examples: \\"apify/web-scraper\\", \\"janedoe/my-actor\\", \\"moJRLRc85AitArpNN\\""},"input":{"type":"string","required":false,"visibility":"user-or-llm","description":"Actor input as JSON string. Example: {\\"startUrls\\": [{\\"url\\": \\"https://example.com\\"}], \\"maxPages\\": 10}"},"memory":{"type":"number","required":false,"visibility":"user-or-llm","description":"Memory in megabytes allocated for the actor run (128-32768). Example: 1024 for 1GB, 2048 for 2GB"},"timeout":{"type":"number","required":false,"visibility":"user-or-llm","description":"Timeout in seconds for the actor run. Example: 300 for 5 minutes, 3600 for 1 hour"},"build":{"type":"string","required":false,"visibility":"user-or-llm","description":"Actor build to run. Examples: \\"latest\\", \\"beta\\", \\"1.2.3\\", \\"build-tag-name\\""}}},"apify_run_task":{"id":"apify_run_task","name":"APIFY Run Task","description":"Run a saved APIFY actor task synchronously and get dataset items (max 5 minutes)","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"APIFY API token from console.apify.com/account#/integrations"},"taskId":{"type":"string","required":true,"visibility":"user-or-llm","description":"Task ID or username/task-name. Examples: \\"janedoe/my-task\\", \\"moJRLRc85AitArpNN\\""},"input":{"type":"string","required":false,"visibility":"user-or-llm","description":"JSON string that overrides the task\'s saved input. Example: {\\"startUrls\\": [{\\"url\\": \\"https://example.com\\"}]}"},"itemLimit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Max dataset items to return (1-250000). Example: 500"},"memory":{"type":"number","required":false,"visibility":"user-or-llm","description":"Memory in megabytes allocated for the run (128-32768). Example: 1024 for 1GB"},"timeout":{"type":"number","required":false,"visibility":"user-or-llm","description":"Timeout in seconds for the run. Example: 300 for 5 minutes"},"build":{"type":"string","required":false,"visibility":"user-or-llm","description":"Actor build to run. Examples: \\"latest\\", \\"beta\\", \\"1.2.3\\""}}},"apollo_account_bulk_create":{"id":"apollo_account_bulk_create","name":"Apollo Bulk Create Accounts","description":"Create up to 100 accounts at once in your Apollo database. Set run_dedupe=true to deduplicate by domain, organization_id, and name. Master key required.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"accounts":{"type":"array","required":true,"visibility":"user-or-llm","description":"Array of accounts to create (max 100). Each account should include a name, and may optionally include domain, phone, phone_status_cd, raw_address, owner_id, linkedin_url, facebook_url, twitter_url, salesforce_id, and hubspot_id."},"append_label_names":{"type":"array","required":false,"visibility":"user-only","description":"Array of label names to add to ALL accounts in this request"},"run_dedupe":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"When true, performs aggressive deduplication by domain, organization_id, and name (defaults to false)"}}},"apollo_account_bulk_update":{"id":"apollo_account_bulk_update","name":"Apollo Bulk Update Accounts","description":"Update up to 1000 existing accounts at once in your Apollo database (higher limit than contacts!). Each account must include an id field. Master key required.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"account_ids":{"type":"array","required":false,"visibility":"user-or-llm","description":"Array of account IDs to update with the same values (max 1000). Use with name/owner_id for uniform updates. Use either this OR account_attributes."},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"When using account_ids, apply this name to all accounts"},"owner_id":{"type":"string","required":false,"visibility":"user-or-llm","description":"When using account_ids, apply this owner to all accounts"},"account_stage_id":{"type":"string","required":false,"visibility":"user-or-llm","description":"When using account_ids, apply this account stage to all accounts"},"account_attributes":{"type":"json","required":false,"visibility":"user-or-llm","description":"Array of account objects with individual updates (each must include id). Example: [{\\"id\\": \\"acc1\\", \\"name\\": \\"Acme\\", \\"owner_id\\": \\"u1\\", \\"account_stage_id\\": \\"s1\\", \\"typed_custom_fields\\": {\\"field_id\\": \\"value\\"}}]"},"async":{"type":"boolean","required":false,"visibility":"user-only","description":"When true, processes the update asynchronously. Only supported when using account_ids; returns 422 if used with account_attributes."}}},"apollo_account_create":{"id":"apollo_account_create","name":"Apollo Create Account","description":"Create a new account (company) in your Apollo database","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Company name (e.g., \\"Acme Corporation\\")"},"domain":{"type":"string","required":false,"visibility":"user-or-llm","description":"Company domain without www. prefix (e.g., \\"acme.com\\")"},"phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Primary phone number for the account"},"owner_id":{"type":"string","required":false,"visibility":"user-only","description":"Apollo user ID of the account owner"},"account_stage_id":{"type":"string","required":false,"visibility":"user-only","description":"Apollo ID for the account stage to assign this account to"},"raw_address":{"type":"string","required":false,"visibility":"user-or-llm","description":"Corporate location (e.g., \\"San Francisco, CA, USA\\")"},"typed_custom_fields":{"type":"json","required":false,"visibility":"user-only","description":"Custom field values as { custom_field_id: value } map"}}},"apollo_account_search":{"id":"apollo_account_search","name":"Apollo Search Accounts","description":"Search your team\'s accounts in Apollo. Display limit: 50,000 records (100 records per page, 500 pages max). Use filters to narrow results. Master key required.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"q_organization_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter accounts by organization name (partial-match search)"},"account_stage_ids":{"type":"array","required":false,"visibility":"user-only","description":"Filter by account stage IDs"},"account_label_ids":{"type":"array","required":false,"visibility":"user-only","description":"Filter by account label IDs"},"sort_by_field":{"type":"string","required":false,"visibility":"user-or-llm","description":"Sort field: \\"account_last_activity_date\\", \\"account_created_at\\", or \\"account_updated_at\\""},"sort_ascending":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Sort ascending when true. Defaults to descending."},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number for pagination (e.g., 1, 2, 3)"},"per_page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Results per page, max 100 (e.g., 25, 50, 100)"}}},"apollo_account_update":{"id":"apollo_account_update","name":"Apollo Update Account","description":"Update an existing account in your Apollo database","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"account_id":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the account to update (e.g., \\"acc_abc123\\")"},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Company name (e.g., \\"Acme Corporation\\")"},"domain":{"type":"string","required":false,"visibility":"user-or-llm","description":"Company domain (e.g., \\"acme.com\\")"},"phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Company phone number"},"owner_id":{"type":"string","required":false,"visibility":"user-only","description":"Apollo user ID of the account owner"},"account_stage_id":{"type":"string","required":false,"visibility":"user-only","description":"Apollo ID for the account stage to assign this account to"},"raw_address":{"type":"string","required":false,"visibility":"user-or-llm","description":"Corporate location (e.g., \\"San Francisco, CA, USA\\")"},"typed_custom_fields":{"type":"json","required":false,"visibility":"user-only","description":"Custom field values as { custom_field_id: value } map"}}},"apollo_contact_bulk_create":{"id":"apollo_contact_bulk_create","name":"Apollo Bulk Create Contacts","description":"Create up to 100 contacts at once in your Apollo database. Supports deduplication to prevent creating duplicate contacts. Master key required.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"contacts":{"type":"array","required":true,"visibility":"user-or-llm","description":"Array of contacts to create (max 100). Each contact may include first_name, last_name, email, title, organization_name, account_id, owner_id, contact_stage_id, linkedin_url, phone (single string) or phone_numbers (array of {raw_number, position}), contact_emails, typed_custom_fields, and CRM IDs (salesforce_contact_id, hubspot_id, team_id) for cross-system matching"},"append_label_names":{"type":"array","required":false,"visibility":"user-or-llm","description":"Label names to add to all contacts in this request (e.g., [\\"Hot Lead\\"])"},"run_dedupe":{"type":"boolean","required":false,"visibility":"user-only","description":"Enable deduplication to prevent creating duplicate contacts. When true, existing contacts are returned without modification"}}},"apollo_contact_bulk_update":{"id":"apollo_contact_bulk_update","name":"Apollo Bulk Update Contacts","description":"Update up to 100 existing contacts at once in your Apollo database. Each contact must include an id field. Master key required.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"contact_ids":{"type":"array","required":false,"visibility":"user-or-llm","description":"Array of contact IDs to update. Must be paired with an object-form contact_attributes specifying the fields to apply uniformly to all listed contacts."},"contact_attributes":{"type":"json","required":false,"visibility":"user-or-llm","description":"Required. Either an array of per-contact updates (each with id) — used standalone — or a single object of attributes to apply to all contact_ids. Supported fields: owner_id, email, organization_name, title, first_name, last_name, account_id, present_raw_address, linkedin_url, typed_custom_fields"},"async":{"type":"boolean","required":false,"visibility":"user-only","description":"Force asynchronous processing. Automatically enabled for >100 contacts"}}},"apollo_contact_create":{"id":"apollo_contact_create","name":"Apollo Create Contact","description":"Create a new contact in your Apollo database","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"first_name":{"type":"string","required":true,"visibility":"user-or-llm","description":"First name of the contact"},"last_name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Last name of the contact"},"email":{"type":"string","required":false,"visibility":"user-or-llm","description":"Email address of the contact"},"title":{"type":"string","required":false,"visibility":"user-or-llm","description":"Job title (e.g., \\"VP of Sales\\", \\"Software Engineer\\")"},"account_id":{"type":"string","required":false,"visibility":"user-or-llm","description":"Apollo account ID to associate with (e.g., \\"acc_abc123\\")"},"owner_id":{"type":"string","required":false,"visibility":"user-only","description":"User ID of the contact owner (accepted by Apollo but not officially documented for POST /contacts)"},"organization_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Name of the contact\'s employer (e.g., \\"Apollo\\")"},"website_url":{"type":"string","required":false,"visibility":"user-or-llm","description":"Corporate website URL (e.g., \\"https://www.apollo.io/\\")"},"label_names":{"type":"array","required":false,"visibility":"user-or-llm","description":"Lists/labels to add the contact to (e.g., [\\"Prospects\\"])"},"contact_stage_id":{"type":"string","required":false,"visibility":"user-or-llm","description":"Apollo ID for the contact stage"},"present_raw_address":{"type":"string","required":false,"visibility":"user-or-llm","description":"Personal location for the contact (e.g., \\"Atlanta, United States\\")"},"direct_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Primary phone number"},"corporate_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Work/office phone number"},"mobile_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Mobile phone number"},"home_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Home phone number"},"other_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Alternative phone number"},"typed_custom_fields":{"type":"json","required":false,"visibility":"user-or-llm","description":"Custom field values keyed by custom field ID"},"run_dedupe":{"type":"boolean","required":false,"visibility":"user-only","description":"When true, Apollo deduplicates against existing contacts"}}},"apollo_contact_search":{"id":"apollo_contact_search","name":"Apollo Search Contacts","description":"Search your team\'s contacts in Apollo","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"q_keywords":{"type":"string","required":false,"visibility":"user-or-llm","description":"Keywords to search for"},"contact_stage_ids":{"type":"array","required":false,"visibility":"user-only","description":"Filter by contact stage IDs"},"contact_label_ids":{"type":"array","required":false,"visibility":"user-only","description":"Filter by Apollo label IDs (lists)"},"sort_by_field":{"type":"string","required":false,"visibility":"user-only","description":"Sort field: contact_last_activity_date, contact_email_last_opened_at, contact_email_last_clicked_at, contact_created_at, or contact_updated_at"},"sort_ascending":{"type":"boolean","required":false,"visibility":"user-only","description":"When true, sort ascending. Must be used together with sort_by_field"},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number for pagination (e.g., 1, 2, 3)"},"per_page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Results per page, max 100 (e.g., 25, 50, 100)"}}},"apollo_contact_update":{"id":"apollo_contact_update","name":"Apollo Update Contact","description":"Update an existing contact in your Apollo database","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"contact_id":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the contact to update (e.g., \\"con_abc123\\")"},"first_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"First name of the contact"},"last_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Last name of the contact"},"email":{"type":"string","required":false,"visibility":"user-or-llm","description":"Email address"},"title":{"type":"string","required":false,"visibility":"user-or-llm","description":"Job title (e.g., \\"VP of Sales\\", \\"Software Engineer\\")"},"account_id":{"type":"string","required":false,"visibility":"user-or-llm","description":"Apollo account ID (e.g., \\"acc_abc123\\")"},"owner_id":{"type":"string","required":false,"visibility":"user-only","description":"User ID of the contact owner (accepted by Apollo but not officially documented for PATCH /contacts/{id})"},"organization_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Name of the contact\'s employer (e.g., \\"Apollo\\")"},"website_url":{"type":"string","required":false,"visibility":"user-or-llm","description":"Corporate website URL (e.g., \\"https://www.apollo.io/\\")"},"label_names":{"type":"array","required":false,"visibility":"user-or-llm","description":"Lists/labels to add the contact to (e.g., [\\"Prospects\\"])"},"contact_stage_id":{"type":"string","required":false,"visibility":"user-or-llm","description":"Apollo ID for the contact stage"},"present_raw_address":{"type":"string","required":false,"visibility":"user-or-llm","description":"Personal location for the contact (e.g., \\"Atlanta, United States\\")"},"direct_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Primary phone number"},"corporate_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Work/office phone number"},"mobile_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Mobile phone number"},"home_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Home phone number"},"other_phone":{"type":"string","required":false,"visibility":"user-or-llm","description":"Alternative phone number"},"typed_custom_fields":{"type":"json","required":false,"visibility":"user-or-llm","description":"Custom field values keyed by custom field ID"}}},"apollo_email_accounts":{"id":"apollo_email_accounts","name":"Apollo Get Email Accounts","description":"Get list of team\'s linked email accounts in Apollo","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"}}},"apollo_opportunity_create":{"id":"apollo_opportunity_create","name":"Apollo Create Opportunity","description":"Create a new deal for an account in your Apollo database (master key required)","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the opportunity/deal (e.g., \\"Enterprise License - Q1\\")"},"account_id":{"type":"string","required":false,"visibility":"user-or-llm","description":"ID of the account this opportunity belongs to (e.g., \\"acc_abc123\\")"},"amount":{"type":"string","required":false,"visibility":"user-or-llm","description":"Monetary value as a plain number string with no commas or currency symbols"},"opportunity_stage_id":{"type":"string","required":false,"visibility":"user-only","description":"ID of the opportunity stage"},"owner_id":{"type":"string","required":false,"visibility":"user-only","description":"User ID of the opportunity owner"},"closed_date":{"type":"string","required":false,"visibility":"user-or-llm","description":"Expected close date in YYYY-MM-DD format"},"typed_custom_fields":{"type":"json","required":false,"visibility":"user-only","description":"Custom field values as { custom_field_id: value } map"}}},"apollo_opportunity_get":{"id":"apollo_opportunity_get","name":"Apollo Get Opportunity","description":"Retrieve complete details of a specific deal/opportunity by ID","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"opportunity_id":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the opportunity to retrieve (e.g., \\"opp_abc123\\")"}}},"apollo_opportunity_search":{"id":"apollo_opportunity_search","name":"Apollo Search Opportunities","description":"Search and list all deals/opportunities in your team\'s Apollo account","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"sort_by_field":{"type":"string","required":false,"visibility":"user-or-llm","description":"Sort field: \\"amount\\", \\"is_closed\\", or \\"is_won\\""},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number for pagination (e.g., 1, 2, 3)"},"per_page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Results per page, max 100 (e.g., 25, 50, 100)"}}},"apollo_opportunity_update":{"id":"apollo_opportunity_update","name":"Apollo Update Opportunity","description":"Update an existing deal/opportunity in your Apollo database","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"opportunity_id":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the opportunity to update (e.g., \\"opp_abc123\\")"},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Name of the opportunity/deal (e.g., \\"Enterprise License - Q1\\")"},"amount":{"type":"string","required":false,"visibility":"user-or-llm","description":"Monetary value as a plain number string with no commas or currency symbols"},"opportunity_stage_id":{"type":"string","required":false,"visibility":"user-only","description":"ID of the opportunity stage"},"owner_id":{"type":"string","required":false,"visibility":"user-only","description":"User ID of the opportunity owner"},"closed_date":{"type":"string","required":false,"visibility":"user-or-llm","description":"Expected close date in YYYY-MM-DD format"},"typed_custom_fields":{"type":"json","required":false,"visibility":"user-only","description":"Custom field values as { custom_field_id: value } map"}}},"apollo_organization_bulk_enrich":{"id":"apollo_organization_bulk_enrich","name":"Apollo Bulk Organization Enrichment","description":"Enrich data for up to 10 organizations at once using Apollo","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"domains":{"type":"array","required":true,"visibility":"user-or-llm","description":"Array of company domains to enrich (max 10, no www. or @, e.g., [\\"apollo.io\\", \\"stripe.com\\"])"}}},"apollo_organization_enrich":{"id":"apollo_organization_enrich","name":"Apollo Organization Enrichment","description":"Enrich data for a single organization using Apollo","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"domain":{"type":"string","required":true,"visibility":"user-or-llm","description":"Company domain (e.g., \\"apollo.io\\", \\"acme.com\\")"}}},"apollo_organization_search":{"id":"apollo_organization_search","name":"Apollo Organization Search","description":"Search Apollo\'s database for companies using filters","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"organization_locations":{"type":"array","required":false,"visibility":"user-or-llm","description":"Company HQ locations (cities, US states, or countries)"},"organization_not_locations":{"type":"array","required":false,"visibility":"user-or-llm","description":"Exclude companies whose HQ is in these locations"},"organization_num_employees_ranges":{"type":"array","required":false,"visibility":"user-or-llm","description":"Employee count ranges as \\"min,max\\" strings (e.g., [\\"1,10\\", \\"250,500\\", \\"10000,20000\\"])"},"q_organization_keyword_tags":{"type":"array","required":false,"visibility":"user-or-llm","description":"Industry or keyword tags"},"q_organization_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Organization name to search for (e.g., \\"Acme\\", \\"TechCorp\\")"},"organization_ids":{"type":"array","required":false,"visibility":"user-or-llm","description":"Apollo organization IDs to include (e.g., [\\"5e66b6381e05b4008c8331b8\\"])"},"q_organization_domains_list":{"type":"array","required":false,"visibility":"user-or-llm","description":"Domain names to filter by (no www. or @, up to 1,000)"},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number for pagination (e.g., 1, 2, 3)"},"per_page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Results per page, max 100 (e.g., 25, 50, 100)"}}},"apollo_people_bulk_enrich":{"id":"apollo_people_bulk_enrich","name":"Apollo Bulk People Enrichment","description":"Enrich data for up to 10 people at once using Apollo","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"people":{"type":"array","required":true,"visibility":"user-or-llm","description":"Array of people to enrich (max 10)"},"reveal_personal_emails":{"type":"boolean","required":false,"visibility":"user-only","description":"Reveal personal email addresses (uses credits)"},"reveal_phone_number":{"type":"boolean","required":false,"visibility":"user-only","description":"Reveal phone numbers (uses credits, requires webhook_url)"},"webhook_url":{"type":"string","required":false,"visibility":"user-only","description":"Webhook URL for async phone number delivery (required when reveal_phone_number is true)"}}},"apollo_people_enrich":{"id":"apollo_people_enrich","name":"Apollo People Enrichment","description":"Enrich data for a single person using Apollo","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"first_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"First name of the person"},"last_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Last name of the person"},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Full name of the person (alternative to first_name/last_name)"},"id":{"type":"string","required":false,"visibility":"user-or-llm","description":"Apollo ID for the person"},"hashed_email":{"type":"string","required":false,"visibility":"user-or-llm","description":"MD5 or SHA-256 hashed email"},"email":{"type":"string","required":false,"visibility":"user-or-llm","description":"Email address of the person"},"organization_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Company name where the person works"},"domain":{"type":"string","required":false,"visibility":"user-or-llm","description":"Company domain (e.g., \\"apollo.io\\", \\"acme.com\\")"},"linkedin_url":{"type":"string","required":false,"visibility":"user-or-llm","description":"LinkedIn profile URL"},"reveal_personal_emails":{"type":"boolean","required":false,"visibility":"user-only","description":"Reveal personal email addresses (uses credits)"},"reveal_phone_number":{"type":"boolean","required":false,"visibility":"user-only","description":"Reveal phone numbers (uses credits, requires webhook_url)"},"webhook_url":{"type":"string","required":false,"visibility":"user-only","description":"Webhook URL for async phone number delivery (required when reveal_phone_number is true)"}}},"apollo_people_search":{"id":"apollo_people_search","name":"Apollo People Search","description":"Search Apollo\'s database for people using demographic filters","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key"},"person_titles":{"type":"array","required":false,"visibility":"user-or-llm","description":"Job titles to search for (e.g., [\\"CEO\\", \\"VP of Sales\\"])"},"include_similar_titles":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Whether to return people with job titles similar to person_titles"},"person_locations":{"type":"array","required":false,"visibility":"user-or-llm","description":"Locations to search in (e.g., [\\"San Francisco, CA\\", \\"New York, NY\\"])"},"person_seniorities":{"type":"array","required":false,"visibility":"user-or-llm","description":"Seniority levels (one of: owner, founder, c_suite, partner, vp, head, director, manager, senior, entry, intern)"},"organization_ids":{"type":"array","required":false,"visibility":"user-or-llm","description":"Apollo organization IDs to filter by (e.g., [\\"5e66b6381e05b4008c8331b8\\"])"},"organization_names":{"type":"array","required":false,"visibility":"user-or-llm","description":"Company names to search within (legacy filter)"},"organization_locations":{"type":"array","required":false,"visibility":"user-or-llm","description":"Headquarters locations of the people\'s current employer (e.g., [\'texas\', \'tokyo\', \'spain\'])"},"q_organization_domains_list":{"type":"array","required":false,"visibility":"user-or-llm","description":"Employer domain names (e.g., [\\"apollo.io\\", \\"microsoft.com\\"]) — up to 1,000, no www. or @"},"organization_num_employees_ranges":{"type":"array","required":false,"visibility":"user-or-llm","description":"Employee count ranges for the person\'s current employer. Each entry is \\"min,max\\" (e.g., [\\"1,10\\", \\"250,500\\", \\"10000,20000\\"])"},"contact_email_status":{"type":"array","required":false,"visibility":"user-or-llm","description":"Email statuses to filter by: \\"verified\\", \\"unverified\\", \\"likely to engage\\", \\"unavailable\\""},"q_keywords":{"type":"string","required":false,"visibility":"user-or-llm","description":"Keywords to search for"},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number for pagination, default 1 (e.g., 1, 2, 3)"},"per_page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Results per page, default 25, max 100 (e.g., 25, 50, 100)"}}},"apollo_sequence_add_contacts":{"id":"apollo_sequence_add_contacts","name":"Apollo Add Contacts to Sequence","description":"Add contacts to an Apollo sequence","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"sequence_id":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the sequence to add contacts to (e.g., \\"seq_abc123\\")"},"contact_ids":{"type":"array","required":false,"visibility":"user-or-llm","description":"Array of contact IDs to add to the sequence (e.g., [\\"con_abc123\\", \\"con_def456\\"]). Either contact_ids or label_names must be provided."},"label_names":{"type":"array","required":false,"visibility":"user-or-llm","description":"Array of label names to identify contacts to add to the sequence. Either contact_ids or label_names must be provided."},"send_email_from_email_account_id":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the email account to send from. Use the Get Email Accounts operation to look this up."},"send_email_from_email_address":{"type":"string","required":false,"visibility":"user-only","description":"Specific email address to send from within the email account."},"sequence_no_email":{"type":"boolean","required":false,"visibility":"user-only","description":"Add contacts even if they have no email address"},"sequence_unverified_email":{"type":"boolean","required":false,"visibility":"user-only","description":"Add contacts with unverified email addresses"},"sequence_job_change":{"type":"boolean","required":false,"visibility":"user-only","description":"Add contacts who recently changed jobs"},"sequence_active_in_other_campaigns":{"type":"boolean","required":false,"visibility":"user-only","description":"Add contacts active in other campaigns"},"sequence_finished_in_other_campaigns":{"type":"boolean","required":false,"visibility":"user-only","description":"Add contacts who finished other campaigns"},"sequence_same_company_in_same_campaign":{"type":"boolean","required":false,"visibility":"user-only","description":"Add contacts even if others from the same company are in the sequence"},"contacts_without_ownership_permission":{"type":"boolean","required":false,"visibility":"user-only","description":"Add contacts without ownership permission"},"add_if_in_queue":{"type":"boolean","required":false,"visibility":"user-only","description":"Add contacts even if they are in the queue"},"contact_verification_skipped":{"type":"boolean","required":false,"visibility":"user-only","description":"Skip contact verification when adding"},"user_id":{"type":"string","required":false,"visibility":"user-only","description":"ID of the user performing the action"},"status":{"type":"string","required":false,"visibility":"user-only","description":"Initial status for added contacts: \\"active\\" or \\"paused\\""},"auto_unpause_at":{"type":"string","required":false,"visibility":"user-only","description":"ISO 8601 datetime to automatically unpause contacts"}}},"apollo_sequence_search":{"id":"apollo_sequence_search","name":"Apollo Search Sequences","description":"Search for sequences/campaigns in your team\'s Apollo account (master key required)","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"q_name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Search sequences by name (e.g., \\"Outbound Q1\\", \\"Follow-up\\")"},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number for pagination (e.g., 1, 2, 3)"},"per_page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Results per page, max 100 (e.g., 25, 50, 100)"}}},"apollo_task_create":{"id":"apollo_task_create","name":"Apollo Create Task","description":"Create one or more tasks in Apollo (one task per contact_id, master key required)","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"user_id":{"type":"string","required":true,"visibility":"user-or-llm","description":"ID of the Apollo user the task is assigned to"},"contact_ids":{"type":"array","required":true,"visibility":"user-or-llm","description":"Array of contact IDs. One task is created per contact."},"priority":{"type":"string","required":false,"visibility":"user-or-llm","description":"Task priority: \\"high\\", \\"medium\\", or \\"low\\" (defaults to \\"medium\\")"},"due_at":{"type":"string","required":true,"visibility":"user-or-llm","description":"Due date/time in ISO 8601 format (e.g., \\"2024-12-31T23:59:59Z\\")"},"type":{"type":"string","required":true,"visibility":"user-or-llm","description":"Task type: \\"call\\", \\"outreach_manual_email\\", \\"linkedin_step_connect\\", \\"linkedin_step_message\\", \\"linkedin_step_view_profile\\", \\"linkedin_step_interact_post\\", or \\"action_item\\""},"status":{"type":"string","required":true,"visibility":"user-or-llm","description":"Task status: \\"scheduled\\", \\"completed\\", or \\"skipped\\""},"note":{"type":"string","required":false,"visibility":"user-or-llm","description":"Free-form note providing context for the task"}}},"apollo_task_search":{"id":"apollo_task_search","name":"Apollo Search Tasks","description":"Search for tasks in Apollo","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Apollo API key (master key required)"},"sort_by_field":{"type":"string","required":false,"visibility":"user-or-llm","description":"Sort field: \\"task_due_at\\" or \\"task_priority\\""},"open_factor_names":{"type":"array","required":false,"visibility":"user-or-llm","description":"Filter by status. Common values: [\\"task_types\\"] for open tasks, [\\"task_completed_at\\"] for completed tasks."},"page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Page number for pagination (e.g., 1, 2, 3)"},"per_page":{"type":"number","required":false,"visibility":"user-or-llm","description":"Results per page, max 100 (e.g., 25, 50, 100)"}}},"appconfig_create_application":{"id":"appconfig_create_application","name":"AppConfig Create Application","description":"Create an application in AWS AppConfig","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the application to create"},"description":{"type":"string","required":false,"visibility":"user-or-llm","description":"Description of the application"}}},"appconfig_create_configuration_profile":{"id":"appconfig_create_configuration_profile","name":"AppConfig Create Configuration Profile","description":"Create a configuration profile in an AWS AppConfig application","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID to create the configuration profile in"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the configuration profile"},"locationUri":{"type":"string","required":true,"visibility":"user-or-llm","description":"Where the configuration is stored. Use \\"hosted\\" for AppConfig-hosted configurations, or an SSM/S3 URI"},"description":{"type":"string","required":false,"visibility":"user-or-llm","description":"Description of the configuration profile"},"retrievalRoleArn":{"type":"string","required":false,"visibility":"user-or-llm","description":"ARN of an IAM role to retrieve the configuration (required for non-hosted URIs)"},"type":{"type":"string","required":false,"visibility":"user-or-llm","description":"Profile type: AWS.Freeform (default) or AWS.AppConfig.FeatureFlags"}}},"appconfig_create_environment":{"id":"appconfig_create_environment","name":"AppConfig Create Environment","description":"Create an environment for an AWS AppConfig application","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID to create the environment in"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the environment to create"},"description":{"type":"string","required":false,"visibility":"user-or-llm","description":"Description of the environment"}}},"appconfig_create_hosted_configuration_version":{"id":"appconfig_create_hosted_configuration_version","name":"AppConfig Create Hosted Configuration Version","description":"Create a new hosted configuration version for an AppConfig configuration profile","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the configuration profile"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID to add the version to"},"content":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration content (e.g., a JSON or YAML document)"},"contentType":{"type":"string","required":true,"visibility":"user-or-llm","description":"Content type of the configuration (e.g., application/json, text/plain)"},"description":{"type":"string","required":false,"visibility":"user-or-llm","description":"Description of the configuration version"},"latestVersionNumber":{"type":"number","required":false,"visibility":"user-or-llm","description":"The version number of the latest version, used for optimistic concurrency"},"versionLabel":{"type":"string","required":false,"visibility":"user-or-llm","description":"A user-defined label for the configuration version"}}},"appconfig_delete_application":{"id":"appconfig_delete_application","name":"AppConfig Delete Application","description":"Delete an AWS AppConfig application","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID to delete"}}},"appconfig_delete_configuration_profile":{"id":"appconfig_delete_configuration_profile","name":"AppConfig Delete Configuration Profile","description":"Delete an AWS AppConfig configuration profile","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the configuration profile"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID to delete"}}},"appconfig_delete_environment":{"id":"appconfig_delete_environment","name":"AppConfig Delete Environment","description":"Delete an AWS AppConfig environment","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the environment"},"environmentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The environment ID to delete"}}},"appconfig_delete_hosted_configuration_version":{"id":"appconfig_delete_hosted_configuration_version","name":"AppConfig Delete Hosted Configuration Version","description":"Delete a specific hosted configuration version from an AppConfig profile","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the configuration profile"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID that owns the version"},"versionNumber":{"type":"number","required":true,"visibility":"user-or-llm","description":"The version number to delete"}}},"appconfig_get_application":{"id":"appconfig_get_application","name":"AppConfig Get Application","description":"Get details about a single AWS AppConfig application","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID to retrieve"}}},"appconfig_get_configuration":{"id":"appconfig_get_configuration","name":"AppConfig Get Configuration","description":"Retrieve the latest deployed configuration for an AppConfig application, environment, and profile","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID or name to retrieve configuration for"},"environmentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The environment ID or name to retrieve configuration for"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID or name to retrieve"}}},"appconfig_get_configuration_profile":{"id":"appconfig_get_configuration_profile","name":"AppConfig Get Configuration Profile","description":"Get details about a single AWS AppConfig configuration profile","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the configuration profile"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID to retrieve"}}},"appconfig_get_deployment":{"id":"appconfig_get_deployment","name":"AppConfig Get Deployment","description":"Get details about a specific AWS AppConfig deployment","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID of the deployment"},"environmentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The environment ID of the deployment"},"deploymentNumber":{"type":"number","required":true,"visibility":"user-or-llm","description":"The sequence number of the deployment"}}},"appconfig_get_environment":{"id":"appconfig_get_environment","name":"AppConfig Get Environment","description":"Get details about a single AWS AppConfig environment","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the environment"},"environmentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The environment ID to retrieve"}}},"appconfig_get_hosted_configuration_version":{"id":"appconfig_get_hosted_configuration_version","name":"AppConfig Get Hosted Configuration Version","description":"Retrieve a specific hosted configuration version from an AppConfig profile","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the configuration profile"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID to read the version from"},"versionNumber":{"type":"number","required":true,"visibility":"user-or-llm","description":"The version number to retrieve"}}},"appconfig_list_applications":{"id":"appconfig_list_applications","name":"AppConfig List Applications","description":"List applications in AWS AppConfig","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"maxResults":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of applications to return (1-50)"},"nextToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token from a previous response"}}},"appconfig_list_configuration_profiles":{"id":"appconfig_list_configuration_profiles","name":"AppConfig List Configuration Profiles","description":"List configuration profiles for an AWS AppConfig application","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the configuration profiles"},"maxResults":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of configuration profiles to return (1-50)"},"nextToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token from a previous response"}}},"appconfig_list_deployment_strategies":{"id":"appconfig_list_deployment_strategies","name":"AppConfig List Deployment Strategies","description":"List deployment strategies available in AWS AppConfig","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"maxResults":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of deployment strategies to return (1-50)"},"nextToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token from a previous response"}}},"appconfig_list_deployments":{"id":"appconfig_list_deployments","name":"AppConfig List Deployments","description":"List deployments for an AWS AppConfig environment","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID of the deployments"},"environmentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The environment ID of the deployments"},"maxResults":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of deployments to return (1-50)"},"nextToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token from a previous response"}}},"appconfig_list_environments":{"id":"appconfig_list_environments","name":"AppConfig List Environments","description":"List environments for an AWS AppConfig application","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the environments"},"maxResults":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of environments to return (1-50)"},"nextToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token from a previous response"}}},"appconfig_list_hosted_configuration_versions":{"id":"appconfig_list_hosted_configuration_versions","name":"AppConfig List Hosted Configuration Versions","description":"List hosted configuration versions for an AWS AppConfig configuration profile","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the configuration profile"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID to list versions for"},"maxResults":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of versions to return (1-50)"},"nextToken":{"type":"string","required":false,"visibility":"user-or-llm","description":"Pagination token from a previous response"}}},"appconfig_start_deployment":{"id":"appconfig_start_deployment","name":"AppConfig Start Deployment","description":"Start deploying a configuration version to an AWS AppConfig environment","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID to deploy in"},"environmentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The environment ID to deploy to"},"deploymentStrategyId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The deployment strategy ID to use"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID to deploy"},"configurationVersion":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration version to deploy"},"description":{"type":"string","required":false,"visibility":"user-or-llm","description":"Description of the deployment"}}},"appconfig_stop_deployment":{"id":"appconfig_stop_deployment","name":"AppConfig Stop Deployment","description":"Stop an in-progress AWS AppConfig deployment","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID of the deployment"},"environmentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The environment ID of the deployment"},"deploymentNumber":{"type":"number","required":true,"visibility":"user-or-llm","description":"The sequence number of the deployment to stop"}}},"appconfig_update_application":{"id":"appconfig_update_application","name":"AppConfig Update Application","description":"Update the name or description of an AWS AppConfig application","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID to update"},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"New name for the application"},"description":{"type":"string","required":false,"visibility":"user-or-llm","description":"New description for the application"}}},"appconfig_update_configuration_profile":{"id":"appconfig_update_configuration_profile","name":"AppConfig Update Configuration Profile","description":"Update the name, description, or retrieval role of an AppConfig configuration profile","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the configuration profile"},"configurationProfileId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The configuration profile ID to update"},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"New name for the configuration profile"},"description":{"type":"string","required":false,"visibility":"user-or-llm","description":"New description for the configuration profile"},"retrievalRoleArn":{"type":"string","required":false,"visibility":"user-or-llm","description":"New ARN of the IAM role used to retrieve the configuration"}}},"appconfig_update_environment":{"id":"appconfig_update_environment","name":"AppConfig Update Environment","description":"Update the name or description of an AWS AppConfig environment","version":"1.0","params":{"region":{"type":"string","required":true,"visibility":"user-only","description":"AWS region (e.g., us-east-1)"},"accessKeyId":{"type":"string","required":true,"visibility":"user-only","description":"AWS access key ID"},"secretAccessKey":{"type":"string","required":true,"visibility":"user-only","description":"AWS secret access key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The application ID that owns the environment"},"environmentId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The environment ID to update"},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"New name for the environment"},"description":{"type":"string","required":false,"visibility":"user-or-llm","description":"New description for the environment"}}},"arxiv_get_author_papers":{"id":"arxiv_get_author_papers","name":"ArXiv Get Author Papers","description":"Search for papers by a specific author on ArXiv.","version":"1.0.0","params":{"authorName":{"type":"string","required":true,"visibility":"user-or-llm","description":"Author name to search for"},"maxResults":{"type":"number","required":false,"visibility":"user-only","description":"Maximum number of results to return (default: 10, max: 2000)"}}},"arxiv_get_paper":{"id":"arxiv_get_paper","name":"ArXiv Get Paper","description":"Get detailed information about a specific ArXiv paper by its ID.","version":"1.0.0","params":{"paperId":{"type":"string","required":true,"visibility":"user-or-llm","description":"ArXiv paper ID (e.g., \\"1706.03762\\")"}}},"arxiv_search":{"id":"arxiv_search","name":"ArXiv Search","description":"Search for academic papers on ArXiv by keywords, authors, titles, or other fields.","version":"1.0.0","params":{"searchQuery":{"type":"string","required":true,"visibility":"user-or-llm","description":"The search query to execute"},"searchField":{"type":"string","required":false,"visibility":"user-only","description":"Field to search in: all, ti (title), au (author), abs (abstract), co (comment), jr (journal), cat (category), rn (report number)"},"maxResults":{"type":"number","required":false,"visibility":"user-only","description":"Maximum number of results to return (default: 10, max: 2000)"},"sortBy":{"type":"string","required":false,"visibility":"user-only","description":"Sort by: relevance, lastUpdatedDate, submittedDate (default: relevance)"},"sortOrder":{"type":"string","required":false,"visibility":"user-only","description":"Sort order: ascending, descending (default: descending)"}}},"asana_add_comment":{"id":"asana_add_comment","name":"Asana Add Comment","description":"Add a comment (story) to an Asana task","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"taskGid":{"type":"string","required":true,"visibility":"user-or-llm","description":"Asana task GID (numeric string)"},"text":{"type":"string","required":true,"visibility":"user-or-llm","description":"The text content of the comment"}},"oauth":{"required":true,"provider":"asana"}},"asana_add_followers":{"id":"asana_add_followers","name":"Asana Add Followers","description":"Add one or more followers to an Asana task","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"taskGid":{"type":"string","required":true,"visibility":"user-or-llm","description":"GID of the Asana task (numeric string)"},"followers":{"type":"array","required":true,"visibility":"user-or-llm","description":"Array of user GIDs to add as followers to the task"}},"oauth":{"required":true,"provider":"asana"}},"asana_create_project":{"id":"asana_create_project","name":"Asana Create Project","description":"Create a new project in an Asana workspace","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"workspace":{"type":"string","required":true,"visibility":"user-or-llm","description":"Asana workspace GID (numeric string) where the project will be created"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the project"},"notes":{"type":"string","required":false,"visibility":"user-or-llm","description":"Notes or description for the project"}},"oauth":{"required":true,"provider":"asana"}},"asana_create_section":{"id":"asana_create_section","name":"Asana Create Section","description":"Create a new section in an Asana project","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"projectGid":{"type":"string","required":true,"visibility":"user-or-llm","description":"GID of the Asana project (numeric string) to add the section to"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the section"}},"oauth":{"required":true,"provider":"asana"}},"asana_create_subtask":{"id":"asana_create_subtask","name":"Asana Create Subtask","description":"Create a subtask under an existing Asana task","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"taskGid":{"type":"string","required":true,"visibility":"user-or-llm","description":"GID of the parent Asana task (numeric string)"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the subtask"},"notes":{"type":"string","required":false,"visibility":"user-or-llm","description":"Notes or description for the subtask"},"assignee":{"type":"string","required":false,"visibility":"user-or-llm","description":"User GID to assign the subtask to"},"due_on":{"type":"string","required":false,"visibility":"user-or-llm","description":"Due date in YYYY-MM-DD format"}},"oauth":{"required":true,"provider":"asana"}},"asana_create_task":{"id":"asana_create_task","name":"Asana Create Task","description":"Create a new task in Asana","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"workspace":{"type":"string","required":true,"visibility":"user-or-llm","description":"Asana workspace GID (numeric string) where the task will be created"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"Name of the task"},"notes":{"type":"string","required":false,"visibility":"user-or-llm","description":"Notes or description for the task"},"assignee":{"type":"string","required":false,"visibility":"user-or-llm","description":"User GID to assign the task to"},"due_on":{"type":"string","required":false,"visibility":"user-or-llm","description":"Due date in YYYY-MM-DD format"}},"oauth":{"required":true,"provider":"asana"}},"asana_delete_task":{"id":"asana_delete_task","name":"Asana Delete Task","description":"Delete an Asana task by its GID (moves it to the trash)","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"taskGid":{"type":"string","required":true,"visibility":"user-or-llm","description":"GID of the Asana task to delete (numeric string)"}},"oauth":{"required":true,"provider":"asana"}},"asana_get_project":{"id":"asana_get_project","name":"Asana Get Project","description":"Retrieve a single Asana project by its GID","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"projectGid":{"type":"string","required":true,"visibility":"user-or-llm","description":"Asana project GID (numeric string) to retrieve"}},"oauth":{"required":true,"provider":"asana"}},"asana_get_projects":{"id":"asana_get_projects","name":"Asana Get Projects","description":"Retrieve all projects from an Asana workspace","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"workspace":{"type":"string","required":true,"visibility":"user-or-llm","description":"Asana workspace GID (numeric string) to retrieve projects from"}},"oauth":{"required":true,"provider":"asana"}},"asana_get_task":{"id":"asana_get_task","name":"Asana Get Task","description":"Retrieve a single task by GID or get multiple tasks with filters","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"taskGid":{"type":"string","required":false,"visibility":"user-or-llm","description":"The globally unique identifier (GID) of the task. If not provided, will get multiple tasks."},"workspace":{"type":"string","required":false,"visibility":"user-or-llm","description":"Asana workspace GID (numeric string) to filter tasks (required when not using taskGid)"},"project":{"type":"string","required":false,"visibility":"user-or-llm","description":"Asana project GID (numeric string) to filter tasks"},"limit":{"type":"number","required":false,"visibility":"user-or-llm","description":"Maximum number of tasks to return (default: 50)"}},"oauth":{"required":true,"provider":"asana"}},"asana_list_sections":{"id":"asana_list_sections","name":"Asana List Sections","description":"List all sections in an Asana project","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"projectGid":{"type":"string","required":true,"visibility":"user-or-llm","description":"GID of the Asana project (numeric string) to list sections from"}},"oauth":{"required":true,"provider":"asana"}},"asana_list_workspaces":{"id":"asana_list_workspaces","name":"Asana List Workspaces","description":"List all Asana workspaces and organizations the authenticated user belongs to","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"}},"oauth":{"required":true,"provider":"asana"}},"asana_search_tasks":{"id":"asana_search_tasks","name":"Asana Search Tasks","description":"Search for tasks in an Asana workspace","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"workspace":{"type":"string","required":true,"visibility":"user-or-llm","description":"Asana workspace GID (numeric string) to search tasks in"},"text":{"type":"string","required":false,"visibility":"user-or-llm","description":"Text to search for in task names"},"assignee":{"type":"string","required":false,"visibility":"user-or-llm","description":"Filter tasks by assignee user GID"},"projects":{"type":"array","required":false,"visibility":"user-or-llm","description":"Array of Asana project GIDs (numeric strings) to filter tasks by"},"completed":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Filter by completion status"}},"oauth":{"required":true,"provider":"asana"}},"asana_update_task":{"id":"asana_update_task","name":"Asana Update Task","description":"Update an existing task in Asana","version":"1.0.0","params":{"accessToken":{"type":"string","required":true,"visibility":"hidden","description":"OAuth access token for Asana"},"taskGid":{"type":"string","required":true,"visibility":"user-or-llm","description":"Asana task GID (numeric string) of the task to update"},"name":{"type":"string","required":false,"visibility":"user-or-llm","description":"Updated name for the task"},"notes":{"type":"string","required":false,"visibility":"user-or-llm","description":"Updated notes or description for the task"},"assignee":{"type":"string","required":false,"visibility":"user-or-llm","description":"Updated assignee user GID"},"completed":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Mark task as completed or not completed"},"due_on":{"type":"string","required":false,"visibility":"user-or-llm","description":"Updated due date in YYYY-MM-DD format"}},"oauth":{"required":true,"provider":"asana"}},"ashby_add_candidate_tag":{"id":"ashby_add_candidate_tag","name":"Ashby Add Candidate Tag","description":"Adds a tag to a candidate in Ashby and returns the updated candidate.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ashby API Key"},"candidateId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The UUID of the candidate to add the tag to"},"tagId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The UUID of the tag to add"}}},"ashby_anonymize_candidate":{"id":"ashby_anonymize_candidate","name":"Ashby Anonymize Candidate","description":"Strips personally identifiable information from a candidate in Ashby. This does not delete the candidate - the record and its applications remain, with the PII removed. Ashby exposes no candidate deletion endpoint; true deletion is UI-only, restricted by role, and limited to a 10-day window. Requires the candidatesWrite permission.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ashby API Key"},"candidateId":{"type":"string","required":true,"visibility":"user-or-llm","description":"UUID of the candidate to anonymize"}}},"ashby_change_application_source":{"id":"ashby_change_application_source","name":"Ashby Change Application Source","description":"Changes the source attributed to an existing application, so programmatically created applications report correctly on the recruiting side. Requires the candidatesWrite permission.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ashby API Key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"UUID of the application whose source should change"},"sourceId":{"type":"string","required":false,"visibility":"user-or-llm","description":"UUID of the source to attribute the application to, as returned by List Sources. Omit only when unsetSource is true."},"unsetSource":{"type":"boolean","required":false,"visibility":"user-or-llm","description":"Set true to deliberately clear the application source. Required to unset, so that a missing or empty sourceId cannot wipe attribution by accident."}}},"ashby_change_application_stage":{"id":"ashby_change_application_stage","name":"Ashby Change Application Stage","description":"Moves an application to a different interview stage. Requires an archive reason when moving to an Archived stage.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ashby API Key"},"applicationId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The UUID of the application to update the stage of"},"interviewStageId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The UUID of the interview stage to move the application to"},"archiveReasonId":{"type":"string","required":false,"visibility":"user-or-llm","description":"Archive reason UUID. Required when moving to an Archived stage, ignored otherwise"}}},"ashby_create_application":{"id":"ashby_create_application","name":"Ashby Create Application","description":"Creates a new application for a candidate on a job. Optionally specify interview plan, stage, source, and credited user.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ashby API Key"},"candidateId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The UUID of the candidate to consider for the job"},"jobId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The UUID of the job to consider the candidate for"},"interviewPlanId":{"type":"string","required":false,"visibility":"user-or-llm","description":"UUID of the interview plan to use (defaults to the job default plan)"},"interviewStageId":{"type":"string","required":false,"visibility":"user-or-llm","description":"UUID of the interview stage to place the application in (defaults to first Lead stage)"},"sourceId":{"type":"string","required":false,"visibility":"user-or-llm","description":"UUID of the source to set on the application"},"creditedToUserId":{"type":"string","required":false,"visibility":"user-or-llm","description":"UUID of the user the application is credited to"},"createdAt":{"type":"string","required":false,"visibility":"user-or-llm","description":"ISO 8601 timestamp to set as the application creation date (defaults to now)"}}},"ashby_create_candidate":{"id":"ashby_create_candidate","name":"Ashby Create Candidate","description":"Creates a new candidate record in Ashby.","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ashby API Key"},"name":{"type":"string","required":true,"visibility":"user-or-llm","description":"The candidate full name"},"email":{"type":"string","required":false,"visibility":"user-or-llm","description":"Primary email address for the candidate"},"phoneNumber":{"type":"string","required":false,"visibility":"user-or-llm","description":"Primary phone number for the candidate"},"linkedInUrl":{"type":"string","required":false,"visibility":"user-or-llm","description":"LinkedIn profile URL"},"githubUrl":{"type":"string","required":false,"visibility":"user-or-llm","description":"GitHub profile URL"},"website":{"type":"string","required":false,"visibility":"user-or-llm","description":"Personal website URL"},"sourceId":{"type":"string","required":false,"visibility":"user-or-llm","description":"UUID of the source to attribute the candidate to"},"creditedToUserId":{"type":"string","required":false,"visibility":"user-or-llm","description":"UUID of the Ashby user to credit with sourcing this candidate"},"createdAt":{"type":"string","required":false,"visibility":"user-or-llm","description":"Backdated creation timestamp in ISO 8601 (e.g. 2024-01-01T00:00:00Z). Defaults to now."},"alternateEmailAddresses":{"type":"json","required":false,"visibility":"user-or-llm","description":"Array of additional email address strings to add to the candidate, e.g. [\\"a@x.com\\",\\"b@y.com\\"]"}}},"ashby_create_note":{"id":"ashby_create_note","name":"Ashby Create Note","description":"Creates a note on a candidate in Ashby. Supports plain text and HTML content (bold, italic, underline, links, lists, code).","version":"1.0.0","params":{"apiKey":{"type":"string","required":true,"visibility":"user-only","description":"Ashby API Key"},"candidateId":{"type":"string","required":true,"visibility":"user-or-llm","description":"The UUID of the candidate to add the note to"},"note":{"type":"string","required":true,"visibility":"user-or-llm","description":"The note content. If noteType is text/html, supports: , , , ,