@ezmodo/mcp-server 0.13.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.
Files changed (98) hide show
  1. package/README.md +305 -0
  2. package/config/development.js +20 -0
  3. package/config/endpoint-map.js +351 -0
  4. package/config/index.js +34 -0
  5. package/config/production.js +18 -0
  6. package/config/staging.js +18 -0
  7. package/handlers/access.js +141 -0
  8. package/handlers/activity.js +112 -0
  9. package/handlers/agents.js +95 -0
  10. package/handlers/ai-intelligence.js +55 -0
  11. package/handlers/attachments.js +30 -0
  12. package/handlers/catalogs.js +169 -0
  13. package/handlers/components.js +282 -0
  14. package/handlers/context-manifest.js +1150 -0
  15. package/handlers/decisions.js +114 -0
  16. package/handlers/designs.js +118 -0
  17. package/handlers/documents.js +227 -0
  18. package/handlers/entities.js +95 -0
  19. package/handlers/epics.js +190 -0
  20. package/handlers/facts.js +62 -0
  21. package/handlers/feature-flags.js +142 -0
  22. package/handlers/features.js +137 -0
  23. package/handlers/folders.js +127 -0
  24. package/handlers/git-context.js +917 -0
  25. package/handlers/github.js +72 -0
  26. package/handlers/graph.js +23 -0
  27. package/handlers/index.js +205 -0
  28. package/handlers/links.js +156 -0
  29. package/handlers/milestones.js +131 -0
  30. package/handlers/organizations.js +14 -0
  31. package/handlers/projects.js +122 -0
  32. package/handlers/recurring-tasks.js +33 -0
  33. package/handlers/tags.js +124 -0
  34. package/handlers/tasks.js +561 -0
  35. package/handlers/testing.js +116 -0
  36. package/handlers/todos.js +43 -0
  37. package/handlers/watchers.js +54 -0
  38. package/handlers/work-templates.js +32 -0
  39. package/index.js +175 -0
  40. package/lib/active-session.js +86 -0
  41. package/lib/auto-assign.js +93 -0
  42. package/lib/autolink.js +176 -0
  43. package/lib/changed-files.js +22 -0
  44. package/lib/env.js +45 -0
  45. package/lib/git-helpers.js +553 -0
  46. package/lib/git-utils.js +73 -0
  47. package/lib/http-client.js +164 -0
  48. package/lib/links-at-create.js +94 -0
  49. package/lib/local-cache.js +140 -0
  50. package/lib/logger.js +109 -0
  51. package/lib/manifest-loader.js +182 -0
  52. package/lib/manifest-query.js +686 -0
  53. package/lib/repo-config-dir.js +118 -0
  54. package/lib/version.js +10 -0
  55. package/lib/web-url.js +69 -0
  56. package/lib/worktree-tools.js +950 -0
  57. package/package.json +62 -0
  58. package/prompts/ai-workflow-automation.js +96 -0
  59. package/prompts/index.js +39 -0
  60. package/prompts/zephly-usage-guide-content.txt +631 -0
  61. package/prompts/zephly-usage-guide.js +119 -0
  62. package/tools/access-entity-types.js +28 -0
  63. package/tools/access.js +152 -0
  64. package/tools/activity.js +38 -0
  65. package/tools/agents.js +208 -0
  66. package/tools/ai-intelligence.js +111 -0
  67. package/tools/attachments.js +92 -0
  68. package/tools/catalogs.js +341 -0
  69. package/tools/components.js +249 -0
  70. package/tools/context-manifest.js +236 -0
  71. package/tools/decisions.js +168 -0
  72. package/tools/designs.js +222 -0
  73. package/tools/documents.js +287 -0
  74. package/tools/entities.js +223 -0
  75. package/tools/epics.js +267 -0
  76. package/tools/facts.js +70 -0
  77. package/tools/feature-flags.js +300 -0
  78. package/tools/features.js +246 -0
  79. package/tools/folders.js +122 -0
  80. package/tools/git-context.js +109 -0
  81. package/tools/github.js +172 -0
  82. package/tools/graph.js +70 -0
  83. package/tools/index.js +77 -0
  84. package/tools/link-params.js +93 -0
  85. package/tools/linkable-types.js +36 -0
  86. package/tools/links.js +199 -0
  87. package/tools/milestones.js +176 -0
  88. package/tools/organizations.js +23 -0
  89. package/tools/projects.js +172 -0
  90. package/tools/recurring-tasks.js +115 -0
  91. package/tools/tags.js +219 -0
  92. package/tools/task-item-schema.js +57 -0
  93. package/tools/task-type.js +33 -0
  94. package/tools/tasks.js +680 -0
  95. package/tools/testing.js +344 -0
  96. package/tools/todos.js +69 -0
  97. package/tools/watchers.js +81 -0
  98. package/tools/work-templates.js +96 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Project Handlers
