mcp-intervals 1.5.0 → 1.6.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 +37 -10
- package/dist/cli/api.js +1 -1
- package/dist/cli/init.js +0 -0
- package/dist/client.d.ts +24 -16
- package/dist/client.js +75 -32
- package/dist/index.js +6 -2
- package/dist/tools/billing.d.ts +3 -0
- package/dist/tools/billing.js +243 -0
- package/dist/tools/core.d.ts +3 -0
- package/dist/tools/core.js +430 -0
- package/dist/tools/documents.d.ts +3 -0
- package/dist/tools/documents.js +51 -0
- package/dist/tools/helpers.d.ts +49 -0
- package/dist/tools/helpers.js +80 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +16 -0
- package/dist/tools/people.d.ts +3 -0
- package/dist/tools/people.js +177 -0
- package/dist/tools/projects.d.ts +3 -0
- package/dist/tools/projects.js +497 -0
- package/dist/tools/tasks.d.ts +9 -0
- package/dist/tools/tasks.js +171 -0
- package/dist/tools/time.d.ts +3 -0
- package/dist/tools/time.js +109 -0
- package/dist/tools.js +40 -0
- package/package.json +1 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { limitParam, offsetParam, registerEndpoints } from "./helpers.js";
|
|
3
|
+
const clientFields = {
|
|
4
|
+
name: z.string().describe("Client name"),
|
|
5
|
+
datecreated: z.string().describe("Date the client was created (YYYY-MM-DD)"),
|
|
6
|
+
active: z.boolean().describe("Whether the client is active"),
|
|
7
|
+
description: z.string().describe("Client description"),
|
|
8
|
+
email: z.string().describe("Client email"),
|
|
9
|
+
phone: z.string().describe("Client phone"),
|
|
10
|
+
fax: z.string().describe("Client fax"),
|
|
11
|
+
website: z.string().describe("Client website"),
|
|
12
|
+
address: z.string().describe("Client address"),
|
|
13
|
+
};
|
|
14
|
+
const contactFields = {
|
|
15
|
+
personid: z.number().describe("Person ID (use get_people)"),
|
|
16
|
+
value: z.string().describe("The contact value (e.g. the phone number or email address)"),
|
|
17
|
+
contacttypeid: z.number().describe("Contact type ID (use get_contact_types)"),
|
|
18
|
+
contactdescriptorid: z.number().describe("Contact descriptor ID (use get_contact_descriptors)"),
|
|
19
|
+
};
|
|
20
|
+
const specs = [
|
|
21
|
+
// --- Clients ---
|
|
22
|
+
{
|
|
23
|
+
name: "get_clients",
|
|
24
|
+
description: "List clients, optionally filtered by active status.",
|
|
25
|
+
method: "GET",
|
|
26
|
+
path: "/client",
|
|
27
|
+
schema: {
|
|
28
|
+
active: z.boolean().optional().describe("Filter by active state"),
|
|
29
|
+
limit: limitParam,
|
|
30
|
+
offset: offsetParam,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "get_client",
|
|
35
|
+
description: "Get full details of a single client by ID.",
|
|
36
|
+
method: "GET",
|
|
37
|
+
path: "/client",
|
|
38
|
+
idParam: "clientId",
|
|
39
|
+
schema: { clientId: z.number().describe("Client ID") },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "create_client",
|
|
43
|
+
description: "Create a client. Requires name, creation date, and active status.",
|
|
44
|
+
method: "POST",
|
|
45
|
+
path: "/client",
|
|
46
|
+
schema: {
|
|
47
|
+
name: clientFields.name,
|
|
48
|
+
datecreated: clientFields.datecreated,
|
|
49
|
+
active: clientFields.active,
|
|
50
|
+
description: clientFields.description.optional(),
|
|
51
|
+
email: clientFields.email.optional(),
|
|
52
|
+
phone: clientFields.phone.optional(),
|
|
53
|
+
fax: clientFields.fax.optional(),
|
|
54
|
+
website: clientFields.website.optional(),
|
|
55
|
+
address: clientFields.address.optional(),
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "update_client",
|
|
60
|
+
description: "Update a client. Only provide fields you want to change.",
|
|
61
|
+
method: "PUT",
|
|
62
|
+
path: "/client",
|
|
63
|
+
idParam: "clientId",
|
|
64
|
+
schema: {
|
|
65
|
+
clientId: z.number().describe("Client ID to update"),
|
|
66
|
+
name: clientFields.name.optional(),
|
|
67
|
+
datecreated: clientFields.datecreated.optional(),
|
|
68
|
+
active: clientFields.active.optional(),
|
|
69
|
+
description: clientFields.description.optional(),
|
|
70
|
+
email: clientFields.email.optional(),
|
|
71
|
+
phone: clientFields.phone.optional(),
|
|
72
|
+
fax: clientFields.fax.optional(),
|
|
73
|
+
website: clientFields.website.optional(),
|
|
74
|
+
address: clientFields.address.optional(),
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
// --- People ---
|
|
78
|
+
{
|
|
79
|
+
name: "get_people",
|
|
80
|
+
description: "List people (team members) in the account, optionally filtered by active status.",
|
|
81
|
+
method: "GET",
|
|
82
|
+
path: "/person",
|
|
83
|
+
schema: {
|
|
84
|
+
active: z.boolean().optional().describe("Filter by active state"),
|
|
85
|
+
limit: limitParam,
|
|
86
|
+
offset: offsetParam,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "get_person",
|
|
91
|
+
description: "Get details of a single person by ID.",
|
|
92
|
+
method: "GET",
|
|
93
|
+
path: "/person",
|
|
94
|
+
idParam: "personId",
|
|
95
|
+
schema: { personId: z.number().describe("Person ID") },
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "get_me",
|
|
99
|
+
description: "Get the profile of the currently authenticated user, including their person ID.",
|
|
100
|
+
method: "GET",
|
|
101
|
+
path: "/me",
|
|
102
|
+
schema: {},
|
|
103
|
+
},
|
|
104
|
+
// --- Contacts ---
|
|
105
|
+
{
|
|
106
|
+
name: "get_contact_types",
|
|
107
|
+
description: "List contact types (e.g. phone, email, website). Use the IDs with contact descriptor and person contact tools.",
|
|
108
|
+
method: "GET",
|
|
109
|
+
path: "/contacttype",
|
|
110
|
+
schema: {},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "get_contact_descriptors",
|
|
114
|
+
description: "List contact descriptors for a contact type (e.g. 'Work', 'Mobile' for phone).",
|
|
115
|
+
method: "GET",
|
|
116
|
+
path: "/contactdescriptor",
|
|
117
|
+
schema: { contacttypeid: z.number().describe("Contact type ID (use get_contact_types)") },
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: "get_person_contacts",
|
|
121
|
+
description: "List contact information (phone, email, etc.) for a person.",
|
|
122
|
+
method: "GET",
|
|
123
|
+
path: "/personcontact",
|
|
124
|
+
schema: {
|
|
125
|
+
personid: contactFields.personid,
|
|
126
|
+
contacttypeid: z.number().optional().describe("Filter by contact type ID"),
|
|
127
|
+
contactdescriptorid: z.number().optional().describe("Filter by contact descriptor ID"),
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "create_person_contact",
|
|
132
|
+
description: "Add a contact entry (phone number, email address, etc.) to a person.",
|
|
133
|
+
method: "POST",
|
|
134
|
+
path: "/personcontact",
|
|
135
|
+
schema: { ...contactFields },
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "update_person_contact",
|
|
139
|
+
description: "Update a person contact entry. Only provide fields you want to change.",
|
|
140
|
+
method: "PUT",
|
|
141
|
+
path: "/personcontact",
|
|
142
|
+
idParam: "personContactId",
|
|
143
|
+
schema: {
|
|
144
|
+
personContactId: z.number().describe("Person contact ID to update"),
|
|
145
|
+
personid: contactFields.personid.optional(),
|
|
146
|
+
value: contactFields.value.optional(),
|
|
147
|
+
contacttypeid: contactFields.contacttypeid.optional(),
|
|
148
|
+
contactdescriptorid: contactFields.contactdescriptorid.optional(),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: "delete_person_contact",
|
|
153
|
+
description: "Delete a person contact entry by ID. Permanently deletes; cannot be undone.",
|
|
154
|
+
method: "DELETE",
|
|
155
|
+
path: "/personcontact",
|
|
156
|
+
idParam: "personContactId",
|
|
157
|
+
schema: { personContactId: z.number().describe("Person contact ID to delete") },
|
|
158
|
+
},
|
|
159
|
+
// --- Account ---
|
|
160
|
+
{
|
|
161
|
+
name: "get_groups",
|
|
162
|
+
description: "List access level groups (Administrator, Manager, Resource, Executive).",
|
|
163
|
+
method: "GET",
|
|
164
|
+
path: "/group",
|
|
165
|
+
schema: {},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: "get_quota",
|
|
169
|
+
description: "Get current API quota usage: requests consumed, the daily limit, and when the quota resets.",
|
|
170
|
+
method: "GET",
|
|
171
|
+
path: "/quota",
|
|
172
|
+
schema: {},
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
export function registerPeopleTools(server, client) {
|
|
176
|
+
registerEndpoints(server, client, specs);
|
|
177
|
+
}
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { idOrList, limitParam, offsetParam, registerEndpoints, } from "./helpers.js";
|
|
3
|
+
const projectFields = {
|
|
4
|
+
name: z.string().describe("Project name (max 255 characters)"),
|
|
5
|
+
datestart: z.string().describe("Project start date (YYYY-MM-DD)"),
|
|
6
|
+
billable: z.boolean().describe("Whether the project is billable"),
|
|
7
|
+
active: z.boolean().describe("Whether the project is active"),
|
|
8
|
+
clientid: z.number().describe("Client ID (use get_clients)"),
|
|
9
|
+
managerid: z.number().describe("Person ID of the project manager (use get_people)"),
|
|
10
|
+
description: z.string().describe("Project description"),
|
|
11
|
+
dateend: z.string().describe("Project end date (YYYY-MM-DD)"),
|
|
12
|
+
budget: z.number().describe("Budget amount"),
|
|
13
|
+
alert_percent: z.number().describe("Budget alert threshold percentage"),
|
|
14
|
+
};
|
|
15
|
+
const milestoneFields = {
|
|
16
|
+
projectid: z.number().describe("Project ID (use get_projects)"),
|
|
17
|
+
ownerid: idOrList.describe("Person ID of the milestone owner, or comma-delimited list of IDs"),
|
|
18
|
+
title: z.string().describe("Milestone title (max 255 characters)"),
|
|
19
|
+
datedue: z.string().describe("Due date (YYYY-MM-DD)"),
|
|
20
|
+
complete: z.boolean().describe("Whether the milestone is complete"),
|
|
21
|
+
description: z.string().describe("Milestone description"),
|
|
22
|
+
};
|
|
23
|
+
const requestFields = {
|
|
24
|
+
personid: z.number().describe("Person ID submitting the request (use get_people)"),
|
|
25
|
+
priorityid: z.number().describe("Priority ID (use get_task_priorities)"),
|
|
26
|
+
title: z.string().describe("Request title (max 255 characters)"),
|
|
27
|
+
projectid: z.number().describe("Project ID to associate with (use get_projects)"),
|
|
28
|
+
datedue: z.string().describe("Due date (YYYY-MM-DD)"),
|
|
29
|
+
description: z.string().describe("Request description (HTML supported)"),
|
|
30
|
+
};
|
|
31
|
+
const active = z.boolean().optional().describe("Filter by active state");
|
|
32
|
+
const specs = [
|
|
33
|
+
// --- Projects (get_project lives in core) ---
|
|
34
|
+
{
|
|
35
|
+
name: "get_projects",
|
|
36
|
+
description: "List projects, optionally filtered by client or active state.",
|
|
37
|
+
method: "GET",
|
|
38
|
+
path: "/project",
|
|
39
|
+
schema: {
|
|
40
|
+
clientid: z.number().optional().describe("Filter by client ID"),
|
|
41
|
+
active,
|
|
42
|
+
limit: limitParam,
|
|
43
|
+
offset: offsetParam,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "create_project",
|
|
48
|
+
description: "Create a new project. Requires name, start date, billable flag, and active flag.",
|
|
49
|
+
method: "POST",
|
|
50
|
+
path: "/project",
|
|
51
|
+
schema: {
|
|
52
|
+
name: projectFields.name,
|
|
53
|
+
datestart: projectFields.datestart,
|
|
54
|
+
billable: projectFields.billable,
|
|
55
|
+
active: projectFields.active,
|
|
56
|
+
clientid: projectFields.clientid.optional(),
|
|
57
|
+
managerid: projectFields.managerid.optional(),
|
|
58
|
+
description: projectFields.description.optional(),
|
|
59
|
+
dateend: projectFields.dateend.optional(),
|
|
60
|
+
budget: projectFields.budget.optional(),
|
|
61
|
+
alert_percent: projectFields.alert_percent.optional(),
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "update_project",
|
|
66
|
+
description: "Update an existing project. Only provide fields you want to change.",
|
|
67
|
+
method: "PUT",
|
|
68
|
+
path: "/project",
|
|
69
|
+
idParam: "projectId",
|
|
70
|
+
schema: {
|
|
71
|
+
projectId: z.number().describe("Project ID to update"),
|
|
72
|
+
name: projectFields.name.optional(),
|
|
73
|
+
datestart: projectFields.datestart.optional(),
|
|
74
|
+
billable: projectFields.billable.optional(),
|
|
75
|
+
active: projectFields.active.optional(),
|
|
76
|
+
clientid: projectFields.clientid.optional(),
|
|
77
|
+
managerid: projectFields.managerid.optional(),
|
|
78
|
+
description: projectFields.description.optional(),
|
|
79
|
+
dateend: projectFields.dateend.optional(),
|
|
80
|
+
budget: projectFields.budget.optional(),
|
|
81
|
+
alert_percent: projectFields.alert_percent.optional(),
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
// --- Milestones (get_milestone lives in core) ---
|
|
85
|
+
{
|
|
86
|
+
name: "get_milestones",
|
|
87
|
+
description: "List milestones, optionally filtered by project.",
|
|
88
|
+
method: "GET",
|
|
89
|
+
path: "/milestone",
|
|
90
|
+
schema: {
|
|
91
|
+
projectid: z.number().optional().describe("Filter by project ID"),
|
|
92
|
+
limit: limitParam,
|
|
93
|
+
offset: offsetParam,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "create_milestone",
|
|
98
|
+
description: "Create a milestone within a project. Requires project, owner, title, due date, and complete status.",
|
|
99
|
+
method: "POST",
|
|
100
|
+
path: "/milestone",
|
|
101
|
+
schema: {
|
|
102
|
+
projectid: milestoneFields.projectid,
|
|
103
|
+
ownerid: milestoneFields.ownerid,
|
|
104
|
+
title: milestoneFields.title,
|
|
105
|
+
datedue: milestoneFields.datedue,
|
|
106
|
+
complete: milestoneFields.complete,
|
|
107
|
+
description: milestoneFields.description.optional(),
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "update_milestone",
|
|
112
|
+
description: "Update an existing milestone. Only provide fields you want to change.",
|
|
113
|
+
method: "PUT",
|
|
114
|
+
path: "/milestone",
|
|
115
|
+
idParam: "milestoneId",
|
|
116
|
+
schema: {
|
|
117
|
+
milestoneId: z.number().describe("Milestone ID to update"),
|
|
118
|
+
projectid: milestoneFields.projectid.optional(),
|
|
119
|
+
ownerid: milestoneFields.ownerid.optional(),
|
|
120
|
+
title: milestoneFields.title.optional(),
|
|
121
|
+
datedue: milestoneFields.datedue.optional(),
|
|
122
|
+
complete: milestoneFields.complete.optional(),
|
|
123
|
+
description: milestoneFields.description.optional(),
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
// --- Milestone notes ---
|
|
127
|
+
{
|
|
128
|
+
name: "get_milestone_notes",
|
|
129
|
+
description: "List notes on milestones.",
|
|
130
|
+
method: "GET",
|
|
131
|
+
path: "/milestonenote",
|
|
132
|
+
schema: {
|
|
133
|
+
milestoneid: z.number().optional().describe("Filter by milestone ID"),
|
|
134
|
+
limit: limitParam,
|
|
135
|
+
offset: offsetParam,
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "create_milestone_note",
|
|
140
|
+
description: "Add a note to a milestone.",
|
|
141
|
+
method: "POST",
|
|
142
|
+
path: "/milestonenote",
|
|
143
|
+
schema: {
|
|
144
|
+
milestoneid: z.number().describe("Milestone ID (use get_milestones)"),
|
|
145
|
+
note: z.string().describe("Note body (HTML supported)"),
|
|
146
|
+
public: z.boolean().describe("Whether the note is publicly visible"),
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: "update_milestone_note",
|
|
151
|
+
description: "Update a milestone note (Administrator only). Only provide fields you want to change.",
|
|
152
|
+
method: "PUT",
|
|
153
|
+
path: "/milestonenote",
|
|
154
|
+
idParam: "milestoneNoteId",
|
|
155
|
+
schema: {
|
|
156
|
+
milestoneNoteId: z.number().describe("Milestone note ID to update"),
|
|
157
|
+
milestoneid: z.number().optional().describe("Milestone ID"),
|
|
158
|
+
note: z.string().optional().describe("Note body (HTML supported)"),
|
|
159
|
+
public: z.boolean().optional().describe("Whether the note is publicly visible"),
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: "delete_milestone_note",
|
|
164
|
+
description: "Delete a milestone note by ID (Administrator only). Permanently deletes; cannot be undone.",
|
|
165
|
+
method: "DELETE",
|
|
166
|
+
path: "/milestonenote",
|
|
167
|
+
idParam: "milestoneNoteId",
|
|
168
|
+
schema: { milestoneNoteId: z.number().describe("Milestone note ID to delete") },
|
|
169
|
+
},
|
|
170
|
+
// --- Project notes ---
|
|
171
|
+
{
|
|
172
|
+
name: "get_project_notes",
|
|
173
|
+
description: "List project notes.",
|
|
174
|
+
method: "GET",
|
|
175
|
+
path: "/projectnote",
|
|
176
|
+
schema: {
|
|
177
|
+
projectid: z.number().optional().describe("Filter by project ID"),
|
|
178
|
+
clientid: z.number().optional().describe("Filter by client ID"),
|
|
179
|
+
authorid: z.number().optional().describe("Filter by author person ID"),
|
|
180
|
+
search: z.string().optional().describe("Search text"),
|
|
181
|
+
limit: limitParam,
|
|
182
|
+
offset: offsetParam,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: "get_project_note",
|
|
187
|
+
description: "Get a single project note by ID.",
|
|
188
|
+
method: "GET",
|
|
189
|
+
path: "/projectnote",
|
|
190
|
+
idParam: "projectNoteId",
|
|
191
|
+
schema: { projectNoteId: z.number().describe("Project note ID") },
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: "create_project_note",
|
|
195
|
+
description: "Create a note on a project. The project must be active.",
|
|
196
|
+
method: "POST",
|
|
197
|
+
path: "/projectnote",
|
|
198
|
+
schema: {
|
|
199
|
+
projectid: z.number().describe("Project ID (use get_projects)"),
|
|
200
|
+
title: z.string().describe("Note title (max 255 characters)"),
|
|
201
|
+
note: z.string().describe("Note body (HTML supported)"),
|
|
202
|
+
secure: z.boolean().describe("Whether the note is secure (restricted visibility)"),
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
name: "update_project_note",
|
|
207
|
+
description: "Update a project note. Only provide fields you want to change.",
|
|
208
|
+
method: "PUT",
|
|
209
|
+
path: "/projectnote",
|
|
210
|
+
idParam: "projectNoteId",
|
|
211
|
+
schema: {
|
|
212
|
+
projectNoteId: z.number().describe("Project note ID to update"),
|
|
213
|
+
projectid: z.number().optional().describe("Project ID"),
|
|
214
|
+
title: z.string().optional().describe("Note title (max 255 characters)"),
|
|
215
|
+
note: z.string().optional().describe("Note body (HTML supported)"),
|
|
216
|
+
secure: z.boolean().optional().describe("Whether the note is secure (restricted visibility)"),
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: "delete_project_note",
|
|
221
|
+
description: "Delete a project note by ID. Permanently deletes; cannot be undone.",
|
|
222
|
+
method: "DELETE",
|
|
223
|
+
path: "/projectnote",
|
|
224
|
+
idParam: "projectNoteId",
|
|
225
|
+
schema: { projectNoteId: z.number().describe("Project note ID to delete") },
|
|
226
|
+
},
|
|
227
|
+
// --- Project team ---
|
|
228
|
+
{
|
|
229
|
+
name: "get_project_team",
|
|
230
|
+
description: "List team members on a project.",
|
|
231
|
+
method: "GET",
|
|
232
|
+
path: "/projectteam",
|
|
233
|
+
schema: { projectid: z.number().describe("Project ID (use get_projects)") },
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: "add_project_team_member",
|
|
237
|
+
description: "Add a person to a project team (Administrator only).",
|
|
238
|
+
method: "POST",
|
|
239
|
+
path: "/projectteam",
|
|
240
|
+
schema: {
|
|
241
|
+
projectid: z.number().describe("Project ID (use get_projects)"),
|
|
242
|
+
personid: z.number().describe("Person ID to add (use get_people)"),
|
|
243
|
+
securenotes: z.boolean().optional().describe("Whether the person can access secure project notes"),
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: "remove_project_team_member",
|
|
248
|
+
description: "Remove a person from a project team (Administrator only).",
|
|
249
|
+
method: "DELETE",
|
|
250
|
+
path: "/projectteam",
|
|
251
|
+
schema: {
|
|
252
|
+
projectid: z.number().describe("Project ID (use get_projects)"),
|
|
253
|
+
personid: z.number().describe("Person ID to remove"),
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
// --- Project modules ---
|
|
257
|
+
{
|
|
258
|
+
name: "get_project_modules",
|
|
259
|
+
description: "List modules assigned to projects. Module IDs are needed when creating tasks.",
|
|
260
|
+
method: "GET",
|
|
261
|
+
path: "/projectmodule",
|
|
262
|
+
schema: {
|
|
263
|
+
projectid: z.number().optional().describe("Filter by project ID"),
|
|
264
|
+
active,
|
|
265
|
+
personid: z.number().optional().describe("Filter by person ID"),
|
|
266
|
+
limit: limitParam,
|
|
267
|
+
offset: offsetParam,
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
name: "add_project_module",
|
|
272
|
+
description: "Add a module to a project. Provide moduleid to use a default module, or module (name) to create a custom one.",
|
|
273
|
+
method: "POST",
|
|
274
|
+
path: "/projectmodule",
|
|
275
|
+
schema: {
|
|
276
|
+
projectid: z.number().describe("Project ID (use get_projects)"),
|
|
277
|
+
active: z.boolean().describe("Whether the module is active on this project"),
|
|
278
|
+
moduleid: z.number().optional().describe("Default module ID (required for a default module; use get_modules)"),
|
|
279
|
+
module: z.string().optional().describe("Custom module name (required for a custom module, max 155 characters)"),
|
|
280
|
+
description: z.string().optional().describe("Module description"),
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: "update_project_module",
|
|
285
|
+
description: "Update a project module assignment.",
|
|
286
|
+
method: "PUT",
|
|
287
|
+
path: "/projectmodule",
|
|
288
|
+
idParam: "projectModuleId",
|
|
289
|
+
schema: {
|
|
290
|
+
projectModuleId: z.number().describe("Project module ID to update"),
|
|
291
|
+
active: z.boolean().describe("Whether the module is active on this project"),
|
|
292
|
+
module: z.string().optional().describe("Updated module name (max 155 characters)"),
|
|
293
|
+
description: z.string().optional().describe("Module description"),
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: "remove_project_module",
|
|
298
|
+
description: "Remove a module from a project.",
|
|
299
|
+
method: "DELETE",
|
|
300
|
+
path: "/projectmodule",
|
|
301
|
+
idParam: "projectModuleId",
|
|
302
|
+
schema: { projectModuleId: z.number().describe("Project module ID to delete") },
|
|
303
|
+
},
|
|
304
|
+
// --- Project work types ---
|
|
305
|
+
{
|
|
306
|
+
name: "get_project_worktypes",
|
|
307
|
+
description: "List work types assigned to projects.",
|
|
308
|
+
method: "GET",
|
|
309
|
+
path: "/projectworktype",
|
|
310
|
+
schema: {
|
|
311
|
+
projectid: z.number().optional().describe("Filter by project ID"),
|
|
312
|
+
active,
|
|
313
|
+
personid: z.number().optional().describe("Filter by person ID"),
|
|
314
|
+
limit: limitParam,
|
|
315
|
+
offset: offsetParam,
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
name: "add_project_worktype",
|
|
320
|
+
description: "Add a work type to a project. Provide worktypeid for a default work type, or worktype (name) + hourlyrate for a custom one.",
|
|
321
|
+
method: "POST",
|
|
322
|
+
path: "/projectworktype",
|
|
323
|
+
schema: {
|
|
324
|
+
projectid: z.number().describe("Project ID (use get_projects)"),
|
|
325
|
+
active: z.boolean().describe("Whether the work type is active on this project"),
|
|
326
|
+
worktypeid: z.number().optional().describe("Default work type ID (use get_worktypes)"),
|
|
327
|
+
worktype: z.string().optional().describe("Custom work type name (max 155 characters)"),
|
|
328
|
+
hourlyrate: z.number().optional().describe("Hourly rate (required for a custom work type)"),
|
|
329
|
+
esttime: z.number().optional().describe("Estimated hours"),
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
name: "update_project_worktype",
|
|
334
|
+
description: "Update a project work type assignment.",
|
|
335
|
+
method: "PUT",
|
|
336
|
+
path: "/projectworktype",
|
|
337
|
+
idParam: "projectWorktypeId",
|
|
338
|
+
schema: {
|
|
339
|
+
projectWorktypeId: z.number().describe("Project work type ID to update"),
|
|
340
|
+
active: z.boolean().optional().describe("Whether the work type is active on this project"),
|
|
341
|
+
esttime: z.number().optional().describe("Estimated hours"),
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
name: "remove_project_worktype",
|
|
346
|
+
description: "Remove a work type from a project.",
|
|
347
|
+
method: "DELETE",
|
|
348
|
+
path: "/projectworktype",
|
|
349
|
+
idParam: "projectWorktypeId",
|
|
350
|
+
schema: { projectWorktypeId: z.number().describe("Project work type ID to delete") },
|
|
351
|
+
},
|
|
352
|
+
// --- Project labels ---
|
|
353
|
+
{
|
|
354
|
+
name: "get_project_labels",
|
|
355
|
+
description: "List project labels (used to categorize and color-code projects).",
|
|
356
|
+
method: "GET",
|
|
357
|
+
path: "/projectlabel",
|
|
358
|
+
schema: { active, limit: limitParam, offset: offsetParam },
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: "get_project_label",
|
|
362
|
+
description: "Get a single project label by ID.",
|
|
363
|
+
method: "GET",
|
|
364
|
+
path: "/projectlabel",
|
|
365
|
+
idParam: "projectLabelId",
|
|
366
|
+
schema: { projectLabelId: z.number().describe("Project label ID") },
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: "create_project_label",
|
|
370
|
+
description: "Create a project label.",
|
|
371
|
+
method: "POST",
|
|
372
|
+
path: "/projectlabel",
|
|
373
|
+
schema: {
|
|
374
|
+
name: z.string().describe("Label name (max 55 characters)"),
|
|
375
|
+
color: z.string().describe("6-character hex color (e.g. FF5733)"),
|
|
376
|
+
priority: z.number().describe("Sort order (higher value = higher priority)"),
|
|
377
|
+
active: z.boolean().describe("Whether the label is active"),
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
name: "update_project_label",
|
|
382
|
+
description: "Update a project label. Only provide fields you want to change.",
|
|
383
|
+
method: "PUT",
|
|
384
|
+
path: "/projectlabel",
|
|
385
|
+
idParam: "projectLabelId",
|
|
386
|
+
schema: {
|
|
387
|
+
projectLabelId: z.number().describe("Project label ID to update"),
|
|
388
|
+
name: z.string().optional().describe("Label name (max 55 characters)"),
|
|
389
|
+
color: z.string().optional().describe("6-character hex color (e.g. FF5733)"),
|
|
390
|
+
priority: z.number().optional().describe("Sort order (higher value = higher priority)"),
|
|
391
|
+
active: z.boolean().optional().describe("Whether the label is active"),
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
// --- Default modules ---
|
|
395
|
+
{
|
|
396
|
+
name: "get_modules",
|
|
397
|
+
description: "List all default modules. Module IDs are required when creating tasks and time entries.",
|
|
398
|
+
method: "GET",
|
|
399
|
+
path: "/module",
|
|
400
|
+
schema: { active, limit: limitParam, offset: offsetParam },
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
name: "get_module",
|
|
404
|
+
description: "Get a single default module by ID.",
|
|
405
|
+
method: "GET",
|
|
406
|
+
path: "/module",
|
|
407
|
+
idParam: "moduleId",
|
|
408
|
+
schema: { moduleId: z.number().describe("Module ID") },
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
name: "create_module",
|
|
412
|
+
description: "Create a default module.",
|
|
413
|
+
method: "POST",
|
|
414
|
+
path: "/module",
|
|
415
|
+
schema: {
|
|
416
|
+
name: z.string().describe("Module name (max 155 characters)"),
|
|
417
|
+
description: z.string().optional().describe("Module description (max 155 characters)"),
|
|
418
|
+
active: z.boolean().optional().describe("Whether the module is active"),
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
name: "update_module",
|
|
423
|
+
description: "Update a default module. Only provide fields you want to change.",
|
|
424
|
+
method: "PUT",
|
|
425
|
+
path: "/module",
|
|
426
|
+
idParam: "moduleId",
|
|
427
|
+
schema: {
|
|
428
|
+
moduleId: z.number().describe("Module ID to update"),
|
|
429
|
+
name: z.string().optional().describe("Module name (max 155 characters)"),
|
|
430
|
+
description: z.string().optional().describe("Module description (max 155 characters)"),
|
|
431
|
+
active: z.boolean().optional().describe("Whether the module is active"),
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
// --- Requests ---
|
|
435
|
+
{
|
|
436
|
+
name: "get_requests",
|
|
437
|
+
description: "List work requests, optionally filtered by priority, person, or project.",
|
|
438
|
+
method: "GET",
|
|
439
|
+
path: "/request",
|
|
440
|
+
schema: {
|
|
441
|
+
priorityid: z.number().optional().describe("Filter by priority ID"),
|
|
442
|
+
personid: z.number().optional().describe("Filter by person ID"),
|
|
443
|
+
projectid: z.number().optional().describe("Filter by project ID"),
|
|
444
|
+
limit: limitParam,
|
|
445
|
+
offset: offsetParam,
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
name: "get_request",
|
|
450
|
+
description: "Get full details of a single request by ID.",
|
|
451
|
+
method: "GET",
|
|
452
|
+
path: "/request",
|
|
453
|
+
idParam: "requestId",
|
|
454
|
+
schema: { requestId: z.number().describe("Request ID") },
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
name: "create_request",
|
|
458
|
+
description: "Create a work request.",
|
|
459
|
+
method: "POST",
|
|
460
|
+
path: "/request",
|
|
461
|
+
schema: {
|
|
462
|
+
personid: requestFields.personid,
|
|
463
|
+
priorityid: requestFields.priorityid,
|
|
464
|
+
title: requestFields.title,
|
|
465
|
+
projectid: requestFields.projectid.optional(),
|
|
466
|
+
datedue: requestFields.datedue.optional(),
|
|
467
|
+
description: requestFields.description.optional(),
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: "update_request",
|
|
472
|
+
description: "Update a request. Only provide fields you want to change.",
|
|
473
|
+
method: "PUT",
|
|
474
|
+
path: "/request",
|
|
475
|
+
idParam: "requestId",
|
|
476
|
+
schema: {
|
|
477
|
+
requestId: z.number().describe("Request ID to update"),
|
|
478
|
+
personid: requestFields.personid.optional(),
|
|
479
|
+
priorityid: requestFields.priorityid.optional(),
|
|
480
|
+
title: requestFields.title.optional(),
|
|
481
|
+
projectid: requestFields.projectid.optional(),
|
|
482
|
+
datedue: requestFields.datedue.optional(),
|
|
483
|
+
description: requestFields.description.optional(),
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
name: "delete_request",
|
|
488
|
+
description: "Delete a request by ID. Permanently deletes; cannot be undone.",
|
|
489
|
+
method: "DELETE",
|
|
490
|
+
path: "/request",
|
|
491
|
+
idParam: "requestId",
|
|
492
|
+
schema: { requestId: z.number().describe("Request ID to delete") },
|
|
493
|
+
},
|
|
494
|
+
];
|
|
495
|
+
export function registerProjectTools(server, client) {
|
|
496
|
+
registerEndpoints(server, client, specs);
|
|
497
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { IntervalsClient } from "../client.js";
|
|
4
|
+
declare const localTaskId: z.ZodNumber;
|
|
5
|
+
declare const resolveLocalTask: (field: string, target: string) => (args: Record<string, unknown>, client: IntervalsClient) => Promise<{
|
|
6
|
+
[x: string]: unknown;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function registerTaskTools(server: McpServer, client: IntervalsClient): void;
|
|
9
|
+
export { localTaskId, resolveLocalTask };
|