@besales/mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +127 -0
- package/bin/besales-mcp.js +10 -0
- package/dist/auth/oauth-client.d.ts +32 -0
- package/dist/auth/oauth-client.js +180 -0
- package/dist/auth/oauth-client.js.map +1 -0
- package/dist/auth/token-storage.d.ts +7 -0
- package/dist/auth/token-storage.js +17 -0
- package/dist/auth/token-storage.js.map +1 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.js +70 -0
- package/dist/cli.js.map +1 -0
- package/dist/http/api-client.d.ts +51 -0
- package/dist/http/api-client.js +115 -0
- package/dist/http/api-client.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/package-metadata.d.ts +1 -0
- package/dist/package-metadata.js +6 -0
- package/dist/package-metadata.js.map +1 -0
- package/dist/resources/concepts/external-execution.md +22 -0
- package/dist/resources/concepts/handoff.md +16 -0
- package/dist/resources/concepts/icp.md +16 -0
- package/dist/resources/concepts/sandbox.md +17 -0
- package/dist/resources/concepts/triggers.md +16 -0
- package/dist/resources/registry.d.ts +5 -0
- package/dist/resources/registry.js +33 -0
- package/dist/resources/registry.js.map +1 -0
- package/dist/schemas/mcp-tools.json +1192 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.js +74 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/contracts.d.ts +22 -0
- package/dist/tools/contracts.js +24 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/definitions.d.ts +307 -0
- package/dist/tools/definitions.js +859 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/registry.d.ts +11 -0
- package/dist/tools/registry.js +52 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/result.d.ts +4 -0
- package/dist/tools/result.js +78 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/types/api-contract.gen.d.ts +6975 -0
- package/dist/types/api-contract.gen.js +6 -0
- package/dist/types/api-contract.gen.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +13 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mask.d.ts +1 -0
- package/dist/utils/mask.js +7 -0
- package/dist/utils/mask.js.map +1 -0
- package/docs/host-setup.md +256 -0
- package/package.json +81 -0
- package/scripts/install-claude-desktop.js +77 -0
- package/scripts/mock-api-server.js +56 -0
- package/scripts/mock-credentials.js +34 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { normalizeApiBaseUrl } from '../auth/oauth-client.js';
|
|
3
|
+
import { TokenStorage } from '../auth/token-storage.js';
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
export const API_REQUEST_TIMEOUT_MS = 60_000;
|
|
6
|
+
export class ApiClientError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
responseMessage;
|
|
9
|
+
constructor(message, status, responseMessage) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.responseMessage = responseMessage;
|
|
13
|
+
this.name = 'ApiClientError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class ApiClientNetworkError extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'ApiClientNetworkError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class ApiClient {
|
|
23
|
+
apiBaseUrl;
|
|
24
|
+
tokenStorage;
|
|
25
|
+
transport;
|
|
26
|
+
timeoutMs;
|
|
27
|
+
constructor(options = {}) {
|
|
28
|
+
this.apiBaseUrl = normalizeApiBaseUrl(options.apiBaseUrl);
|
|
29
|
+
this.tokenStorage = options.tokenStorage ?? new TokenStorage();
|
|
30
|
+
this.transport =
|
|
31
|
+
options.transport ??
|
|
32
|
+
axios.create({
|
|
33
|
+
timeout: options.timeoutMs ?? API_REQUEST_TIMEOUT_MS,
|
|
34
|
+
});
|
|
35
|
+
this.timeoutMs = options.timeoutMs ?? API_REQUEST_TIMEOUT_MS;
|
|
36
|
+
}
|
|
37
|
+
async post(path, body) {
|
|
38
|
+
return this.request('POST', path, body);
|
|
39
|
+
}
|
|
40
|
+
async patch(path, body) {
|
|
41
|
+
return this.request('PATCH', path, body);
|
|
42
|
+
}
|
|
43
|
+
async getStoredWorkspaceId() {
|
|
44
|
+
return this.tokenStorage.get('workspace_id');
|
|
45
|
+
}
|
|
46
|
+
async request(method, path, body) {
|
|
47
|
+
const apiKey = await this.tokenStorage.get('api_key');
|
|
48
|
+
if (!apiKey) {
|
|
49
|
+
throw new ApiClientError('Not connected to Animaly');
|
|
50
|
+
}
|
|
51
|
+
const url = buildApiUrl(this.apiBaseUrl, path);
|
|
52
|
+
try {
|
|
53
|
+
const response = await this.transport.request({
|
|
54
|
+
method,
|
|
55
|
+
url,
|
|
56
|
+
data: body,
|
|
57
|
+
headers: {
|
|
58
|
+
Authorization: `Bearer ${apiKey}`,
|
|
59
|
+
},
|
|
60
|
+
timeout: this.timeoutMs,
|
|
61
|
+
});
|
|
62
|
+
logger.debug({ method, path, status: response.status }, 'Animaly API call completed');
|
|
63
|
+
return response.data;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (axios.isAxiosError(error)) {
|
|
67
|
+
const status = error.response?.status;
|
|
68
|
+
const responseMessage = getSafeResponseMessage(error.response?.data);
|
|
69
|
+
if (status) {
|
|
70
|
+
throw new ApiClientError(`Animaly API request failed with status ${status}`, status, responseMessage);
|
|
71
|
+
}
|
|
72
|
+
throw new ApiClientNetworkError(error.message);
|
|
73
|
+
}
|
|
74
|
+
if (error instanceof ApiClientError || error instanceof ApiClientNetworkError) {
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
if (error instanceof Error) {
|
|
78
|
+
throw new ApiClientNetworkError(error.message);
|
|
79
|
+
}
|
|
80
|
+
throw new ApiClientNetworkError('Unknown Animaly API transport error');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export function buildApiUrl(apiBaseUrl, path) {
|
|
85
|
+
const normalizedBaseUrl = normalizeApiBaseUrl(apiBaseUrl);
|
|
86
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
87
|
+
if (normalizedPath.startsWith('/api/v2/')) {
|
|
88
|
+
throw new ApiClientError('ApiClient paths must be relative to /api/v2');
|
|
89
|
+
}
|
|
90
|
+
return `${normalizedBaseUrl}${normalizedPath}`;
|
|
91
|
+
}
|
|
92
|
+
function getSafeResponseMessage(data) {
|
|
93
|
+
if (!data || typeof data !== 'object') {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
const maybeMessage = data.message;
|
|
97
|
+
if (typeof maybeMessage === 'string') {
|
|
98
|
+
return maybeMessage;
|
|
99
|
+
}
|
|
100
|
+
if (Array.isArray(maybeMessage)) {
|
|
101
|
+
return maybeMessage.filter((item) => typeof item === 'string').join('; ');
|
|
102
|
+
}
|
|
103
|
+
const maybeError = data.error;
|
|
104
|
+
if (typeof maybeError === 'string') {
|
|
105
|
+
return maybeError;
|
|
106
|
+
}
|
|
107
|
+
if (maybeError && typeof maybeError === 'object') {
|
|
108
|
+
const nestedMessage = maybeError.message;
|
|
109
|
+
if (typeof nestedMessage === 'string') {
|
|
110
|
+
return nestedMessage;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/http/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { createAuthorizationUrl, createCodeChallenge, DEFAULT_API_BASE_URL, generateCodeVerifier, generateState, normalizeApiBaseUrl, OauthClient, } from './auth/oauth-client.js';
|
|
2
|
+
export type { OAuthConnectResult, OauthClientOptions } from './auth/oauth-client.js';
|
|
3
|
+
export { TOKEN_STORAGE_SERVICE, TokenStorage, } from './auth/token-storage.js';
|
|
4
|
+
export type { TokenStorageAccount } from './auth/token-storage.js';
|
|
5
|
+
export { getHelpText, runCli } from './cli.js';
|
|
6
|
+
export type { CliDeps, CliIo, CredentialStorage, OAuthConnector } from './cli.js';
|
|
7
|
+
export { API_REQUEST_TIMEOUT_MS, ApiClient, ApiClientError, ApiClientNetworkError, buildApiUrl, } from './http/api-client.js';
|
|
8
|
+
export type { ApiClientOptions, ApiMethod, ApiTransport, ApiTransportRequest, ApiTransportResponse, CredentialReader, ToolApiClient, } from './http/api-client.js';
|
|
9
|
+
export { readPackageVersion } from './package-metadata.js';
|
|
10
|
+
export { resources } from './resources/registry.js';
|
|
11
|
+
export type { RegisteredResource } from './resources/registry.js';
|
|
12
|
+
export { callRegisteredTool, createMcpServer, listRegisteredResources, listRegisteredTools, readRegisteredResource, startMcpServer, } from './server.js';
|
|
13
|
+
export type { StartedMcpServer, StartMcpServerOptions } from './server.js';
|
|
14
|
+
export { createTools, tools } from './tools/registry.js';
|
|
15
|
+
export type { RegisteredTool, ToolFactoryOptions } from './tools/registry.js';
|
|
16
|
+
export { maskApiKey } from './utils/mask.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { createAuthorizationUrl, createCodeChallenge, DEFAULT_API_BASE_URL, generateCodeVerifier, generateState, normalizeApiBaseUrl, OauthClient, } from './auth/oauth-client.js';
|
|
2
|
+
export { TOKEN_STORAGE_SERVICE, TokenStorage, } from './auth/token-storage.js';
|
|
3
|
+
export { getHelpText, runCli } from './cli.js';
|
|
4
|
+
export { API_REQUEST_TIMEOUT_MS, ApiClient, ApiClientError, ApiClientNetworkError, buildApiUrl, } from './http/api-client.js';
|
|
5
|
+
export { readPackageVersion } from './package-metadata.js';
|
|
6
|
+
export { resources } from './resources/registry.js';
|
|
7
|
+
export { callRegisteredTool, createMcpServer, listRegisteredResources, listRegisteredTools, readRegisteredResource, startMcpServer, } from './server.js';
|
|
8
|
+
export { createTools, tools } from './tools/registry.js';
|
|
9
|
+
export { maskApiKey } from './utils/mask.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,mBAAmB,EACnB,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,qBAAqB,EACrB,YAAY,GACb,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAE/C,OAAO,EACL,sBAAsB,EACtB,SAAS,EACT,cAAc,EACd,qBAAqB,EACrB,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAU9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,uBAAuB,EACvB,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function readPackageVersion(): string;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
export function readPackageVersion() {
|
|
3
|
+
const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
4
|
+
return packageJson.version ?? '0.0.0';
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=package-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-metadata.js","sourceRoot":"","sources":["../src/package-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMvC,MAAM,UAAU,kBAAkB;IAChC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC/C,CAAC;IAErB,OAAO,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# External Execution Pattern
|
|
2
|
+
|
|
3
|
+
External execution — это двухшаговый паттерн для LLM-heavy операций, когда backend создаёт operation request и возвращает Claude инструкции, а Claude локально выполняет stages и отправляет результат обратно. Это позволяет использовать сильную локальную модель для сложной генерации, анализа или классификации, не делая prompt-services единственным местом исполнения LLM.
|
|
4
|
+
|
|
5
|
+
Паттерн всегда состоит из пары tools:
|
|
6
|
+
|
|
7
|
+
1. `*_get_instructions` — получить `operationId`, stages, schemas, ограничения, expiry и human-readable instructions.
|
|
8
|
+
2. `*_submit` — отправить structured result, compiled prompt, findings или generated QA обратно в `ai-aniomaly`.
|
|
9
|
+
|
|
10
|
+
Execution mode выбирается на backend по auth context. JWT scope `mcp:*` означает external default: backend не выполняет LLM-операцию сам, а ждёт результат от Claude. JWT scope `ui:*` означает internal default: UI может проксировать операцию в prompt-services. Старые tokens без scopes должны оставаться совместимыми и вести себя как internal.
|
|
11
|
+
|
|
12
|
+
Claude должен соблюдать invariants:
|
|
13
|
+
|
|
14
|
+
- Не менять `operationId` между get и submit.
|
|
15
|
+
- Выполнять все stages в заданном порядке.
|
|
16
|
+
- Возвращать JSON в форме, которую запросил backend.
|
|
17
|
+
- При 410 expired начинать заново с matching `*_get_instructions`.
|
|
18
|
+
- Не отправлять raw secrets, API keys или Authorization headers в submit body.
|
|
19
|
+
|
|
20
|
+
Связанные external pairs включают prompt generation, prompt iterate, prompt analyze, ICP analysis, sandbox findings, simulation findings и Q&A generation.
|
|
21
|
+
|
|
22
|
+
Практическое правило: если tool name заканчивается на `_get_instructions`, Claude должен сначала прочитать instructions, выполнить локальную работу, затем вызвать соответствующий `_submit` tool. Direct tools вроде `besales_icp_create` или `besales_sandbox_run_start` не требуют этого двухшагового режима.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Multi-agent Routing & Handoffs
|
|
2
|
+
|
|
3
|
+
Handoff — это управляемая передача диалога между агентами или от AI к человеку. Он отличается от обычного routing тем, что происходит внутри уже начавшегося conversation и должен сохранять контекст: intent, summary, extracted slots, важные ограничения, историю решений и причину передачи.
|
|
4
|
+
|
|
5
|
+
Routing отвечает на вопрос "какой агент должен принять входящий запрос сейчас". Handoff отвечает на вопрос "когда текущий агент понял, что другой агент или оператор лучше продолжит диалог". В v2-модели это не свободная LLM-команда, а набор правил и переходов с проверкой условий, прав и audit trail.
|
|
6
|
+
|
|
7
|
+
Claude должен учитывать несколько принципов:
|
|
8
|
+
|
|
9
|
+
- Handoff не должен терять память диалога: новый агент получает краткий structured summary.
|
|
10
|
+
- Передача человеку должна быть явной, особенно при юридических, финансовых, конфликтных или sales-closing сценариях.
|
|
11
|
+
- Multi-agent маршруты должны быть детерминированными там, где это возможно, и LLM-assisted только для классификации intent или ambiguity resolution.
|
|
12
|
+
- Sandbox должен проверять handoff behavior без реального перевода клиента в production queue.
|
|
13
|
+
|
|
14
|
+
В рамках Track D нет отдельного MCP tool для универсального handoff. Этот resource нужен как контекст для prompt generation, analysis и sandbox findings. Если пользователь просит улучшить routing/handoff, Claude должен формулировать требования к агенту и подсвечивать, какие проверки нужно прогнать в sandbox, а не вызывать несуществующий hidden action.
|
|
15
|
+
|
|
16
|
+
Практическое правило: handoff считается хорошим, если пользователь понимает, почему его переводят, следующий обработчик получает достаточный контекст, а audit trail объясняет причину решения.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# ICP Concept Reference
|
|
2
|
+
|
|
3
|
+
ICP (Ideal Customer Profile) в Besales описывает не абстрактную аудиторию для рассылок, а рабочую модель покупателя, по которой строятся промпты, сценарии проверки и sandbox-симуляции. ICP объединяет сегменты, personas, реальные или импортированные dialogue samples и test scenarios. Он помогает агенту отвечать не "для всех", а под конкретные боли, критерии выбора, возражения и стиль коммуникации целевого клиента.
|
|
4
|
+
|
|
5
|
+
В v1.5 ICP хранится в новых таблицах `icp_profiles`, `icp_segments`, `icp_dialogue_samples`, `personas`, `test_scenarios` и связывается с агентами через `agent_icp_links`. Эти таблицы создаются сразу в v2-shape, поэтому MCP tools работают с будущей моделью данных без прямого доступа к существующим v1 сущностям.
|
|
6
|
+
|
|
7
|
+
Когда Claude создаёт ICP через MCP, он должен сначала определить workspace context и выбрать источник: ручное описание, CRM dialogues или AI-generated draft. Для CRM-источника используется импорт samples с анонимизацией и подтверждением GDPR. После накопления samples Claude может запросить analysis instructions, локально выполнить stage-пайплайн сегментации/persona generation и отправить результат через submit tool.
|
|
8
|
+
|
|
9
|
+
Связанные tools:
|
|
10
|
+
|
|
11
|
+
- `besales_icp_create` — создать ICP-профиль.
|
|
12
|
+
- `besales_icp_import_dialogues` — импортировать и анонимизировать CRM-диалоги.
|
|
13
|
+
- `besales_icp_analysis_get_instructions` — получить stages для анализа ICP.
|
|
14
|
+
- `besales_icp_analysis_submit` — сохранить сегменты, personas и сценарии после external execution.
|
|
15
|
+
|
|
16
|
+
Практическое правило: если пользователь просит "создай ICP для SaaS B2B", Claude должен создать профиль, затем уточнить или импортировать samples, после чего выполнить analysis pair. ICP не заменяет prompt generation, а даёт ей качественный контекст.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Sandbox Reference
|
|
2
|
+
|
|
3
|
+
Sandbox в Besales — это контролируемый прогон агента по ICP personas и test scenarios до выката изменений в production. Цель sandbox не в том, чтобы отправить реальные сообщения клиентам, а в том, чтобы проверить промпт, routing, ответы на возражения, handoff-поведение и качество реакции на разные сегменты.
|
|
4
|
+
|
|
5
|
+
В v1.5 sandbox реализуется как отдельный домен с `sandbox_runs` и `sandbox_run_feedbacks`. Запуск создаёт run для агента и набора сценариев, а дальнейший анализ findings может выполняться через external execution pair. Production runtime остаётся authoritative через `AgentChat.baseSystemPrompt`, но sandbox позволяет безопасно оценить draft или updated prompt до approve/finalize.
|
|
6
|
+
|
|
7
|
+
Для Claude важна последовательность:
|
|
8
|
+
|
|
9
|
+
1. Запустить sandbox run через `besales_sandbox_run_start`.
|
|
10
|
+
2. Получить или дождаться результатов run в backend/UI.
|
|
11
|
+
3. Вызвать `besales_sandbox_findings_get_instructions`, если нужно проанализировать findings.
|
|
12
|
+
4. Локально выполнить stages: сгруппировать проблемы, оценить severity, предложить улучшения.
|
|
13
|
+
5. Отправить результат через `besales_sandbox_findings_submit`.
|
|
14
|
+
|
|
15
|
+
Sandbox не должен обращаться к реальным channel adapters и не должен создавать внешние side effects. Если сценарий требует проверки CRM или отправки сообщений, backend должен использовать sandbox adapters/ports или mock behavior.
|
|
16
|
+
|
|
17
|
+
Практическое правило: sandbox — это безопасная проверка качества агента. Claude должен использовать его перед финализацией рискованных prompt changes, особенно если ICP содержит несколько сегментов или есть новые handoff/routing правила.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Actions & Triggers Reference
|
|
2
|
+
|
|
3
|
+
Actions и triggers описывают управляемые действия агента: что можно сделать, при каких условиях и через какой безопасный runtime path. В v2-подходе LLM не должен галлюцинировать UUID триггеров или напрямую выбирать произвольные side effects. Вместо этого агент получает ограниченный набор action keys, а серверная оркестрация проверяет условия, права, governance и порядок выполнения.
|
|
4
|
+
|
|
5
|
+
Trigger — это событие или условие, которое запускает действие: intent в диалоге, значение переменной, изменение pipeline/status, ручной запуск или системный workflow. Action — декларативная конфигурация шага: отправить сообщение, установить переменную, вызвать CRM-операцию, передать диалог оператору, инициировать routing или другой безопасный side effect.
|
|
6
|
+
|
|
7
|
+
Для Claude Desktop это reference resource, а не action surface. MCP tools из Track D не дают прямой универсальный `run_trigger` tool: пользовательские side effects должны идти через конкретные `/api/v2/*` endpoints и backend governance. Если пользователь просит "добавь триггер", Claude должен использовать это описание как терминологический контекст и перейти к соответствующим UI/API задачам, а не пытаться вызвать скрытый trigger напрямую.
|
|
8
|
+
|
|
9
|
+
Связанные идеи:
|
|
10
|
+
|
|
11
|
+
- LLM-visible actions должны иметь стабильные semantic keys, а не database IDs.
|
|
12
|
+
- Runtime должен фильтровать доступные actions по агенту, workspace и mode.
|
|
13
|
+
- Sandbox проверяет effects через sandbox ports, не через production side effects.
|
|
14
|
+
- Handoff и routing являются отдельными управляемыми flows, а не свободным текстовым "переключи агента".
|
|
15
|
+
|
|
16
|
+
Практическое правило: Claude может объяснять и проектировать triggers/actions, но исполнять должен только конкретные MCP tools или backend endpoints, которые явно есть в contract.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { getResourceContracts } from '../tools/contracts.js';
|
|
3
|
+
const conceptFilesByUri = {
|
|
4
|
+
'besales://concepts/icp': 'icp.md',
|
|
5
|
+
'besales://concepts/triggers': 'triggers.md',
|
|
6
|
+
'besales://concepts/sandbox': 'sandbox.md',
|
|
7
|
+
'besales://concepts/handoff': 'handoff.md',
|
|
8
|
+
'besales://concepts/external-execution': 'external-execution.md',
|
|
9
|
+
};
|
|
10
|
+
function conceptUrl(fileName) {
|
|
11
|
+
return new URL(`./concepts/${fileName}`, import.meta.url);
|
|
12
|
+
}
|
|
13
|
+
function createResource(contract) {
|
|
14
|
+
const fileName = conceptFilesByUri[contract.uri];
|
|
15
|
+
if (!fileName) {
|
|
16
|
+
throw new Error(`Concept resource file mapping not found: ${contract.uri}`);
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
uri: contract.uri,
|
|
20
|
+
name: contract.name,
|
|
21
|
+
description: contract.description,
|
|
22
|
+
mimeType: contract.mimeType,
|
|
23
|
+
async read() {
|
|
24
|
+
return {
|
|
25
|
+
uri: contract.uri,
|
|
26
|
+
mimeType: contract.mimeType,
|
|
27
|
+
text: await readFile(conceptUrl(fileName), 'utf-8'),
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export const resources = getResourceContracts().map(createResource);
|
|
33
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/resources/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5C,OAAO,EAAE,oBAAoB,EAAyB,MAAM,uBAAuB,CAAC;AAMpF,MAAM,iBAAiB,GAAqC;IAC1D,wBAAwB,EAAE,QAAQ;IAClC,6BAA6B,EAAE,aAAa;IAC5C,4BAA4B,EAAE,YAAY;IAC1C,4BAA4B,EAAE,YAAY;IAC1C,uCAAuC,EAAE,uBAAuB;CACjE,CAAC;AAEF,SAAS,UAAU,CAAC,QAAgB;IAClC,OAAO,IAAI,GAAG,CAAC,cAAc,QAAQ,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,cAAc,CAAC,QAA0B;IAChD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAEjD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,4CAA4C,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO;QACL,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,KAAK,CAAC,IAAI;YACR,OAAO;gBACL,GAAG,EAAE,QAAQ,CAAC,GAAG;gBACjB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,IAAI,EAAE,MAAM,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;aACpD,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAyB,oBAAoB,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC"}
|