mcp-creatio 0.4.0 → 0.5.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/README.md +252 -212
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +18 -11
- package/dist/cli.js.map +1 -1
- package/dist/creatio/auth/auth.d.ts +2 -0
- package/dist/creatio/auth/auth.d.ts.map +1 -1
- package/dist/creatio/auth/auth.js.map +1 -1
- package/dist/creatio/auth/providers/base-provider.d.ts +1 -0
- package/dist/creatio/auth/providers/base-provider.d.ts.map +1 -1
- package/dist/creatio/auth/providers/base-provider.js +3 -0
- package/dist/creatio/auth/providers/base-provider.js.map +1 -1
- package/dist/creatio/auth/providers/oauth2-code-provider.d.ts +3 -0
- package/dist/creatio/auth/providers/oauth2-code-provider.d.ts.map +1 -1
- package/dist/creatio/auth/providers/oauth2-code-provider.js +30 -24
- package/dist/creatio/auth/providers/oauth2-code-provider.js.map +1 -1
- package/dist/creatio/providers/configuration-provider.d.ts +3 -2
- package/dist/creatio/providers/configuration-provider.d.ts.map +1 -1
- package/dist/creatio/providers/crud-provider.d.ts +2 -0
- package/dist/creatio/providers/crud-provider.d.ts.map +1 -1
- package/dist/creatio/services/configuration-service-provider.d.ts.map +1 -1
- package/dist/creatio/services/configuration-service-provider.js +11 -3
- package/dist/creatio/services/configuration-service-provider.js.map +1 -1
- package/dist/creatio/services/http-client.d.ts.map +1 -1
- package/dist/creatio/services/http-client.js +0 -1
- package/dist/creatio/services/http-client.js.map +1 -1
- package/dist/creatio/services/metadata-store.d.ts +5 -0
- package/dist/creatio/services/metadata-store.d.ts.map +1 -1
- package/dist/creatio/services/metadata-store.js +18 -6
- package/dist/creatio/services/metadata-store.js.map +1 -1
- package/dist/creatio/services/odata-crud-provider.d.ts +3 -1
- package/dist/creatio/services/odata-crud-provider.d.ts.map +1 -1
- package/dist/creatio/services/odata-crud-provider.js +31 -8
- package/dist/creatio/services/odata-crud-provider.js.map +1 -1
- package/dist/server/http/creatio-oauth-handlers.d.ts +0 -1
- package/dist/server/http/creatio-oauth-handlers.d.ts.map +1 -1
- package/dist/server/http/creatio-oauth-handlers.js +30 -23
- package/dist/server/http/creatio-oauth-handlers.js.map +1 -1
- package/dist/server/http/httpServer.d.ts +9 -0
- package/dist/server/http/httpServer.d.ts.map +1 -1
- package/dist/server/http/httpServer.js +34 -11
- package/dist/server/http/httpServer.js.map +1 -1
- package/dist/server/http/mcp-handlers.d.ts.map +1 -1
- package/dist/server/http/mcp-handlers.js +4 -1
- package/dist/server/http/mcp-handlers.js.map +1 -1
- package/dist/server/http/mcp-oauth-handlers.d.ts.map +1 -1
- package/dist/server/http/mcp-oauth-handlers.js +18 -6
- package/dist/server/http/mcp-oauth-handlers.js.map +1 -1
- package/dist/server/http/middleware.d.ts +7 -0
- package/dist/server/http/middleware.d.ts.map +1 -1
- package/dist/server/http/middleware.js +23 -0
- package/dist/server/http/middleware.js.map +1 -1
- package/dist/server/http/rate-limiter.d.ts +24 -0
- package/dist/server/http/rate-limiter.d.ts.map +1 -0
- package/dist/server/http/rate-limiter.js +42 -0
- package/dist/server/http/rate-limiter.js.map +1 -0
- package/dist/server/mcp/creatio-rest.d.ts +44 -0
- package/dist/server/mcp/creatio-rest.d.ts.map +1 -0
- package/dist/server/mcp/creatio-rest.js +26 -0
- package/dist/server/mcp/creatio-rest.js.map +1 -0
- package/dist/server/mcp/crtmcp/crt-mcp-client.d.ts +55 -0
- package/dist/server/mcp/crtmcp/crt-mcp-client.d.ts.map +1 -0
- package/dist/server/mcp/crtmcp/crt-mcp-client.js +67 -0
- package/dist/server/mcp/crtmcp/crt-mcp-client.js.map +1 -0
- package/dist/server/mcp/crtmcp/crt-mcp-tool-preparer.d.ts +20 -0
- package/dist/server/mcp/crtmcp/crt-mcp-tool-preparer.d.ts.map +1 -0
- package/dist/server/mcp/crtmcp/crt-mcp-tool-preparer.js +74 -0
- package/dist/server/mcp/crtmcp/crt-mcp-tool-preparer.js.map +1 -0
- package/dist/server/mcp/dataforge/dataforge-client.d.ts +64 -0
- package/dist/server/mcp/dataforge/dataforge-client.d.ts.map +1 -0
- package/dist/server/mcp/dataforge/dataforge-client.js +130 -0
- package/dist/server/mcp/dataforge/dataforge-client.js.map +1 -0
- package/dist/server/mcp/dataforge/dataforge-tool-preparer.d.ts +17 -0
- package/dist/server/mcp/dataforge/dataforge-tool-preparer.d.ts.map +1 -0
- package/dist/server/mcp/dataforge/dataforge-tool-preparer.js +42 -0
- package/dist/server/mcp/dataforge/dataforge-tool-preparer.js.map +1 -0
- package/dist/server/mcp/filters.d.ts.map +1 -1
- package/dist/server/mcp/filters.js +20 -4
- package/dist/server/mcp/filters.js.map +1 -1
- package/dist/server/mcp/globalsearch/globalsearch-client.d.ts +50 -0
- package/dist/server/mcp/globalsearch/globalsearch-client.d.ts.map +1 -0
- package/dist/server/mcp/globalsearch/globalsearch-client.js +118 -0
- package/dist/server/mcp/globalsearch/globalsearch-client.js.map +1 -0
- package/dist/server/mcp/globalsearch/globalsearch-tool-preparer.d.ts +16 -0
- package/dist/server/mcp/globalsearch/globalsearch-tool-preparer.d.ts.map +1 -0
- package/dist/server/mcp/globalsearch/globalsearch-tool-preparer.js +34 -0
- package/dist/server/mcp/globalsearch/globalsearch-tool-preparer.js.map +1 -0
- package/dist/server/mcp/json-schema-to-zod.d.ts +3 -0
- package/dist/server/mcp/json-schema-to-zod.d.ts.map +1 -0
- package/dist/server/mcp/json-schema-to-zod.js +54 -0
- package/dist/server/mcp/json-schema-to-zod.js.map +1 -0
- package/dist/server/mcp/server.d.ts +18 -0
- package/dist/server/mcp/server.d.ts.map +1 -1
- package/dist/server/mcp/server.js +93 -25
- package/dist/server/mcp/server.js.map +1 -1
- package/dist/server/mcp/tool-preparer.d.ts +26 -0
- package/dist/server/mcp/tool-preparer.d.ts.map +1 -0
- package/dist/server/mcp/tool-preparer.js +11 -0
- package/dist/server/mcp/tool-preparer.js.map +1 -0
- package/dist/server/mcp/tools-data.d.ts +69 -10
- package/dist/server/mcp/tools-data.d.ts.map +1 -1
- package/dist/server/mcp/tools-data.js +222 -32
- package/dist/server/mcp/tools-data.js.map +1 -1
- package/dist/server/oauth/oauth-server.d.ts +0 -1
- package/dist/server/oauth/oauth-server.d.ts.map +1 -1
- package/dist/server/oauth/oauth-server.js +11 -21
- package/dist/server/oauth/oauth-server.js.map +1 -1
- package/dist/server/oauth/storage.d.ts +0 -2
- package/dist/server/oauth/storage.d.ts.map +1 -1
- package/dist/server/oauth/storage.js +0 -6
- package/dist/server/oauth/storage.js.map +1 -1
- package/dist/server/oauth/validators.d.ts +6 -0
- package/dist/server/oauth/validators.d.ts.map +1 -1
- package/dist/server/oauth/validators.js +28 -0
- package/dist/server/oauth/validators.js.map +1 -1
- package/dist/services/session-context.d.ts +8 -7
- package/dist/services/session-context.d.ts.map +1 -1
- package/dist/services/session-context.js +7 -27
- package/dist/services/session-context.js.map +1 -1
- package/package.json +18 -9
- package/.dockerignore +0 -12
- package/.editorconfig +0 -14
- package/.eslintrc.cjs +0 -18
- package/.gitattributes +0 -8
- package/.github/workflows/docker-publish.yml +0 -50
- package/.prettierignore +0 -3
- package/.prettierrc +0 -9
- package/.vscode/launch.json +0 -23
- package/.vscode/mcp.json +0 -13
- package/.vscode/settings.json +0 -16
- package/Agent.md +0 -190
- package/Debug.md +0 -32
- package/Dockerfile +0 -23
- package/docs/coding-style.md +0 -30
- package/eslint.config.cjs +0 -95
- package/src/cli.ts +0 -162
- package/src/config-builder.ts +0 -76
- package/src/consts.ts +0 -3
- package/src/creatio/auth/auth-manager.ts +0 -27
- package/src/creatio/auth/auth.ts +0 -31
- package/src/creatio/auth/index.ts +0 -3
- package/src/creatio/auth/providers/base-oauth2-provider.ts +0 -62
- package/src/creatio/auth/providers/base-provider.ts +0 -42
- package/src/creatio/auth/providers/index.ts +0 -4
- package/src/creatio/auth/providers/legacy-provider.ts +0 -70
- package/src/creatio/auth/providers/oauth2-code-provider.ts +0 -252
- package/src/creatio/auth/providers/oauth2-provider.ts +0 -91
- package/src/creatio/auth/providers/type.ts +0 -5
- package/src/creatio/client-config.ts +0 -34
- package/src/creatio/engines/admin-operation/admin-operation-engine.ts +0 -44
- package/src/creatio/engines/configuration/configuration-engine.ts +0 -26
- package/src/creatio/engines/crud/crud-engine.ts +0 -47
- package/src/creatio/engines/engine-manager.ts +0 -157
- package/src/creatio/engines/engine-registry.ts +0 -39
- package/src/creatio/engines/engine.ts +0 -3
- package/src/creatio/engines/feature/feature-engine.ts +0 -20
- package/src/creatio/engines/index.ts +0 -10
- package/src/creatio/engines/process/process-engine.ts +0 -20
- package/src/creatio/engines/sys-settings/sys-settings-engine.ts +0 -41
- package/src/creatio/engines/user/user-engine.ts +0 -20
- package/src/creatio/index.ts +0 -6
- package/src/creatio/provider-context.ts +0 -21
- package/src/creatio/providers/admin-operation-provider.ts +0 -34
- package/src/creatio/providers/configuration-provider.ts +0 -22
- package/src/creatio/providers/crud-provider.ts +0 -45
- package/src/creatio/providers/feature-provider.ts +0 -10
- package/src/creatio/providers/index.ts +0 -7
- package/src/creatio/providers/process-provider.ts +0 -15
- package/src/creatio/providers/sys-settings-provider.ts +0 -63
- package/src/creatio/providers/user-provider.ts +0 -12
- package/src/creatio/services/admin-operation-service-provider.ts +0 -115
- package/src/creatio/services/configuration-service-provider.ts +0 -127
- package/src/creatio/services/creatio-service-context.ts +0 -55
- package/src/creatio/services/feature-service-provider.ts +0 -60
- package/src/creatio/services/http-client.ts +0 -174
- package/src/creatio/services/index.ts +0 -10
- package/src/creatio/services/metadata-store.ts +0 -181
- package/src/creatio/services/odata-crud-provider.ts +0 -210
- package/src/creatio/services/process-service-provider.ts +0 -76
- package/src/creatio/services/sys-settings-service-provider.ts +0 -192
- package/src/creatio/services/user-info-provider.ts +0 -41
- package/src/index.ts +0 -44
- package/src/log.ts +0 -183
- package/src/server/http/creatio-oauth-handlers.ts +0 -146
- package/src/server/http/httpServer.ts +0 -150
- package/src/server/http/index.ts +0 -5
- package/src/server/http/mcp-handlers.ts +0 -92
- package/src/server/http/mcp-oauth-handlers.ts +0 -108
- package/src/server/http/middleware.ts +0 -91
- package/src/server/index.ts +0 -2
- package/src/server/mcp/filters.ts +0 -97
- package/src/server/mcp/index.ts +0 -1
- package/src/server/mcp/prompts-data.ts +0 -1292
- package/src/server/mcp/server.ts +0 -442
- package/src/server/mcp/tools-data.ts +0 -748
- package/src/server/oauth/client-manager.ts +0 -47
- package/src/server/oauth/index.ts +0 -6
- package/src/server/oauth/oauth-server.ts +0 -185
- package/src/server/oauth/storage.ts +0 -106
- package/src/server/oauth/token-manager.ts +0 -80
- package/src/server/oauth/types.ts +0 -55
- package/src/server/oauth/validators.ts +0 -56
- package/src/services/index.ts +0 -2
- package/src/services/session-context.ts +0 -232
- package/src/services/token-refresh-scheduler.ts +0 -68
- package/src/types/index.ts +0 -1
- package/src/types/network.ts +0 -7
- package/src/utils/context.ts +0 -49
- package/src/utils/env.ts +0 -12
- package/src/utils/index.ts +0 -5
- package/src/utils/mcp.ts +0 -8
- package/src/utils/network.ts +0 -65
- package/src/utils/pkce.ts +0 -39
- package/src/version.ts +0 -15
- package/tsconfig.json +0 -28
|
@@ -1,1292 +0,0 @@
|
|
|
1
|
-
const DEFAULT_ACTIVITY_IDS = {
|
|
2
|
-
TYPE_TASK: 'fbe0acdc-cfc0-df11-b00f-001d60e938c6',
|
|
3
|
-
CATEGORY_TODO: 'f2c0ce0e-cfc1-df11-b00f-001d60e938c6',
|
|
4
|
-
STATUS_NOT_STARTED: '384d4b84-58e6-df11-971b-001d60e938c6',
|
|
5
|
-
PRIORITY_MEDIUM: 'ab96fa02-7fe6-df11-971b-001d60e938c6',
|
|
6
|
-
} as const;
|
|
7
|
-
|
|
8
|
-
const ACTIVITY_TYPE_TABLE = `
|
|
9
|
-
| User says / intent | TypeId → Type (fixed) | Category (set via ActivityCategoryId) |
|
|
10
|
-
|--------------------|-----------------------|---------------------------------------|
|
|
11
|
-
| task / todo (default) | Task | To do |
|
|
12
|
-
| meeting / meet / sync | Task | Meeting |
|
|
13
|
-
| call / phone | Task | Call |
|
|
14
|
-
| email / mail | Task | Email |
|
|
15
|
-
|
|
16
|
-
💡 We deliberately keep Type always = Task for speed. Change only if user explicitly insists: "Use real meeting type".
|
|
17
|
-
`.trim();
|
|
18
|
-
|
|
19
|
-
const CREATE_ACTIVITY_WORKFLOW = `
|
|
20
|
-
# 🆕 Create Activity in Creatio (Optimized 99% Case)
|
|
21
|
-
|
|
22
|
-
⚠️⚠️⚠️ FIRST STEP - ALWAYS CALL get-current-user-info FIRST! ⚠️⚠️⚠️
|
|
23
|
-
|
|
24
|
-
Before creating ANY activity, you MUST:
|
|
25
|
-
1. Call 'get-current-user-info' tool (no parameters)
|
|
26
|
-
2. Extract contactId from response
|
|
27
|
-
3. Store contactId in memory
|
|
28
|
-
4. Use contactId as OwnerId and AuthorId in the activity
|
|
29
|
-
|
|
30
|
-
DO NOT skip this step! Activities require valid OwnerId and AuthorId (both = contactId).
|
|
31
|
-
|
|
32
|
-
## Why Simplified?
|
|
33
|
-
Business usage: almost all activities should just appear in calendar quickly. So we hardcode **Type = Task** and only adjust the **Category** to reflect intent (meeting / call / email / todo). This minimizes API calls and cognitive load.
|
|
34
|
-
|
|
35
|
-
If user explicitly insists: "Use real meeting type" / "Set actual Call type" → THEN switch to extended lookup mode (ActivityType + ActivityCategory must match). Otherwise stay in fast mode.
|
|
36
|
-
|
|
37
|
-
⚠️ ABSOLUTE RULE:
|
|
38
|
-
Always set **TypeId = Task** for intents like "meeting", "meet", "sync", "call", "phone", "email", "mail", "todo", "task" UNLESS (and only unless) the user explicitly demands a non-Task type using phrases such as:
|
|
39
|
-
"real meeting type", "actual meeting type", "true call type", "use real ActivityType", "not a task", "change the Type itself", "use Visit type", "use Call type id".
|
|
40
|
-
|
|
41
|
-
Plain requests like "create a meeting", "schedule a call", "create email follow-up" DO *NOT* justify changing Type. Treat them as Category changes only.
|
|
42
|
-
|
|
43
|
-
🚫 NEVER perform ActivityType lookups for Meeting/Call/Email unless escalation trigger is present. Doing so wastes calls and breaks the 99% optimization goal.
|
|
44
|
-
|
|
45
|
-
❌ WRONG (for ordinary meeting request): Query ActivityType 'Visit' then set TypeId=Visit.
|
|
46
|
-
✅ RIGHT: Keep TypeId=Task; lookup only ActivityCategory 'Meeting'.
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
## 📋 STEP 1: Parse Intent → Decide Category (Type fixed = Task)
|
|
50
|
-
|
|
51
|
-
Ask (if unclear): "What kind of activity? (task / meeting / call / email)". Default = task.
|
|
52
|
-
|
|
53
|
-
${ACTIVITY_TYPE_TABLE}
|
|
54
|
-
|
|
55
|
-
GUIDs we already have (hardcoded):
|
|
56
|
-
- TypeId (Task): ${DEFAULT_ACTIVITY_IDS.TYPE_TASK}
|
|
57
|
-
- Default Category (To do): ${DEFAULT_ACTIVITY_IDS.CATEGORY_TODO}
|
|
58
|
-
- Default Status (Not started): ${DEFAULT_ACTIVITY_IDS.STATUS_NOT_STARTED}
|
|
59
|
-
- Default Priority (Medium): ${DEFAULT_ACTIVITY_IDS.PRIORITY_MEDIUM}
|
|
60
|
-
|
|
61
|
-
If category ≠ To do (e.g. Meeting / Call / Email) and you don't have its GUID cached:
|
|
62
|
-
1. Query ActivityCategory by Name (e.g. filter: "Name eq 'Meeting'") select Id top 1
|
|
63
|
-
2. Use returned Id as ActivityCategoryId
|
|
64
|
-
|
|
65
|
-
Do NOT query ActivityType unless user demands non-Task type explicitly.
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
## 👤 STEP 2: Resolve ContactId (Owner/Author) - USE get-current-user-info!
|
|
69
|
-
|
|
70
|
-
🎯 **DEFAULT BEHAVIOR: Activities are ALWAYS created for the current user!**
|
|
71
|
-
|
|
72
|
-
Unless the user **explicitly** requests to create an activity for someone else (e.g., "create a task for John", "schedule meeting for Anna"),
|
|
73
|
-
**ALWAYS** use the current user's ContactId as both OwnerId and AuthorId.
|
|
74
|
-
|
|
75
|
-
### Get Current User ContactId:
|
|
76
|
-
|
|
77
|
-
**MANDATORY FIRST CALL:** Use \`get-current-user-info\` tool:
|
|
78
|
-
|
|
79
|
-
STEP 1: Call \`get-current-user-info\` (no parameters) ← DO THIS NOW if not done yet!
|
|
80
|
-
STEP 2: Extract \`contactId\` from response
|
|
81
|
-
STEP 3: Use contactId for OwnerId & AuthorId
|
|
82
|
-
|
|
83
|
-
**Alternative (Legacy):** Query SysAdminUnit once for ContactId (NOT Id!). Store and reuse.
|
|
84
|
-
|
|
85
|
-
⚠️ CRITICAL:
|
|
86
|
-
- Never use SysAdminUnit.Id for Owner/Author fields. Always use ContactId!
|
|
87
|
-
- By default, OwnerId = AuthorId = current user's ContactId
|
|
88
|
-
- Only change if user explicitly says "for [other person]"
|
|
89
|
-
|
|
90
|
-
See /contactid-guide prompt for detailed explanation.
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
## ⏰ STEP 3: Timezone Handling
|
|
94
|
-
|
|
95
|
-
Always confirm timezone → convert to UTC → ISO 8601 with Z. See /datetime-guide for full details.
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
## 🔨 STEP 4: Construct Payload
|
|
99
|
-
|
|
100
|
-
Base payload:
|
|
101
|
-
\`\`\`json
|
|
102
|
-
{
|
|
103
|
-
"entity": "Activity",
|
|
104
|
-
"data": {
|
|
105
|
-
"Title": "<title>",
|
|
106
|
-
"TypeId": "${DEFAULT_ACTIVITY_IDS.TYPE_TASK}",
|
|
107
|
-
"ActivityCategoryId": "<category-guid>",
|
|
108
|
-
"StartDate": "<utc-start>",
|
|
109
|
-
"DueDate": "<utc-due>",
|
|
110
|
-
"StatusId": "${DEFAULT_ACTIVITY_IDS.STATUS_NOT_STARTED}",
|
|
111
|
-
"OwnerId": "<contactId>",
|
|
112
|
-
"AuthorId": "<contactId>",
|
|
113
|
-
"PriorityId": "${DEFAULT_ACTIVITY_IDS.PRIORITY_MEDIUM}",
|
|
114
|
-
"ShowInScheduler": true
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
\`\`\`
|
|
118
|
-
|
|
119
|
-
**CRITICAL:** Always set \`"ShowInScheduler": true\` for meetings/calls/events so they appear in the calendar!
|
|
120
|
-
Only set to false if user explicitly requests the activity to be hidden from calendar.
|
|
121
|
-
|
|
122
|
-
If user supplies duration only (e.g. 30m) → compute DueDate = StartDate + duration.
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
## 👥 STEP 5: Add Participants (Optional)
|
|
126
|
-
|
|
127
|
-
If user requests to add participants to a meeting/call/activity:
|
|
128
|
-
- User says: "add John to the meeting", "invite Anna", "add participant [Name]"
|
|
129
|
-
|
|
130
|
-
### How to Add Participants:
|
|
131
|
-
|
|
132
|
-
1. **Find the Contact:** Query Contact entity by Name to get ContactId
|
|
133
|
-
\`\`\`json
|
|
134
|
-
{
|
|
135
|
-
"entity": "Contact",
|
|
136
|
-
"filter": "contains(Name, 'John')",
|
|
137
|
-
"select": ["Id", "Name"],
|
|
138
|
-
"top": 1
|
|
139
|
-
}
|
|
140
|
-
\`\`\`
|
|
141
|
-
|
|
142
|
-
2. **Create ActivityParticipant record:**
|
|
143
|
-
\`\`\`json
|
|
144
|
-
{
|
|
145
|
-
"entity": "ActivityParticipant",
|
|
146
|
-
"data": {
|
|
147
|
-
"ActivityId": "<activity-guid>",
|
|
148
|
-
"ParticipantId": "<contact-guid>"
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
\`\`\`
|
|
152
|
-
|
|
153
|
-
⚠️ **IMPORTANT:**
|
|
154
|
-
- ActivityId = GUID of the Activity (meeting/call/task)
|
|
155
|
-
- ParticipantId = ContactId of the person to add
|
|
156
|
-
- **NO other fields needed!** Just these two fields are sufficient.
|
|
157
|
-
- You can add multiple participants by creating multiple ActivityParticipant records
|
|
158
|
-
|
|
159
|
-
### Example:
|
|
160
|
-
User: "Add John and Mary to tomorrow's meeting"
|
|
161
|
-
1. Create Activity → get activityId
|
|
162
|
-
2. Find Contact "John" → get johnContactId
|
|
163
|
-
3. Create ActivityParticipant { ActivityId: activityId, ParticipantId: johnContactId }
|
|
164
|
-
4. Find Contact "Mary" → get maryContactId
|
|
165
|
-
5. Create ActivityParticipant { ActivityId: activityId, ParticipantId: maryContactId }
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
## ✅ Example (Meeting intent, fast mode)
|
|
169
|
-
|
|
170
|
-
User: "Schedule meeting tomorrow 14:00" → ask timezone → user: "UTC+2" → 14:00 UTC+2 = 12:00Z.
|
|
171
|
-
1. Resolve ContactId (SysAdminUnit query once)
|
|
172
|
-
2. Lookup ActivityCategory 'Meeting' (if not cached)
|
|
173
|
-
3. Create with Type=Task, Category=Meeting
|
|
174
|
-
|
|
175
|
-
---
|
|
176
|
-
## 🔁 Escalation to Extended Mode (Rare)
|
|
177
|
-
Trigger only if user supplies explicit escalation phrase (contains one of: "real", "actual", "true", "non-task", "not a task", "use real type", "use Visit type", "use Call type", "change the TypeId"). Simple intent words (meeting/call/email) are NOT escalation.
|
|
178
|
-
If triggered:
|
|
179
|
-
1. Query ActivityType by Name (Call / Email / Visit)
|
|
180
|
-
2. Query matching ActivityCategory
|
|
181
|
-
3. Replace TypeId with looked up Id. (Ensure combination is valid.)
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
## 🚨 Common Mistakes
|
|
185
|
-
❌ Unnecessary lookups for Meeting/Call when fast mode sufficient
|
|
186
|
-
❌ Using SysAdminUnit.Id instead of ContactId
|
|
187
|
-
❌ Skipping timezone confirmation
|
|
188
|
-
❌ Forgetting Z suffix
|
|
189
|
-
❌ Mismatching explicit non-Task request (ignore only if user accepts fast mode)
|
|
190
|
-
❌ Adding extra fields to ActivityParticipant (only ActivityId + ParticipantId needed!)
|
|
191
|
-
❌ Forgetting to create ActivityParticipant records when user asks to add participants
|
|
192
|
-
|
|
193
|
-
---
|
|
194
|
-
## 🧠 Decision Heuristics
|
|
195
|
-
If user is vague: default Category = To do.
|
|
196
|
-
If keywords: "meeting", "meet", "sync" → Meeting category.
|
|
197
|
-
"call", "phone" → Call category.
|
|
198
|
-
"email", "mail" → Email category.
|
|
199
|
-
Explicit: "task" / nothing → To do.
|
|
200
|
-
|
|
201
|
-
Return the minimal number of read calls (cache category GUIDs when first resolved in session).
|
|
202
|
-
`.trim();
|
|
203
|
-
|
|
204
|
-
const DATETIME_GUIDE = `
|
|
205
|
-
# ⏰ DateTime and Timezone Guide for Creatio
|
|
206
|
-
|
|
207
|
-
## The Problem
|
|
208
|
-
You do NOT automatically know the user's timezone!
|
|
209
|
-
Dates in Creatio must be stored in UTC with ISO 8601 format.
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
## ✅ The Solution: Always Ask!
|
|
214
|
-
|
|
215
|
-
### Step 1: Identify Date/Time from User
|
|
216
|
-
User says: "Create meeting tomorrow at 2pm"
|
|
217
|
-
- Tomorrow = calculate date
|
|
218
|
-
- 2pm = time in **user's local timezone**
|
|
219
|
-
|
|
220
|
-
### Step 2: Ask for Timezone
|
|
221
|
-
**You:** "What timezone are you in?"
|
|
222
|
-
|
|
223
|
-
**User might say:**
|
|
224
|
-
- "UTC+3" or "GMT+3"
|
|
225
|
-
- "Europe/Kiev" or "Europe/Warsaw"
|
|
226
|
-
- "EST" or "PST"
|
|
227
|
-
- "My local time is 2pm now" (calculate offset)
|
|
228
|
-
|
|
229
|
-
### Step 3: Convert to UTC
|
|
230
|
-
Formula: **UTC = Local Time - Offset**
|
|
231
|
-
|
|
232
|
-
Examples:
|
|
233
|
-
- 2pm UTC+3 → 2pm - 3h = **11am UTC**
|
|
234
|
-
- 9am UTC-5 (EST) → 9am - (-5h) = 9am + 5h = **2pm UTC**
|
|
235
|
-
- 10pm UTC+0 → **10pm UTC** (no conversion)
|
|
236
|
-
|
|
237
|
-
### Step 4: Format as ISO 8601 with Z suffix
|
|
238
|
-
Format: \`YYYY-MM-DDTHH:mm:ss**Z**\`
|
|
239
|
-
|
|
240
|
-
Examples:
|
|
241
|
-
- \`2024-01-16T11:00:00Z\`
|
|
242
|
-
- \`2024-12-25T14:30:00Z\`
|
|
243
|
-
- \`2025-03-01T00:00:00Z\`
|
|
244
|
-
|
|
245
|
-
**The Z suffix means UTC!** Never omit it.
|
|
246
|
-
|
|
247
|
-
---
|
|
248
|
-
|
|
249
|
-
## 📋 Common Timezone Reference
|
|
250
|
-
|
|
251
|
-
| Timezone | Offset | Example: 2pm local → UTC |
|
|
252
|
-
|-------------------|---------|--------------------------|
|
|
253
|
-
| UTC+0 (London) | +0 | 2pm → 2pm UTC |
|
|
254
|
-
| UTC+1 (Paris) | +1 | 2pm → 1pm UTC |
|
|
255
|
-
| UTC+2 (Kyiv) | +2 | 2pm → 12pm UTC |
|
|
256
|
-
| UTC+3 (Moscow) | +3 | 2pm → 11am UTC |
|
|
257
|
-
| UTC-5 (EST/NY) | -5 | 2pm → 7pm UTC |
|
|
258
|
-
| UTC-8 (PST/LA) | -8 | 2pm → 10pm UTC |
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
## 💡 Conversation Examples
|
|
263
|
-
|
|
264
|
-
### Example 1: Clear timezone
|
|
265
|
-
**User:** "Create task tomorrow at 9am EST"
|
|
266
|
-
**You:** *(recognize EST = UTC-5)*
|
|
267
|
-
- Tomorrow = 2024-01-16
|
|
268
|
-
- 9am EST = 9am + 5h = 2pm UTC
|
|
269
|
-
- Store: \`"StartDate": "2024-01-16T14:00:00Z"\`
|
|
270
|
-
|
|
271
|
-
### Example 2: Ask for clarification
|
|
272
|
-
**User:** "Meeting at 3pm"
|
|
273
|
-
**You:** "What timezone are you in?"
|
|
274
|
-
**User:** "UTC+3"
|
|
275
|
-
**You:** *(calculate)*
|
|
276
|
-
- 3pm UTC+3 = 3pm - 3h = 12pm UTC
|
|
277
|
-
- Store: \`"StartDate": "2024-01-16T12:00:00Z"\`
|
|
278
|
-
|
|
279
|
-
### Example 3: Relative time
|
|
280
|
-
**User:** "Create task in 2 hours"
|
|
281
|
-
**You:** "What timezone?"
|
|
282
|
-
**User:** "It's 4pm here, UTC+2"
|
|
283
|
-
**You:** *(calculate)*
|
|
284
|
-
- Now: 4pm UTC+2 = 2pm UTC
|
|
285
|
-
- In 2 hours: 2pm + 2h = 4pm UTC
|
|
286
|
-
- Store: \`"StartDate": "2024-01-16T16:00:00Z"\`
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
## 🚨 Critical Rules
|
|
291
|
-
|
|
292
|
-
1. ⚠️ **ALWAYS ask timezone** - never assume!
|
|
293
|
-
2. ⚠️ **ALWAYS use Z suffix** - indicates UTC
|
|
294
|
-
3. ⚠️ **Subtract offset for east** (UTC+) - e.g., UTC+3 → subtract 3
|
|
295
|
-
4. ⚠️ **Add offset for west** (UTC-) - e.g., UTC-5 → add 5
|
|
296
|
-
5. ⚠️ **Store in UTC** - Creatio expects UTC, not local time
|
|
297
|
-
|
|
298
|
-
---
|
|
299
|
-
|
|
300
|
-
## 🎯 Quick Checklist
|
|
301
|
-
|
|
302
|
-
Before storing ANY date in Creatio:
|
|
303
|
-
- [ ] Asked user for timezone?
|
|
304
|
-
- [ ] Converted local time to UTC?
|
|
305
|
-
- [ ] Used ISO 8601 format?
|
|
306
|
-
- [ ] Added Z suffix?
|
|
307
|
-
- [ ] Double-checked offset direction?
|
|
308
|
-
|
|
309
|
-
If all ✅ → Good to go!
|
|
310
|
-
`.trim();
|
|
311
|
-
|
|
312
|
-
const CONTACTID_GUIDE = `
|
|
313
|
-
# 👤 ContactId Rule - UNIVERSAL for ALL Creatio Entities
|
|
314
|
-
|
|
315
|
-
## 🚨 CRITICAL RULE (Read This First!)
|
|
316
|
-
|
|
317
|
-
In Creatio, there are TWO types of IDs:
|
|
318
|
-
|
|
319
|
-
1. **SysAdminUnit.Id** = User account ID (for login/permissions)
|
|
320
|
-
2. **SysAdminUnit.ContactId** = Contact ID (for CRM records)
|
|
321
|
-
|
|
322
|
-
### For CRM fields, ALWAYS use ContactId!
|
|
323
|
-
|
|
324
|
-
This applies to **ALL entities**, not just Activity:
|
|
325
|
-
- Activity.OwnerId = ContactId ✅
|
|
326
|
-
- Activity.AuthorId = ContactId ✅
|
|
327
|
-
- Lead.OwnerId = ContactId ✅
|
|
328
|
-
- Opportunity.OwnerId = ContactId ✅
|
|
329
|
-
- Case.OwnerId = ContactId ✅
|
|
330
|
-
- Account.OwnerId = ContactId ✅
|
|
331
|
-
|
|
332
|
-
---
|
|
333
|
-
|
|
334
|
-
## 🎯 The Workflow (RECOMMENDED!)
|
|
335
|
-
|
|
336
|
-
### 🔑 DEFAULT RULE: Current User by Default!
|
|
337
|
-
|
|
338
|
-
**ALWAYS assume activities/tasks/leads/opportunities are for the CURRENT USER unless explicitly told otherwise!**
|
|
339
|
-
|
|
340
|
-
Examples:
|
|
341
|
-
- ❌ "Create task" → DO NOT ask "for whom?" → Create for current user!
|
|
342
|
-
- ❌ "Schedule meeting tomorrow" → DO NOT ask "whose meeting?" → Current user's meeting!
|
|
343
|
-
- ✅ "Create task for John" → Only THEN create for someone else
|
|
344
|
-
- ✅ "Schedule meeting with Anna as owner" → Only THEN change owner
|
|
345
|
-
|
|
346
|
-
**This is the expected behavior! Don't annoy users by asking obvious questions.**
|
|
347
|
-
|
|
348
|
-
### Step 1: Use get-current-user-info Tool (BEST METHOD!)
|
|
349
|
-
|
|
350
|
-
**RECOMMENDED:** Use the dedicated tool to get user information:
|
|
351
|
-
|
|
352
|
-
Call \`get-current-user-info\` tool (no parameters needed)
|
|
353
|
-
|
|
354
|
-
**Returns:**
|
|
355
|
-
\`\`\`json
|
|
356
|
-
{
|
|
357
|
-
"userId": "410006e1-ca4e-4502-a9ec-e54d922d2c00",
|
|
358
|
-
"contactId": "76929f8c-7e15-4c64-bdb0-adc62d383727", // ← USE THIS!
|
|
359
|
-
"userName": "Current User",
|
|
360
|
-
"cultureName": "en-US"
|
|
361
|
-
}
|
|
362
|
-
\`\`\`
|
|
363
|
-
|
|
364
|
-
**Why this is better:**
|
|
365
|
-
- ✅ Single call, all info
|
|
366
|
-
- ✅ No need to know username
|
|
367
|
-
- ✅ Gets ContactId directly
|
|
368
|
-
- ✅ More reliable
|
|
369
|
-
- ✅ Use contactId for ALL Owner/Author fields by default
|
|
370
|
-
|
|
371
|
-
### Alternative: Query SysAdminUnit (Legacy Method)
|
|
372
|
-
|
|
373
|
-
If you need to query manually:
|
|
374
|
-
|
|
375
|
-
\`\`\`json
|
|
376
|
-
{
|
|
377
|
-
"entity": "SysAdminUnit",
|
|
378
|
-
"filter": "Name eq '<your_username>'",
|
|
379
|
-
"select": ["ContactId"],
|
|
380
|
-
"top": 1
|
|
381
|
-
}
|
|
382
|
-
\`\`\`
|
|
383
|
-
|
|
384
|
-
**Returns:**
|
|
385
|
-
\`\`\`json
|
|
386
|
-
[{
|
|
387
|
-
"ContactId": "76929f8c-7e15-4c64-bfb1-40c705d25fcd"
|
|
388
|
-
}]
|
|
389
|
-
\`\`\`
|
|
390
|
-
|
|
391
|
-
### Step 2: Store ContactId in Memory
|
|
392
|
-
|
|
393
|
-
Remember the ContactId for the entire conversation:
|
|
394
|
-
|
|
395
|
-
\`\`\`typescript
|
|
396
|
-
const currentUserContactId = "76929f8c-7e15-4c64-bfb1-40c705d25fcd";
|
|
397
|
-
\`\`\`
|
|
398
|
-
|
|
399
|
-
### Step 3: Use This ContactId EVERYWHERE
|
|
400
|
-
|
|
401
|
-
For **ANY** entity that has owner/author/creator fields:
|
|
402
|
-
|
|
403
|
-
\`\`\`json
|
|
404
|
-
{
|
|
405
|
-
"entity": "Activity",
|
|
406
|
-
"data": {
|
|
407
|
-
"OwnerId": currentUserContactId, // ← ContactId
|
|
408
|
-
"AuthorId": currentUserContactId // ← ContactId
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
\`\`\`
|
|
412
|
-
|
|
413
|
-
\`\`\`json
|
|
414
|
-
{
|
|
415
|
-
"entity": "Lead",
|
|
416
|
-
"data": {
|
|
417
|
-
"OwnerId": currentUserContactId // ← ContactId
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
\`\`\`
|
|
421
|
-
|
|
422
|
-
\`\`\`json
|
|
423
|
-
{
|
|
424
|
-
"entity": "Opportunity",
|
|
425
|
-
"data": {
|
|
426
|
-
"OwnerId": currentUserContactId // ← ContactId
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
\`\`\`
|
|
430
|
-
|
|
431
|
-
---
|
|
432
|
-
|
|
433
|
-
## ❌ Common Mistake
|
|
434
|
-
|
|
435
|
-
### WRONG (using SysAdminUnit.Id):
|
|
436
|
-
\`\`\`json
|
|
437
|
-
// Step 1: Query SysAdminUnit
|
|
438
|
-
read("SysAdminUnit", "Name eq '<your_username>'", ["Id"], 1)
|
|
439
|
-
// → Returns: [{ "Id": "410006e1-ca4e-4502-a9ec-e54d922d2c00" }]
|
|
440
|
-
|
|
441
|
-
// Step 2: Use .Id (WRONG!)
|
|
442
|
-
create("Activity", {
|
|
443
|
-
"OwnerId": "410006e1-ca4e-4502-a9ec-e54d922d2c00" // ❌ This is user ID!
|
|
444
|
-
})
|
|
445
|
-
// → ERROR: Invalid reference or constraint violation!
|
|
446
|
-
\`\`\`
|
|
447
|
-
|
|
448
|
-
### ✅ CORRECT (using ContactId):
|
|
449
|
-
\`\`\`json
|
|
450
|
-
// Step 1: Query SysAdminUnit
|
|
451
|
-
read("SysAdminUnit", "Name eq '<your_username>'", ["ContactId"], 1)
|
|
452
|
-
// → Returns: [{ "ContactId": "76929f8c-7e15-4c64-bfb1-40c705d25fcd" }]
|
|
453
|
-
|
|
454
|
-
// Step 2: Use .ContactId (CORRECT!)
|
|
455
|
-
create("Activity", {
|
|
456
|
-
"OwnerId": "76929f8c-7e15-4c64-bfb1-40c705d25fcd" // ✅ This is contact ID!
|
|
457
|
-
})
|
|
458
|
-
// → SUCCESS!
|
|
459
|
-
\`\`\`
|
|
460
|
-
|
|
461
|
-
---
|
|
462
|
-
|
|
463
|
-
## 🔍 Visual Explanation
|
|
464
|
-
|
|
465
|
-
\`\`\`
|
|
466
|
-
SysAdminUnit "<your_username>":
|
|
467
|
-
├─ Id: "410006e1..." ← USER account (for system/permissions)
|
|
468
|
-
│ └─ Used for: Login, roles, access rights
|
|
469
|
-
│
|
|
470
|
-
└─ ContactId: "76929f8c..." ← CONTACT record (for CRM)
|
|
471
|
-
└─ Used for: Activities, Leads, Opportunities, Owners, Authors
|
|
472
|
-
|
|
473
|
-
Contact "John Doe":
|
|
474
|
-
└─ Id: "76929f8c..." ← Same as SysAdminUnit.ContactId!
|
|
475
|
-
└─ This is the CRM person record
|
|
476
|
-
\`\`\`
|
|
477
|
-
|
|
478
|
-
---
|
|
479
|
-
|
|
480
|
-
## 📋 When to Use Each ID
|
|
481
|
-
|
|
482
|
-
| Field Type | Use This | Example Entity |
|
|
483
|
-
|-------------------------------|-----------------|------------------------|
|
|
484
|
-
| OwnerId | **ContactId** | Activity, Lead, Case |
|
|
485
|
-
| AuthorId | **ContactId** | Activity |
|
|
486
|
-
| CreatedById | **ContactId** | Any entity |
|
|
487
|
-
| ModifiedById | **ContactId** | Any entity |
|
|
488
|
-
| ContactId (in Activity) | **ContactId** | Activity |
|
|
489
|
-
| ParticipantId | **ContactId** | ActivityParticipant |
|
|
490
|
-
| ResponsibleId | **ContactId** | Lead, Opportunity |
|
|
491
|
-
| System permissions/roles | **Id** | SysAdminUnit relations |
|
|
492
|
-
|
|
493
|
-
**Rule of thumb:** If it's a CRM field → **ContactId**. Always.
|
|
494
|
-
|
|
495
|
-
---
|
|
496
|
-
|
|
497
|
-
## 🎯 Best Practice
|
|
498
|
-
|
|
499
|
-
At the **start of any workflow** that needs user identity:
|
|
500
|
-
|
|
501
|
-
1. Query \`SysAdminUnit\` once
|
|
502
|
-
2. Select \`["ContactId"]\`
|
|
503
|
-
3. Store in variable
|
|
504
|
-
4. Use everywhere
|
|
505
|
-
|
|
506
|
-
**Don't query multiple times!** One query per session is enough.
|
|
507
|
-
|
|
508
|
-
---
|
|
509
|
-
|
|
510
|
-
## ⚠️ What If I Used Wrong ID?
|
|
511
|
-
|
|
512
|
-
You'll see errors like:
|
|
513
|
-
- "Foreign key constraint violation"
|
|
514
|
-
- "Invalid reference"
|
|
515
|
-
- "Record not found"
|
|
516
|
-
- Owner field is empty or points to wrong person
|
|
517
|
-
|
|
518
|
-
**Solution:** Go back and use ContactId instead of Id!
|
|
519
|
-
|
|
520
|
-
---
|
|
521
|
-
|
|
522
|
-
## 💡 Summary
|
|
523
|
-
|
|
524
|
-
- **SysAdminUnit.Id** = User account (system)
|
|
525
|
-
- **SysAdminUnit.ContactId** = Contact person (CRM)
|
|
526
|
-
- **For CRM fields** → ALWAYS use ContactId
|
|
527
|
-
- **Query once** → Use everywhere
|
|
528
|
-
- **This rule applies** → ALL entities in Creatio
|
|
529
|
-
|
|
530
|
-
Remember: **ContactId, not Id!** 🎯
|
|
531
|
-
`.trim();
|
|
532
|
-
|
|
533
|
-
const TAGGING_GUIDE = `
|
|
534
|
-
# 🏷️ Tagging Records in Creatio
|
|
535
|
-
|
|
536
|
-
## 🚨 CRITICAL DECISION: Which Tag System?
|
|
537
|
-
|
|
538
|
-
Creatio has TWO tagging systems that may coexist:
|
|
539
|
-
|
|
540
|
-
### 1️⃣ LEGACY System (Entity-Specific) - **DEFAULT & RECOMMENDED**
|
|
541
|
-
- Uses: \`<Entity>Tag\` and \`<Entity>InTag\` tables
|
|
542
|
-
- Examples: \`ActivityTag\` + \`ActivityInTag\`, \`AccountTag\` + \`AccountInTag\`
|
|
543
|
-
- Fields: \`TagId\` (from <Entity>Tag), \`EntityId\` (record GUID)
|
|
544
|
-
- **Use this by DEFAULT unless user explicitly asks for universal tags!**
|
|
545
|
-
|
|
546
|
-
### 2️⃣ NEW System (Universal)
|
|
547
|
-
- Uses: \`Tag\` and \`TagInRecord\` tables
|
|
548
|
-
- Fields: \`TagId\`, \`RecordId\`, \`RecordSchemaName\`
|
|
549
|
-
- Only use if user specifically says "use universal tags" or "use new tag system"
|
|
550
|
-
|
|
551
|
-
---
|
|
552
|
-
|
|
553
|
-
## ⚡ Quick Decision Flow
|
|
554
|
-
|
|
555
|
-
**MANDATORY behavior:**
|
|
556
|
-
1. Check if \`<Entity>Tag\` exists (e.g., \`ActivityTag\`)
|
|
557
|
-
2. If BOTH systems exist (Legacy AND Universal):
|
|
558
|
-
→ **ALWAYS ASK USER**: "Which tagging system should I use: legacy (ActivityTag/ActivityInTag) or universal (Tag/TagInRecord)?"
|
|
559
|
-
→ Wait for explicit user response - NO DEFAULT!
|
|
560
|
-
→ User must choose: "legacy" or "universal"
|
|
561
|
-
3. If ONLY legacy exists → Use legacy (no question needed)
|
|
562
|
-
4. If ONLY universal exists → Use universal (no question needed)
|
|
563
|
-
|
|
564
|
-
**CRITICAL:** Never auto-choose when both systems are available! Always ask and wait for clear answer!
|
|
565
|
-
|
|
566
|
-
---
|
|
567
|
-
|
|
568
|
-
## 📋 STEP-BY-STEP WORKFLOW
|
|
569
|
-
|
|
570
|
-
### Step 1: Identify Target Entity & Record
|
|
571
|
-
- Extract entity name (Activity, Contact, Account, etc.)
|
|
572
|
-
- Get record GUID (from context or ask user)
|
|
573
|
-
- Store as: \`entityName\`, \`recordId\`
|
|
574
|
-
|
|
575
|
-
### Step 2: Choose System (MANDATORY CHECK!)
|
|
576
|
-
|
|
577
|
-
**Always perform this check:**
|
|
578
|
-
|
|
579
|
-
1. Try describe-entity on \`<Entity>Tag\` (e.g., "ActivityTag")
|
|
580
|
-
2. Try describe-entity on \`Tag\`
|
|
581
|
-
3. Determine availability:
|
|
582
|
-
- BOTH exist → **ASK USER MANDATORY**: "I found both tagging systems. Which one should I use: legacy (<Entity>Tag) or universal (Tag)?"
|
|
583
|
-
- ONLY legacy exists → Use legacy automatically
|
|
584
|
-
- ONLY universal exists → Use universal automatically
|
|
585
|
-
- NEITHER exists → Error (cannot tag)
|
|
586
|
-
|
|
587
|
-
**User response handling:**
|
|
588
|
-
- "legacy" / "old" / "entity-specific" / "<Entity>Tag" → useLegacy = true
|
|
589
|
-
- "universal" / "new" / "Tag" / "TagInRecord" → useLegacy = false
|
|
590
|
-
- If unclear response → Ask again for clarification
|
|
591
|
-
|
|
592
|
-
**NEVER skip the question when both systems are present!**
|
|
593
|
-
**NEVER assume a default - wait for explicit user choice!**
|
|
594
|
-
|
|
595
|
-
### Step 3: Resolve or Create Tag
|
|
596
|
-
|
|
597
|
-
**Tag name can be ANY value provided by user** (e.g., "VIP", "Urgent", "Follow-up", "Important", etc.)
|
|
598
|
-
|
|
599
|
-
**For LEGACY system:**
|
|
600
|
-
1. Try to find existing tag: read <Entity>Tag where Name eq '<TagName>' select Id top 1
|
|
601
|
-
2. If not found, create it: create <Entity>Tag with Name: "<TagName>"
|
|
602
|
-
3. Returns tag Id (GUID)
|
|
603
|
-
|
|
604
|
-
**For UNIVERSAL system:**
|
|
605
|
-
1. Try to find existing tag: read Tag where Name eq '<TagName>' and EntitySchemaName eq '<Entity>' select Id top 1
|
|
606
|
-
2. If not found, create it: create Tag with Name: "<TagName>", EntitySchemaName: "<Entity>"
|
|
607
|
-
3. Returns tag Id (GUID)
|
|
608
|
-
|
|
609
|
-
### Step 4: Check if Already Tagged
|
|
610
|
-
Avoid duplicate links!
|
|
611
|
-
|
|
612
|
-
**LEGACY:**
|
|
613
|
-
- read <Entity>InTag where TagId eq <tag-guid> and EntityId eq <record-guid> select Id top 1
|
|
614
|
-
|
|
615
|
-
**UNIVERSAL:**
|
|
616
|
-
- read TagInRecord where TagId eq <tag-guid> and RecordId eq <record-guid> select Id top 1
|
|
617
|
-
|
|
618
|
-
### Step 5: Create Link (if not exists)
|
|
619
|
-
|
|
620
|
-
**LEGACY:**
|
|
621
|
-
- create <Entity>InTag with TagId: <tag-guid>, EntityId: <record-guid>
|
|
622
|
-
|
|
623
|
-
**UNIVERSAL:**
|
|
624
|
-
- create TagInRecord with TagId: <tag-guid>, RecordId: <record-guid>, RecordSchemaName: "<Entity>"
|
|
625
|
-
|
|
626
|
-
---
|
|
627
|
-
|
|
628
|
-
## 💡 Examples
|
|
629
|
-
|
|
630
|
-
### Example 1: Add "VIP" tag to Activity (Standard Request)
|
|
631
|
-
|
|
632
|
-
User: "Add tag VIP to this meeting"
|
|
633
|
-
|
|
634
|
-
LLM Actions:
|
|
635
|
-
1. Detect: Entity = Activity, recordId from context
|
|
636
|
-
2. Check: ActivityTag exists? YES. Tag exists? YES (BOTH found!)
|
|
637
|
-
3. ASK USER: "Which tagging system should I use: legacy (ActivityTag) or universal (Tag)?"
|
|
638
|
-
4. User: "legacy"
|
|
639
|
-
5. Query: ActivityTag where Name='VIP' (found: "9dd32c9f...")
|
|
640
|
-
6. Check: ActivityInTag link exists? NO
|
|
641
|
-
7. Create: ActivityInTag with TagId: "9dd32c9f...", EntityId: "meeting-id"
|
|
642
|
-
8. Report: "Added VIP tag to meeting using legacy system"
|
|
643
|
-
|
|
644
|
-
### Example 2: User explicitly wants universal system
|
|
645
|
-
|
|
646
|
-
User: "Add tag Important using the new universal tag system"
|
|
647
|
-
|
|
648
|
-
LLM Actions:
|
|
649
|
-
1. User specified "new universal" (useLegacy = false, skip question!)
|
|
650
|
-
2. Query: Tag where Name='Important' and EntitySchemaName='Activity'
|
|
651
|
-
3. If not found: Create Tag with Name: "Important", EntitySchemaName: "Activity"
|
|
652
|
-
4. Create: TagInRecord with TagId, RecordId, RecordSchemaName: "Activity"
|
|
653
|
-
5. Report: "Added Important tag using universal system"
|
|
654
|
-
|
|
655
|
-
### Example 3: Legacy system doesn't exist
|
|
656
|
-
|
|
657
|
-
User: "Add tag to CustomEntity"
|
|
658
|
-
|
|
659
|
-
LLM Actions:
|
|
660
|
-
1. Check: CustomEntityTag exists? NO
|
|
661
|
-
2. Auto-fallback: Use universal system
|
|
662
|
-
3. Query/Create in Tag table
|
|
663
|
-
4. Link via TagInRecord
|
|
664
|
-
|
|
665
|
-
---
|
|
666
|
-
|
|
667
|
-
## 🚨 Common Mistakes to Avoid
|
|
668
|
-
|
|
669
|
-
❌ **WRONG:** Auto-choosing system when both exist
|
|
670
|
-
✅ **RIGHT:** ALWAYS ask user when both legacy and universal are available
|
|
671
|
-
|
|
672
|
-
❌ **WRONG:** Creating duplicate tags without checking
|
|
673
|
-
✅ **RIGHT:** Always check existence first
|
|
674
|
-
|
|
675
|
-
❌ **WRONG:** Not checking if link already exists
|
|
676
|
-
✅ **RIGHT:** Query <Entity>InTag or TagInRecord before creating
|
|
677
|
-
|
|
678
|
-
❌ **WRONG:** Skipping the mandatory question
|
|
679
|
-
✅ **RIGHT:** If both systems exist, MUST ask user which one to use
|
|
680
|
-
|
|
681
|
-
---
|
|
682
|
-
|
|
683
|
-
## 📊 Quick Reference Table
|
|
684
|
-
|
|
685
|
-
| Entity | Tag Table | Link Table | Tag Field | Record Field |
|
|
686
|
-
|-----------|----------------|-------------------|-----------|--------------|
|
|
687
|
-
| Activity | ActivityTag | ActivityInTag | TagId | EntityId |
|
|
688
|
-
| Account | AccountTag | AccountInTag | TagId | EntityId |
|
|
689
|
-
| Contact | ContactTag | ContactInTag | TagId | EntityId |
|
|
690
|
-
| Lead | LeadTag | LeadInTag | TagId | EntityId |
|
|
691
|
-
| Case | CaseTag | CaseInTag | TagId | EntityId |
|
|
692
|
-
| *Universal* | Tag | TagInRecord | TagId | RecordId |
|
|
693
|
-
|
|
694
|
-
---
|
|
695
|
-
|
|
696
|
-
## ✅ Final Checklist
|
|
697
|
-
|
|
698
|
-
Before creating a tag link:
|
|
699
|
-
- [ ] Entity and record GUID identified
|
|
700
|
-
- [ ] System auto-detected (legacy preferred)
|
|
701
|
-
- [ ] Tag resolved or created in correct table
|
|
702
|
-
- [ ] Existing link checked (no duplicates)
|
|
703
|
-
- [ ] Link created in correct table
|
|
704
|
-
- [ ] User notified of success
|
|
705
|
-
|
|
706
|
-
---
|
|
707
|
-
|
|
708
|
-
## 🎯 Remember
|
|
709
|
-
|
|
710
|
-
**The Golden Rule:** When BOTH systems exist - ALWAYS ASK USER (no defaults!)
|
|
711
|
-
|
|
712
|
-
Question format: "I found both tagging systems for <Entity>. Which should I use: legacy (<Entity>Tag) or universal (Tag)?"
|
|
713
|
-
|
|
714
|
-
**Wait for explicit answer!** Do not proceed until user chooses.
|
|
715
|
-
|
|
716
|
-
Only skip question if:
|
|
717
|
-
- ONLY legacy exists → Use legacy automatically
|
|
718
|
-
- ONLY universal exists → Use universal automatically
|
|
719
|
-
- User already specified in original request (e.g., "use new tag system")
|
|
720
|
-
|
|
721
|
-
**Tag names:** Can be ANY value user provides (VIP, Urgent, Important, Follow-up, etc.)
|
|
722
|
-
|
|
723
|
-
**DO NOT assume or auto-choose when both are present!**
|
|
724
|
-
`.trim();
|
|
725
|
-
|
|
726
|
-
const SYS_SETTINGS_VALUE_TYPES_TABLE = `
|
|
727
|
-
| valueTypeName | Display label |
|
|
728
|
-
| ------------- | ----------------------- |
|
|
729
|
-
| Binary | BLOB |
|
|
730
|
-
| Boolean | Boolean |
|
|
731
|
-
| DateTime | Date/Time |
|
|
732
|
-
| Date | Date |
|
|
733
|
-
| Time | Time |
|
|
734
|
-
| Integer | Integer |
|
|
735
|
-
| Money | Currency (0.01) |
|
|
736
|
-
| Float | Decimal |
|
|
737
|
-
| Lookup | Lookup |
|
|
738
|
-
| ShortText | Text (50 characters) |
|
|
739
|
-
| MediumText | Text (250 characters) |
|
|
740
|
-
| LongText | Text (500 characters) |
|
|
741
|
-
| Text | Text |
|
|
742
|
-
| MaxSizeText | Unlimited length text |
|
|
743
|
-
| SecureText | Encrypted string |
|
|
744
|
-
`.trim();
|
|
745
|
-
|
|
746
|
-
const SYS_SETTINGS_GUIDE = `
|
|
747
|
-
# ⚙️ Creating Creatio System Settings
|
|
748
|
-
|
|
749
|
-
## Supported valueTypeName values
|
|
750
|
-
Always use the **value** column (not the display label) when filling \`definition.valueTypeName\`.
|
|
751
|
-
|
|
752
|
-
${SYS_SETTINGS_VALUE_TYPES_TABLE}
|
|
753
|
-
|
|
754
|
-
## Discovering existing system settings
|
|
755
|
-
To inspect what system settings already exist (names, codes, value types, cache flags, etc.), query the
|
|
756
|
-
\`VwSysSetting\` view via the standard \`read\` tool. Example:
|
|
757
|
-
|
|
758
|
-
\`\`\`json
|
|
759
|
-
{
|
|
760
|
-
"entity": "VwSysSetting",
|
|
761
|
-
"select": [
|
|
762
|
-
"Id",
|
|
763
|
-
"Name",
|
|
764
|
-
"Code",
|
|
765
|
-
"Description",
|
|
766
|
-
"ValueTypeName",
|
|
767
|
-
"IsPersonal",
|
|
768
|
-
"IsCacheable"
|
|
769
|
-
],
|
|
770
|
-
"top": 50
|
|
771
|
-
}
|
|
772
|
-
\`\`\`
|
|
773
|
-
|
|
774
|
-
Filter by \`Code\` or \`Name\` to narrow results (e.g., \`"filters":{"all":[{"field":"Code","op":"contains","value":"Product"}]}\`).
|
|
775
|
-
This is the fastest way to learn which settings already exist before inserting new ones.
|
|
776
|
-
|
|
777
|
-
## Lookup referenceSchemaUId
|
|
778
|
-
- Required only when \`valueTypeName = "Lookup"\`.
|
|
779
|
-
- Set \`definition.referenceSchemaUId\` to the EntitySchema UId of the lookup target.
|
|
780
|
-
- Fetch the UId from \`VwWorkspaceObjects\` by filtering on the schema name.
|
|
781
|
-
|
|
782
|
-
### Example MCP read request
|
|
783
|
-
\`\`\`json
|
|
784
|
-
{
|
|
785
|
-
"entity": "VwWorkspaceObjects",
|
|
786
|
-
"filters": {
|
|
787
|
-
"all": [
|
|
788
|
-
{ "field": "Name", "op": "eq", "value": "Account" }
|
|
789
|
-
]
|
|
790
|
-
},
|
|
791
|
-
"select": ["UId", "Name", "Caption"]
|
|
792
|
-
}
|
|
793
|
-
\`\`\`
|
|
794
|
-
|
|
795
|
-
Use the returned \`UId\` as \`referenceSchemaUId\` inside the \`create-sys-setting\` tool payload.
|
|
796
|
-
|
|
797
|
-
## Quick workflow reminder
|
|
798
|
-
1. Insert sys setting metadata via \`create-sys-setting\`.
|
|
799
|
-
2. Optionally include \`initialValue\` to write the first value immediately.
|
|
800
|
-
3. For additional updates later, call \`set-sys-settings-value\`.
|
|
801
|
-
`.trim();
|
|
802
|
-
|
|
803
|
-
export const CREATE_ACTIVITY_PROMPT = {
|
|
804
|
-
name: 'create-activity-guide',
|
|
805
|
-
title: 'Create Activity in Creatio',
|
|
806
|
-
description:
|
|
807
|
-
'Complete step-by-step guide for creating Activities (tasks/meetings/calls) in Creatio',
|
|
808
|
-
argsSchema: {},
|
|
809
|
-
callback: () => ({
|
|
810
|
-
messages: [
|
|
811
|
-
{
|
|
812
|
-
role: 'user' as const,
|
|
813
|
-
content: {
|
|
814
|
-
type: 'text' as const,
|
|
815
|
-
text: CREATE_ACTIVITY_WORKFLOW,
|
|
816
|
-
},
|
|
817
|
-
},
|
|
818
|
-
],
|
|
819
|
-
}),
|
|
820
|
-
};
|
|
821
|
-
export const DATETIME_PROMPT = {
|
|
822
|
-
name: 'datetime-guide',
|
|
823
|
-
title: 'DateTime and Timezone Guide',
|
|
824
|
-
description: 'How to ask users for timezone and convert to UTC for Creatio',
|
|
825
|
-
argsSchema: {},
|
|
826
|
-
callback: () => ({
|
|
827
|
-
messages: [
|
|
828
|
-
{
|
|
829
|
-
role: 'user' as const,
|
|
830
|
-
content: {
|
|
831
|
-
type: 'text' as const,
|
|
832
|
-
text: DATETIME_GUIDE,
|
|
833
|
-
},
|
|
834
|
-
},
|
|
835
|
-
],
|
|
836
|
-
}),
|
|
837
|
-
};
|
|
838
|
-
|
|
839
|
-
export const CONTACTID_PROMPT = {
|
|
840
|
-
name: 'contactid-guide',
|
|
841
|
-
title: 'ContactId Rule for All Entities',
|
|
842
|
-
description:
|
|
843
|
-
'CRITICAL: Always use SysAdminUnit.ContactId (not .Id!) for all CRM fields across all entities',
|
|
844
|
-
argsSchema: {},
|
|
845
|
-
callback: () => ({
|
|
846
|
-
messages: [
|
|
847
|
-
{
|
|
848
|
-
role: 'user' as const,
|
|
849
|
-
content: {
|
|
850
|
-
type: 'text' as const,
|
|
851
|
-
text: CONTACTID_GUIDE,
|
|
852
|
-
},
|
|
853
|
-
},
|
|
854
|
-
],
|
|
855
|
-
}),
|
|
856
|
-
};
|
|
857
|
-
|
|
858
|
-
export const TAGGING_PROMPT = {
|
|
859
|
-
name: 'tagging-guide',
|
|
860
|
-
title: 'Tagging Records (New & Legacy Systems)',
|
|
861
|
-
description:
|
|
862
|
-
'Guide for adding tags to records using Tag/TagInRecord or legacy <Entity>Tag / <Entity>InTag tables',
|
|
863
|
-
argsSchema: {},
|
|
864
|
-
callback: () => ({
|
|
865
|
-
messages: [
|
|
866
|
-
{
|
|
867
|
-
role: 'user' as const,
|
|
868
|
-
content: { type: 'text' as const, text: TAGGING_GUIDE },
|
|
869
|
-
},
|
|
870
|
-
],
|
|
871
|
-
}),
|
|
872
|
-
};
|
|
873
|
-
|
|
874
|
-
export const SYS_SETTINGS_PROMPT = {
|
|
875
|
-
name: 'sys-settings-guide',
|
|
876
|
-
title: 'Creatio System Settings Guide',
|
|
877
|
-
description:
|
|
878
|
-
'Value type options and lookup reference instructions for create-sys-setting / set-sys-settings-value workflows',
|
|
879
|
-
argsSchema: {},
|
|
880
|
-
callback: () => ({
|
|
881
|
-
messages: [
|
|
882
|
-
{
|
|
883
|
-
role: 'user' as const,
|
|
884
|
-
content: { type: 'text' as const, text: SYS_SETTINGS_GUIDE },
|
|
885
|
-
},
|
|
886
|
-
],
|
|
887
|
-
}),
|
|
888
|
-
};
|
|
889
|
-
|
|
890
|
-
const FEATURE_TOGGLE_GUIDE = `
|
|
891
|
-
# 🚦 Feature Toggling Guide for Creatio
|
|
892
|
-
|
|
893
|
-
## 🧭 Quick Map
|
|
894
|
-
|
|
895
|
-
Creatio feature toggles are stored in TWO database-backed entities, both reachable via OData:
|
|
896
|
-
|
|
897
|
-
| Entity | What it represents | When to use |
|
|
898
|
-
|--------------------------|--------------------------------------------------------------------------|--------------------------------------|
|
|
899
|
-
| \`Feature\` | Catalog row for a feature (Code, Name, Description, DefaultState) | Read/create/update/delete the toggle |
|
|
900
|
-
| \`AdminUnitFeatureState\` | Per-user/role override (FeatureId, SysAdminUnitId, FeatureState) | Override a feature for one principal |
|
|
901
|
-
|
|
902
|
-
There is **NO** dedicated feature CRUD tool — use the existing \`read\`, \`create\`, \`update\`, \`delete\` tools on the entity sets above. The only feature-specific tool is \`refresh-feature-cache\`.
|
|
903
|
-
|
|
904
|
-
> ℹ️ The Freedom UI in Creatio shows a virtual section called *AppFeature* that adds a couple of computed columns (\`Source\`, \`StateForCurrentUser\`). Those virtual entities are **not** exposed through OData — always use the persisted \`Feature\` and \`AdminUnitFeatureState\` tables from automation.
|
|
905
|
-
|
|
906
|
-
---
|
|
907
|
-
|
|
908
|
-
## 📋 Feature Columns
|
|
909
|
-
|
|
910
|
-
| Column | Type | Notes |
|
|
911
|
-
|-----------------|----------|------------------------------------------------------------------------|
|
|
912
|
-
| \`Id\` | Guid | Primary key |
|
|
913
|
-
| \`Code\` | string | Feature code. Must match \`^[a-zA-Z]+[a-zA-Z0-9-_.]*$\` |
|
|
914
|
-
| \`Name\` | string | Display name (commonly equal to \`Code\`) |
|
|
915
|
-
| \`Description\` | string | Optional description |
|
|
916
|
-
| \`DefaultState\` | Int32 | **0 = disabled, 1 = enabled**. NOT a boolean — always send integers. |
|
|
917
|
-
| \`ProcessListeners\` | Int32 | Internal flag — leave it as the default value |
|
|
918
|
-
| \`CreatedOn\` / \`ModifiedOn\` | DateTime | Audit fields |
|
|
919
|
-
|
|
920
|
-
---
|
|
921
|
-
|
|
922
|
-
## 📋 AdminUnitFeatureState Columns
|
|
923
|
-
|
|
924
|
-
| Column | Type | Notes |
|
|
925
|
-
|-------------------|--------|------------------------------------------------------------------|
|
|
926
|
-
| \`Id\` | Guid | Primary key |
|
|
927
|
-
| \`FeatureId\` | Guid | FK → \`Feature.Id\` |
|
|
928
|
-
| \`SysAdminUnitId\` | Guid | FK → \`SysAdminUnit.Id\` (the user or role) |
|
|
929
|
-
| \`FeatureState\` | Int32 | **0 = disabled, 1 = enabled** for that admin unit |
|
|
930
|
-
| \`ProcessListeners\`| Int32 | Internal flag — leave default |
|
|
931
|
-
|
|
932
|
-
\`SysAdminUnitId\` is the **SysAdminUnit.Id** of the principal (not its ContactId). Look it up explicitly when you only know a user/role name.
|
|
933
|
-
|
|
934
|
-
---
|
|
935
|
-
|
|
936
|
-
## 🛠️ Common Workflows
|
|
937
|
-
|
|
938
|
-
### 1. List features
|
|
939
|
-
|
|
940
|
-
\`\`\`json
|
|
941
|
-
{
|
|
942
|
-
"entity": "Feature",
|
|
943
|
-
"select": ["Id", "Code", "Name", "Description", "DefaultState"],
|
|
944
|
-
"top": 200,
|
|
945
|
-
"orderBy": "Code asc"
|
|
946
|
-
}
|
|
947
|
-
\`\`\`
|
|
948
|
-
|
|
949
|
-
### 2. Look up one feature by code
|
|
950
|
-
|
|
951
|
-
\`\`\`json
|
|
952
|
-
{
|
|
953
|
-
"entity": "Feature",
|
|
954
|
-
"filters": { "all": [ { "field": "Code", "op": "eq", "value": "MyFeature" } ] },
|
|
955
|
-
"select": ["Id", "Code", "DefaultState"],
|
|
956
|
-
"top": 1
|
|
957
|
-
}
|
|
958
|
-
\`\`\`
|
|
959
|
-
|
|
960
|
-
### 3. Enable or disable a feature globally (change default state)
|
|
961
|
-
|
|
962
|
-
\`\`\`json
|
|
963
|
-
{
|
|
964
|
-
"entity": "Feature",
|
|
965
|
-
"id": "<feature-guid>",
|
|
966
|
-
"data": { "DefaultState": 1 }
|
|
967
|
-
}
|
|
968
|
-
\`\`\`
|
|
969
|
-
|
|
970
|
-
Use \`1\` to enable, \`0\` to disable. After the update, run \`refresh-feature-cache\` with the same feature \`Code\` so the new value is visible to every connected user.
|
|
971
|
-
|
|
972
|
-
### 4. Create a new feature
|
|
973
|
-
|
|
974
|
-
\`\`\`json
|
|
975
|
-
{
|
|
976
|
-
"entity": "Feature",
|
|
977
|
-
"data": {
|
|
978
|
-
"Code": "MyNewFeature",
|
|
979
|
-
"Name": "MyNewFeature",
|
|
980
|
-
"Description": "Enables the new dashboard",
|
|
981
|
-
"DefaultState": 0
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
\`\`\`
|
|
985
|
-
|
|
986
|
-
Then refresh the cache.
|
|
987
|
-
|
|
988
|
-
### 5. Override a feature for a specific user or role
|
|
989
|
-
|
|
990
|
-
First resolve the principal's \`SysAdminUnit.Id\`:
|
|
991
|
-
|
|
992
|
-
\`\`\`json
|
|
993
|
-
{
|
|
994
|
-
"entity": "SysAdminUnit",
|
|
995
|
-
"filters": { "all": [ { "field": "Name", "op": "eq", "value": "Supervisor" } ] },
|
|
996
|
-
"select": ["Id", "Name", "SysAdminUnitTypeValue"],
|
|
997
|
-
"top": 1
|
|
998
|
-
}
|
|
999
|
-
\`\`\`
|
|
1000
|
-
|
|
1001
|
-
Then create or update the override:
|
|
1002
|
-
|
|
1003
|
-
\`\`\`json
|
|
1004
|
-
{
|
|
1005
|
-
"entity": "AdminUnitFeatureState",
|
|
1006
|
-
"data": {
|
|
1007
|
-
"FeatureId": "<feature-guid>",
|
|
1008
|
-
"SysAdminUnitId": "<sysadminunit-guid>",
|
|
1009
|
-
"FeatureState": 1
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
\`\`\`
|
|
1013
|
-
|
|
1014
|
-
If an override row already exists for the same \`(FeatureId, SysAdminUnitId)\` pair, query it first and \`update\` it instead of creating a duplicate. Refresh the cache afterwards.
|
|
1015
|
-
|
|
1016
|
-
### 6. Inspect overrides for a feature
|
|
1017
|
-
|
|
1018
|
-
\`\`\`json
|
|
1019
|
-
{
|
|
1020
|
-
"entity": "AdminUnitFeatureState",
|
|
1021
|
-
"filters": { "all": [ { "field": "FeatureId", "op": "eq", "value": "<feature-guid>" } ] },
|
|
1022
|
-
"select": ["Id", "FeatureId", "SysAdminUnitId", "FeatureState"]
|
|
1023
|
-
}
|
|
1024
|
-
\`\`\`
|
|
1025
|
-
|
|
1026
|
-
### 7. Remove an override
|
|
1027
|
-
|
|
1028
|
-
\`\`\`json
|
|
1029
|
-
{ "entity": "AdminUnitFeatureState", "id": "<override-guid>" }
|
|
1030
|
-
\`\`\`
|
|
1031
|
-
|
|
1032
|
-
### 8. Delete a feature
|
|
1033
|
-
|
|
1034
|
-
\`\`\`json
|
|
1035
|
-
{ "entity": "Feature", "id": "<feature-guid>" }
|
|
1036
|
-
\`\`\`
|
|
1037
|
-
|
|
1038
|
-
Deletes the catalog row. Existing \`AdminUnitFeatureState\` rows tied to that feature should be removed first (query them with the filter from step 6) — Creatio will reject the delete if dependent rows remain.
|
|
1039
|
-
|
|
1040
|
-
---
|
|
1041
|
-
|
|
1042
|
-
## 🔁 When to refresh the cache
|
|
1043
|
-
|
|
1044
|
-
Call the \`refresh-feature-cache\` tool **after** any write that changes feature state:
|
|
1045
|
-
- Updated \`Feature.DefaultState\` → refresh with that feature's \`Code\`.
|
|
1046
|
-
- Created, updated, or deleted an \`AdminUnitFeatureState\` row → refresh with the affected feature's \`Code\`.
|
|
1047
|
-
- If you do not know (or don't have) the code, call \`refresh-feature-cache\` with no arguments to clear the cache for every feature.
|
|
1048
|
-
|
|
1049
|
-
Reads alone do **not** require a refresh.
|
|
1050
|
-
|
|
1051
|
-
---
|
|
1052
|
-
|
|
1053
|
-
## ❌ Common Mistakes
|
|
1054
|
-
|
|
1055
|
-
- ❌ Sending \`true\`/\`false\` for \`DefaultState\` or \`FeatureState\` — both columns are **Int32** (0 / 1).
|
|
1056
|
-
- ❌ Using \`AppFeature\` / \`AppFeatureState\` over OData — those are virtual UI-only entities. Use \`Feature\` / \`AdminUnitFeatureState\`.
|
|
1057
|
-
- ❌ Confusing \`SysAdminUnit.Id\` with \`ContactId\` — overrides use \`SysAdminUnit.Id\`.
|
|
1058
|
-
- ❌ Forgetting to call \`refresh-feature-cache\` after writes (other users keep seeing the old state).
|
|
1059
|
-
- ❌ Creating a duplicate \`AdminUnitFeatureState\` for the same \`(FeatureId, SysAdminUnitId)\` pair instead of updating the existing one.
|
|
1060
|
-
- ❌ Using a \`Code\` that doesn't match \`^[a-zA-Z]+[a-zA-Z0-9-_.]*$\` — the platform validator rejects it.
|
|
1061
|
-
- ❌ Trying to manage features that are NOT in the \`Feature\` table — Creatio OData v4 does not expose virtual entities (\`AppFeature\` / \`AppFeatureState\`). Features defined only in \`web.config\` or via non-DB providers are invisible to MCP until a backing row exists in \`Feature\`.
|
|
1062
|
-
|
|
1063
|
-
---
|
|
1064
|
-
|
|
1065
|
-
## ✅ Final Checklist
|
|
1066
|
-
|
|
1067
|
-
Before reporting a feature change as done:
|
|
1068
|
-
- [ ] Used \`Feature\` for the catalog and \`AdminUnitFeatureState\` for per-user/role overrides.
|
|
1069
|
-
- [ ] Sent state values as integers (0 / 1), not booleans.
|
|
1070
|
-
- [ ] Resolved the principal via \`SysAdminUnit\` (Id, not ContactId).
|
|
1071
|
-
- [ ] Called \`refresh-feature-cache\` (with \`featureCode\` when possible) after every write.
|
|
1072
|
-
`.trim();
|
|
1073
|
-
|
|
1074
|
-
export const FEATURE_TOGGLE_PROMPT = {
|
|
1075
|
-
name: 'feature-toggle-guide',
|
|
1076
|
-
title: 'Creatio Feature Toggle Guide',
|
|
1077
|
-
description:
|
|
1078
|
-
'How to read, create, update and delete feature toggles via the AppFeature / AppFeatureState OData entities, and when to call refresh-feature-cache',
|
|
1079
|
-
argsSchema: {},
|
|
1080
|
-
callback: () => ({
|
|
1081
|
-
messages: [
|
|
1082
|
-
{
|
|
1083
|
-
role: 'user' as const,
|
|
1084
|
-
content: { type: 'text' as const, text: FEATURE_TOGGLE_GUIDE },
|
|
1085
|
-
},
|
|
1086
|
-
],
|
|
1087
|
-
}),
|
|
1088
|
-
};
|
|
1089
|
-
|
|
1090
|
-
const ADMIN_OPERATION_GUIDE = `
|
|
1091
|
-
# 🛡️ Creatio System Operations (SysAdminOperation) Guide
|
|
1092
|
-
|
|
1093
|
-
## 🧭 Quick Map
|
|
1094
|
-
|
|
1095
|
-
Creatio system operations are admin-level permission flags that gate features such as \`CanUseODataService\`, \`CanManageAdministration\`, \`CanChangeAdminOperationGrantee\`, etc. They live in two database tables:
|
|
1096
|
-
|
|
1097
|
-
| Table | Holds | OData reachable? |
|
|
1098
|
-
|-----------------------------|----------------------------------------------------------------|------------------|
|
|
1099
|
-
| \`SysAdminOperation\` | The operation definition: Name, Code, Description | Read ✅ / Write ❌ |
|
|
1100
|
-
| \`SysAdminOperationGrantee\` | Per-admin-unit grants (FK to operation + SysAdminUnit + allow) | Read ✅ / Write ❌ |
|
|
1101
|
-
|
|
1102
|
-
Modification of both tables is blocked through OData v4 (\`DataServiceRestrictedModifySchemas\` in \`Web.config\`). All writes go through Creatio's dedicated **\`/0/rest/RightsService/\`** endpoints, wrapped by these MCP tools:
|
|
1103
|
-
|
|
1104
|
-
| Need | Tool |
|
|
1105
|
-
|------------------------------------------|---------------------------------------|
|
|
1106
|
-
| Read catalog / grant rows | Standard \`read\` on the two entities |
|
|
1107
|
-
| Create or rename an operation | \`upsert-admin-operation\` |
|
|
1108
|
-
| Delete operation(s) | \`delete-admin-operation\` |
|
|
1109
|
-
| Grant or revoke for users/roles | \`set-admin-operation-grantee\` |
|
|
1110
|
-
| Remove a specific grant row by Id | \`delete-admin-operation-grantee\` |
|
|
1111
|
-
|
|
1112
|
-
⚠️ Do NOT attempt \`create\` / \`update\` / \`delete\` on \`SysAdminOperation\` or \`SysAdminOperationGrantee\` through the generic OData tools — Creatio rejects those writes.
|
|
1113
|
-
|
|
1114
|
-
---
|
|
1115
|
-
|
|
1116
|
-
## 📋 SysAdminOperation Columns
|
|
1117
|
-
|
|
1118
|
-
| Column | Type | Notes |
|
|
1119
|
-
|-----------------|----------|--------------------------------------------------------------------|
|
|
1120
|
-
| \`Id\` | Guid | Primary key |
|
|
1121
|
-
| \`Code\` | string | Operation code, e.g., \`CanUseODataService\`. Conventionally PascalCase. |
|
|
1122
|
-
| \`Name\` | string | Display name |
|
|
1123
|
-
| \`Description\` | string | Optional description |
|
|
1124
|
-
|
|
1125
|
-
## 📋 SysAdminOperationGrantee Columns
|
|
1126
|
-
|
|
1127
|
-
| Column | Type | Notes |
|
|
1128
|
-
|-------------------------|---------|-----------------------------------------------------------------------------|
|
|
1129
|
-
| \`Id\` | Guid | Primary key |
|
|
1130
|
-
| \`SysAdminOperationId\` | Guid | FK to \`SysAdminOperation\` |
|
|
1131
|
-
| \`SysAdminUnitId\` | Guid | FK to \`SysAdminUnit\` (use SysAdminUnit.Id, NOT ContactId) |
|
|
1132
|
-
| \`CanExecute\` | bool | \`true\` = allow, \`false\` = deny |
|
|
1133
|
-
| \`Position\` | Int32 | Order within conflicting rules; lower wins for the same admin unit |
|
|
1134
|
-
|
|
1135
|
-
---
|
|
1136
|
-
|
|
1137
|
-
## 🛠️ Common Workflows
|
|
1138
|
-
|
|
1139
|
-
### 1. List system operations
|
|
1140
|
-
|
|
1141
|
-
\`\`\`json
|
|
1142
|
-
{
|
|
1143
|
-
"entity": "SysAdminOperation",
|
|
1144
|
-
"select": ["Id", "Code", "Name", "Description"],
|
|
1145
|
-
"top": 200,
|
|
1146
|
-
"orderBy": "Code asc"
|
|
1147
|
-
}
|
|
1148
|
-
\`\`\`
|
|
1149
|
-
|
|
1150
|
-
### 2. Look up an operation by code
|
|
1151
|
-
|
|
1152
|
-
\`\`\`json
|
|
1153
|
-
{
|
|
1154
|
-
"entity": "SysAdminOperation",
|
|
1155
|
-
"filters": { "all": [ { "field": "Code", "op": "eq", "value": "CanUseODataService" } ] },
|
|
1156
|
-
"select": ["Id", "Code", "Name", "Description"],
|
|
1157
|
-
"top": 1
|
|
1158
|
-
}
|
|
1159
|
-
\`\`\`
|
|
1160
|
-
|
|
1161
|
-
### 3. Create a new system operation
|
|
1162
|
-
|
|
1163
|
-
Call \`upsert-admin-operation\` without an \`id\`:
|
|
1164
|
-
|
|
1165
|
-
\`\`\`json
|
|
1166
|
-
{
|
|
1167
|
-
"name": "Can do MCP test",
|
|
1168
|
-
"code": "CanDoMcpTest",
|
|
1169
|
-
"description": "Demo operation managed via MCP"
|
|
1170
|
-
}
|
|
1171
|
-
\`\`\`
|
|
1172
|
-
|
|
1173
|
-
The response includes the generated \`id\`. Capture it for the grant step.
|
|
1174
|
-
|
|
1175
|
-
### 4. Rename / re-describe an existing operation
|
|
1176
|
-
|
|
1177
|
-
Call \`upsert-admin-operation\` with the existing \`id\`:
|
|
1178
|
-
|
|
1179
|
-
\`\`\`json
|
|
1180
|
-
{
|
|
1181
|
-
"id": "<operation-guid>",
|
|
1182
|
-
"name": "Can do MCP test (renamed)",
|
|
1183
|
-
"code": "CanDoMcpTest",
|
|
1184
|
-
"description": "Updated description"
|
|
1185
|
-
}
|
|
1186
|
-
\`\`\`
|
|
1187
|
-
|
|
1188
|
-
Code is required even when unchanged.
|
|
1189
|
-
|
|
1190
|
-
### 5. Grant the operation to a user or role
|
|
1191
|
-
|
|
1192
|
-
Resolve the SysAdminUnit first:
|
|
1193
|
-
|
|
1194
|
-
\`\`\`json
|
|
1195
|
-
{
|
|
1196
|
-
"entity": "SysAdminUnit",
|
|
1197
|
-
"filters": { "all": [ { "field": "Name", "op": "eq", "value": "Supervisor" } ] },
|
|
1198
|
-
"select": ["Id", "Name", "SysAdminUnitTypeValue"],
|
|
1199
|
-
"top": 1
|
|
1200
|
-
}
|
|
1201
|
-
\`\`\`
|
|
1202
|
-
|
|
1203
|
-
Then call \`set-admin-operation-grantee\`:
|
|
1204
|
-
|
|
1205
|
-
\`\`\`json
|
|
1206
|
-
{
|
|
1207
|
-
"adminOperationId": "<operation-guid>",
|
|
1208
|
-
"adminUnitIds": ["<sysadminunit-guid-1>", "<sysadminunit-guid-2>"],
|
|
1209
|
-
"canExecute": true
|
|
1210
|
-
}
|
|
1211
|
-
\`\`\`
|
|
1212
|
-
|
|
1213
|
-
Use \`canExecute: false\` to deny instead of allow. The service upserts the grantee rows internally — repeated calls for the same pair update the existing row instead of duplicating it.
|
|
1214
|
-
|
|
1215
|
-
### 6. Inspect current grants for an operation
|
|
1216
|
-
|
|
1217
|
-
⚠️ **Filter via the navigation property, not the raw FK column.** Creatio OData v4 rejects direct \`SysAdminOperationId eq <guid>\` / \`SysAdminUnitId eq <guid>\` filters on this entity with HTTP 500. Use \`SysAdminOperation/Id\` and \`SysAdminUnit/Id\` instead:
|
|
1218
|
-
|
|
1219
|
-
\`\`\`json
|
|
1220
|
-
{
|
|
1221
|
-
"entity": "SysAdminOperationGrantee",
|
|
1222
|
-
"filters": { "all": [ { "field": "SysAdminOperation/Id", "op": "eq", "value": "<operation-guid>" } ] },
|
|
1223
|
-
"select": ["Id", "SysAdminOperationId", "SysAdminUnitId", "CanExecute", "Position"]
|
|
1224
|
-
}
|
|
1225
|
-
\`\`\`
|
|
1226
|
-
|
|
1227
|
-
### 7. Remove a specific grant row
|
|
1228
|
-
|
|
1229
|
-
Use the row Id from step 6:
|
|
1230
|
-
|
|
1231
|
-
\`\`\`json
|
|
1232
|
-
{ "ids": ["<grantee-guid>"] }
|
|
1233
|
-
\`\`\`
|
|
1234
|
-
|
|
1235
|
-
Call \`delete-admin-operation-grantee\`. Prefer toggling \`canExecute\` via \`set-admin-operation-grantee\` if the goal is to flip allow ↔ deny rather than fully remove the rule.
|
|
1236
|
-
|
|
1237
|
-
### 8. Delete an operation entirely
|
|
1238
|
-
|
|
1239
|
-
\`\`\`json
|
|
1240
|
-
{ "ids": ["<operation-guid-1>", "<operation-guid-2>"] }
|
|
1241
|
-
\`\`\`
|
|
1242
|
-
|
|
1243
|
-
Call \`delete-admin-operation\`. RightsService cascades cleanup of related grantee rows.
|
|
1244
|
-
|
|
1245
|
-
---
|
|
1246
|
-
|
|
1247
|
-
## ❌ Common Mistakes
|
|
1248
|
-
|
|
1249
|
-
- ❌ Trying to write to \`SysAdminOperation\` or \`SysAdminOperationGrantee\` via the generic OData \`create\` / \`update\` / \`delete\` tools — these tables are in \`DataServiceRestrictedModifySchemas\`.
|
|
1250
|
-
- ❌ Passing the all-zero GUID as \`id\` to \`upsert-admin-operation\` to "create" — RightsService rejects it. Omit \`id\` and let the tool generate a fresh one.
|
|
1251
|
-
- ❌ Using \`ContactId\` instead of \`SysAdminUnit.Id\` for grantees.
|
|
1252
|
-
- ❌ Forgetting to confirm with \`read\` that the change landed — RightsService responses return \`success: true\` only when the underlying entity actually saved.
|
|
1253
|
-
- ❌ Granting the operation to many units one by one — pass the full \`adminUnitIds\` array in a single call.
|
|
1254
|
-
- ❌ Filtering \`SysAdminOperationGrantee\` by the raw \`SysAdminOperationId\` / \`SysAdminUnitId\` columns — Creatio OData returns HTTP 500 for those. Use the navigation property syntax \`SysAdminOperation/Id\` / \`SysAdminUnit/Id\`.
|
|
1255
|
-
|
|
1256
|
-
---
|
|
1257
|
-
|
|
1258
|
-
## ✅ Final Checklist
|
|
1259
|
-
|
|
1260
|
-
Before reporting a system-operation change as done:
|
|
1261
|
-
- [ ] Used \`SysAdminOperation\` / \`SysAdminOperationGrantee\` only for reading.
|
|
1262
|
-
- [ ] Used \`upsert-admin-operation\` / \`delete-admin-operation\` for catalog writes.
|
|
1263
|
-
- [ ] Used \`set-admin-operation-grantee\` / \`delete-admin-operation-grantee\` for grants.
|
|
1264
|
-
- [ ] Resolved each principal through \`SysAdminUnit\` (Id, not ContactId).
|
|
1265
|
-
- [ ] Re-read the affected rows to confirm the change landed.
|
|
1266
|
-
`.trim();
|
|
1267
|
-
|
|
1268
|
-
export const ADMIN_OPERATION_PROMPT = {
|
|
1269
|
-
name: 'admin-operation-guide',
|
|
1270
|
-
title: 'Creatio System Operations (SysAdminOperation) Guide',
|
|
1271
|
-
description:
|
|
1272
|
-
'How to manage SysAdminOperation and SysAdminOperationGrantee via the dedicated RightsService tools (upsert/delete operation, set/delete grantee), with reads still routed through the standard OData read tool',
|
|
1273
|
-
argsSchema: {},
|
|
1274
|
-
callback: () => ({
|
|
1275
|
-
messages: [
|
|
1276
|
-
{
|
|
1277
|
-
role: 'user' as const,
|
|
1278
|
-
content: { type: 'text' as const, text: ADMIN_OPERATION_GUIDE },
|
|
1279
|
-
},
|
|
1280
|
-
],
|
|
1281
|
-
}),
|
|
1282
|
-
};
|
|
1283
|
-
|
|
1284
|
-
export const ALL_PROMPTS = [
|
|
1285
|
-
CREATE_ACTIVITY_PROMPT,
|
|
1286
|
-
DATETIME_PROMPT,
|
|
1287
|
-
CONTACTID_PROMPT,
|
|
1288
|
-
TAGGING_PROMPT,
|
|
1289
|
-
SYS_SETTINGS_PROMPT,
|
|
1290
|
-
FEATURE_TOGGLE_PROMPT,
|
|
1291
|
-
ADMIN_OPERATION_PROMPT,
|
|
1292
|
-
] as const;
|