3
+ * Handler functions for project-related MCP tools
4
+ */
5
+
6
+ import { callZephlyAPI } from '../lib/http-client.js';
7
+
8
+ /**
9
+ * Dispatch manage_project actions
10
+ */
11
+ export async function manageProject(args) {
12
+ const { action, ...params } = args;
13
+ switch (action) {
14
+ case 'create': return createProject(params);
15
+ case 'update': return updateProject(params);
16
+ case 'generate_how_it_works': return generateProjectHowItWorks(params);
17
+ case 'apply_how_it_works': return applyProjectHowItWorks(params);
18
+ default: throw new Error(`Unknown action: ${action}`);
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Unified get_project handler — by ID (context), search, or list all
24
+ */
25
+ export async function getProject(args) {
26
+ const { projectId, query } = args;
27
+
28
+ // Mode 1: get project context by ID
29
+ if (projectId) {
30
+ return callZephlyAPI('mcpGetProjectContext', { projectId });
31
+ }
32
+
33
+ // Mode 2: search by query text, or list all
34
+ if (query || args.type || args.organizationId) {
35
+ return searchProjects(args);
36
+ }
37
+
38
+ // Mode 3: list all
39
+ return callZephlyAPI('mcpListProjects', {});
40
+ }
41
+
42
+ async function createProject(args) {
43
+ return callZephlyAPI('mcpCreateProject', args);
44
+ }
45
+
46
+ // Update an existing project. Only the fields present in `args` are changed —
47
+ // the server leaves anything unmentioned alone. This is the path that lets an
48
+ // agent set gitUrl/gitProvider after creation, which is what commit-to-task
49
+ // linking and component link resolution key off.
50
+ async function updateProject(args) {
51
+ return callZephlyAPI('mcpUpdateProject', args);
52
+ }
53
+
54
+ // Generate (and persist) the project's grounded "how it works" living description
55
+ // via the model. AI-quota gated server-side (mirrors entities.generateGoalHowItWorks).
56
+ async function generateProjectHowItWorks({ projectId }) {
57
+ return callZephlyAPI('mcpGenerateProjectHowItWorks', { projectId });
58
+ }
59
+
60
+ // Apply (persist) a LOCAL-agent-authored "how it works" for a project (BYO-AI,
61
+ // E-190). Cited sources are validated server-side before saving; no model call.
62
+ async function applyProjectHowItWorks({ projectId, markdown, sources }) {
63
+ return callZephlyAPI('mcpApplyProjectHowItWorks', { projectId, markdown, sources });
64
+ }
65
+
66
+ // Project Story (E-208): a grounded, source-attributed narrative of what has
67
+ // happened to a project since it began. Returns a fresh cached story when
68
+ // available, otherwise generates one (AI-quota gated server-side).
69
+ export async function getProjectStory({ projectId, window, from, to }) {
70
+ return callZephlyAPI('mcpGetProjectStory', { projectId, window, from, to });
71
+ }
72
+
73
+ async function searchProjects(args) {
74
+ const {
75
+ query: searchText,
76
+ type,
77
+ organizationId,
78
+ limit = 50,
79
+ } = args;
80
+
81
+ try {
82
+ const allProjects = await callZephlyAPI('mcpListProjects', {});
83
+
84
+ // callZephlyAPI already unwrapped the {success, data} envelope, so what
85
+ // arrives is `{projects: [...]}` with no `success` flag. Testing for one
86
+ // sent every search down this branch and returned the whole unfiltered
87
+ // list -- a `query` that matched nothing was indistinguishable from one
88
+ // that matched everything.
89
+ if (!Array.isArray(allProjects?.projects)) {
90
+ return allProjects;
91
+ }
92
+
93
+ let filtered = allProjects.projects;
94
+
95
+ if (searchText) {
96
+ const searchLower = searchText.toLowerCase();
97
+ filtered = filtered.filter((project) =>
98
+ project.name.toLowerCase().includes(searchLower) ||
99
+ (project.description && project.description.toLowerCase().includes(searchLower))
100
+ );
101
+ }
102
+
103
+ if (type) {
104
+ filtered = filtered.filter((project) => project.type === type);
105
+ }
106
+
107
+ if (organizationId) {
108
+ filtered = filtered.filter((project) => project.organizationId === organizationId);
109
+ }
110
+
111
+ filtered = filtered.slice(0, limit);
112
+
113
+ return {
114
+ success: true,
115
+ projects: filtered,
116
+ count: filtered.length,
117
+ totalBeforeLimit: allProjects.projects.length,
118
+ };
119
+ } catch (error) {
120
+ throw new Error(`Failed to search projects: ${error.message}`);
121
+ }
122
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Recurring Task Schedule Handlers
3
+ * Handler for the E-211 recurrence-engine MCP tool.
4
+ *
5
+ * Thin wrappers over /api/mcp/v1/recurring-tasks; validation, next_run_at
6
+ * computation, and the schedule lifecycle happen server-side in
7
+ * core/recurringtasks.Service.
8
+ */
9
+
10
+ import { callZephlyAPI } from '../lib/http-client.js';
11
+
12
+ /**
13
+ * Dispatch manage_recurring_task actions.
14
+ */
15
+ export async function manageRecurringTask(args) {
16
+ const { action, ...params } = args;
17
+ switch (action) {
18
+ case 'create': return callZephlyAPI('mcpCreateRecurringTask', params);
19
+ case 'update': return callZephlyAPI('mcpUpdateRecurringTask', params);
20
+ case 'pause': return callZephlyAPI('mcpPauseRecurringTask', { scheduleId: params.scheduleId });
21
+ case 'resume': return callZephlyAPI('mcpResumeRecurringTask', { scheduleId: params.scheduleId });
22
+ case 'delete': return callZephlyAPI('mcpDeleteRecurringTask', { scheduleId: params.scheduleId });
23
+ case 'get': return callZephlyAPI('mcpGetRecurringTask', { scheduleId: params.scheduleId });
24
+ case 'list': {
25
+ const listParams = {};
26
+ if (params.organizationId) listParams.organizationId = params.organizationId;
27
+ if (params.projectId) listParams.projectId = params.projectId;
28
+ return callZephlyAPI('mcpListRecurringTasks', listParams);
29
+ }
30
+ default:
31
+ throw new Error(`Unknown action: ${action}. Expected create, update, pause, resume, delete, list, or get.`);
32
+ }
33
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Tag Handlers
3
+ * Handler functions for tag operations
4
+ *
5
+ * Consolidated: manageTag dispatches create/update/delete/merge/bulk_tag.
6
+ * listTags unifies get/list/findEntities/suggest.
7
+ *
8
+ * list_tags uses local cache for unfiltered requests, falling back to API.
9
+ * Write operations (create, update, delete, merge) invalidate the cache.
10
+ */
11
+
12
+ import { callZephlyAPI } from '../lib/http-client.js';
13
+ import { getCachedTags, updateCacheSections, invalidateCacheSection } from '../lib/local-cache.js';
14
+
15
+ /**
16
+ * Dispatch manage_tag actions to the appropriate handler
17
+ */
18
+ export async function manageTag(args) {
19
+ const { action, ...params } = args;
20
+ switch (action) {
21
+ case 'create': return createTag(params);
22
+ case 'update': return updateTag(params);
23
+ case 'delete': return deleteTag(params);
24
+ case 'merge': return mergeTags(params);
25
+ case 'bulk_tag': return bulkTagEntities(params);
26
+ default: throw new Error(`Unknown action: ${action}`);
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Unified list/get/find/suggest handler for tags
32
+ */
33
+ export async function listTags(args) {
34
+ // Strip routing flags before passing to helpers
35
+ const { suggest, findEntities, ...params } = args;
36
+
37
+ // Mode 1: suggest tags
38
+ if (suggest) {
39
+ return suggestTags(params);
40
+ }
41
+
42
+ // Mode 2: find entities by tags
43
+ if (findEntities) {
44
+ return findEntitiesByTags(params);
45
+ }
46
+
47
+ // Mode 3: single tag lookup by ID or name
48
+ if (params.tagId || params.name) {
49
+ return getTag(params);
50
+ }
51
+
52
+ // Mode 4: list tags with optional filters
53
+ return listTagsFiltered(params);
54
+ }
55
+
56
+ // --- Private helpers ---
57
+
58
+ async function createTag(args) {
59
+ const result = await callZephlyAPI('mcpCreateTag', args);
60
+ await invalidateCacheSection('tags');
61
+ return result;
62
+ }
63
+
64
+ async function updateTag(args) {
65
+ const result = await callZephlyAPI('mcpUpdateTag', args);
66
+ await invalidateCacheSection('tags');
67
+ return result;
68
+ }
69
+
70
+ async function deleteTag(args) {
71
+ const result = await callZephlyAPI('mcpDeleteTag', args);
72
+ await invalidateCacheSection('tags');
73
+ return result;
74
+ }
75
+
76
+ async function mergeTags(args) {
77
+ const result = await callZephlyAPI('mcpMergeTags', args);
78
+ await invalidateCacheSection('tags');
79
+ return result;
80
+ }
81
+
82
+ async function bulkTagEntities(args) {
83
+ return callZephlyAPI('mcpBulkTagEntities', args);
84
+ }
85
+
86
+ async function getTag(args) {
87
+ return callZephlyAPI('mcpGetTag', args);
88
+ }
89
+
90
+ async function listTagsFiltered(args) {
91
+ const hasFilters = args.category || args.searchQuery || args.pinnedOnly || args.includeHidden || args.projectId;
92
+
93
+ if (!hasFilters) {
94
+ const cached = await getCachedTags();
95
+ if (cached !== null) {
96
+ return { tags: cached, cached: true };
97
+ }
98
+ }
99
+
100
+ // Call API
101
+ const result = await callZephlyAPI('mcpListTags', args);
102
+
103
+ // Cache unfiltered results for future use
104
+ if (!hasFilters && result?.tags) {
105
+ const summaries = result.tags.map((t) => ({
106
+ id: t.id,
107
+ name: t.name,
108
+ color: t.color || '',
109
+ category: t.category || 'custom',
110
+ description: t.description || '',
111
+ }));
112
+ await updateCacheSections({ tags: summaries });
113
+ }
114
+
115
+ return result;
116
+ }
117
+
118
+ async function findEntitiesByTags(args) {
119
+ return callZephlyAPI('mcpFindEntitiesByTags', args);
120
+ }
121
+
122
+ async function suggestTags(args) {
123
+ return callZephlyAPI('mcpSuggestTags', args);
124
+ }