Senja MCP Server
A Senja MCP server/CLI that exposes 12 tools for reading, importing, approving, tagging, deleting and exporting testimonials, reading project links, sending form invites, inspecting schemas, reviewing/executing ordered batches, and listing local account profiles.
Read testimonials:
list_testimonials(one native page with query, tags, rating, type, integration, approval, language, sort/order, pagination) andget_testimonial(one exact record with video metadata and links).Import a testimonial:
create_testimonialfor authorized text/video statements with customer fields, rating, tags, media, URLs and optional publish approval (requires confirmation).Update approval or tags:
update_testimonialto set approved status and add/remove tags only (text, rating and customer edits stay dashboard-only).Delete a testimonial:
delete_testimonialpermanently removes one exact record (irreversible, confirmation required).Read project links:
list_linksreturns native form, widget, Wall of Love, quick-link, case-study and sizzle-reel groups with IDs and URLs.Send form invites:
send_invitesemails up to 100 recipients per request through a selected form's existing follow-up sequence (confirmation required; local cap, not a native quota).List accounts:
list_accountsshows local profile labels, default and auth method only — no keys, token paths or network calls.Inspect operation schemas:
get_operation_schemareturns the reviewed method/path/query/body schema and provenance for a supported native tool, without credentials or provider requests.Preview batches:
preview_testimonial_batchlocally validates and SHA-256 hashes 1–20 ordered create/update/delete/invite tasks with no network calls or key loading.Execute reviewed batches:
submit_testimonial_batchprevalidates and sequentially runs the exact hashed task list, stopping at the first failure with known results, failed index and unattempted indices (no retry or rollback).Export testimonials:
export_testimonialspaginates a confirmed GET export into a new exclusive 0600 JSON file with bounded pages/items/bytes and page/offset continuation; never downloads media.Safety controls: explicit
confirmfor mutations/file output,SENJA_READ_ONLYhides and refuses the six write tools,SENJA_ALLOW_DESTRUCTIVE=0blocks effects, named private project profiles with no credential fallback, and optional static audit logging.
Enables managing Senja testimonials attributed to Airbnb as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Amazon as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Discord as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Facebook as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Fiverr as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Google as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Instagram as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Reddit as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Shopify as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Skillshare as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Slack as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to SourceForge as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Telegram as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to TikTok as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Trustpilot as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Udemy as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to WhatsApp as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to WordPress as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Yelp as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to YouTube as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Enables managing Senja testimonials attributed to Zillow as their source, including listing, creating, filtering, updating approval/tags, and exporting.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Senja MCP Serverlist my latest testimonials and approve the ones from clients"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Senja MCP Server & CLI
Senja MCP server and CLI for Codex and AI agents. 12 shared tools for current testimonials and invites, isolated private projects, exact reviewed tasks and bounded exports.
One package supplies both task CLI commands and local MCP tools, with a bundled Claude Desktop extension. Built and maintained by Navid Moazzez. Full setup is on navid.me.
This native terminal illustrates shipped tool names; it is not a recording of real customer messages. Use a private intended-project API key. Account features and email delivery remain subject to Senja. Official hosted MCP already supports search, links and invites; our local task workflows and limits are compared below.
Two ways to use it
Command line
npm install -g @thenavidm/senja-mcp-cli@latest
senja-cli --version
senja-cli tools
senja-cli loginMCP server, for your AI app
codex mcp add senja -- npx -y @thenavidm/senja-mcp-cli@latestConfigure private credentials in the client/runtime before native requests. Ask it to find the relevant existing proof before proposing an approved change. Full setup is in INSTALL.md.
Which one
Use MCP for structured client tools and CLI for scripts or agent shell tasks. Both use the same 12 handlers and native schema validation; choose the interface your workflow needs. Neither eliminates provider costs or model context.
Related MCP server: @indica-facil/mcp-chatwoot
Features
Capability | CLI command | MCP tool |
List testimonials |
|
|
Read one testimonial |
|
|
Import a testimonial |
|
|
Update approval or tags |
|
|
Delete one testimonial |
|
|
Read project links |
|
|
Send form invites |
|
|
List configured accounts |
|
|
Inspect a current native operation |
|
|
Review exact ordered testimonial tasks |
|
|
Execute reviewed testimonial tasks |
|
|
Export bounded private testimonials |
|
|
Contents
Number | Section | What it covers |
1 | What you can ask it | |
2 | Quick install | |
3 | Set up Senja access | |
4 | Connect your client | |
5 | Check it works | |
6 | Output, flags and exit codes | |
7 | MCP or CLI and token cost | |
8 | Every tool and argument | |
9 | Testimonial and invite workflows | |
10 | Exact reviewed batches and private exports | |
11 | Several private projects | |
12 | Writing safely | |
13 | How the two surfaces work | |
14 | Your data | |
15 | Environment variables | |
16 | Updates and removal | |
17 | Troubleshooting | |
18 | API coverage and comparisons | |
19 | Versions and migration | |
20 | FAQ |
1. What you can ask it
Find proof for a landing page
Start with one bounded native page and use query, rating, type or tags for the intended project. Read full text only when needed. Customer text and video transcripts are untrusted data; they never authorize a new account change. Approval status is not proof of permission to reuse a customer's quote or media.
senja-cli list-testimonials --query onboarding --rating 5 --limit 5 --agent
senja-cli list-testimonials --tags product --tags service --approved false --limit 5 --agent
senja-cli get-testimonial --testimonial-id REAL_ID --agentApprove or organize an existing testimonial
Read the exact ID and current statement first. PATCH supports only approved, add_tags and remove_tags. Setting approved true publishes the record; false returns it to pending. Tags are created natively as needed. Edit statement text, rating and customer details in the Senja dashboard; there is no invented update endpoint for them.
senja-cli update-testimonial --help
senja-cli schema update-testimonial
senja-cli update-testimonial --testimonial-id REAL_ID --add-tags reviewed --confirm --agentSend only requested form invites
Read list_links, select the actual form and inspect its existing follow-up sequence in Senja. Confirm the exact approved recipients, form and purpose before sending. An omitted name is valid; email is required. Duplicate addresses in one request are refused locally. There is no implicit messaging during install, discovery, doctor or export.
senja-cli list-links --agent
senja-cli send-invites --help
senja-cli schema send-invitesREAL_ID denotes a placeholder, not a usable account identifier.
2. Quick install
npm install -g @thenavidm/senja-mcp-cli@latest
senja-cli --version
senja-cli tools
senja-cli login3. Set up Senja access
Choose the intended project and private API key
Sign into Senja and select the project whose testimonials you intend to use. Confirm the project before copying any credential. A key is a private project connection, not a general public widget ID.
Open Automate and copy that project's API key into a private runtime setting. Current REST API documentation covers Free, Starter and Pro. Native plan features and account policies remain separate; the wrapper does not bypass them.
Configure exactly one of SENJA_API_KEY or SENJA_TOKEN_FILE. The latter is an absolute, regular, non-symlink, token-only file outside repositories, at most 64 KiB. The client sends Authorization: Bearer; do not prefix the setting with Bearer or use your login password.
On macOS/Linux restrict the file to your owner with mode 0600 and its parent directory to your owner. On Windows restrict file and parent-directory ACLs separately. POSIX modes do not establish Windows privacy. Each server runtime must be able to read its own file; a GUI, Docker or remote host does not inherit a different terminal's environment automatically.
Run senja-cli doctor for local configuration. When you deliberately want an authenticated read, run doctor --network: it requests GET /testimonials?limit=1 and prints count/verification metadata, not customer records. This proves one project read, not ownership, permission for every endpoint, successful email delivery or an approved mutation.
The package does not load .env files, import browser cookies, create keys, connect OAuth or rotate credentials. login prints these setup instructions only. Keep resolved secrets out of code, screenshots, public issues, version control and AI prompts.
Project profiles and revocation
SENJA_ACCOUNTS is a private JSON array of unique {name,api_key,token_file} profiles. Use one credential method per profile. SENJA_DEFAULT_ACCOUNT selects the default label and --account selects an exact label. An incomplete named profile never inherits a global key, another project or an official hosted session after a missing credential or 401/403.
list_accounts returns labels/default/auth/source only, without keys, token paths, native project identity or network traffic. Token-only files cache until restart. Changing a file while a process is running does not rotate its cached connection.
To revoke a key, use the intended project's Automate > Regenerate API Key as its Admin/Owner, update every dependent private integration and restart its processes. The provider says the old key stops working after a short transition. Official hosted MCP authorization is a separate connection. Removing this package does not undo testimonial edits, publish approval, permanent deletion, emailed invites, follow-up sequences or existing exports.
Effects and local limits
There is no universal provider quota invented here. Local spacing defaults to 250 ms and request timeout 30 seconds; other processes share native project quotas. Bodies cap at 1 MiB and responses at 5 MiB. No automatic retry, redirect following or media download occurs. A failed write can have an unknown outcome; inspect native state before any explicit repeat.
send_invites uses a real forms[].id from list_links and that form's existing email/follow-up sequence. It is not a local draft, arbitrary email editor or test-send command. Its local 100-recipient cap is not a documented native quota. Receipt sent/skipped values do not prove delivered messages or consent. Only send to the actual approved recipients and purpose.
4. Connect your client
Full client, OS, desktop, private credential and runtime instructions are in INSTALL.md.
Codex
Codex is the current validation priority. Private token paths must exist in the process or remote environment where the server runs.
codex mcp add senja -- npx -y @thenavidm/senja-mcp-cli@latest
codex mcp listAccount credentials must reach the server through private environment settings. codex mcp add --env NAME=value stores values in your local config, so never commit that config or put secrets in a shared command. In TOML, the equivalent server is:
[mcp_servers.senja]
command = "npx"
args = ["-y", "@thenavidm/senja-mcp-cli@latest"]
env_vars = ["SENJA_API_KEY", "SENJA_TOKEN_FILE", "SENJA_ACCOUNTS", "SENJA_DEFAULT_ACCOUNT", "SENJA_READ_ONLY", "SENJA_ALLOW_DESTRUCTIVE"]env_vars forwards those names from the environment available to Codex. If that environment does not contain them, configure private env settings locally. Codex can also call the CLI directly with SKILL.md and --agent output.
Claude Code
For a user-scoped connection, after privately configuring credentials:
claude mcp add --scope user senja -- npx -y @thenavidm/senja-mcp-cli@latest
claude mcp listUse the client's private local environment settings for the account variable if they are not inherited. Claude's -e NAME=value registration option writes values into its config; only use it locally through your secret manager, with no shared command transcript. Never place credentials in a project .mcp.json. Reconnect and ask Claude to verify credentials.
Alternatively install the CLI, make SKILL.md available to Claude, and use shell commands. Registering both surfaces is optional.
Claude Desktop
Install the .mcpb extension
Download
senja-2.0.0.mcpbfrom GitHub Releases.In a supported Claude Desktop build, open Settings > Extensions > Advanced settings > Install Extension… and select it.
Enter a private project API key in the sensitive setting, OR an absolute private token-only file path. Leave the unused method empty. Requests use Authorization: Bearer. Named profiles require private manual runtime settings.
Enable read-only if you want only the 6 read operations. Reconnect and verify the intended project with one deliberate read.
The bundle includes production dependencies and no credentials. Use a regular private token-only file if you prefer file-based credentials. The manifest requires Node 22 or newer from a compatible host. Organization policy may restrict custom extensions. Manual bundle updates require installing the new version; no automatic directory updates are promised. GUI installation remains unverified separately from archive/protocol checks.
Manual config
Open Settings > Developer > Edit Config, or use your platform's config file:
OS | Typical config path |
macOS |
|
Windows |
|
Linux |
|
{
"mcpServers": {
"senja": {
"command": "npx",
"args": ["-y", "@thenavidm/senja-mcp-cli@latest"],
"env": {
"SENJA_API_KEY": "YOUR_PRIVATE_API_KEY",
"SENJA_TOKEN_FILE": ""
}
}
}
}Replace the placeholders only in your private file. Merge the server entry into an existing mcpServers object instead of replacing other integrations. Fully quit and reopen Claude Desktop. Do not enable an extension and a manual entry with the same name; choose one route.
If a Windows launcher cannot execute npx directly, use "command": "cmd" with "args": ["/c", "npx", "-y", "@thenavidm/senja-mcp-cli@latest"]. An absolute node executable and installed dist/index.js path also avoids launcher/PATH problems.
Cursor
Use private user settings at ~/.cursor/mcp.json, or Settings > Tools & MCP. Cursor documents environment interpolation and envFile support.
{
"mcpServers": {
"senja": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@thenavidm/senja-mcp-cli@latest"],
"env": {
"SENJA_API_KEY": "${env:SENJA_API_KEY}",
"SENJA_TOKEN_FILE": "${env:SENJA_TOKEN_FILE}"
}
}
}
}The environment values must exist for the Cursor process. If you use envFile, keep that file private and outside version control. A project's .cursor/mcp.json must not contain actual credentials. Reconnect the server after saving.
VS Code and Copilot
Use MCP: Open User Configuration. VS Code uses servers and secure inputs, rather than a mcpServers root:
{
"inputs": [
{"type": "promptString", "id": "senja-api-token", "description": "Senja API key (leave empty for a private token file)", "password": true},
{"type": "promptString", "id": "senja-token-file", "description": "Optional private token-file path (leave empty for API key)"}
],
"servers": {
"senja": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@thenavidm/senja-mcp-cli@latest"],
"env": {
"SENJA_API_KEY": "${input:senja-api-token}",
"SENJA_TOKEN_FILE": "${input:senja-token-file}"
}
}
}
}Start Senja through the MCP controls, approve trust if prompted, and enter credentials in the private input prompts. Workspace .vscode/mcp.json may contain this placeholder-only structure, but never resolved secret values. Remote development runs the server in the selected remote environment, so local file paths refer to that environment.
Windsurf
Open Cascade's MCP settings or edit the private user file ~/.codeium/windsurf/mcp_config.json. Use the Claude Desktop manual mcpServers block above with your locally configured env values. See Windsurf's current MCP documentation. Restart or reconnect Senja in Cascade; project files must not contain secrets.
Zed
Open Settings > AI > MCP Servers > Add Server > Add Local Server, or your user settings file. Zed uses context_servers:
{
"context_servers": {
"senja": {
"command": "npx",
"args": ["-y", "@thenavidm/senja-mcp-cli@latest"],
"env": {
"SENJA_API_KEY": "YOUR_PRIVATE_API_KEY",
"SENJA_TOKEN_FILE": ""
}
}
}
}Enter actual values only in private user settings. Check the active-server indicator before prompting. Do not wrap command and args inside a nested command object from older Zed examples.
Gemini CLI
Merge the Claude Desktop manual mcpServers block into your private ~/.gemini/settings.json. Configure the private credential values locally, then restart Gemini CLI and inspect /mcp. See Gemini CLI's MCP configuration. Its project settings must not contain real credentials. You can instead use the CLI from an agent shell.
Other local stdio clients use the same command and arguments, adapted to their config format. A client that only accepts a remote MCP URL cannot connect directly: this package does not ship a public HTTP listener. ChatGPT's remote connector setup is not a substitute for local stdio installation.
Docker
Build locally from the reviewed source; no prebuilt registry image is claimed:
git clone https://github.com/thenavidm/senja-mcp-cli.git
cd senja-mcp-cli
docker build -t senja-mcp-cli .
docker run --rm -i -e SENJA_API_KEY senja-mcp-cliCline and other local MCP clients
Use the client's Add MCP server flow with command npx, arguments -y and @thenavidm/senja-mcp-cli@latest, stdio transport, and private local SENJA_API_KEY or SENJA_TOKEN_FILE settings. UI names depend on the installed client. Reconnect and discover tools before an account call. Browser-only clients need a remote HTTPS connector; use Senja's official server rather than this local stdio command.
5. Check it works
senja-cli --version
senja-cli tools
senja-cli list-accounts --agent
senja-cli doctor
senja-cli doctor --network
senja-cli list-testimonials --limit 1 --agent --select total,testimonials.idOnly the final two commands intentionally contact Senja. The one-item example may return a private ID; use doctor --network if you only need verification metadata. Never create, approve, delete or email a testimonial merely to test installation. Fixtures/protocol discovery, actual provider outcomes, desktop GUI installation and completed Codex usage measurements are distinct checks.
6. Output, flags and exit codes
senja-cli tools --agent
senja-cli list-testimonials --limit 5 --agent --select total,testimonials.id
senja-cli schema send-invites--agent requests JSON/compact/no-input/no-color/yes formatting, not confirmation. Repeated array flags collect tags; one --recipients or --tasks flag contains one JSON object. Whole native bodies use payload or an absolute regular non-symlink payload_file capped1MiB. Do not mix body methods.
Exit | Meaning |
0 | Success |
2 | Usage, invalid native input or refused effect |
3 | Not found |
4 | Authentication/permission |
5 | Native API error |
7 | Rate limited |
10 | Missing/invalid private configuration |
7. MCP or CLI and token cost
MCP clients can load all schemas, defer discovery, or load selected schemas; the mode changes input overhead. CLI use still needs command/schema discovery and model-readable results. --agent and --select can reduce formatting/output for an appropriate task, but do not prove smaller total cost.
Codex is the current verification client. No completed matched provider task/token comparison has been measured for this release. Record actual model/client/package versions, dates, loading settings, prompt/result sizes, successful equivalent outcomes and API usage before publishing numbers. Do not estimate tokens from characters or reuse another client's measurements. Installed skills may incur recurring listing and one-time reading costs, and caching changes billed cost separately from token counts.
8. Every tool and argument
list_testimonials
Read one native page with exact current search, tag, approval, language and date/rating filters.
Argument | Type | Required | Meaning and constraints |
| string | Optional | Native sort field; direction uses order. {"enum": ["date", "rating"]} |
| string | Optional | {"enum": ["asc", "desc"]} |
| boolean | Optional | Exact native/schema value |
| integer | Optional | {"minimum": 1, "maximum": 5} |
| string | Optional | {"enum": ["text", "video"]} |
| string | Optional | {"enum": ["twitter", "product_hunt", "google", "facebook", "reddit", "capterra", "g2", "linkedin", "app_store", "trustpilot", "shopify", "play_store", "yelp", "slack", "discord", "apple_podcasts", "telegram", "whatsapp", "instagram", "youtube", "tiktok", "appsumo", "amazon", "zillow", "udemy", "chrome_web_store", "airbnb", "skillshare", "realtor", "sourceforge", "whop", "wordpress", "fiverr", "homestars", "web_page"]} |
| array | Optional | {"maxItems": 100} |
| string | Optional | Native full-text search, including customer name/email; output may contain personal data. |
| string | Optional | Native ISO 639 language selector. |
| integer | Optional | Native page size. total counts only the current page. {"minimum": 1, "maximum": 1000} |
| integer | Optional | {"minimum": 1} |
| string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |
senja-cli list-testimonials --help
senja-cli schema list-testimonials{
"type": "object",
"properties": {
"sort": {
"type": "string",
"enum": [
"date",
"rating"
],
"description": "Native sort field; direction uses order."
},
"order": {
"type": "string",
"enum": [
"asc",
"desc"
]
},
"approved": {
"type": "boolean"
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"type": {
"type": "string",
"enum": [
"text",
"video"
]
},
"integration": {
"type": "string",
"enum": [
"twitter",
"product_hunt",
"google",
"facebook",
"reddit",
"capterra",
"g2",
"linkedin",
"app_store",
"trustpilot",
"shopify",
"play_store",
"yelp",
"slack",
"discord",
"apple_podcasts",
"telegram",
"whatsapp",
"instagram",
"youtube",
"tiktok",
"appsumo",
"amazon",
"zillow",
"udemy",
"chrome_web_store",
"airbnb",
"skillshare",
"realtor",
"sourceforge",
"whop",
"wordpress",
"fiverr",
"homestars",
"web_page"
]
},
"tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"query": {
"type": "string",
"minLength": 1,
"description": "Native full-text search, including customer name/email; output may contain personal data.",
"maxLength": 10000
},
"lang": {
"type": "string",
"minLength": 1,
"description": "Native ISO 639 language selector.",
"maxLength": 10
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 1000,
"description": "Native page size. total counts only the current page."
},
"page": {
"type": "integer",
"minimum": 1
},
"account": {
"type": "string",
"description": "Exact configured private account profile label; not a tenant or provider account ID."
}
},
"required": [],
"additionalProperties": false
}Native request: GET /testimonials. No native JSON body.
{
"name": "list_testimonials",
"method": "GET",
"path": "/testimonials",
"title": "List testimonials",
"description": "Read one native page with exact current search, tag, approval, language and date/rating filters.",
"group": "testimonials",
"risk": "read",
"params": [
{
"name": "sort",
"key": "sort",
"schema": {
"type": "string",
"enum": [
"date",
"rating"
],
"description": "Native sort field; direction uses order."
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "order",
"key": "order",
"schema": {
"type": "string",
"enum": [
"asc",
"desc"
]
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "approved",
"key": "approved",
"schema": {
"type": "boolean"
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "rating",
"key": "rating",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "type",
"key": "type",
"schema": {
"type": "string",
"enum": [
"text",
"video"
]
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "integration",
"key": "integration",
"schema": {
"type": "string",
"enum": [
"twitter",
"product_hunt",
"google",
"facebook",
"reddit",
"capterra",
"g2",
"linkedin",
"app_store",
"trustpilot",
"shopify",
"play_store",
"yelp",
"slack",
"discord",
"apple_podcasts",
"telegram",
"whatsapp",
"instagram",
"youtube",
"tiktok",
"appsumo",
"amazon",
"zillow",
"udemy",
"chrome_web_store",
"airbnb",
"skillshare",
"realtor",
"sourceforge",
"whop",
"wordpress",
"fiverr",
"homestars",
"web_page"
]
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "tags",
"key": "tags",
"schema": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "query",
"key": "query",
"schema": {
"type": "string",
"minLength": 1,
"description": "Native full-text search, including customer name/email; output may contain personal data.",
"maxLength": 10000
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "lang",
"key": "lang",
"schema": {
"type": "string",
"minLength": 1,
"description": "Native ISO 639 language selector.",
"maxLength": 10
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "limit",
"key": "limit",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 1000,
"description": "Native page size. total counts only the current page."
},
"in": "query",
"required": false,
"style": "form",
"explode": true
},
{
"name": "page",
"key": "page",
"schema": {
"type": "integer",
"minimum": 1
},
"in": "query",
"required": false,
"style": "form",
"explode": true
}
],
"bodySchema": null,
"bodyRequired": false,
"privateOutput": false
}get_testimonial
Read one exact testimonial, including native video metadata and public/dashboard links.
Argument | Type | Required | Meaning and constraints |
| string | Required | Exact testimonial ID. No slash, traversal or arbitrary URL. |
| string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |
senja-cli get-testimonial --help
senja-cli schema get-testimonial{
"type": "object",
"properties": {
"testimonial_id": {
"type": "string",
"minLength": 1,
"description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
},
"account": {
"type": "string",
"description": "Exact configured private account profile label; not a tenant or provider account ID."
}
},
"required": [
"testimonial_id"
],
"additionalProperties": false
}Native request: GET /testimonials/{testimonial_id}. No native JSON body.
{
"name": "get_testimonial",
"method": "GET",
"path": "/testimonials/{testimonial_id}",
"title": "Read one testimonial",
"description": "Read one exact testimonial, including native video metadata and public/dashboard links.",
"group": "testimonials",
"risk": "read",
"params": [
{
"name": "testimonial_id",
"key": "testimonial_id",
"schema": {
"type": "string",
"minLength": 1,
"description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
},
"in": "path",
"required": true,
"style": "form",
"explode": true
}
],
"bodySchema": null,
"bodyRequired": false,
"privateOutput": false
}create_testimonial
Create one text/video testimonial from an authorized existing customer statement. Explicit approval is required.
Argument | Type | Required | Meaning and constraints |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | {"enum": ["text", "video"]} |
| string | Optional | {"format": "email"} |
| integer | Optional | {"minimum": 1, "maximum": 5} |
| string | Optional | {"format": "date-time"} |
| boolean | Optional | Explicitly true publishes the testimonial; false keeps it pending. |
| string | Optional | {"enum": ["twitter", "product_hunt", "google", "facebook", "reddit", "capterra", "g2", "linkedin", "app_store", "trustpilot", "shopify", "play_store", "yelp", "slack", "discord", "apple_podcasts", "telegram", "whatsapp", "instagram", "youtube", "tiktok", "appsumo", "amazon", "zillow", "udemy", "chrome_web_store", "airbnb", "skillshare", "realtor", "sourceforge", "whop", "wordpress", "fiverr", "homestars", "web_page"]} |
| array | Optional | {"maxItems": 100} |
| array | Optional | {"maxItems": 100} |
| string | Optional | Exact native/schema value |
| string | Required | {"format": "uri"} |
| string | Required | {"enum": ["image", "video"]} |
| string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |
| boolean | Optional | Must be true for the requested mutation or exclusive private output file. |
| object | Optional | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Required | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | Exact native/schema value |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Optional | HTTPS URL without embedded credentials; provider retrieves media where supported. {"format": "uri"} |
| string | Required | {"enum": ["text", "video"]} |
| string | Optional | {"format": "email"} |
| integer | Optional | {"minimum": 1, "maximum": 5} |
| string | Optional | {"format": "date-time"} |
| boolean | Optional | Explicitly true publishes the testimonial; false keeps it pending. |
| string | Optional | {"enum": ["twitter", "product_hunt", "google", "facebook", "reddit", "capterra", "g2", "linkedin", "app_store", "trustpilot", "shopify", "play_store", "yelp", "slack", "discord", "apple_podcasts", "telegram", "whatsapp", "instagram", "youtube", "tiktok", "appsumo", "amazon", "zillow", "udemy", "chrome_web_store", "airbnb", "skillshare", "realtor", "sourceforge", "whop", "wordpress", "fiverr", "homestars", "web_page"]} |
| array | Optional | {"maxItems": 100} |
| array | Optional | {"maxItems": 100} |
| string | Optional | Exact native/schema value |
| string | Required | {"format": "uri"} |
| string | Required | {"enum": ["image", "video"]} |
| string | Optional | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. |
senja-cli create-testimonial --help
senja-cli schema create-testimonial{
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"description": ""
},
"text": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_name": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_company": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_tagline": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_username": {
"type": "string",
"minLength": 1,
"description": ""
},
"form_id": {
"type": "string",
"minLength": 1,
"description": ""
},
"url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"thumbnail_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_avatar": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_company_logo": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"video_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"type": {
"type": "string",
"enum": [
"text",
"video"
]
},
"customer_email": {
"type": "string",
"minLength": 1,
"description": "",
"format": "email"
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"date": {
"type": "string",
"minLength": 1,
"description": "",
"format": "date-time"
},
"approved": {
"type": "boolean",
"description": "Explicitly true publishes the testimonial; false keeps it pending."
},
"integration": {
"type": "string",
"enum": [
"twitter",
"product_hunt",
"google",
"facebook",
"reddit",
"capterra",
"g2",
"linkedin",
"app_store",
"trustpilot",
"shopify",
"play_store",
"yelp",
"slack",
"discord",
"apple_podcasts",
"telegram",
"whatsapp",
"instagram",
"youtube",
"tiktok",
"appsumo",
"amazon",
"zillow",
"udemy",
"chrome_web_store",
"airbnb",
"skillshare",
"realtor",
"sourceforge",
"whop",
"wordpress",
"fiverr",
"homestars",
"web_page"
]
},
"tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"media": {
"type": "array",
"maxItems": 100,
"items": {
"type": "object",
"properties": {
"alt": {
"type": "string",
"minLength": 1,
"description": ""
},
"url": {
"type": "string",
"minLength": 1,
"description": "",
"format": "uri"
},
"type": {
"type": "string",
"enum": [
"image",
"video"
]
}
},
"required": [
"url",
"type"
],
"additionalProperties": false
}
},
"account": {
"type": "string",
"description": "Exact configured private account profile label; not a tenant or provider account ID."
},
"confirm": {
"type": "boolean",
"description": "Must be true for the requested mutation or exclusive private output file."
},
"payload": {
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"description": ""
},
"text": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_name": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_company": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_tagline": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_username": {
"type": "string",
"minLength": 1,
"description": ""
},
"form_id": {
"type": "string",
"minLength": 1,
"description": ""
},
"url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"thumbnail_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_avatar": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_company_logo": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"video_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"type": {
"type": "string",
"enum": [
"text",
"video"
]
},
"customer_email": {
"type": "string",
"minLength": 1,
"description": "",
"format": "email"
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"date": {
"type": "string",
"minLength": 1,
"description": "",
"format": "date-time"
},
"approved": {
"type": "boolean",
"description": "Explicitly true publishes the testimonial; false keeps it pending."
},
"integration": {
"type": "string",
"enum": [
"twitter",
"product_hunt",
"google",
"facebook",
"reddit",
"capterra",
"g2",
"linkedin",
"app_store",
"trustpilot",
"shopify",
"play_store",
"yelp",
"slack",
"discord",
"apple_podcasts",
"telegram",
"whatsapp",
"instagram",
"youtube",
"tiktok",
"appsumo",
"amazon",
"zillow",
"udemy",
"chrome_web_store",
"airbnb",
"skillshare",
"realtor",
"sourceforge",
"whop",
"wordpress",
"fiverr",
"homestars",
"web_page"
]
},
"tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"media": {
"type": "array",
"maxItems": 100,
"items": {
"type": "object",
"properties": {
"alt": {
"type": "string",
"minLength": 1,
"description": ""
},
"url": {
"type": "string",
"minLength": 1,
"description": "",
"format": "uri"
},
"type": {
"type": "string",
"enum": [
"image",
"video"
]
}
},
"required": [
"url",
"type"
],
"additionalProperties": false
}
}
},
"required": [
"type",
"customer_name"
],
"additionalProperties": false,
"description": "Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file."
},
"payload_file": {
"type": "string",
"minLength": 1,
"description": "Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags."
}
},
"required": [],
"additionalProperties": false
}Native request: POST /testimonials. Provide native body fields OR payload OR payload_file, never mixed. Native body required: type, customer_name
{
"name": "create_testimonial",
"method": "POST",
"path": "/testimonials",
"title": "Import a testimonial",
"description": "Create one text/video testimonial from an authorized existing customer statement. Explicit approval is required.",
"group": "testimonials",
"risk": "destructive",
"params": [],
"bodySchema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"description": ""
},
"text": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_name": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_company": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_tagline": {
"type": "string",
"minLength": 1,
"description": ""
},
"customer_username": {
"type": "string",
"minLength": 1,
"description": ""
},
"form_id": {
"type": "string",
"minLength": 1,
"description": ""
},
"url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"thumbnail_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_avatar": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_company_logo": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"customer_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"video_url": {
"type": "string",
"minLength": 1,
"description": "HTTPS URL without embedded credentials; provider retrieves media where supported.",
"format": "uri"
},
"type": {
"type": "string",
"enum": [
"text",
"video"
]
},
"customer_email": {
"type": "string",
"minLength": 1,
"description": "",
"format": "email"
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"date": {
"type": "string",
"minLength": 1,
"description": "",
"format": "date-time"
},
"approved": {
"type": "boolean",
"description": "Explicitly true publishes the testimonial; false keeps it pending."
},
"integration": {
"type": "string",
"enum": [
"twitter",
"product_hunt",
"google",
"facebook",
"reddit",
"capterra",
"g2",
"linkedin",
"app_store",
"trustpilot",
"shopify",
"play_store",
"yelp",
"slack",
"discord",
"apple_podcasts",
"telegram",
"whatsapp",
"instagram",
"youtube",
"tiktok",
"appsumo",
"amazon",
"zillow",
"udemy",
"chrome_web_store",
"airbnb",
"skillshare",
"realtor",
"sourceforge",
"whop",
"wordpress",
"fiverr",
"homestars",
"web_page"
]
},
"tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"media": {
"type": "array",
"maxItems": 100,
"items": {
"type": "object",
"properties": {
"alt": {
"type": "string",
"minLength": 1,
"description": ""
},
"url": {
"type": "string",
"minLength": 1,
"description": "",
"format": "uri"
},
"type": {
"type": "string",
"enum": [
"image",
"video"
]
}
},
"required": [
"url",
"type"
],
"additionalProperties": false
}
}
},
"required": [
"type",
"customer_name"
],
"additionalProperties": false
},
"bodyRequired": true,
"privateOutput": false
}update_testimonial
Change only native approval status and tag additions/removals. Text, rating and customer edits remain dashboard-only.
Argument | Type | Required | Meaning and constraints |
| string | Required | Exact testimonial ID. No slash, traversal or arbitrary URL. |
| boolean | Optional | Exact native/schema value |
| array | Optional | {"maxItems": 100} |
| array | Optional | {"maxItems": 100} |
| string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |
| boolean | Optional | Must be true for the requested mutation or exclusive private output file. |
| object | Optional | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. |
| boolean | Optional | Exact native/schema value |
| array | Optional | {"maxItems": 100} |
| array | Optional | {"maxItems": 100} |
| string | Optional | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. |
senja-cli update-testimonial --help
senja-cli schema update-testimonial{
"type": "object",
"properties": {
"testimonial_id": {
"type": "string",
"minLength": 1,
"description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
},
"approved": {
"type": "boolean"
},
"add_tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"remove_tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"account": {
"type": "string",
"description": "Exact configured private account profile label; not a tenant or provider account ID."
},
"confirm": {
"type": "boolean",
"description": "Must be true for the requested mutation or exclusive private output file."
},
"payload": {
"type": "object",
"properties": {
"approved": {
"type": "boolean"
},
"add_tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"remove_tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
}
},
"required": [],
"additionalProperties": false,
"description": "Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file."
},
"payload_file": {
"type": "string",
"minLength": 1,
"description": "Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags."
}
},
"required": [
"testimonial_id"
],
"additionalProperties": false
}Native request: PATCH /testimonials/{testimonial_id}. Provide native body fields OR payload OR payload_file, never mixed. Native body requires at least one approval or nonempty tag change.
{
"name": "update_testimonial",
"method": "PATCH",
"path": "/testimonials/{testimonial_id}",
"title": "Update approval or tags",
"description": "Change only native approval status and tag additions/removals. Text, rating and customer edits remain dashboard-only.",
"group": "testimonials",
"risk": "destructive",
"params": [
{
"name": "testimonial_id",
"key": "testimonial_id",
"schema": {
"type": "string",
"minLength": 1,
"description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
},
"in": "path",
"required": true,
"style": "form",
"explode": true
}
],
"bodySchema": {
"type": "object",
"properties": {
"approved": {
"type": "boolean"
},
"add_tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"remove_tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
}
},
"required": [],
"additionalProperties": false
},
"bodyRequired": true,
"privateOutput": false
}delete_testimonial
Permanently delete exactly the requested testimonial. Irreversible; confirmation required.
Argument | Type | Required | Meaning and constraints |
| string | Required | Exact testimonial ID. No slash, traversal or arbitrary URL. |
| string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |
| boolean | Optional | Must be true for the requested mutation or exclusive private output file. |
senja-cli delete-testimonial --help
senja-cli schema delete-testimonial{
"type": "object",
"properties": {
"testimonial_id": {
"type": "string",
"minLength": 1,
"description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
},
"account": {
"type": "string",
"description": "Exact configured private account profile label; not a tenant or provider account ID."
},
"confirm": {
"type": "boolean",
"description": "Must be true for the requested mutation or exclusive private output file."
}
},
"required": [
"testimonial_id"
],
"additionalProperties": false
}Native request: DELETE /testimonials/{testimonial_id}. No native JSON body.
{
"name": "delete_testimonial",
"method": "DELETE",
"path": "/testimonials/{testimonial_id}",
"title": "Delete one testimonial",
"description": "Permanently delete exactly the requested testimonial. Irreversible; confirmation required.",
"group": "testimonials",
"risk": "destructive",
"params": [
{
"name": "testimonial_id",
"key": "testimonial_id",
"schema": {
"type": "string",
"minLength": 1,
"description": "Exact testimonial ID. No slash, traversal or arbitrary URL."
},
"in": "path",
"required": true,
"style": "form",
"explode": true
}
],
"bodySchema": null,
"bodyRequired": false,
"privateOutput": false
}list_links
Read native form, widget, Wall of Love, quick-link, case-study and sizzle-reel groups with their IDs and URLs.
Argument | Type | Required | Meaning and constraints |
| string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |
senja-cli list-links --help
senja-cli schema list-links{
"type": "object",
"properties": {
"account": {
"type": "string",
"description": "Exact configured private account profile label; not a tenant or provider account ID."
}
},
"required": [],
"additionalProperties": false
}Native request: GET /links. No native JSON body.
{
"name": "list_links",
"method": "GET",
"path": "/links",
"title": "Read project links",
"description": "Read native form, widget, Wall of Love, quick-link, case-study and sizzle-reel groups with their IDs and URLs.",
"group": "project_links",
"risk": "read",
"params": [],
"bodySchema": null,
"bodyRequired": false,
"privateOutput": false
}send_invites
Send email invites using a selected form and its existing follow-up sequence. Local cap100 recipients, not a documented provider quota.
Argument | Type | Required | Meaning and constraints |
| string | Optional | Exact forms[].id from list_links. |
| array | Optional | {"minItems": 1, "maxItems": 100} |
| string | Required | {"format": "email"} |
| string | Optional | Exact native/schema value |
| string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |
| boolean | Optional | Must be true for the requested mutation or exclusive private output file. |
| object | Optional | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. |
| string | Required | Exact forms[].id from list_links. |
| array | Required | {"minItems": 1, "maxItems": 100} |
| string | Required | {"format": "email"} |
| string | Optional | Exact native/schema value |
| string | Optional | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. |
senja-cli send-invites --help
senja-cli schema send-invites{
"type": "object",
"properties": {
"form_id": {
"type": "string",
"minLength": 1,
"description": "Exact forms[].id from list_links."
},
"recipients": {
"type": "array",
"minItems": 1,
"maxItems": 100,
"items": {
"type": "object",
"properties": {
"email": {
"type": "string",
"minLength": 1,
"description": "",
"format": "email"
},
"name": {
"type": "string",
"minLength": 1,
"description": ""
}
},
"required": [
"email"
],
"additionalProperties": false
}
},
"account": {
"type": "string",
"description": "Exact configured private account profile label; not a tenant or provider account ID."
},
"confirm": {
"type": "boolean",
"description": "Must be true for the requested mutation or exclusive private output file."
},
"payload": {
"type": "object",
"properties": {
"form_id": {
"type": "string",
"minLength": 1,
"description": "Exact forms[].id from list_links."
},
"recipients": {
"type": "array",
"minItems": 1,
"maxItems": 100,
"items": {
"type": "object",
"properties": {
"email": {
"type": "string",
"minLength": 1,
"description": "",
"format": "email"
},
"name": {
"type": "string",
"minLength": 1,
"description": ""
}
},
"required": [
"email"
],
"additionalProperties": false
}
}
},
"required": [
"form_id",
"recipients"
],
"additionalProperties": false,
"description": "Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file."
},
"payload_file": {
"type": "string",
"minLength": 1,
"description": "Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags."
}
},
"required": [],
"additionalProperties": false
}Native request: POST /invites. Provide native body fields OR payload OR payload_file, never mixed. Native body required: form_id, recipients
{
"name": "send_invites",
"method": "POST",
"path": "/invites",
"title": "Send form invites",
"description": "Send email invites using a selected form and its existing follow-up sequence. Local cap100 recipients, not a documented provider quota.",
"group": "invites",
"risk": "destructive",
"params": [],
"bodySchema": {
"type": "object",
"properties": {
"form_id": {
"type": "string",
"minLength": 1,
"description": "Exact forms[].id from list_links."
},
"recipients": {
"type": "array",
"minItems": 1,
"maxItems": 100,
"items": {
"type": "object",
"properties": {
"email": {
"type": "string",
"minLength": 1,
"description": "",
"format": "email"
},
"name": {
"type": "string",
"minLength": 1,
"description": ""
}
},
"required": [
"email"
],
"additionalProperties": false
}
}
},
"required": [
"form_id",
"recipients"
],
"additionalProperties": false
},
"bodyRequired": true,
"privateOutput": false
}list_accounts
Local profile labels/default/auth method only. No keys, token paths, provider identity or network request.
Argument | Type | Required | Meaning and constraints |
senja-cli list-accounts --help
senja-cli schema list-accounts{
"type": "object",
"properties": {},
"required": [],
"additionalProperties": false
}get_operation_schema
Local reviewed method/path/query/body schema and provenance for one native tool. No credentials or provider request.
Argument | Type | Required | Meaning and constraints |
| string | Required | Exact native tool name, e.g. update_testimonial or send_invites. {"enum": ["list_testimonials", "get_testimonial", "create_testimonial", "update_testimonial", "delete_testimonial", "list_links", "send_invites"]} |
senja-cli get-operation-schema --help
senja-cli schema get-operation-schema{
"type": "object",
"properties": {
"operation": {
"type": "string",
"enum": [
"list_testimonials",
"get_testimonial",
"create_testimonial",
"update_testimonial",
"delete_testimonial",
"list_links",
"send_invites"
],
"description": "Exact native tool name, e.g. update_testimonial or send_invites."
}
},
"required": [
"operation"
],
"additionalProperties": false
}preview_testimonial_batch
Local validation and SHA-256 of exact ordered testimonial/import/invite work, selected profile label and reviewed schema. No provider reads, key load, identity check, price or rollback guarantee.
Argument | Type | Required | Meaning and constraints |
| array | Required | One to twenty exact ordered supported testimonial/import/invite operations. Invite requests may include up to 100 recipients each; review the exact complete recipient list and existing form follow-up sequence. {"minItems": 1, "maxItems": 20} |
| string | Required | {"enum": ["create_testimonial", "update_testimonial", "delete_testimonial", "send_invites"]} |
| object | Required | Actual native tool arguments without account, confirm, payload_file or output_file. |
| string | Optional | Exact selected private account profile; binds label, not key ownership. |
senja-cli preview-testimonial-batch --help
senja-cli schema preview-testimonial-batch{
"type": "object",
"properties": {
"tasks": {
"type": "array",
"minItems": 1,
"maxItems": 20,
"description": "One to twenty exact ordered supported testimonial/import/invite operations. Invite requests may include up to 100 recipients each; review the exact complete recipient list and existing form follow-up sequence.",
"items": {
"type": "object",
"properties": {
"tool": {
"type": "string",
"enum": [
"create_testimonial",
"update_testimonial",
"delete_testimonial",
"send_invites"
]
},
"arguments": {
"type": "object",
"description": "Actual native tool arguments without account, confirm, payload_file or output_file."
}
},
"required": [
"tool",
"arguments"
],
"additionalProperties": false
}
},
"account": {
"type": "string",
"description": "Exact selected private account profile; binds label, not key ownership."
}
},
"required": [
"tasks"
],
"additionalProperties": false
}submit_testimonial_batch
Confirmed one-to-twenty ordered testimonial/import/invite tasks. Prevalidate all and verify exact hash before first request. Stop on first failure with known results/failed index/unattempted indices; no retries, rollback or implicit continuation.
Argument | Type | Required | Meaning and constraints |
| array | Required | One to twenty exact ordered supported testimonial/import/invite operations. Invite requests may include up to 100 recipients each; review the exact complete recipient list and existing form follow-up sequence. {"minItems": 1, "maxItems": 20} |
| string | Required | {"enum": ["create_testimonial", "update_testimonial", "delete_testimonial", "send_invites"]} |
| object | Required | Actual native tool arguments without account, confirm, payload_file or output_file. |
| string | Optional | Exact selected private account profile; binds label, not key ownership. |
| boolean | Optional | Explicit approval for this exact requested ordered batch. |
| string | Required | Exact preview_testimonial_batch hash for identical requests, profile label, schema and order. {"pattern": "^[a-f0-9]{64}$"} |
senja-cli submit-testimonial-batch --help
senja-cli schema submit-testimonial-batch{
"type": "object",
"properties": {
"tasks": {
"type": "array",
"minItems": 1,
"maxItems": 20,
"description": "One to twenty exact ordered supported testimonial/import/invite operations. Invite requests may include up to 100 recipients each; review the exact complete recipient list and existing form follow-up sequence.",
"items": {
"type": "object",
"properties": {
"tool": {
"type": "string",
"enum": [
"create_testimonial",
"update_testimonial",
"delete_testimonial",
"send_invites"
]
},
"arguments": {
"type": "object",
"description": "Actual native tool arguments without account, confirm, payload_file or output_file."
}
},
"required": [
"tool",
"arguments"
],
"additionalProperties": false
}
},
"account": {
"type": "string",
"description": "Exact selected private account profile; binds label, not key ownership."
},
"confirm": {
"type": "boolean",
"description": "Explicit approval for this exact requested ordered batch."
},
"review_sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "Exact preview_testimonial_batch hash for identical requests, profile label, schema and order."
}
},
"required": [
"tasks",
"review_sha256"
],
"additionalProperties": false
}export_testimonials
Confirmed paginated GET export to an exclusive new 0600 JSON file. Stop on short native page or local caps. Never downloads media, follows URLs, overwrites files, retries or implies an atomic complete backup.
Argument | Type | Required | Meaning and constraints |
| string | Optional | Native sort field; direction uses order. {"enum": ["date", "rating"]} |
| string | Optional | {"enum": ["asc", "desc"]} |
| boolean | Optional | Exact native/schema value |
| integer | Optional | {"minimum": 1, "maximum": 5} |
| string | Optional | {"enum": ["text", "video"]} |
| string | Optional | {"enum": ["twitter", "product_hunt", "google", "facebook", "reddit", "capterra", "g2", "linkedin", "app_store", "trustpilot", "shopify", "play_store", "yelp", "slack", "discord", "apple_podcasts", "telegram", "whatsapp", "instagram", "youtube", "tiktok", "appsumo", "amazon", "zillow", "udemy", "chrome_web_store", "airbnb", "skillshare", "realtor", "sourceforge", "whop", "wordpress", "fiverr", "homestars", "web_page"]} |
| array | Optional | {"maxItems": 100} |
| string | Optional | Native full-text search, including customer name/email; output may contain personal data. |
| string | Optional | Native ISO 639 language selector. |
| integer | Optional | Native page size. total counts only the current page. {"minimum": 1, "maximum": 1000} |
| integer | Optional | {"minimum": 1} |
| string | Optional | Exact configured private account profile label; not a tenant or provider account ID. |
| boolean | Optional | Explicit approval for this exact requested ordered batch. |
| integer | Optional | Resume inside the first requested page using an export receipt offset and identical filters/page size. Provider state may have changed. {"minimum": 0, "maximum": 999} |
| integer | Optional | Local request budget, default 10. {"minimum": 1, "maximum": 100} |
| integer | Optional | Local item budget, default 1000. May stop within a page; receipt records an offset. {"minimum": 1, "maximum": 10000} |
| string | Required | Absolute new file in an existing private directory. Restrict Windows ACLs separately. |
senja-cli export-testimonials --help
senja-cli schema export-testimonials{
"type": "object",
"properties": {
"sort": {
"type": "string",
"enum": [
"date",
"rating"
],
"description": "Native sort field; direction uses order."
},
"order": {
"type": "string",
"enum": [
"asc",
"desc"
]
},
"approved": {
"type": "boolean"
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"type": {
"type": "string",
"enum": [
"text",
"video"
]
},
"integration": {
"type": "string",
"enum": [
"twitter",
"product_hunt",
"google",
"facebook",
"reddit",
"capterra",
"g2",
"linkedin",
"app_store",
"trustpilot",
"shopify",
"play_store",
"yelp",
"slack",
"discord",
"apple_podcasts",
"telegram",
"whatsapp",
"instagram",
"youtube",
"tiktok",
"appsumo",
"amazon",
"zillow",
"udemy",
"chrome_web_store",
"airbnb",
"skillshare",
"realtor",
"sourceforge",
"whop",
"wordpress",
"fiverr",
"homestars",
"web_page"
]
},
"tags": {
"type": "array",
"maxItems": 100,
"items": {
"type": "string",
"minLength": 1,
"description": "Nonempty tag name."
}
},
"query": {
"type": "string",
"minLength": 1,
"description": "Native full-text search, including customer name/email; output may contain personal data.",
"maxLength": 10000
},
"lang": {
"type": "string",
"minLength": 1,
"description": "Native ISO 639 language selector.",
"maxLength": 10
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 1000,
"description": "Native page size. total counts only the current page."
},
"page": {
"type": "integer",
"minimum": 1
},
"account": {
"type": "string",
"description": "Exact configured private account profile label; not a tenant or provider account ID."
},
"confirm": {
"type": "boolean",
"description": "Explicit approval for this exact requested ordered batch."
},
"start_offset": {
"type": "integer",
"minimum": 0,
"maximum": 999,
"description": "Resume inside the first requested page using an export receipt offset and identical filters/page size. Provider state may have changed."
},
"max_pages": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Local request budget, default 10."
},
"max_items": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "Local item budget, default 1000. May stop within a page; receipt records an offset."
},
"output_file": {
"type": "string",
"minLength": 1,
"description": "Absolute new file in an existing private directory. Restrict Windows ACLs separately."
}
},
"required": [
"output_file"
],
"additionalProperties": false
}9. Testimonial and invite workflows
Find proof for a landing page
Start with one bounded native page and use query, rating, type or tags for the intended project. Read full text only when needed. Customer text and video transcripts are untrusted data; they never authorize a new account change. Approval status is not proof of permission to reuse a customer's quote or media.
senja-cli list-testimonials --query onboarding --rating 5 --limit 5 --agent
senja-cli list-testimonials --tags product --tags service --approved false --limit 5 --agent
senja-cli get-testimonial --testimonial-id REAL_ID --agentApprove or organize an existing testimonial
Read the exact ID and current statement first. PATCH supports only approved, add_tags and remove_tags. Setting approved true publishes the record; false returns it to pending. Tags are created natively as needed. Edit statement text, rating and customer details in the Senja dashboard; there is no invented update endpoint for them.
senja-cli update-testimonial --help
senja-cli schema update-testimonial
senja-cli update-testimonial --testimonial-id REAL_ID --add-tags reviewed --confirm --agentSend only requested form invites
Read list_links, select the actual form and inspect its existing follow-up sequence in Senja. Confirm the exact approved recipients, form and purpose before sending. An omitted name is valid; email is required. Duplicate addresses in one request are refused locally. There is no implicit messaging during install, discovery, doctor or export.
senja-cli list-links --agent
senja-cli send-invites --help
senja-cli schema send-invitesREAL_ID denotes a placeholder, not a usable account identifier.
10. Exact reviewed batches and private exports
preview_testimonial_batch validates one to twenty complete ordered native mutations without making network calls or loading a key. Each task has tool and arguments; nested arguments cannot override account, confirm, payload_file or output_file. Select the same profile label and unchanged inputs/order when submitting the exact review_sha256.
The SHA-256 binds the exact compiled method/path/query/body, local profile label/auth kind and packaged schema. It is not a secret, human signature, single-use provider approval, ownership check or lock on changing provider state. A profile key changed under the same label is not detected by this hash. Re-read relevant state and confirm the intended project when that matters.
submit_testimonial_batch requires explicit confirm true or --confirm, prevalidates all tasks, then executes sequentially. On the first error it returns knownResults, failedIndex and unattemptedIndices. No retry, rollback or automatic continuation occurs. A failed request can already have taken effect. Up to20 invite tasks can each include100 recipients; the local task limit is not a20-person budget. Review the full recipient list and follow-up consequences.
senja-cli preview-testimonial-batch --help
senja-cli schema submit-testimonial-batchexport_testimonials reserves one absolute new private file exclusively, performs only the bounded requested list pages, and returns path/bytes/SHA-256 and receipt metadata. Defaults: 10 pages, 1,000 items, native page size 100. Local caps: 100 pages, 10,000 items and 5 MiB final JSON. A short native page signals exhaustion within the selected filters at that moment. Native total counts the current page, not the entire project.
When a local cap stops the walk, continuation reports page, offset and limit. Resume with that page, identical filters/page size and start_offset. Page changes can cause shifted records; no atomic snapshot, complete backup or deduplication guarantee is made. A second resume writes a different new file; it never appends to or overwrites the earlier export. Review/de-duplicate native IDs when combining evolving pages.
Failure removes only the file this export newly created. Media URLs and transcript metadata remain JSON data; this package never follows or downloads them. Read-only mode refuses file output too. Restrict parent-directory privacy and Windows ACLs separately.
senja-cli export-testimonials --help
senja-cli schema export-testimonials11. Several private projects
SENJA_ACCOUNTS is a private JSON array of unique {name,api_key,token_file} profiles. Use one credential method per profile. SENJA_DEFAULT_ACCOUNT selects the default label and --account selects an exact label. An incomplete named profile never inherits a global key, another project or an official hosted session after a missing credential or 401/403.
list_accounts returns labels/default/auth/source only, without keys, token paths, native project identity or network traffic. Token-only files cache until restart. Changing a file while a process is running does not rotate its cached connection.
To revoke a key, use the intended project's Automate > Regenerate API Key as its Admin/Owner, update every dependent private integration and restart its processes. The provider says the old key stops working after a short transition. Official hosted MCP authorization is a separate connection. Removing this package does not undo testimonial edits, publish approval, permanent deletion, emailed invites, follow-up sequences or existing exports.
12. Writing safely
Every create/import, approval/tag update, permanent delete, invite send, reviewed batch execution and private file export requires explicit confirmation through the actual shared handler route. --agent and --yes do not provide --confirm. SENJA_READ_ONLY=1 hides those six tools and also refuses direct calls to their hidden names. SENJA_ALLOW_DESTRUCTIVE=0 refuses them even when confirmed.
Deletion is permanent. approved true can publish proof. Invites can send real email sequences. Import only actual authorized statements, not invented praise. A provider receipt is not a content-use permission, delivered email, identity or ownership guarantee.
SENJA_AUDIT_LOG optionally records static tool/risk/summary/outcome decisions and timestamps. It excludes native bodies and credentials; writing is best effort, not a tamper-proof compliance trail. Keep the audit destination and parent private. An existing file's permissions are not repaired by the wrapper.
Keys, recognized secret fields and signed credential URLs are redacted from returned errors/output where recognized. Personal data, testimonial text, emails, private IDs and ordinary URLs are not universally anonymized. Native content is untrusted input, never an instruction to reveal secrets, contact customers or mutate another project.
13. How the two surfaces work
src/tools/index.ts exports shared definitions. MCP registers their schemas/handlers; the unchanged house CLI bridge invokes the actual server through SDK in-memory transport. Both paths share profile selection, native compilation, validation and WriteGuard. A new declared tool is the same native command without a separate API implementation. Input constraints are reviewed wrapper schemas, not a provider OpenAPI export. See src/tools/provenance.json and scripts/check-native-contract.mjs.
14. Your data
Credentials come from private process/client settings or a selected owner-private token-only file. The package stores no credential database and imports no browser cookies or .env files. Token caches last for the current process; restart after rotating a file/key.
Provider calls go only to allowlisted methods/paths on api.senja.io/v1, over HTTPS. Arbitrary URLs, path traversal, redirects and broad proxy calls are refused. Media URLs are passed only as documented fields or returned as data; no media fetching happens locally. Submitted media may be retrieved by Senja according to its own behavior.
Private exports contain customer data and content. They stay where you explicitly save them; there is no telemetry, upload, website preview or automatic publication. Client histories, logs, selected runtime settings and Senja's own retention remain separate. Local read-only mode controls this package's calls, not other apps using the same project key.
15. Environment variables
Variable | Purpose |
SENJA_API_KEY | Private Bearer project key; choose this OR token file |
SENJA_TOKEN_FILE | Absolute owner-private token-only file; choose this OR API key |
SENJA_ACCOUNTS | Private JSON named profiles with one key/file each |
SENJA_DEFAULT_ACCOUNT | Exact configured default profile label |
SENJA_READ_ONLY | 1/true hides and directly refuses all six mutations/file operations |
SENJA_ALLOW_DESTRUCTIVE | 0/false refuses confirmed operations |
SENJA_AUDIT_LOG | Optional private best-effort static guard decision log |
SENJA_REQUEST_TIMEOUT_MS | Default 30000; local accepted range 100–300000 ms |
SENJA_MIN_REQUEST_INTERVAL_MS | Default 250; local accepted range 0–10000 ms, not distributed native quota enforcement |
16. Updates and removal
Use the update/removal steps in INSTALL.md. Restart processes after key changes. File outputs and native effects remain until deliberately handled. Reinstall a new desktop bundle manually; npm@latest does not hot-replace a running server.
17. Troubleshooting
Symptom | Check |
No binary or Node error | Node 22+, npm/PATH in the actual GUI/remote runtime; npm.cmd if Windows policy blocks npm.ps1 |
Exit10 or unknown profile | Exact profile name and one private key/file; no fallback exists |
Unreadable token file | Absolute owner-private regular non-symlink file under 64 KiB; restart after replacing it |
401/403 | Selected project/key/permissions and revocation; official hosted auth is separate |
Old sort/per_page/language rejected | Use sort date/rating, order asc/desc, limit and lang |
PATCH edit refused | Only approved/add_tags/remove_tags; use dashboard for text/customer/rating edits |
Cannot send or delete | Explicit --confirm and local policy; inspect native permissions and real purpose |
Invites skipped | Inspect native sent/skipped receipt and existing form sequence; do not blindly repeat |
Export stopped at cap | Inspect page/offset/limit and resume to a different new private file |
Existing output file | Choose a new file; never remove/overwrite unrelated data |
Review hash mismatch | Preview the exact unchanged order/inputs/profile/schema again |
429 or uncertain write result | No automatic retry; inspect native state and available rate-limit guidance |
Browser-only client | Use official hosted MCP; local stdio needs a supported server runtime |
Desktop GUI blocked | Organization/client support and Node 22 runtime; archive discovery does not prove GUI acceptance |
18. API coverage and comparisons
Official hosted MCP
Senja already has official account MCP at https://mcp.senja.io. It searches testimonials, finds proof for a use case, creates testimonials, tags records, retrieves asset links/embeds and sends form invites. Current setup docs include Free, Starter and Pro. Hosted account authorization and client approvals are separate from this local API-key package.
Use the official connector when that native experience fits your task. A dedicated official task CLI was not identified in the provider material reviewed on October 3, 2026; this is not a universal or permanent absence claim. This package does not claim to add invites that the official MCP already supports, expose every Senja UI feature, create Studio graphics or replace native embed editing.
Reviewed community server
andrewconnell/senja-mcp at commit 417445647eac47f94c2d12d9196a68d2e1d22559 exposes three testimonial MCP tools. Its inspected API client already uses Bearer auth, separate sort/order, lang/limit and repeated tag query values. Its package does not declare a standalone task CLI; its create handler has no mandatory confirmation argument. This says nothing about external clients' approval controls.
The reviewed interface describes a data array and paid-plan prerequisite; current provider documentation describes testimonials and current-page total, and covers Free/Starter/Pro. Our request/response fixtures follow current provider fields. Community customer_website is not the current documented customer_url field.
Useful owned workflows and limits
The verified addition is a shared task CLI/local MCP with isolated named project profiles, mandatory mutation/file approval, direct read-only refusal, locally reviewed ordered writes and bounded private paginated export with explicit page/offset continuation. These controls are exercised in fixtures and real protocol/CLI processes. They do not establish overall superiority, authenticated account outcomes or token savings.
Capability | This package | Existing alternatives |
Task interface | 12 shared MCP tools and task CLI commands | Official hosted MCP and reviewed community stdio MCP |
Native public API | Seven reviewed documented endpoints | Official hosted tools may cover different native features |
Project credentials | Unique local profiles, no global credential fallback | Official connector authorization stays native |
Ordered changes | Exact local hash, prevalidation, stop on failure | Not a provider-state lock or replacement for client approval |
Private export | Bounded pages/items/bytes and exclusive JSON file | Not an atomic complete backup, consent registry or media downloader |
Task tokens | Actual matched Codex measurement pending | No percentage or zero-total-token claim |
19. Versions and migration
Component | Reviewed version |
Package/desktop | 2.0.0 |
Native public API | v1; seven endpoints checked 2026-10-03 |
Community source | 417445647eac47f94c2d12d9196a68d2e1d22559 |
Node | >=22 |
Historical private MCP | 1.0.0; three tools |
Matched Codex task/token usage | Pending |
Legacy caller | Current contract | Required change |
per_page | limit | Use native page-size field |
language | lang | Use native language selector |
date_asc/date_desc sort | sort date/rating plus order | Send field and direction separately |
tags string | tags array | Repeat --tags or use a JSON array |
create name/email/headline/company | customer_name/customer_email/customer_tagline/customer_company | Use native fields and required type |
avatar_url/company_logo_url | customer_avatar/customer_company_logo | Use native HTTPS fields |
url used as customer website | url is source; customer_url is customer website | Choose the actual intended field |
Three tools with startup key requirement | 12 tools with credential-free discovery and guarded effects | Discover tools before private setup; update scripts for approval |
No CLI binary | senja-cli and senja-mcp | Use @thenavidm scope and @latest |
CHANGELOG.md records the dated major update. Private legacy history stays private; source publishing starts from a clean verified snapshot, preserving AGPL-3.0.
20. FAQ
Yes. Its hosted connector already searches testimonials, creates proof, retrieves asset links and sends form invites. This package adds a shared terminal/local task interface and the documented local workflows. Use the official option when it fits your needs; the comparison does not claim ours replaces its full native feature set.
The CLI runs the same discovered tools through the same in-memory MCP handlers, input validation and write guard. Scripts can use JSON, field selection and exit codes. A dedicated official task CLI was not identified in the reviewed provider material; that finding is dated, not a permanent absence claim.
Current provider REST and MCP setup documentation includes Free, Starter and Pro. Account restrictions and native feature eligibility remain in Senja. The package is free under AGPL-3.0 and cannot bypass a plan or permission check; do not reuse older community paid-only prerequisites as current facts.
Choose the intended project and open Automate in Senja. Store exactly one key privately in SENJA_API_KEY or an absolute owner-private SENJA_TOKEN_FILE outside repositories. The client uses Bearer authentication. Never paste resolved secrets into README examples, public issues, screenshots or AI chats.
Yes. SENJA_ACCOUNTS supplies unique private named profiles, each with its own key or token file. Select an exact name with --account. Named profiles never inherit global credentials or another project. Labels are local settings and do not prove the provider key owner or project identity.
No. login prints private setup instructions and never makes a request, opens an OAuth flow, generates a key or imports a browser session. doctor without --network checks configuration only. doctor --network deliberately makes one limit=1 testimonial request and prints verification metadata.
The reviewed catalogue includes testimonial list/get/create/PATCH/delete, project links and form invites, plus five local/workflow helpers. This is the current seven-endpoint public REST scope reviewed for this package, not a claim to expose every hosted MCP or Senja UI action.
Native PATCH supports only approval status and tag additions/removals. Text, rating and customer edits belong in the Senja dashboard. create_testimonial uses actual customer_name/type fields for an authorized import; it does not invent a generalized edit API.
Yes, according to current native API documentation; false returns it to pending. These are confirmed account changes. Approval does not establish customer permission to reuse their words or media, and reading a testimonial never authorizes publishing it elsewhere.
Use native query for text/title/customer-field search, repeat --tags for tag names, and use rating/type/integration/approved/lang as appropriate. sort is date or rating and order is asc or desc. The wrapper rejects stale per_page, language and combined date_desc-style sort arguments before network traffic.
No. Native total counts the current returned page. Export stops on a short native page or explicit local caps, recording page/offset/limit continuation. It does not infer a project-wide count from total or promise a consistent snapshot while provider content changes.
Use export_testimonials with explicit confirmation and an absolute new private file. Defaults are10pages and1000items; local maximums are100pages,10000items and5MiB JSON. Resume to a different file using the recorded page/start_offset/limit and unchanged filters. Combine/de-duplicate changing native IDs deliberately; no automatic append or atomic backup is promised.
No. JSON includes native media URLs, transcripts and metadata where returned. The package never follows these URLs or downloads video/image/audio files. Signed credential URLs and known keys are redacted where recognized; other personal/customer content is still private data.
The selected form ID and its existing email/follow-up sequence determine native messages. Use a real forms[].id from list_links and only explicitly approved recipients. The local 100-recipient cap is not a native quota. Native sent/skipped receipts do not prove inbox delivery or consent, and invites also exist in the official MCP.
It prevalidates every complete task and binds exact order/requests/profile label/schema to a local hash before sequential execution. The hash is not a single-use provider token, human signature, provider-state lock, consent record or ownership proof. Reconfirm changing provider state when your task requires it.
Execution stops at the first failure with knownResults, failedIndex and unattemptedIndices. A failed write may already have taken effect and native follow-up emails can continue. There is no retry, rollback or automatic continuation. Inspect native state and receipts before explicitly requesting another action.
No. SENJA_READ_ONLY=1 both hides the six confirmed tools and refuses direct hidden calls through the actual handlers. It also refuses private file exports. SENJA_ALLOW_DESTRUCTIVE=0 disables these effects even when confirmed; --agent and --yes never provide explicit --confirm.
Codex and compatible local stdio clients can register npx -y @thenavidm/senja-mcp-cli@latest. INSTALL.md covers Claude Code/Desktop, Cursor, VS Code/Copilot, Windsurf, Zed, Gemini CLI, Docker and other stdio clients, plus Windows/macOS/Linux runtime notes. Browser-only clients need a remote connector such as the official hosted MCP.
The .mcpb includes production dependencies and asks for private sensitive settings or a token file, but compatible hosts still need a Node 22 runtime and organization support. Install newer bundle versions manually. npx@latest resolves the current registry version when the server is restarted; it does not replace a running process or provide guaranteed background updates.
Actual equivalent successful Codex task/token measurements are pending. MCP loading modes, CLI schema/help discovery, outputs, skills and caching all affect costs. No character-based estimate, universal superiority or zero-total-token claim is published. Proven fixture behavior and actual public artifact checks are listed separately from authenticated outcomes and desktop GUI acceptance.
Questions
Open a secret-free issue. Read CONTRIBUTING.md and SECURITY.md.
About the author
Navid Moazzez is a leading AI business strategist, and the host of the AI Creator Summit, watched by 100,000+ creators. He helps creators and founders master AI and build their own AI Operating System (AI OS) to automate their business and life. He creates useful free tools, MCP servers and CLIs that creators and founders can use in their own workflows.
Links
Personal website: navid.me
Link in bio: navid.bio
Navid Media: navid.media
YouTube: @thenavidm and @thenavidai
X: @thenavidm
Instagram: @thenavidm
LinkedIn: thenavidm
If this is useful, star the repo and come say hi on X.
Dependencies
Runtime: MCP TypeScript SDK, Ajv and ajv-formats. Development: TypeScript, Vitest, Vite and MCPB. Exact locked versions appear above. Packaging tools are excluded from desktop runtime.
License
Preserves AGPL-3.0 and existing private legacy history. Read THIRD_PARTY_NOTICES.md. Senja service terms and trademarks remain separate.
© 2026 Navid Media. Made with ❤️ by Navid Moazzez.
Available Tools
12 toolscreate_testimonialImport a testimonialBDestructive
Create one text/video testimonial from an authorized existing customer statement. Explicit approval is required.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | HTTPS URL without embedded credentials; provider retrieves media where supported. | |
| date | No | ||
| tags | No | ||
| text | No | ||
| type | No | ||
| media | No | ||
| title | No | ||
| rating | No | ||
| account | No | Exact configured private account profile label; not a tenant or provider account ID. | |
| confirm | No | Must be true for the requested mutation or exclusive private output file. | |
| form_id | No | ||
| payload | No | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. | |
| approved | No | Explicitly true publishes the testimonial; false keeps it pending. | |
| video_url | No | HTTPS URL without embedded credentials; provider retrieves media where supported. | |
| integration | No | ||
| customer_url | No | HTTPS URL without embedded credentials; provider retrieves media where supported. | |
| payload_file | No | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. | |
| customer_name | No | ||
| thumbnail_url | No | HTTPS URL without embedded credentials; provider retrieves media where supported. | |
| customer_email | No | ||
| customer_avatar | No | HTTPS URL without embedded credentials; provider retrieves media where supported. | |
| customer_company | No | ||
| customer_tagline | No | ||
| customer_username | No | ||
| customer_company_logo | No | HTTPS URL without embedded credentials; provider retrieves media where supported. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, openWorldHint=true, idempotentHint=false, and readOnlyHint=false, so the mutating/non-idempotent nature is covered. The description adds the useful prerequisite that an authorized statement and explicit approval are required, but says nothing about side effects, rate limits, or auth beyond that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the action and the approval precondition front-loaded and no wasted words. It is efficient, though the brevity is under-specification rather than deliberate economy given the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 25-parameter creation tool with nested payload objects, dual input modes, and no output schema, this description is far too thin. It omits required-field guidance (0 required params is ambiguous), how payload and confirm interact, and what the operation returns.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 25 parameters and only 44% schema description coverage, the description carries a heavy compensation burden, yet it only alludes to the text/video 'type' and the customer statement. It explains nothing about the payload vs payload_file vs flat body-flag modes, confirm, account, integration, or the customer_* fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create one text/video testimonial') and adds a scope qualifier ('one', from an authorized existing customer statement) that implicitly distinguishes it from the batch siblings. It does not name an alternative tool, but the single-item scope is clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a precondition ('from an authorized existing customer statement') and 'explicit approval is required', which implies the confirm/approved flags. However, it never names when to use this versus preview_testimonial_batch, submit_testimonial_batch, or update_testimonial, leaving the routing decision to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_testimonialDelete one testimonialADestructive
Permanently delete exactly the requested testimonial. Irreversible; confirmation required.
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Exact configured private account profile label; not a tenant or provider account ID. | |
| confirm | No | Must be true for the requested mutation or exclusive private output file. | |
| testimonial_id | Yes | Exact testimonial ID. No slash, traversal or arbitrary URL. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the safety profile is partly covered. The description earns credit by escalating severity with 'Permanently' and 'Irreversible' and by disclosing the confirmation prerequisite, which the annotations do not convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the destructive nature front-loaded before the confirmation requirement. Every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but for a destructive single-record delete the description supplies purpose, irreversibility, and the confirmation gate, while annotations carry the safety hints. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so account, confirm, and testimonial_id are already fully documented in the schema. The description adds only the notion that deletion is single-target; it doesn't elaborate on the confirm flag or account-label semantics. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Permanently delete ... testimonial') with a scoping qualifier ('exactly the requested') that distinguishes it from a batch delete. It does not explicitly name a sibling, but among the listed siblings the delete intent is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description adds a procedural condition ('confirmation required') that implies when the tool can be invoked, but it never states when to prefer this over update_testimonial or how it interacts with siblings. Usage is implied rather than explicitly guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_testimonialsExport bounded private testimonialsADestructive
Confirmed paginated GET export to an exclusive new0600 JSON file. Stop on short native page or local caps. Never downloads media, follows URLs, overwrites files, retries or implies an atomic complete backup.
| Name | Required | Description | Default |
|---|---|---|---|
| lang | No | Native ISO 639 language selector. | |
| page | No | ||
| sort | No | Native sort field; direction uses order. | |
| tags | No | ||
| type | No | ||
| limit | No | Native page size. total counts only the current page. | |
| order | No | ||
| query | No | Native full-text search, including customer name/email; output may contain personal data. | |
| rating | No | ||
| account | No | Exact configured private account profile label; not a tenant or provider account ID. | |
| confirm | No | Explicit approval for this exact requested ordered batch. | |
| approved | No | ||
| max_items | No | Local item budget, default1000. May stop within a page; receipt records an offset. | |
| max_pages | No | Local request budget, default10. | |
| integration | No | ||
| output_file | Yes | Absolute new file in an existing private directory. Restrict Windows ACLs separately. | |
| start_offset | No | Resume inside the first requested page using an export receipt offset and identical filters/page size. Provider state may have changed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly=false, destructive=true, openWorld=true, idempotent=false, but the description goes well beyond them: exclusive file creation with 0600 permissions, no overwriting, no media/URL fetching, no retries, and an explicit warning that the result is not an atomic complete backup. These are exactly the behavioral traits an agent needs before calling a file-writing export.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with the core action front-loaded and zero filler. It is occasionally over-compressed (bare '0600', 'native page', 'local caps') in a way that costs a little readability, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists and there are 17 parameters, so the description carries substantial burden. It thoroughly covers the behavioral envelope and failure/stop semantics, but leaves the confirmation workflow, account/integration scoping, and the shape of the resulting file largely unexplained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 59% across 17 parameters, so the description must carry weight. It alludes conceptually to confirm ('Confirmed'), the local caps (max_items/max_pages), and page size ('short native page'), but never clarifies undocumented fields such as approved, account, integration, or start_offset behavior. Partial compensation, not full.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb+resource+artifact: a paginated GET export of testimonials written to an exclusive new 0600 JSON file. An agent can immediately distinguish this from list_testimonials or preview_testimonial_batch. It stops short of naming a sibling to avoid, which keeps it from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives operational guidance on when to stop (short native page or local caps) and a list of non-goals (no media download, no URL following, no retries, no atomic backup), which implicitly scopes the tool. However it never states when to prefer this over list_testimonials, preview_testimonial_batch, or submit_testimonial_batch, nor the prerequisites implied by 'Confirmed'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_operation_schemaInspect a current native operationARead-onlyIdempotent
Local reviewed method/path/query/body schema and provenance for one native tool. No credentials or provider request.
| Name | Required | Description | Default |
|---|---|---|---|
| operation | Yes | Exact native tool name, e.g. update_testimonial or send_invites. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, and closed-world. The description adds meaningful context beyond that: it is the 'local reviewed' copy and requires no credentials or provider request, which tells the agent this is a side-effect-free metadata read rather than a live call. It stops short of describing the returned structure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, front-loaded sentences with no filler: the first states what is returned, the second removes a likely misassumption (that a call might touch credentials or a provider). Nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does sketch the return content (method/path/query/body schema plus provenance) and rules out auth or network side effects. It does not describe the shape or format of that schema object, leaving a small gap for a 1-parameter introspection tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with an enumerated list of valid operation names and an example format, so the schema carries the parameter semantics. The description's 'for one native tool' reinforces that the single parameter selects an operation, matching the baseline for a fully documented schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (inspect/return) and resource (schema + provenance for one native operation), so an agent can tell this is a metadata lookup rather than an actual operation. It does not explicitly contrast itself with the sibling operation tools (get_testimonial, update_testimonial, etc.), but 'for one native tool' plus the tool name make the distinction inferable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use, when-not-to-use, or alternative guidance. 'Local reviewed ... No credentials or provider request' hints that this is an offline introspection call, but the description never says to call it before invoking a native tool or how it relates to the sibling operations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_testimonialRead one testimonialBRead-onlyIdempotent
Read one exact testimonial, including native video metadata and public/dashboard links.
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Exact configured private account profile label; not a tenant or provider account ID. | |
| testimonial_id | Yes | Exact testimonial ID. No slash, traversal or arbitrary URL. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false, and openWorldHint, so the safety and access profile is covered. The description adds that the read includes native video metadata plus public/dashboard links, which is useful context about what it returns, but says nothing about permissions, error cases, or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that front-loads the action and resource and wastes nothing. Appropriately sized for a two-parameter read tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations covering safety and schema at 100% coverage, the core is complete. But the description hints at a rich return payload (native video metadata, public/dashboard links) with no output schema, so it stops short of telling the agent what it will receive or when this read is preferable to list_testimonials.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the two parameters are fully documented in the schema itself, including the account label caveat and the traversal guard on testimonial_id. The description adds no param-level meaning, which matches the baseline when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Read') and resource ('one exact testimonial') with singular scope, distinguishing it from the sibling list_testimonials. However, it doesn't name or contrast any alternative for retrieving a testimonial by ID, so sibling differentiation is only implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance, no prerequisites, and no mention of alternatives. The description never signals that list_testimonials is for enumeration while this is for a single lookup, leaving the agent to infer routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_accountsList configured accountsBRead-onlyIdempotent
Local profile labels/default/auth method only. No keys, token paths, provider identity or network request.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so safety is covered. The description adds genuine context beyond that: output is limited to local profile labels/defaults/auth method and deliberately excludes keys, token paths, and provider identity, telling the agent the result is safe to surface.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is very short (two fragments) and wastes no words, but it is telegraphic and front-loads a qualifier rather than the core action. The terseness borders on under-specification rather than disciplined conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, read-only listing tool with no output schema and strong annotations, the description covers the essential safety and scope facts. However, it never plainly states what the tool does or what the returned list contains beyond field-level exclusions, leaving the purpose inferable only from the title.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics for the description to carry. Baseline of 4 applies; nothing is missing on this dimension.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description never states a verb or resource — it only describes the scope of what is returned ("Local profile labels/default/auth method only"). The title supplies the actual purpose, so the agent can infer this lists local accounts, but the description itself is vague about the action.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance and no named alternative among the numerous list_* siblings (list_customers, list_partners, list_domains, etc.). The agent must infer that this tool is for enumerating locally configured account profiles rather than any remote data.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_linksRead project linksBRead-onlyIdempotent
Read native form, widget, Wall of Love, quick-link, case-study and sizzle-reel groups with their IDs and URLs.
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Exact configured private account profile label; not a tenant or provider account ID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is fully covered without the description. The description contributes the shape of what comes back (groups + IDs + URLs), which is useful given there is no output schema, but says nothing about pagination, scoping, or whether results are filtered by the account parameter.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence listing the covered resource types with zero filler. Everything in it earns its place by substituting for a missing output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-required-parameter, read-only listing tool, the definition is nearly sufficient: it tells the agent what categories of records are returned and what identifiers accompany them. The remaining gap is that it never mentions the optional 'account' scoping filter that the schema exposes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema's own note for 'account' is unusually precise (it warns that this is a configured profile label, not a tenant or provider account ID). The description adds nothing about the parameter, so the baseline 3 applies when the schema carries the full burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Read') and enumerates the exact resource families returned (native form, widget, Wall of Love, quick-link, case-study, sizzle-reel groups) with IDs and URLs. This is far more specific than the name 'list_links', though it never names a sibling or clarifies the relationship to the testimonial-centric tools around it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no prerequisites, and no mention of alternatives such as list_testimonials or list_accounts. The agent must infer from the name alone that this is the discovery call for link groups.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_testimonialsList testimonialsCRead-onlyIdempotent
Read one native page with exact current search, tag, approval, language and date/rating filters.
| Name | Required | Description | Default |
|---|---|---|---|
| lang | No | Native ISO 639 language selector. | |
| page | No | ||
| sort | No | Native sort field; direction uses order. | |
| tags | No | ||
| type | No | ||
| limit | No | Native page size. total counts only the current page. | |
| order | No | ||
| query | No | Native full-text search, including customer name/email; output may contain personal data. | |
| rating | No | ||
| account | No | Exact configured private account profile label; not a tenant or provider account ID. | |
| approved | No | ||
| integration | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover read-only, idempotent, non-destructive. The description adds one meaningful behavioral note: output may contain personal data (customer name/email), which is genuinely useful. But it does not clarify pagination behavior, total counts, or result limits, leaving meaningful gaps for a 12-param listing tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence, no filler, front-loaded with the core action. It is compact but at the cost of detail; reasonable for its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter tool with no output schema, the description is thin. It doesn't explain return shape (e.g., what 'total counts only the current page' implies), pagination usage, sort/order interaction, or the account/integration filters. It leaves the agent without enough to call it confidently.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 42%, so roughly half the parameters are undocumented in the schema. The description lists filter categories (search, tag, approval, language, date/rating) but doesn't map them to specific parameters or explain semantics like 'exact configured private account profile label.' Baseline 3 is the ceiling given the description doesn't compensate for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description says it reads a 'native page' of testimonials and enumerates filter dimensions, but 'one native page' is unusual phrasing that doesn't clearly state whether pagination is supported (the schema has a 'page' param, so it must be). It never explicitly distinguishes from siblings like get_testimonial or export_testimonials.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this versus get_testimonial (single fetch) or export_testimonials (bulk export). The reader must infer that this is the list/browse operation, but nothing is stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
preview_testimonial_batchReview exact ordered testimonial tasksBRead-onlyIdempotent
Local validation and SHA-256 of exact ordered testimonial/import/invite work, selected profile label and reviewed schema. No provider reads, key load, identity check, price or rollback guarantee.
| Name | Required | Description | Default |
|---|---|---|---|
| tasks | Yes | One to twenty exact ordered supported testimonial/import/invite operations. Invite requests may include up to100 recipients each; review the exact complete recipient list and existing form follow-up sequence. | |
| account | No | Exact selected private account profile; binds label, not key ownership. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnly, idempotent, closed-world, non-destructive, so the bar is lower; the description still adds real value by enumerating what is NOT performed (no provider reads, no key load, no identity check, no price, no rollback guarantee). That negative-space disclosure meaningfully bounds what a preview guarantees.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with no filler, leading with the core operation before the disclaimers. Slightly over-compressed – the SHA-256 and 'reviewed schema' references are opaque without more context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description arguably should say what a preview yields (the hash, validation result) and how it feeds the submit step, and it does not. It covers the operation's boundaries well but leaves the agent guessing about the return payload and the preview-to-submit workflow.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters, including the enum of sub-tools and the recipient-list caveat on tasks. The description adds only loose echoes ('exact ordered ... work', 'selected profile label') without new syntax or format detail, matching the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific action-and-resource pair: local validation plus SHA-256 hashing of an ordered testimonial/import/invite batch. An agent can grasp it's a dry-run validator, but the phrasing is dense jargon and it never names the sibling it pairs with (submit_testimonial_batch), so differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance at all, and the obvious alternative submit_testimonial_batch is never mentioned. The 'No provider reads...' clauses hint at preview semantics but stop short of telling the agent when to reach for this versus submitting the batch for real.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_invitesSend form invitesBDestructive
Send email invites using a selected form and its existing follow-up sequence. Local cap100 recipients, not a documented provider quota.
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Exact configured private account profile label; not a tenant or provider account ID. | |
| confirm | No | Must be true for the requested mutation or exclusive private output file. | |
| form_id | No | Exact forms[].id from list_links. | |
| payload | No | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. | |
| recipients | No | ||
| payload_file | No | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, openWorldHint=true, and idempotentHint=false, so the safety profile is covered. The description adds useful context that the 100-recipient limit is a local tool cap rather than a provider quota, but it does not disclose that `confirm` must be set, that sending is irreversible, or anything about the follow-up sequence behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the action front-loaded and no padding. The second sentence's phrasing ("Local cap100 recipients") is slightly clipped but still readable and earns its place by clarifying the limit's origin.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, open-world mutation with 6 params (0 required) and no output schema, the description is adequate but thin: it never mentions the required `confirm` flag or that the mutation cannot be undone, leaving that entirely to the schema and annotations. It is callable, but not fully self-explanatory.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 83%, so the schema already documents `account`, `confirm`, `form_id`, `payload`, and `payload_file` in detail. The description only echoes the recipient cap (maxItems 100) and adds no syntax or format meaning beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb+resource ("Send email invites") and adds scope detail ("using a selected form and its existing follow-up sequence"). It does not need to differentiate from siblings since none of the listed testimonial/link tools overlap with invite sending, so 4 is appropriate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use or when-not-to-use guidance, and no alternative tool is named. The only contextual note is the recipient cap, which is a constraint rather than usage direction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_testimonial_batchExecute reviewed testimonial tasksADestructive
Confirmed one-to-twenty ordered testimonial/import/invite tasks. Prevalidate all and verify exact hash before first request. Stop on first failure with known results/failed index/unattempted indices; no retries, rollback or implicit continuation.
| Name | Required | Description | Default |
|---|---|---|---|
| tasks | Yes | One to twenty exact ordered supported testimonial/import/invite operations. Invite requests may include up to100 recipients each; review the exact complete recipient list and existing form follow-up sequence. | |
| account | No | Exact selected private account profile; binds label, not key ownership. | |
| confirm | No | Explicit approval for this exact requested ordered batch. | |
| review_sha256 | Yes | Exact preview_testimonial_batch hash for identical requests, profile label, schema and order. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (destructiveHint, non-idempotent) by disclosing exact failure semantics: stop on first failure, no retries, no rollback, no implicit continuation, and a return shape of known results plus failed index and unattempted indices. This is precisely the operational knowledge an agent needs before firing a destructive batch.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with scope and then failure behavior; every clause carries operational weight. The opening is a noun fragment that reads telegraphically, but nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, non-idempotent batch tool with no output schema, it covers scope limits, ordering, the confirmation gate, and the failure/return contract. It leaves the hash-mismatch path and interaction with the preview sibling implicit, which is the main remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the schema already documents tasks, account, confirm, and review_sha256. The description reinforces ordering and the pre-request hash gate but adds little syntax or per-parameter meaning beyond what the schema states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource and scope precisely: a confirmed, ordered batch of one-to-twenty testimonial/import/invite tasks, executed with hash verification. It is distinguishable from the preview_testimonial_batch sibling by being the execution stage, though it never names that sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: 'Confirmed' and 'verify exact hash before first request' suggest the tool must follow a preview/confirm flow, but the description never says to call preview_testimonial_batch first or what to do when the hash mismatches. No explicit when-not or alternative routing is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_testimonialUpdate approval or tagsADestructive
Change only native approval status and tag additions/removals. Text, rating and customer edits remain dashboard-only.
| Name | Required | Description | Default |
|---|---|---|---|
| account | No | Exact configured private account profile label; not a tenant or provider account ID. | |
| confirm | No | Must be true for the requested mutation or exclusive private output file. | |
| payload | No | Complete native JSON body; do not mix with body flags or payload_file. Arrays use repeated JSON object flags or a whole native array in a private file. | |
| add_tags | No | ||
| approved | No | ||
| remove_tags | No | ||
| payload_file | No | Absolute regular non-symlink JSON body file, at most 1 MiB. Cannot mix with payload/body flags. | |
| testimonial_id | Yes | Exact testimonial ID. No slash, traversal or arbitrary URL. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, idempotentHint=false and openWorldHint=true, so the safety profile is covered. The description adds the useful scope constraint that only approval and tags are mutable, but it says nothing about the mandatory confirm flag, whether tag removal is reversible, or auth requirements — context that matters for a destructive mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the mutable scope stated first and the exclusion second. No filler, no restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, non-idempotent mutation with a nested payload, mutually exclusive body options and no output schema, the description covers the editable surface but omits the confirm prerequisite and the payload-vs-payload_file exclusivity that an agent must get right to call it successfully.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 63% with 8 parameters, including a nested payload object, confirm, account and payload_file. The description maps conceptually to approved/add_tags/remove_tags but adds no syntax, mutual-exclusivity (payload vs. payload_file vs. flat flags) or identifier-format detail beyond what the schema already documents. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific mutation scope: approval status plus tag additions/removals, and explicitly excludes text, rating and customer edits. An agent immediately knows the editable surface. It does not name a sibling, but no sibling offers a competing update operation, so the field-level scoping does the differentiating work.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear when-not: text, rating and customer edits are 'dashboard-only,' which tells the agent to route those requests elsewhere. It stops short of giving positive selection criteria (e.g., when to prefer this over batch submission) or noting prerequisites such as the confirm flag.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
12 tool updates
v2.0.0- First observed
create_testimonial - First observed
delete_testimonial - First observed
export_testimonials - First observed
get_operation_schema - First observed
get_testimonial - First observed
list_accounts - First observed
list_links - First observed
list_testimonials - First observed
preview_testimonial_batch - First observed
send_invites - First observed
submit_testimonial_batch - First observed
update_testimonial
TDQS
Scored across 12 tools
The CRUD tools for testimonials are clearly distinct, and the batch, export, links, and account tools have different scopes. There is minor potential confusion between list_testimonials and export_testimonials, but the descriptions clarify their distinct purposes.
All tools follow a consistent snake_case verb_noun pattern, including multi-word names like get_operation_schema and preview_testimonial_batch. No mixed conventions or vague verbs.
With 12 tools, the set is well-scoped for testimonial management, covering core CRUD, batch operations, export, and auxiliary functions without excessive clutter.
The surface covers testimonial CRUD (update is intentionally limited), batch preview/submit, export, links, invites, and account listing. Some gaps exist, such as no direct text/rating edits or invite sequence management, but core workflows are well supported.
Maintenance
Related MCP Connectors
60+ Meta Ads tools for AI agents: audits, campaign management, audiences and CAPI tracking.
SEO & marketing toolkit for AI agents: GA4, Search Console, AdSense, GTM, PageSpeed, Trends.
Bounded tools for rendering, extraction, RAG, enrichment, local discovery and review analysis.
YouTube transcripts, search, channels, playlists and bulk transcript jobs for AI agents. 14 tools.
Related MCP Servers
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI agents to fully automate Appwrite backend operations with 143 tools covering databases, users, storage, functions, messaging, and more. Supports advanced features like GeoJSON attributes, file uploads, function deployment, and bulk operations.3 npm-
- AlicenseNot gradedqualityBmaintenanceExposes the full Chatwoot API as 129 tools for AI assistants, enabling account, contact, conversation, message, inbox, team, report, help center, automation, and custom attribute management, plus exclusive Kanban and scheduled message features.9 npmMIT
- AlicenseBqualityBmaintenanceEnables AI agents to manage Wistia media, folders, captions, channels, webinars, sharing, analytics, uploads, accounts, and background jobs through 169 stable API tools with guarded writes, bounded paging, and private account handling.16946 npmAGPL 3.0
- FlicenseBqualityBmaintenanceEnables AI agents and clients to discover accounts and channels, read scheduling and analytics data, and manage posts, content items, and templates through 41 GraphQL-backed tools with private credential profiles and confirmation-gated mutations.41-