@jorgeluismlima/teamwork-mcp 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/dist/index.js +479 -2
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -21,11 +21,21 @@ This server exposes the following tools:
|
|
|
21
21
|
* **`list_of_teamwork_project_categories`**: Helper tool to list categories.
|
|
22
22
|
|
|
23
23
|
### People & Companies
|
|
24
|
-
* **`
|
|
24
|
+
* **`list_people`**: Lists all people across the site with comprehensive filtering (user type, search term, job role, etc.).
|
|
25
|
+
* **`get_project_people`**: Lists all people associated with a project, with 30+ optional filters.
|
|
25
26
|
* **`get_person`**: Retrieves detailed information about a specific person (user).
|
|
26
27
|
* **`list_companies`**: Lists companies (clients).
|
|
27
28
|
* **`get_company`**: Retrieves details of a specific company.
|
|
28
29
|
|
|
30
|
+
### Projects & Updates
|
|
31
|
+
* **`get_project`**: Retrieves detailed information about a specific project, with comprehensive filtering and include options.
|
|
32
|
+
* **`get_all_project_updates`**: Lists updates across all projects.
|
|
33
|
+
* **`get_project_updates`**: Lists updates for a specific project.
|
|
34
|
+
|
|
35
|
+
### Tags
|
|
36
|
+
* **`get_all_tags`**: Lists all tags with filtering by name, item type, etc.
|
|
37
|
+
* **`get_tag`**: Retrieves details of a specific tag.
|
|
38
|
+
|
|
29
39
|
## Configuration
|
|
30
40
|
|
|
31
41
|
To use this server, you need to configure the following environment variables:
|
package/dist/index.js
CHANGED
|
@@ -315,11 +315,134 @@ server.tool("get_time_entries", {
|
|
|
315
315
|
return handleApiError(error);
|
|
316
316
|
}
|
|
317
317
|
});
|
|
318
|
+
server.tool("list_people", {
|
|
319
|
+
userType: z.enum(["account", "collaborator", "contact"]).optional().describe("user type"),
|
|
320
|
+
updatedAfter: z.string().optional().describe("date time"),
|
|
321
|
+
searchTerm: z.string().optional().describe("filter by comment content"),
|
|
322
|
+
orderMode: z.enum(["asc", "desc"]).optional().describe("order mode"),
|
|
323
|
+
orderBy: z.enum(["name", "namecaseinsensitive", "company"]).optional().describe("order by"),
|
|
324
|
+
lastLoginAfter: z.string().optional().describe("last login after"),
|
|
325
|
+
pageSize: z.number().optional().describe("number of items in a page"),
|
|
326
|
+
page: z.number().optional().describe("page number"),
|
|
327
|
+
skipCounts: z.boolean().optional().describe("SkipCounts allows you to skip doing counts"),
|
|
328
|
+
showDeleted: z.boolean().optional().describe("include deleted items"),
|
|
329
|
+
searchUserJobRole: z.boolean().optional().describe("Include user job role in search"),
|
|
330
|
+
orderPrioritiseCurrentUser: z.boolean().optional().describe("Force to have the current/session user in the response"),
|
|
331
|
+
onlySiteOwner: z.boolean().optional().describe("only site owner"),
|
|
332
|
+
onlyOwnerCompany: z.boolean().optional().describe("return people only from the owner company"),
|
|
333
|
+
inclusiveFilter: z.boolean().optional().describe("make the filter inclusive for user ids, teamIds, companyIds"),
|
|
334
|
+
includeServiceAccounts: z.boolean().optional().describe("include service accounts"),
|
|
335
|
+
includePlaceholders: z.boolean().optional().describe("include placeholder users"),
|
|
336
|
+
includeCollaborators: z.boolean().optional().describe("exclude collaborators types"),
|
|
337
|
+
includeClients: z.boolean().optional().describe("include clients"),
|
|
338
|
+
filterByNoCostRate: z.boolean().optional().describe("Returns users who are missing cost rates"),
|
|
339
|
+
excludeContacts: z.boolean().optional().describe("exclude contact types"),
|
|
340
|
+
adminsOnly: z.boolean().optional().describe("only include users with administrator status"),
|
|
341
|
+
teamIds: z.array(z.number()).optional().describe("team ids"),
|
|
342
|
+
projectIds: z.array(z.number()).optional().describe("filter by project ids"),
|
|
343
|
+
jobRoleIds: z.array(z.number()).optional().describe("filter by job role ids"),
|
|
344
|
+
include: z.array(z.string()).optional().describe("include related data"),
|
|
345
|
+
ids: z.array(z.number()).optional().describe("filter by user ids"),
|
|
346
|
+
excludeProjectIds: z.array(z.number()).optional().describe("exclude people assigned to certain project id"),
|
|
347
|
+
excludeIds: z.array(z.number()).optional().describe("exclude certain user ids"),
|
|
348
|
+
emails: z.array(z.string()).optional().describe("filter by user emails"),
|
|
349
|
+
companyIds: z.array(z.number()).optional().describe("company ids"),
|
|
350
|
+
}, async (args) => {
|
|
351
|
+
try {
|
|
352
|
+
const params = { ...args };
|
|
353
|
+
// Helper to join arrays
|
|
354
|
+
const joinParam = (arr) => arr ? arr.join(',') : undefined;
|
|
355
|
+
if (args.teamIds)
|
|
356
|
+
params.teamIds = joinParam(args.teamIds);
|
|
357
|
+
if (args.projectIds)
|
|
358
|
+
params.projectIds = joinParam(args.projectIds);
|
|
359
|
+
if (args.jobRoleIds)
|
|
360
|
+
params.jobRoleIds = joinParam(args.jobRoleIds);
|
|
361
|
+
if (args.include)
|
|
362
|
+
params.include = joinParam(args.include);
|
|
363
|
+
if (args.ids)
|
|
364
|
+
params.ids = joinParam(args.ids);
|
|
365
|
+
if (args.excludeProjectIds)
|
|
366
|
+
params.excludeProjectIds = joinParam(args.excludeProjectIds);
|
|
367
|
+
if (args.excludeIds)
|
|
368
|
+
params.excludeIds = joinParam(args.excludeIds);
|
|
369
|
+
if (args.emails)
|
|
370
|
+
params.emails = joinParam(args.emails);
|
|
371
|
+
if (args.companyIds)
|
|
372
|
+
params.companyIds = joinParam(args.companyIds);
|
|
373
|
+
const response = await axiosInstance.get("/people.json", { params });
|
|
374
|
+
return {
|
|
375
|
+
content: [
|
|
376
|
+
{
|
|
377
|
+
type: "text",
|
|
378
|
+
text: JSON.stringify(response.data, null, 2),
|
|
379
|
+
},
|
|
380
|
+
],
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
return handleApiError(error);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
318
387
|
server.tool("get_project_people", {
|
|
319
388
|
projectId: z.number().describe("The ID of the project"),
|
|
320
|
-
|
|
389
|
+
userType: z.enum(["account", "collaborator", "contact"]).optional().describe("user type"),
|
|
390
|
+
updatedAfter: z.string().optional().describe("date time"),
|
|
391
|
+
searchTerm: z.string().optional().describe("filter by comment content"),
|
|
392
|
+
orderMode: z.enum(["asc", "desc"]).optional().describe("order mode"),
|
|
393
|
+
orderBy: z.enum(["name", "namecaseinsensitive", "company"]).optional().describe("order by"),
|
|
394
|
+
lastLoginAfter: z.string().optional().describe("last login after"),
|
|
395
|
+
pageSize: z.number().optional().describe("number of items in a page"),
|
|
396
|
+
page: z.number().optional().describe("page number"),
|
|
397
|
+
skipCounts: z.boolean().optional().describe("SkipCounts allows you to skip doing counts"),
|
|
398
|
+
showDeleted: z.boolean().optional().describe("include deleted items"),
|
|
399
|
+
searchUserJobRole: z.boolean().optional().describe("Include user job role in search"),
|
|
400
|
+
orderPrioritiseCurrentUser: z.boolean().optional().describe("Force to have the current/session user in the response"),
|
|
401
|
+
onlySiteOwner: z.boolean().optional().describe("only site owner"),
|
|
402
|
+
onlyOwnerCompany: z.boolean().optional().describe("return people only from the owner company"),
|
|
403
|
+
inclusiveFilter: z.boolean().optional().describe("make the filter inclusive"),
|
|
404
|
+
includeServiceAccounts: z.boolean().optional().describe("include service accounts"),
|
|
405
|
+
includePlaceholders: z.boolean().optional().describe("include placeholder users"),
|
|
406
|
+
includeObservers: z.boolean().optional().describe("include project observers"),
|
|
407
|
+
includeCollaborators: z.boolean().optional().describe("exclude collaborators types"),
|
|
408
|
+
includeClients: z.boolean().optional().describe("include clients"),
|
|
409
|
+
filterByNoCostRate: z.boolean().optional().describe("Returns users who are missing cost rates"),
|
|
410
|
+
excludeContacts: z.boolean().optional().describe("exclude contact types"),
|
|
411
|
+
adminsOnly: z.boolean().optional().describe("only include users with administrator status"),
|
|
412
|
+
teamIds: z.array(z.number()).optional().describe("team ids"),
|
|
413
|
+
projectIds: z.array(z.number()).optional().describe("filter by project ids"),
|
|
414
|
+
jobRoleIds: z.array(z.number()).optional().describe("filter by job role ids"),
|
|
415
|
+
include: z.array(z.string()).optional().describe("include related data"),
|
|
416
|
+
ids: z.array(z.number()).optional().describe("filter by user ids"),
|
|
417
|
+
excludeProjectIds: z.array(z.number()).optional().describe("exclude people assigned to certain project id"),
|
|
418
|
+
excludeIds: z.array(z.number()).optional().describe("exclude certain user ids"),
|
|
419
|
+
emails: z.array(z.string()).optional().describe("filter by user emails"),
|
|
420
|
+
companyIds: z.array(z.number()).optional().describe("company ids"),
|
|
421
|
+
}, async (args) => {
|
|
321
422
|
try {
|
|
322
|
-
const
|
|
423
|
+
const { projectId, ...restParams } = args;
|
|
424
|
+
const params = { ...restParams };
|
|
425
|
+
// Helper to join arrays
|
|
426
|
+
const joinParam = (arr) => arr ? arr.join(',') : undefined;
|
|
427
|
+
if (args.teamIds)
|
|
428
|
+
params.teamIds = joinParam(args.teamIds);
|
|
429
|
+
if (args.projectIds)
|
|
430
|
+
params.projectIds = joinParam(args.projectIds);
|
|
431
|
+
if (args.jobRoleIds)
|
|
432
|
+
params.jobRoleIds = joinParam(args.jobRoleIds);
|
|
433
|
+
if (args.include)
|
|
434
|
+
params.include = joinParam(args.include);
|
|
435
|
+
if (args.ids)
|
|
436
|
+
params.ids = joinParam(args.ids);
|
|
437
|
+
if (args.excludeProjectIds)
|
|
438
|
+
params.excludeProjectIds = joinParam(args.excludeProjectIds);
|
|
439
|
+
if (args.excludeIds)
|
|
440
|
+
params.excludeIds = joinParam(args.excludeIds);
|
|
441
|
+
if (args.emails)
|
|
442
|
+
params.emails = joinParam(args.emails);
|
|
443
|
+
if (args.companyIds)
|
|
444
|
+
params.companyIds = joinParam(args.companyIds);
|
|
445
|
+
const response = await axiosInstance.get(`/projects/${projectId}/people.json`, { params });
|
|
323
446
|
return {
|
|
324
447
|
content: [
|
|
325
448
|
{
|
|
@@ -603,6 +726,360 @@ server.tool("list_of_teamwork_project_categories", {}, async () => {
|
|
|
603
726
|
return handleApiError(error);
|
|
604
727
|
}
|
|
605
728
|
});
|
|
729
|
+
server.tool("get_project", {
|
|
730
|
+
projectId: z.number().describe("The ID of the project"),
|
|
731
|
+
updatedAfter: z.string().optional().describe("updated after"),
|
|
732
|
+
timeMode: z.enum(["timelogs", "estimated"]).optional().describe("profitability time mode"),
|
|
733
|
+
searchTerm: z.string().optional().describe("filter by project name"),
|
|
734
|
+
reportType: z.enum(["project", "health"]).optional().describe("define the type of the report"),
|
|
735
|
+
reportTimezone: z.string().optional().describe("Optional to configure the report dates displayed in a timezone"),
|
|
736
|
+
reportFormat: z.enum(["csv", "html", "pdf", "xls"]).optional().describe("define the format of the report"),
|
|
737
|
+
projectType: z.string().optional().describe("filter by project type"),
|
|
738
|
+
orderMode: z.enum(["asc", "desc"]).optional().describe("order mode"),
|
|
739
|
+
orderBy: z.enum(["companyname", "datecreated", "duedate", "lastactivity", "name", "namecaseinsensitive", "ownercompany", "starred", "categoryname"]).optional().describe("order by"),
|
|
740
|
+
notCompletedBefore: z.string().optional().describe("filter by projects that have not been completed before the given date"),
|
|
741
|
+
minLastActivityDate: z.string().optional().describe("filter by min last activity date"),
|
|
742
|
+
maxLastActivityDate: z.string().optional().describe("filter by max last activity date"),
|
|
743
|
+
userId: z.number().optional().describe("filter by user id"),
|
|
744
|
+
pageSize: z.number().optional().describe("number of items in a page"),
|
|
745
|
+
page: z.number().optional().describe("page number"),
|
|
746
|
+
orderByCustomFieldId: z.number().optional().describe("order by custom field id when orderBy is equal to customfield"),
|
|
747
|
+
minBudgetCapacityUsedPercent: z.number().optional().describe("filter by minimum budget capacity used"),
|
|
748
|
+
maxBudgetCapacityUsedPercent: z.number().optional().describe("filter by maximum budget capacity used"),
|
|
749
|
+
useFormulaFields: z.boolean().optional().describe("use formula fields"),
|
|
750
|
+
skipCounts: z.boolean().optional().describe("SkipCounts allows you to skip doing counts on a list API endpoint for performance reasons"),
|
|
751
|
+
searchCompanies: z.boolean().optional().describe("include companies in the search"),
|
|
752
|
+
searchByLetter: z.boolean().optional().describe("search projects beginning with the search term character only"),
|
|
753
|
+
onlyStarredProjects: z.boolean().optional().describe("filter by starred projects only"),
|
|
754
|
+
onlyProjectsWithExplicitMembership: z.boolean().optional().describe("only show projects with explicit membership"),
|
|
755
|
+
onlyProjectsThatCanLogTime: z.boolean().optional().describe("can log time on projects"),
|
|
756
|
+
onlyProjectsThatCanAddTasks: z.boolean().optional().describe("can add tasks on projects"),
|
|
757
|
+
onlyArchivedProjects: z.boolean().optional().describe("return only archived projects"),
|
|
758
|
+
matchAllProjectTags: z.boolean().optional().describe("match all project tags"),
|
|
759
|
+
matchAllExcludedTags: z.boolean().optional().describe("match all excluded project tags"),
|
|
760
|
+
isReportDownload: z.boolean().optional().describe("generate a report document"),
|
|
761
|
+
includeTentativeProjects: z.boolean().optional().describe("include alongside normal projects, tentative ones"),
|
|
762
|
+
includeTabSystemStatus: z.boolean().optional().describe("include tab system status in response"),
|
|
763
|
+
includeSubCategories: z.boolean().optional().describe("include sub categories when filtering by ids"),
|
|
764
|
+
includeStats: z.boolean().optional().describe("include project status counts"),
|
|
765
|
+
includeProjectUserInfo: z.boolean().optional().describe("fetch user-specific data such as isStarred"),
|
|
766
|
+
includeProjectProfitability: z.boolean().optional().describe("include project profitability in response"),
|
|
767
|
+
includeProjectDates: z.boolean().optional().describe("include minimum and maximum start/end dates for projects"),
|
|
768
|
+
includeCustomFields: z.boolean().optional().describe("include custom fields"),
|
|
769
|
+
includeCounts: z.boolean().optional().describe("include project related counts"),
|
|
770
|
+
includeCompletedStatus: z.boolean().optional().describe("include completed projects when filtering by project statuses current,late"),
|
|
771
|
+
includeArchivedProjects: z.boolean().optional().describe("include archived projects"),
|
|
772
|
+
hideObservedProjects: z.boolean().optional().describe("hide projects where the logged-in user is just an observer"),
|
|
773
|
+
alwaysIncludeFiltering: z.boolean().optional().describe("includes filters when project ids are provided"),
|
|
774
|
+
usersWithExplicitMembershipIds: z.array(z.number()).optional().describe("only show projects that have an explicit common membership with provided user ids"),
|
|
775
|
+
teamIds: z.array(z.number()).optional().describe("filter by projects that contain users associated with the team ids"),
|
|
776
|
+
selectedColumns: z.array(z.string()).optional().describe("select the columns to use in exports"),
|
|
777
|
+
projectTagIds: z.array(z.number()).optional().describe("filter by project tag ids"),
|
|
778
|
+
projectStatuses: z.array(z.string()).optional().describe("filter by project status (active, current, late, upcoming, completed, deleted)"),
|
|
779
|
+
projectOwnerIds: z.array(z.number()).optional().describe("filter by project owner ids"),
|
|
780
|
+
projectIds: z.array(z.number()).optional().describe("filter by project ids"),
|
|
781
|
+
projectHealths: z.array(z.number()).optional().describe("filter by project healths (0: not set, 1: bad, 2: ok, 3: good)"),
|
|
782
|
+
projectCompanyIds: z.array(z.number()).optional().describe("filter by company ids"),
|
|
783
|
+
projectCategoryIds: z.array(z.number()).optional().describe("filter by project category ids"),
|
|
784
|
+
includeCustomFieldIds: z.array(z.number()).optional().describe("include specific custom fields"),
|
|
785
|
+
include: z.array(z.string()).optional().describe("include related data"),
|
|
786
|
+
featuresEnabled: z.array(z.string()).optional().describe("filter by projects that have features enabled"),
|
|
787
|
+
excludeTagIds: z.array(z.number()).optional().describe("exclude by project tag ids"),
|
|
788
|
+
excludeProjectIds: z.array(z.number()).optional().describe("exclude certain project ids"),
|
|
789
|
+
// Field arrays for flattening
|
|
790
|
+
fieldsWorkflows: z.array(z.string()).optional().describe("fields[workflows]"),
|
|
791
|
+
fieldsUsers: z.array(z.string()).optional().describe("fields[users]"),
|
|
792
|
+
fieldsTags: z.array(z.string()).optional().describe("fields[tags]"),
|
|
793
|
+
fieldsStages: z.array(z.string()).optional().describe("fields[stages]"),
|
|
794
|
+
fieldsProjects: z.array(z.string()).optional().describe("fields[projects]"),
|
|
795
|
+
fieldsProjectCategories: z.array(z.string()).optional().describe("fields[projectcategories]"),
|
|
796
|
+
fieldsProjectUpdates: z.array(z.string()).optional().describe("fields[projectUpdates]"),
|
|
797
|
+
fieldsProjectBudgets: z.array(z.string()).optional().describe("fields[projectBudgets]"),
|
|
798
|
+
fieldsPortfolioColumns: z.array(z.string()).optional().describe("fields[portfolioColumns]"),
|
|
799
|
+
fieldsPortfolioCards: z.array(z.string()).optional().describe("fields[portfolioCards]"),
|
|
800
|
+
fieldsPortfolioBoards: z.array(z.string()).optional().describe("fields[portfolioBoards]"),
|
|
801
|
+
fieldsIndustries: z.array(z.string()).optional().describe("fields[industries]"),
|
|
802
|
+
fieldsCustomFields: z.array(z.string()).optional().describe("fields[customfields]"),
|
|
803
|
+
fieldsCustomFieldProjects: z.array(z.string()).optional().describe("fields[customfieldProjects]"),
|
|
804
|
+
fieldsCountries: z.array(z.string()).optional().describe("fields[countries]"),
|
|
805
|
+
fieldsCompanies: z.array(z.string()).optional().describe("fields[companies]"),
|
|
806
|
+
}, async (args) => {
|
|
807
|
+
try {
|
|
808
|
+
const { projectId, ...restParams } = args;
|
|
809
|
+
const params = { ...restParams };
|
|
810
|
+
const joinParam = (arr) => arr ? arr.join(',') : undefined;
|
|
811
|
+
if (args.usersWithExplicitMembershipIds)
|
|
812
|
+
params.usersWithExplicitMembershipIds = joinParam(args.usersWithExplicitMembershipIds);
|
|
813
|
+
if (args.teamIds)
|
|
814
|
+
params.teamIds = joinParam(args.teamIds);
|
|
815
|
+
if (args.selectedColumns)
|
|
816
|
+
params.selectedColumns = joinParam(args.selectedColumns);
|
|
817
|
+
if (args.projectTagIds)
|
|
818
|
+
params.projectTagIds = joinParam(args.projectTagIds);
|
|
819
|
+
if (args.projectStatuses)
|
|
820
|
+
params.projectStatuses = joinParam(args.projectStatuses);
|
|
821
|
+
if (args.projectOwnerIds)
|
|
822
|
+
params.projectOwnerIds = joinParam(args.projectOwnerIds);
|
|
823
|
+
if (args.projectIds)
|
|
824
|
+
params.projectIds = joinParam(args.projectIds);
|
|
825
|
+
if (args.projectHealths)
|
|
826
|
+
params.projectHealths = joinParam(args.projectHealths);
|
|
827
|
+
if (args.projectCompanyIds)
|
|
828
|
+
params.projectCompanyIds = joinParam(args.projectCompanyIds);
|
|
829
|
+
if (args.projectCategoryIds)
|
|
830
|
+
params.projectCategoryIds = joinParam(args.projectCategoryIds);
|
|
831
|
+
if (args.includeCustomFieldIds)
|
|
832
|
+
params.includeCustomFieldIds = joinParam(args.includeCustomFieldIds);
|
|
833
|
+
if (args.include)
|
|
834
|
+
params.include = joinParam(args.include);
|
|
835
|
+
if (args.featuresEnabled)
|
|
836
|
+
params.featuresEnabled = joinParam(args.featuresEnabled);
|
|
837
|
+
if (args.excludeTagIds)
|
|
838
|
+
params.excludeTagIds = joinParam(args.excludeTagIds);
|
|
839
|
+
if (args.excludeProjectIds)
|
|
840
|
+
params.excludeProjectIds = joinParam(args.excludeProjectIds);
|
|
841
|
+
// Handle fields arrays
|
|
842
|
+
if (args.fieldsWorkflows)
|
|
843
|
+
params['fields[workflows]'] = joinParam(args.fieldsWorkflows);
|
|
844
|
+
if (args.fieldsUsers)
|
|
845
|
+
params['fields[users]'] = joinParam(args.fieldsUsers);
|
|
846
|
+
if (args.fieldsTags)
|
|
847
|
+
params['fields[tags]'] = joinParam(args.fieldsTags);
|
|
848
|
+
if (args.fieldsStages)
|
|
849
|
+
params['fields[stages]'] = joinParam(args.fieldsStages);
|
|
850
|
+
if (args.fieldsProjects)
|
|
851
|
+
params['fields[projects]'] = joinParam(args.fieldsProjects);
|
|
852
|
+
if (args.fieldsProjectCategories)
|
|
853
|
+
params['fields[projectcategories]'] = joinParam(args.fieldsProjectCategories);
|
|
854
|
+
if (args.fieldsProjectUpdates)
|
|
855
|
+
params['fields[projectUpdates]'] = joinParam(args.fieldsProjectUpdates);
|
|
856
|
+
if (args.fieldsProjectBudgets)
|
|
857
|
+
params['fields[projectBudgets]'] = joinParam(args.fieldsProjectBudgets);
|
|
858
|
+
if (args.fieldsPortfolioColumns)
|
|
859
|
+
params['fields[portfolioColumns]'] = joinParam(args.fieldsPortfolioColumns);
|
|
860
|
+
if (args.fieldsPortfolioCards)
|
|
861
|
+
params['fields[portfolioCards]'] = joinParam(args.fieldsPortfolioCards);
|
|
862
|
+
if (args.fieldsPortfolioBoards)
|
|
863
|
+
params['fields[portfolioBoards]'] = joinParam(args.fieldsPortfolioBoards);
|
|
864
|
+
if (args.fieldsIndustries)
|
|
865
|
+
params['fields[industries]'] = joinParam(args.fieldsIndustries);
|
|
866
|
+
if (args.fieldsCustomFields)
|
|
867
|
+
params['fields[customfields]'] = joinParam(args.fieldsCustomFields);
|
|
868
|
+
if (args.fieldsCustomFieldProjects)
|
|
869
|
+
params['fields[customfieldProjects]'] = joinParam(args.fieldsCustomFieldProjects);
|
|
870
|
+
if (args.fieldsCountries)
|
|
871
|
+
params['fields[countries]'] = joinParam(args.fieldsCountries);
|
|
872
|
+
if (args.fieldsCompanies)
|
|
873
|
+
params['fields[companies]'] = joinParam(args.fieldsCompanies);
|
|
874
|
+
const response = await axiosInstance.get(`/projects/${projectId}.json`, { params });
|
|
875
|
+
return {
|
|
876
|
+
content: [
|
|
877
|
+
{
|
|
878
|
+
type: "text",
|
|
879
|
+
text: JSON.stringify(response.data, null, 2),
|
|
880
|
+
},
|
|
881
|
+
],
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
catch (error) {
|
|
885
|
+
return handleApiError(error);
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
server.tool("get_all_project_updates", {
|
|
889
|
+
updatedAfter: z.string().optional().describe("filter by updated after"),
|
|
890
|
+
projectStatus: z.string().optional().describe("filter by project status"),
|
|
891
|
+
orderMode: z.enum(["asc", "desc"]).optional().describe("order mode"),
|
|
892
|
+
orderBy: z.enum(["date", "color", "health", "project", "user"]).optional().describe("order by"),
|
|
893
|
+
createdAfter: z.string().optional().describe("filter by creation date"),
|
|
894
|
+
projectId: z.number().optional().describe("filter by project id"),
|
|
895
|
+
pageSize: z.number().optional().describe("number of items in a page"),
|
|
896
|
+
page: z.number().optional().describe("page number"),
|
|
897
|
+
skipCounts: z.boolean().optional().describe("SkipCounts allows you to skip doing counts"),
|
|
898
|
+
showDeleted: z.boolean().optional().describe("include deleted items"),
|
|
899
|
+
reactions: z.boolean().optional().describe("add reactions to the response"),
|
|
900
|
+
onlyStarredProjects: z.boolean().optional().describe("filter by starred projects only"),
|
|
901
|
+
matchAllProjectTags: z.boolean().optional().describe("match all project tags"),
|
|
902
|
+
includeArchivedProjects: z.boolean().optional().describe("include archived projects"),
|
|
903
|
+
emoji: z.boolean().optional().describe("parse emojis to unicode"),
|
|
904
|
+
activeOnly: z.boolean().optional().describe("filter by active"),
|
|
905
|
+
projectTagIds: z.array(z.number()).optional().describe("filter by project tag ids"),
|
|
906
|
+
projectStatuses: z.array(z.string()).optional().describe("list of project status"),
|
|
907
|
+
projectOwnerIds: z.array(z.number()).optional().describe("filter by project owner ids"),
|
|
908
|
+
projectHealths: z.array(z.number()).optional().describe("filter by project health"),
|
|
909
|
+
projectCompanyIds: z.array(z.number()).optional().describe("filter by company ids"),
|
|
910
|
+
projectCategoryIds: z.array(z.number()).optional().describe("filter by project category ids"),
|
|
911
|
+
include: z.array(z.string()).optional().describe("include"),
|
|
912
|
+
fieldsUsers: z.array(z.string()).optional().describe("fields[users]"),
|
|
913
|
+
fieldsProjects: z.array(z.string()).optional().describe("fields[projects]"),
|
|
914
|
+
fieldsProjectUpdates: z.array(z.string()).optional().describe("fields[projectUpdates]"),
|
|
915
|
+
}, async (args) => {
|
|
916
|
+
try {
|
|
917
|
+
const params = { ...args };
|
|
918
|
+
const joinParam = (arr) => arr ? arr.join(',') : undefined;
|
|
919
|
+
if (args.projectTagIds)
|
|
920
|
+
params.projectTagIds = joinParam(args.projectTagIds);
|
|
921
|
+
if (args.projectStatuses)
|
|
922
|
+
params.projectStatuses = joinParam(args.projectStatuses);
|
|
923
|
+
if (args.projectOwnerIds)
|
|
924
|
+
params.projectOwnerIds = joinParam(args.projectOwnerIds);
|
|
925
|
+
if (args.projectHealths)
|
|
926
|
+
params.projectHealths = joinParam(args.projectHealths);
|
|
927
|
+
if (args.projectCompanyIds)
|
|
928
|
+
params.projectCompanyIds = joinParam(args.projectCompanyIds);
|
|
929
|
+
if (args.projectCategoryIds)
|
|
930
|
+
params.projectCategoryIds = joinParam(args.projectCategoryIds);
|
|
931
|
+
if (args.include)
|
|
932
|
+
params.include = joinParam(args.include);
|
|
933
|
+
if (args.fieldsUsers)
|
|
934
|
+
params['fields[users]'] = joinParam(args.fieldsUsers);
|
|
935
|
+
if (args.fieldsProjects)
|
|
936
|
+
params['fields[projects]'] = joinParam(args.fieldsProjects);
|
|
937
|
+
if (args.fieldsProjectUpdates)
|
|
938
|
+
params['fields[projectUpdates]'] = joinParam(args.fieldsProjectUpdates);
|
|
939
|
+
const response = await axiosInstance.get("/projects/updates.json", { params });
|
|
940
|
+
return {
|
|
941
|
+
content: [
|
|
942
|
+
{
|
|
943
|
+
type: "text",
|
|
944
|
+
text: JSON.stringify(response.data, null, 2),
|
|
945
|
+
},
|
|
946
|
+
],
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
catch (error) {
|
|
950
|
+
return handleApiError(error);
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
server.tool("get_project_updates", {
|
|
954
|
+
projectId: z.number().describe("The ID of the project"),
|
|
955
|
+
updatedAfter: z.string().optional().describe("filter by updated after"),
|
|
956
|
+
projectStatus: z.string().optional().describe("filter by project status"),
|
|
957
|
+
orderMode: z.enum(["asc", "desc"]).optional().describe("order mode"),
|
|
958
|
+
orderBy: z.enum(["date", "color", "health", "project", "user"]).optional().describe("order by"),
|
|
959
|
+
createdAfter: z.string().optional().describe("filter by creation date"),
|
|
960
|
+
pageSize: z.number().optional().describe("number of items in a page"),
|
|
961
|
+
page: z.number().optional().describe("page number"),
|
|
962
|
+
skipCounts: z.boolean().optional().describe("SkipCounts allows you to skip doing counts"),
|
|
963
|
+
showDeleted: z.boolean().optional().describe("include deleted items"),
|
|
964
|
+
reactions: z.boolean().optional().describe("add reactions to the response"),
|
|
965
|
+
onlyStarredProjects: z.boolean().optional().describe("filter by starred projects only"),
|
|
966
|
+
matchAllProjectTags: z.boolean().optional().describe("match all project tags"),
|
|
967
|
+
includeArchivedProjects: z.boolean().optional().describe("include archived projects"),
|
|
968
|
+
emoji: z.boolean().optional().describe("parse emojis to unicode"),
|
|
969
|
+
activeOnly: z.boolean().optional().describe("filter by active"),
|
|
970
|
+
projectTagIds: z.array(z.number()).optional().describe("filter by project tag ids"),
|
|
971
|
+
projectStatuses: z.array(z.string()).optional().describe("list of project status"),
|
|
972
|
+
projectOwnerIds: z.array(z.number()).optional().describe("filter by project owner ids"),
|
|
973
|
+
projectHealths: z.array(z.number()).optional().describe("filter by project health"),
|
|
974
|
+
projectCompanyIds: z.array(z.number()).optional().describe("filter by company ids"),
|
|
975
|
+
projectCategoryIds: z.array(z.number()).optional().describe("filter by project category ids"),
|
|
976
|
+
include: z.array(z.string()).optional().describe("include"),
|
|
977
|
+
fieldsUsers: z.array(z.string()).optional().describe("fields[users]"),
|
|
978
|
+
fieldsProjects: z.array(z.string()).optional().describe("fields[projects]"),
|
|
979
|
+
fieldsProjectUpdates: z.array(z.string()).optional().describe("fields[projectUpdates]"),
|
|
980
|
+
}, async (args) => {
|
|
981
|
+
try {
|
|
982
|
+
const { projectId, ...restParams } = args;
|
|
983
|
+
const params = { ...restParams };
|
|
984
|
+
const joinParam = (arr) => arr ? arr.join(',') : undefined;
|
|
985
|
+
if (args.projectTagIds)
|
|
986
|
+
params.projectTagIds = joinParam(args.projectTagIds);
|
|
987
|
+
if (args.projectStatuses)
|
|
988
|
+
params.projectStatuses = joinParam(args.projectStatuses);
|
|
989
|
+
if (args.projectOwnerIds)
|
|
990
|
+
params.projectOwnerIds = joinParam(args.projectOwnerIds);
|
|
991
|
+
if (args.projectHealths)
|
|
992
|
+
params.projectHealths = joinParam(args.projectHealths);
|
|
993
|
+
if (args.projectCompanyIds)
|
|
994
|
+
params.projectCompanyIds = joinParam(args.projectCompanyIds);
|
|
995
|
+
if (args.projectCategoryIds)
|
|
996
|
+
params.projectCategoryIds = joinParam(args.projectCategoryIds);
|
|
997
|
+
if (args.include)
|
|
998
|
+
params.include = joinParam(args.include);
|
|
999
|
+
if (args.fieldsUsers)
|
|
1000
|
+
params['fields[users]'] = joinParam(args.fieldsUsers);
|
|
1001
|
+
if (args.fieldsProjects)
|
|
1002
|
+
params['fields[projects]'] = joinParam(args.fieldsProjects);
|
|
1003
|
+
if (args.fieldsProjectUpdates)
|
|
1004
|
+
params['fields[projectUpdates]'] = joinParam(args.fieldsProjectUpdates);
|
|
1005
|
+
const response = await axiosInstance.get(`/projects/${projectId}/updates.json`, { params });
|
|
1006
|
+
return {
|
|
1007
|
+
content: [
|
|
1008
|
+
{
|
|
1009
|
+
type: "text",
|
|
1010
|
+
text: JSON.stringify(response.data, null, 2),
|
|
1011
|
+
},
|
|
1012
|
+
],
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
catch (error) {
|
|
1016
|
+
return handleApiError(error);
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
server.tool("get_all_tags", {
|
|
1020
|
+
updatedAfter: z.string().optional().describe("search for tags updated after the provided date"),
|
|
1021
|
+
searchTerm: z.string().optional().describe("filter by search term"),
|
|
1022
|
+
orderMode: z.enum(["asc", "desc"]).optional().describe("order mode"),
|
|
1023
|
+
orderBy: z.enum(["name", "count", "project", "color", "datelastupdated", "projectdatelastused"]).optional().describe("order by"),
|
|
1024
|
+
itemType: z.enum(["all", "project", "task", "tasklist", "milestone", "message", "comment", "timelog", "file", "user", "company", "invoice", "risk", "notebook", "link", "event", "notebookversion", "fileversion"]).optional().describe("filter by item type"),
|
|
1025
|
+
filter: z.enum(["all", "recent"]).optional().describe("mode used when filtering the tags"),
|
|
1026
|
+
pageSize: z.number().optional().describe("number of items in a page"),
|
|
1027
|
+
page: z.number().optional().describe("page number"),
|
|
1028
|
+
withCounters: z.boolean().optional().describe("include in the response the number of items that use the tag"),
|
|
1029
|
+
skipSpecial: z.boolean().optional().describe("do not include in the response special tags"),
|
|
1030
|
+
skipCounts: z.boolean().optional().describe("SkipCounts allows you to skip doing counts"),
|
|
1031
|
+
searchRightOnly: z.boolean().optional().describe("search term will be placed as a prefix to match the tag names"),
|
|
1032
|
+
skipIds: z.array(z.number()).optional().describe("skip from the result tags with the defined ids"),
|
|
1033
|
+
projectIds: z.array(z.number()).optional().describe("filter by projects"),
|
|
1034
|
+
include: z.array(z.string()).optional().describe("include"),
|
|
1035
|
+
ids: z.array(z.number()).optional().describe("filter by ids"),
|
|
1036
|
+
fieldsTags: z.array(z.string()).optional().describe("fields[tags]"),
|
|
1037
|
+
}, async (args) => {
|
|
1038
|
+
try {
|
|
1039
|
+
const params = { ...args };
|
|
1040
|
+
const joinParam = (arr) => arr ? arr.join(',') : undefined;
|
|
1041
|
+
if (args.skipIds)
|
|
1042
|
+
params.skipIds = joinParam(args.skipIds);
|
|
1043
|
+
if (args.projectIds)
|
|
1044
|
+
params.projectIds = joinParam(args.projectIds);
|
|
1045
|
+
if (args.include)
|
|
1046
|
+
params.include = joinParam(args.include);
|
|
1047
|
+
if (args.ids)
|
|
1048
|
+
params.ids = joinParam(args.ids);
|
|
1049
|
+
if (args.fieldsTags)
|
|
1050
|
+
params['fields[tags]'] = joinParam(args.fieldsTags);
|
|
1051
|
+
const response = await axiosInstance.get("/tags.json", { params });
|
|
1052
|
+
return {
|
|
1053
|
+
content: [
|
|
1054
|
+
{
|
|
1055
|
+
type: "text",
|
|
1056
|
+
text: JSON.stringify(response.data, null, 2),
|
|
1057
|
+
},
|
|
1058
|
+
],
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
catch (error) {
|
|
1062
|
+
return handleApiError(error);
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
server.tool("get_tag", {
|
|
1066
|
+
tagId: z.number().describe("The ID of the tag"),
|
|
1067
|
+
}, async ({ tagId }) => {
|
|
1068
|
+
try {
|
|
1069
|
+
const response = await axiosInstance.get(`/tags/${tagId}.json`);
|
|
1070
|
+
return {
|
|
1071
|
+
content: [
|
|
1072
|
+
{
|
|
1073
|
+
type: "text",
|
|
1074
|
+
text: JSON.stringify(response.data, null, 2),
|
|
1075
|
+
},
|
|
1076
|
+
],
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
catch (error) {
|
|
1080
|
+
return handleApiError(error);
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
606
1083
|
async function main() {
|
|
607
1084
|
const transport = new StdioServerTransport();
|
|
608
1085
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.0
|
|
7
|
-
"description": "MCP Server for Teamwork",
|
|
6
|
+
"version": "1.1.0",
|
|
7
|
+
"description": "MCP Server for Teamwork API V3 - Projects, Time Entries, People, Companies, Tags, and Updates",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"bin": {
|
|
10
10
|
"teamwork-mcp": "./dist/index.js"
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc",
|
|
18
18
|
"start": "node dist/index.js",
|
|
19
|
-
"dev": "tsc --watch"
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
20
21
|
},
|
|
21
22
|
"keywords": [
|
|
22
23
|
"mcp",
|