viviscape-mcp 2.0.2 → 2.2.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 +43 -1
- package/dist/api-client.d.ts +151 -1
- package/dist/api-client.js +515 -71
- package/dist/auth/permissions.js +2 -0
- package/dist/enums.d.ts +48 -0
- package/dist/enums.js +67 -0
- package/dist/index.js +463 -34
- package/dist/projection.d.ts +47 -0
- package/dist/projection.js +132 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,12 +105,54 @@ The server exposes tools across these domains:
|
|
|
105
105
|
- **Companies** - `company_add`, `company_list`, `company_update`
|
|
106
106
|
- **Projects** - `project_get`, `project_list`, `project_list_active`, `project_staff`, `project_tasks`, `projects_by_company`
|
|
107
107
|
- **Tasks** - `task_add`, `task_get`, `task_update`, `tasks_open`, `tasks_pending`, `tasks_by_company`, `tasks_by_milestone`
|
|
108
|
+
- **Task comments** - `task_comments`, `task_comment_get`, `task_comment_add`, `task_comment_update`, `task_comment_remove`, `task_mark_read`
|
|
109
|
+
- **Task assignment** - `task_assignee_add`, `task_assignee_remove`, `task_set_leader`, `task_set_attention`, `task_delete`, `task_merge`
|
|
110
|
+
- **Milestones** - `milestone_list`, `milestones_active`, `milestones_by_company`, `milestones_by_user`, `milestone_get`, `milestone_add`, `milestone_update`, `milestone_clone`, `milestone_remove`
|
|
111
|
+
- **Project writes** - `project_add`, `project_update`, `project_set_status`, `project_user_add`, `project_user_remove`
|
|
112
|
+
- **Reference** - `enums` (the status, priority, and group-type values the platform accepts)
|
|
108
113
|
- **Time logs** - `timelog_add`, `timelog_update`
|
|
109
|
-
- **Notes** - `note_add`, `note_get`, `note_update`, `note_remove`, `notes_mine`, `notes_query`
|
|
114
|
+
- **Notes** - `note_add`, `note_get`, `note_update`, `note_remove`, `notes_mine`, `notes_query`, `notes_account`, `note_revisions`
|
|
115
|
+
- **Note filing** - `note_companies`, `note_users`, `note_tags`, `note_attachments`, `notebook`, `notebook_users` (each takes an `action`)
|
|
116
|
+
- **Files** - `project_files` (list/upload/update/delete/download), `task_files`
|
|
110
117
|
- **Insights** - hours by person/service/project, AI summary, person stats, time totals
|
|
111
118
|
- **Account** - `account_info`, `account_services`, `account_users`
|
|
112
119
|
- **Auth** - `auth_login`, `auth_status`, `auth_logout`
|
|
113
120
|
|
|
121
|
+
### Status and priority values
|
|
122
|
+
|
|
123
|
+
Use the `enums` tool rather than guessing. The platform's vocabularies are:
|
|
124
|
+
|
|
125
|
+
| field | values |
|
|
126
|
+
|---|---|
|
|
127
|
+
| task status | backlog, new, research, inprogress, pendingreview, inreview, testing, waitingcustomer, waitingteammember, onhold, cancelled, completed |
|
|
128
|
+
| priority | low, moderate, important, urgent, critical |
|
|
129
|
+
| project status | new, inprogress, complete |
|
|
130
|
+
| prospect status | new, firstcontact, negotiation, pending, won, lost, spam |
|
|
131
|
+
|
|
132
|
+
Two traps: tasks complete as `completed` while projects complete as
|
|
133
|
+
`complete`, and priority is *not* low/medium/high. Task and project tools
|
|
134
|
+
validate these with `z.enum`, so an invalid value is rejected before it reaches
|
|
135
|
+
the API.
|
|
136
|
+
|
|
137
|
+
### Paging and field selection
|
|
138
|
+
|
|
139
|
+
List tools (`tasks_open`, `project_list_active`, `project_tasks`, and the rest)
|
|
140
|
+
return a page of trimmed rows rather than every column of every row. A task row
|
|
141
|
+
carries ~94 columns and a project row 87, most of them irrelevant to project
|
|
142
|
+
work, so each list tool accepts:
|
|
143
|
+
|
|
144
|
+
- `fields` - columns to return; omit for a curated default, or pass `["all"]`
|
|
145
|
+
- `limit` / `offset` - page window, default 50 rows
|
|
146
|
+
|
|
147
|
+
Responses are wrapped as `{ total, returned, offset, next_offset, fields, items }`
|
|
148
|
+
so a caller can tell when more rows exist. Task lists also accept
|
|
149
|
+
`company_id`, `project_id`, `assignee_id`, `status`, `priority`,
|
|
150
|
+
`due_before`, `due_after`, and `search`; `tasks_open` pushes `company_id`
|
|
151
|
+
and `only_mine` to the server and filters the rest in-process.
|
|
152
|
+
|
|
153
|
+
In practice this took `tasks_open` from 97 KB to 6.4 KB and
|
|
154
|
+
`project_list_active` from 375 KB to 19 KB.
|
|
155
|
+
|
|
114
156
|
## Development
|
|
115
157
|
|
|
116
158
|
```bash
|
package/dist/api-client.d.ts
CHANGED
|
@@ -21,6 +21,16 @@ export declare class ViviScapeClient {
|
|
|
21
21
|
get session(): Credentials;
|
|
22
22
|
private get ctx();
|
|
23
23
|
private request;
|
|
24
|
+
/**
|
|
25
|
+
* Shared response handling for the binary upload paths, which cannot go
|
|
26
|
+
* through request() because that always sends JSON.
|
|
27
|
+
*/
|
|
28
|
+
private send;
|
|
29
|
+
private authHeaders;
|
|
30
|
+
/** multipart/form-data upload; fetch sets the boundary, so no Content-Type here. */
|
|
31
|
+
private postMultipart;
|
|
32
|
+
/** Raw-body upload with metadata in headers (the groups/file/add contract). */
|
|
33
|
+
private postBytes;
|
|
24
34
|
private get;
|
|
25
35
|
private post;
|
|
26
36
|
addProspect(data: Record<string, unknown>): Promise<unknown>;
|
|
@@ -52,15 +62,108 @@ export declare class ViviScapeClient {
|
|
|
52
62
|
getProjectStaff(projectId: number): Promise<unknown>;
|
|
53
63
|
getProjectsByCompany(userId: number, companyId: number): Promise<unknown>;
|
|
54
64
|
getActiveProjectsByUser(userId: number): Promise<unknown>;
|
|
65
|
+
/**
|
|
66
|
+
* Create a project (group). GEN_Group has ~40 fields; live rows for this
|
|
67
|
+
* tenant show account_id 0, platform_account_id = pid, and group type 5
|
|
68
|
+
* (PROJECT), so those are the defaults here.
|
|
69
|
+
*
|
|
70
|
+
* There is no delete route for projects -- a created project can only be
|
|
71
|
+
* archived or renamed afterward.
|
|
72
|
+
*/
|
|
73
|
+
addProject(data: {
|
|
74
|
+
company_id: number;
|
|
75
|
+
name: string;
|
|
76
|
+
short_description?: string;
|
|
77
|
+
description?: string;
|
|
78
|
+
status?: string;
|
|
79
|
+
is_public?: boolean;
|
|
80
|
+
staff?: number[];
|
|
81
|
+
}): Promise<unknown>;
|
|
82
|
+
/** Update a project by merging changes onto the row the API already has. */
|
|
83
|
+
updateProject(projectId: number, changes: Record<string, unknown>): Promise<unknown>;
|
|
84
|
+
/** Status-only update; leaves budget and approved time untouched. */
|
|
85
|
+
setProjectStatus(projectId: number, status: string, billable?: boolean): Promise<unknown>;
|
|
86
|
+
addProjectUser(projectId: number, userId: number, opts?: {
|
|
87
|
+
is_contact?: boolean;
|
|
88
|
+
is_lead?: boolean;
|
|
89
|
+
}): Promise<unknown>;
|
|
90
|
+
removeProjectUser(projectId: number, userId: number): Promise<unknown>;
|
|
55
91
|
addTask(data: Record<string, unknown>): Promise<unknown>;
|
|
56
92
|
updateTask(data: Record<string, unknown>): Promise<unknown>;
|
|
57
93
|
getProjectTasks(projectId: number): Promise<unknown>;
|
|
58
|
-
|
|
94
|
+
/**
|
|
95
|
+
* The account/tasks/open route filters server-side on company, ownership, and
|
|
96
|
+
* a date window; pass them through instead of hardcoding "everything".
|
|
97
|
+
*/
|
|
98
|
+
getOpenTasks(opts?: {
|
|
99
|
+
company_id?: number;
|
|
100
|
+
only_mine?: boolean;
|
|
101
|
+
team?: string;
|
|
102
|
+
start?: string;
|
|
103
|
+
end?: string;
|
|
104
|
+
}): Promise<unknown>;
|
|
59
105
|
getTask(taskId: number): Promise<unknown>;
|
|
60
106
|
getPendingTasks(userId: number): Promise<unknown>;
|
|
61
107
|
getTasksByMilestone(milestoneId: number): Promise<unknown>;
|
|
62
108
|
getTasksByGroupAndUser(groupId: number, userId: number): Promise<unknown>;
|
|
63
109
|
getCompanyTasks(companyId: number): Promise<unknown>;
|
|
110
|
+
getTaskComments(taskId: number): Promise<unknown>;
|
|
111
|
+
getTaskComment(commentId: string): Promise<unknown>;
|
|
112
|
+
/**
|
|
113
|
+
* NOTE: on platform account 1, the backend fires a client-notification webhook
|
|
114
|
+
* for comments on tasks whose client_id > 0. Adding a comment can therefore
|
|
115
|
+
* reach the customer -- the tool description says so too.
|
|
116
|
+
*/
|
|
117
|
+
addTaskComment(data: {
|
|
118
|
+
task_id: number;
|
|
119
|
+
comment: string;
|
|
120
|
+
client_id?: number;
|
|
121
|
+
source?: string;
|
|
122
|
+
}): Promise<unknown>;
|
|
123
|
+
updateTaskComment(data: {
|
|
124
|
+
comment_id: string;
|
|
125
|
+
task_id: number;
|
|
126
|
+
comment: string;
|
|
127
|
+
}): Promise<unknown>;
|
|
128
|
+
/**
|
|
129
|
+
* The backend's remove proxy answers 500 even on success: it returns 400 when
|
|
130
|
+
* the upstream delete fails, so a 500 means it crashed deserializing an empty
|
|
131
|
+
* success body (res.data.ToString() on null). Verify by re-reading the thread
|
|
132
|
+
* rather than reporting a failure that did not happen.
|
|
133
|
+
*/
|
|
134
|
+
removeTaskComment(commentId: string, taskId?: number): Promise<unknown>;
|
|
135
|
+
markTaskRead(taskId: number): Promise<unknown>;
|
|
136
|
+
addTaskAssignee(data: {
|
|
137
|
+
task_id: number;
|
|
138
|
+
user_id: number;
|
|
139
|
+
leader?: boolean;
|
|
140
|
+
attention?: boolean;
|
|
141
|
+
notify?: boolean;
|
|
142
|
+
}): Promise<unknown>;
|
|
143
|
+
/** Takes the assignee_id from the task's staff_assignees, not a user_id. */
|
|
144
|
+
removeTaskAssignee(assigneeId: number): Promise<unknown>;
|
|
145
|
+
setTaskLeader(taskId: number, userId: number): Promise<unknown>;
|
|
146
|
+
setTaskAttention(taskId: number, userId: number, flag: boolean): Promise<unknown>;
|
|
147
|
+
deleteTask(taskId: number): Promise<unknown>;
|
|
148
|
+
/** Fold one task into another; the source task is consumed. */
|
|
149
|
+
mergeTasks(fromTaskId: number, toTaskId: number): Promise<unknown>;
|
|
150
|
+
getMilestones(projectId: number): Promise<unknown>;
|
|
151
|
+
getActiveMilestones(): Promise<unknown>;
|
|
152
|
+
getMilestonesByCompany(companyId: number): Promise<unknown>;
|
|
153
|
+
getMilestonesByUser(userId: number): Promise<unknown>;
|
|
154
|
+
getMilestone(milestoneId: number): Promise<unknown>;
|
|
155
|
+
addMilestone(data: Record<string, unknown>): Promise<unknown>;
|
|
156
|
+
updateMilestone(data: Record<string, unknown>): Promise<unknown>;
|
|
157
|
+
/** Copy a milestone (and its task template) into a project. */
|
|
158
|
+
cloneMilestone(milestoneId: number, projectId: number, title?: string): Promise<unknown>;
|
|
159
|
+
/**
|
|
160
|
+
* Known broken upstream: milestone/remove answers 500 and the milestone
|
|
161
|
+
* survives. The proxy returns 400 with detail when the upstream delete fails,
|
|
162
|
+
* so the 500 is a crash in its own success branch (Convert.ToBoolean on a
|
|
163
|
+
* non-boolean data payload) -- but unlike the comment-remove case the record
|
|
164
|
+
* is genuinely still there. Verify and say so plainly instead of pretending.
|
|
165
|
+
*/
|
|
166
|
+
removeMilestone(milestoneId: number): Promise<unknown>;
|
|
64
167
|
addTimeLog(data: Record<string, unknown>): Promise<unknown>;
|
|
65
168
|
updateTimeLog(data: Record<string, unknown>): Promise<unknown>;
|
|
66
169
|
getMyNotes(): Promise<unknown>;
|
|
@@ -69,6 +172,53 @@ export declare class ViviScapeClient {
|
|
|
69
172
|
updateNote(data: Record<string, unknown>): Promise<unknown>;
|
|
70
173
|
removeNote(noteId: number | string): Promise<unknown>;
|
|
71
174
|
queryNotes(data: Record<string, unknown>): Promise<unknown>;
|
|
175
|
+
getAccountNotes(companyId?: number, userId?: number): Promise<unknown>;
|
|
176
|
+
getNoteRevisions(noteId: string): Promise<unknown>;
|
|
177
|
+
getNoteCompanies(noteId: string): Promise<unknown>;
|
|
178
|
+
addNoteCompany(noteId: string, companyId: number): Promise<unknown>;
|
|
179
|
+
removeNoteCompany(assignmentId: string): Promise<unknown>;
|
|
180
|
+
getNoteUsers(noteId: string): Promise<unknown>;
|
|
181
|
+
addNoteUser(noteId: string, userId: number, permission?: string): Promise<unknown>;
|
|
182
|
+
updateNoteUser(assignmentId: string, noteId: string, userId: number, permission: string): Promise<unknown>;
|
|
183
|
+
removeNoteUser(assignmentId: string): Promise<unknown>;
|
|
184
|
+
getNoteTags(noteId: string): Promise<unknown>;
|
|
185
|
+
addNoteTag(noteId: string, tag: string): Promise<unknown>;
|
|
186
|
+
removeNoteTag(tagId: string): Promise<unknown>;
|
|
187
|
+
getNoteAttachments(noteId: string): Promise<unknown>;
|
|
188
|
+
/** Uploads a local file as a note attachment. knowledge=true marks it for extraction. */
|
|
189
|
+
uploadNoteAttachment(noteId: string, filePath: string, knowledge?: boolean): Promise<unknown>;
|
|
190
|
+
removeNoteAttachment(attachmentId: string): Promise<unknown>;
|
|
191
|
+
/** Flag an attachment as knowledge-base material (drives text extraction). */
|
|
192
|
+
setNoteAttachmentKnowledge(attachment: Record<string, unknown>): Promise<unknown>;
|
|
193
|
+
getNotebooks(userId?: number): Promise<unknown>;
|
|
194
|
+
getNotebookNotes(bookId: string): Promise<unknown>;
|
|
195
|
+
addNotebook(name: string, description?: string): Promise<unknown>;
|
|
196
|
+
updateNotebook(bookId: string, changes: Record<string, unknown>): Promise<unknown>;
|
|
197
|
+
removeNotebook(bookId: string): Promise<unknown>;
|
|
198
|
+
/** Add or remove notes from a notebook in one call. */
|
|
199
|
+
assignNotesToBook(bookId: string, noteIds: string[], assign?: boolean): Promise<unknown>;
|
|
200
|
+
getNotebookUsers(bookId: string): Promise<unknown>;
|
|
201
|
+
addNotebookUser(bookId: string, userId: number, permission?: string): Promise<unknown>;
|
|
202
|
+
updateNotebookUser(assignmentId: string, bookId: string, userId: number, permission: string): Promise<unknown>;
|
|
203
|
+
removeNotebookUser(assignmentId: string): Promise<unknown>;
|
|
204
|
+
getProjectFiles(projectId: number, userId?: number): Promise<unknown>;
|
|
205
|
+
getTaskFiles(taskId: number): Promise<unknown>;
|
|
206
|
+
/**
|
|
207
|
+
* Upload a file to a project. This route takes the raw bytes as the body and
|
|
208
|
+
* every piece of metadata as a header, and the handler reads each header
|
|
209
|
+
* without a null check -- so all of them must be sent, even when empty.
|
|
210
|
+
*/
|
|
211
|
+
uploadProjectFile(opts: {
|
|
212
|
+
project_id: number;
|
|
213
|
+
file_path: string;
|
|
214
|
+
title?: string;
|
|
215
|
+
task_id?: number;
|
|
216
|
+
notify?: boolean;
|
|
217
|
+
}): Promise<unknown>;
|
|
218
|
+
updateProjectFile(file: Record<string, unknown>): Promise<unknown>;
|
|
219
|
+
deleteProjectFile(fileId: number): Promise<unknown>;
|
|
220
|
+
/** Returns whatever the download route serves; usually a redirect target or URL. */
|
|
221
|
+
downloadProjectFile(fileId: number): Promise<unknown>;
|
|
72
222
|
getAccountInfo(): Promise<unknown>;
|
|
73
223
|
getActiveServices(): Promise<unknown>;
|
|
74
224
|
getAllServices(): Promise<unknown>;
|