@besales/mcp
v0.25.0
Published
Model Context Protocol server for Animaly / Besales
Readme
@besales/mcp
Model Context Protocol server for Animaly / Besales.
Status: public npm package candidate.
Install
Requirements:
- Node.js 20+
- BeSales account with an active workspace
- Claude Desktop, Claude Code, Codex CLI, or another MCP-capable host
No global install is required. Production users can run the package with npx:
npx -y @besales/mcp connect
npx -y @besales/mcp status
npx -y @besales/mcpconnect opens the browser consent flow and stores an MCP API key plus the
selected workspace in the local keychain. Workspace-level tools use that
connected workspace by default, so normal users should not provide
workspace_id manually.
For production, do not set BESALES_API_BASE_URL or
BESALES_OAUTH_AUTHORIZE_URL. They default to:
BESALES_API_BASE_URL→https://core.besales.ai/api/v2(backend API host — used for MCP tool calls)BESALES_OAUTH_AUTHORIZE_URL→https://app.besales.ai/settings/mcp/consent(frontend bridge page — opened in the browser duringconnect; it mints a one-time setup ticket and forwards to the backend consent page. After approvalconnectreceives a one-timecodeon the loopback callback and exchanges it with the PKCEcode_verifierat/api/v2/auth/mcp-token— the API key never travels in a URL)
For staging or local development override them per command:
BESALES_API_BASE_URL=http://localhost:3000/api/v2 \
BESALES_OAUTH_AUTHORIZE_URL=http://localhost:5173/settings/mcp/consent \
npx -y @besales/mcp connectConfigure Your MCP Host
After connect, add the server to your MCP host and restart the host.
Claude Desktop config:
{
"mcpServers": {
"besales": {
"command": "npx",
"args": ["-y", "@besales/mcp"]
}
}
}Claude Code:
claude mcp add --scope user besales -- npx -y @besales/mcpCodex CLI:
codex mcp add besales -- npx -y @besales/mcpEquivalent Codex config:
[mcp_servers.besales]
command = "npx"
args = ["-y", "@besales/mcp"]For staging/local backends, include both backend and frontend bridge URLs in the host env. For example:
[mcp_servers.besales.env]
BESALES_API_BASE_URL = "http://localhost:3000/api/v2"
BESALES_OAUTH_AUTHORIZE_URL = "http://localhost:5173/settings/mcp/consent"Multiple Workspaces
besales-mcp can hold keys for several workspaces at once — even across
different accounts. Connect each one once (switch the account/workspace in
the browser before each connect); keys are cached in your OS keychain and
switching afterwards needs no browser.
npx -y @besales/mcp connect # workspace A (browser logged into account A)
npx -y @besales/mcp connect # workspace B (re-login in the browser first)
npx -y @besales/mcp connections # list all connections, marks the active oneBind a host session to a specific workspace with BESALES_WORKSPACE_ID in that
server's env block — the cleanest "one session = one workspace" setup (one
project/profile per workspace):
{
"mcpServers": {
"besales": {
"command": "npx",
"args": ["-y", "@besales/mcp"],
"env": { "BESALES_WORKSPACE_ID": "<workspace-uuid>" }
}
}
}[mcp_servers.besales.env]
BESALES_WORKSPACE_ID = "<workspace-uuid>"Workspace selection precedence, per tool call:
BESALES_WORKSPACE_ID(env) — authoritative; an explicit, mismatchingworkspace_idargument is refused.- an explicit
workspace_idargument (only when the env var is not set). - the session binding set by the
besales_workspace_usetool (in-memory, this session/process only — see below). - the global active workspace set by
besales-mcp use <id>. - the only connected workspace (error if several are connected and none chosen).
active is global across all env-less sessions, and BESALES_WORKSPACE_ID
always overrides it. Get workspace ids from besales-mcp connections.
GUI hosts without per-session env (e.g. Claude Desktop)
When the host has no place to set BESALES_WORKSPACE_ID per session (you just
click "new session"), there are two ways to keep several workspaces apart.
Recommended — one pinned named server per workspace (survives reconnects). Run once per workspace:
yarn install:claude-desktop --name besales-acme --workspace <uuid-A>
yarn install:claude-desktop --name besales-globex --workspace <uuid-B>This adds env-pinned mcpServers entries (with a timestamped config backup);
restart Claude Desktop. Their tools appear namespaced —
mcp__besales-acme__besales_* (always workspace A) and
mcp__besales-globex__besales_* (always B). Because the pin lives in the host
config, it survives MCP reconnects and never silently drifts to the wrong
workspace. Both toolsets are visible in every session; you just address the one
you mean.
Quick / in-session — besales_workspace_use (does NOT survive a reconnect).
Ask the assistant to call besales_workspace_use <workspaceId> to bind the
current session in-memory. Each host session runs its own besales-mcp process,
so it is per-session and touches neither the global active nor other sessions.
Caveat: the binding is in-memory only — when the host respawns the server
(reconnect, which GUI hosts do often), it is lost and falls back to the global
active. Use it for a stable stretch, not as a durable lock; for that use the
pinned named servers above. besales_workspace_current shows the current binding
- source and lists connected workspaces; it is refused under a
BESALES_WORKSPACE_IDpin (env wins).
BESALES_WORKSPACE_IDis read once at process start — exporting it after a session is already open has no effect. Restart the session to re-pin via env.
First Smoke
Start a fresh host session after changing MCP config, then ask a natural business request:
Use besales MCP to create an ICP for SaaS B2B sales automation.The assistant should discover and call the relevant besales_* tools itself.
Users should not mention tool_search and should not be asked for a
workspace_id.
Expected quick checks:
npx -y @besales/mcp statusshows connected credentials.- The host shows the
besalesMCP server as connected. - Direct tools such as
besales_icp_creatework. - External flows use
*_get_instructions, execute stages locally in the host, then call the matching*_submittool.
To switch workspace, connect each one once (see Multiple Workspaces)
and either set BESALES_WORKSPACE_ID per host session or run
npx -y @besales/mcp use <workspaceId>. No browser re-auth is needed once a
workspace is connected.
If the host still asks for workspace_id, it is usually using an old cached
tool schema or an old package version. Restart the host/session and use
@besales/mcp@latest in the host args if needed.
Development
yarn install
yarn types:gen:api
yarn types:gen:mcp
yarn buildThe generated files in src/types/ and src/schemas/ are committed because
the source contracts live outside this independent repository.
Run a lightweight local mock API for MCP Inspector tool-call smoke tests:
Terminal 1:
yarn dev:mockTerminal 2:
yarn dev:mock:seed
BESALES_API_BASE_URL=http://127.0.0.1:3100/api/v2 node bin/besales-mcp.jsyarn dev:mock:seed and yarn dev:mock:clear use the same keytar entries as
real besales-mcp connect credentials. They can overwrite or clear a local real
connection for the current macOS user.
The mock server only verifies request wiring. Live tool E2E depends on the
matching ai-aniomaly /api/v2/* endpoints.
Remove seeded mock credentials after smoke testing:
yarn dev:mock:clearCLI
node bin/besales-mcp.js connect # connect (or refresh) a workspace
node bin/besales-mcp.js connections # list connected workspaces (* = active)
node bin/besales-mcp.js use <workspaceId> # set the active (default) workspace
node bin/besales-mcp.js status # show the active workspace
node bin/besales-mcp.js disconnect # disconnect the active workspace only
node bin/besales-mcp.js disconnect <id> # disconnect one workspace
node bin/besales-mcp.js disconnect --all # disconnect every workspace
node bin/besales-mcp.js # start the MCP serverBESALES_API_BASE_URL defaults to https://core.besales.ai/api/v2 (backend).
BESALES_OAUTH_AUTHORIZE_URL defaults to
https://app.besales.ai/settings/mcp/consent (frontend bridge). For local
development point them at your local backend and frontend respectively.
Tool calls require stored credentials. Run node bin/besales-mcp.js connect
against a backend that implements the MCP OAuth endpoints
(/api/v2/auth/mcp-connect* + /api/v2/auth/mcp-token), or run
yarn dev:mock:seed for mock-only smoke tests.
For production users, do not set BESALES_API_BASE_URL or
BESALES_OAUTH_AUTHORIZE_URL. Run:
npx -y @besales/mcp connectThe browser consent flow stores the connected workspace key in the local
keychain. Workspace-level tools default to the session's workspace, so users
should not provide workspace_id manually. To work with several workspaces,
connect each once and pin sessions via BESALES_WORKSPACE_ID (or switch the
global default with besales-mcp use <id>) — see
Multiple Workspaces.
Available tools (143 tools by category)
Counts are derived from src/schemas/mcp-tools.json (summary.tools_by_category)
and asserted in src/tools/registry.spec.ts:
| Category | Tools | Notes |
|---|---|---|
| ICP (profiles, dialogue import, analysis) | 5 | incl. besales_icp_analysis_* external pair |
| ICP — read (profile / segments / scenarios / samples) | 4 | besales_icp_list / _get / _scenarios_list / _sample_messages (read-only over existing GET /api/v2/icp/*) |
| Prompt generation / analysis / lint / patch sessions | 13 | besales_prompt_*, besales_qa_generation_* external pairs |
| Sandbox / simulation / test-scenario generation | 7 | besales_sandbox_*, besales_simulation_*, besales_test_scenario_* |
| Model comparison (bake-off) | 4 | besales_model_catalog_list + besales_model_comparison_run_start / _get / _eval_submit (on-demand multi-model prompt comparison) |
| Agent / router / triggers / behavior / facts | 14 | Platform Setup Bridge (incl. besales_agent_clone, besales_behavior_update, besales_pipeline_settings_update, besales_platform_settings_update) + besales_facts_* |
| Knowledge — spaces | 6 | besales_knowledge_space_* |
| Knowledge — documents | 4 | incl. besales_knowledge_document_upload |
| Knowledge — Q&A | 7 | CRUD + semantic search + move |
| Knowledge — websites | 4 | crawl + Pinecone upsert |
| Knowledge — tables | 6 | Google Sheets link + reindex |
| Workbook ingestion (xlsx / Google Sheets) | 3 | besales_workbook_* |
| Feedback sheets (Google Sheets QA) | 5 | besales_feedback_sheet_* |
| Variables (unified) | 5 | besales_variable_* |
| CRM — pipelines, statuses, platform link | 11 | besales_crm_pipeline_*, besales_platform_pipeline_* |
| CRM — connection / field mapping / operators / activate | 7 | besales_crm_create_* (AmoCRM/Bitrix24 via browser-secrets), besales_crm_field_mapping_*, besales_crm_operator_*, besales_crm_activate (live token check + activate, deactivates other workspace CRMs) |
| Platform — provisioning / OAuth | 3 | besales_platform_create_init, besales_platform_create_status, besales_platform_create_oauth_init (Instagram/Avito) |
| Platform — clone | 3 | besales_platform_clone_* |
| Data sources (1С, категория «БД») | 9 | besales_datasource_create_* (Setup URL pattern), _list / _health / _catalogs / _catalog_roles / _role_assign / _enable / _vectorize. 1С — товарная БД через OData; чтение/запись — действия триггеров, не tools агента |
| Files | 3 | besales_file_upload_request + status + list |
| Context / overview / audit | 3 | besales_workspace_overview, besales_platform_context_get, besales_audit_revert |
| Session / workspace binding | 2 | besales_workspace_use, besales_workspace_current (in-memory per-session, local — no backend) |
Recent capabilities:
- OAuth PKCE provisioning —
besales_platform_create_oauth_initopens the authorization flow in the browser for Instagram/Avito so the OAuth code never passes through the LLM. - CRM connection via browser-secrets —
besales_crm_create_initprovisions AmoCRM/Bitrix24 (and GetCourse/Telegram) using the Setup URL pattern, where the user pastes credentials in the browser instead of through the chat. - Setup URL pattern —
*_initreturns a one-time URL; the user completes sensitive input in the browser and the host polls*_statusuntil ready. - File upload — two-step flow (
besales_file_upload_request→besales_file_upload_status) so binaries are uploaded directly, not via MCP. - Platform provisioning & clone — create channels and clone an existing
platform configuration (
besales_platform_clone_preview/_execute). - Knowledge ingestion — full namespace/document/Q&A/website/table CRUD plus workbook ingestion from xlsx and Google Sheets.
Resources
The package exposes 7 MCP concept resources:
besales://concepts/icpbesales://concepts/triggersbesales://concepts/sandboxbesales://concepts/handoffbesales://concepts/external-executionbesales://concepts/feedback-sheetsbesales://concepts/workbook-classification
Inspect them locally:
yarn dlx @modelcontextprotocol/inspector node bin/besales-mcp.jsThe Inspector should show 143 tools and 30 resources.
Claude Desktop
For local development before the package is published, install a Claude Desktop config entry with:
yarn install:claude-desktopThe installer creates a timestamped backup of the existing config and writes only
the mcpServers.besales entry. It uses the absolute Node executable path because
GUI apps may not inherit the shell PATH.
Host Setup
Host-specific local setup and smoke steps for MCP Inspector, Claude Desktop, Claude Code, and Codex CLI are documented in docs/host-setup.md.
Scope
- Claude Desktop / Claude Code / Codex call this package through MCP.
- This package calls Animaly only through
ai-aniomaly/api/v2/*. - Direct calls to
prompt-servicesare intentionally out of scope.
The package exposes 128 active MCP tools from src/schemas/mcp-tools.json.
Token scopes
Read and PromptHub/ICP/sandbox operations are covered by the composite mcp:*
scope granted during connect. Setup mutations (knowledge ingestion, variables,
CRM pipelines, platform settings/provisioning, clone, the Platform Setup Bridge,
etc.) additionally require the mcp:platform-setup scope — a plain mcp:* key
on its own does not authorize setup mutations.
