memory-journal-mcp 4.4.2 → 5.0.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 (291) hide show
  1. package/.github/workflows/codeql.yml +1 -6
  2. package/.github/workflows/docker-publish.yml +15 -49
  3. package/.github/workflows/lint-and-test.yml +1 -1
  4. package/.github/workflows/secrets-scanning.yml +4 -3
  5. package/.github/workflows/security-update.yml +3 -3
  6. package/CHANGELOG.md +213 -0
  7. package/CONTRIBUTING.md +132 -97
  8. package/DOCKER_README.md +184 -235
  9. package/Dockerfile +27 -24
  10. package/README.md +218 -190
  11. package/SECURITY.md +27 -35
  12. package/dist/cli.js +16 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/constants/ServerInstructions.d.ts +5 -1
  15. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  16. package/dist/constants/ServerInstructions.js +133 -73
  17. package/dist/constants/ServerInstructions.js.map +1 -1
  18. package/dist/constants/icons.d.ts +2 -2
  19. package/dist/constants/icons.d.ts.map +1 -1
  20. package/dist/constants/icons.js +7 -6
  21. package/dist/constants/icons.js.map +1 -1
  22. package/dist/database/SqliteAdapter.d.ts +37 -24
  23. package/dist/database/SqliteAdapter.d.ts.map +1 -1
  24. package/dist/database/SqliteAdapter.js +319 -157
  25. package/dist/database/SqliteAdapter.js.map +1 -1
  26. package/dist/database/schema.d.ts +45 -0
  27. package/dist/database/schema.d.ts.map +1 -0
  28. package/dist/database/schema.js +92 -0
  29. package/dist/database/schema.js.map +1 -0
  30. package/dist/filtering/ToolFilter.d.ts +1 -1
  31. package/dist/filtering/ToolFilter.d.ts.map +1 -1
  32. package/dist/filtering/ToolFilter.js +13 -2
  33. package/dist/filtering/ToolFilter.js.map +1 -1
  34. package/dist/github/GitHubIntegration.d.ts.map +1 -1
  35. package/dist/github/GitHubIntegration.js +1 -3
  36. package/dist/github/GitHubIntegration.js.map +1 -1
  37. package/dist/handlers/prompts/github.d.ts +12 -0
  38. package/dist/handlers/prompts/github.d.ts.map +1 -0
  39. package/dist/handlers/prompts/github.js +178 -0
  40. package/dist/handlers/prompts/github.js.map +1 -0
  41. package/dist/handlers/prompts/index.d.ts +23 -2
  42. package/dist/handlers/prompts/index.d.ts.map +1 -1
  43. package/dist/handlers/prompts/index.js +7 -432
  44. package/dist/handlers/prompts/index.js.map +1 -1
  45. package/dist/handlers/prompts/workflow.d.ts +12 -0
  46. package/dist/handlers/prompts/workflow.d.ts.map +1 -0
  47. package/dist/handlers/prompts/workflow.js +277 -0
  48. package/dist/handlers/prompts/workflow.js.map +1 -0
  49. package/dist/handlers/resources/core.d.ts +11 -0
  50. package/dist/handlers/resources/core.d.ts.map +1 -0
  51. package/dist/handlers/resources/core.js +433 -0
  52. package/dist/handlers/resources/core.js.map +1 -0
  53. package/dist/handlers/resources/github.d.ts +11 -0
  54. package/dist/handlers/resources/github.d.ts.map +1 -0
  55. package/dist/handlers/resources/github.js +314 -0
  56. package/dist/handlers/resources/github.js.map +1 -0
  57. package/dist/handlers/resources/graph.d.ts +11 -0
  58. package/dist/handlers/resources/graph.d.ts.map +1 -0
  59. package/dist/handlers/resources/graph.js +204 -0
  60. package/dist/handlers/resources/graph.js.map +1 -0
  61. package/dist/handlers/resources/index.d.ts +5 -20
  62. package/dist/handlers/resources/index.d.ts.map +1 -1
  63. package/dist/handlers/resources/index.js +16 -1278
  64. package/dist/handlers/resources/index.js.map +1 -1
  65. package/dist/handlers/resources/shared.d.ts +60 -0
  66. package/dist/handlers/resources/shared.d.ts.map +1 -0
  67. package/dist/handlers/resources/shared.js +49 -0
  68. package/dist/handlers/resources/shared.js.map +1 -0
  69. package/dist/handlers/resources/team.d.ts +13 -0
  70. package/dist/handlers/resources/team.d.ts.map +1 -0
  71. package/dist/handlers/resources/team.js +119 -0
  72. package/dist/handlers/resources/team.js.map +1 -0
  73. package/dist/handlers/resources/templates.d.ts +13 -0
  74. package/dist/handlers/resources/templates.d.ts.map +1 -0
  75. package/dist/handlers/resources/templates.js +310 -0
  76. package/dist/handlers/resources/templates.js.map +1 -0
  77. package/dist/handlers/tools/admin.d.ts +8 -0
  78. package/dist/handlers/tools/admin.d.ts.map +1 -0
  79. package/dist/handlers/tools/admin.js +270 -0
  80. package/dist/handlers/tools/admin.js.map +1 -0
  81. package/dist/handlers/tools/analytics.d.ts +8 -0
  82. package/dist/handlers/tools/analytics.d.ts.map +1 -0
  83. package/dist/handlers/tools/analytics.js +256 -0
  84. package/dist/handlers/tools/analytics.js.map +1 -0
  85. package/dist/handlers/tools/backup.d.ts +8 -0
  86. package/dist/handlers/tools/backup.d.ts.map +1 -0
  87. package/dist/handlers/tools/backup.js +224 -0
  88. package/dist/handlers/tools/backup.js.map +1 -0
  89. package/dist/handlers/tools/core.d.ts +9 -0
  90. package/dist/handlers/tools/core.d.ts.map +1 -0
  91. package/dist/handlers/tools/core.js +326 -0
  92. package/dist/handlers/tools/core.js.map +1 -0
  93. package/dist/handlers/tools/export.d.ts +8 -0
  94. package/dist/handlers/tools/export.d.ts.map +1 -0
  95. package/dist/handlers/tools/export.js +89 -0
  96. package/dist/handlers/tools/export.js.map +1 -0
  97. package/dist/handlers/tools/github/helpers.d.ts +34 -0
  98. package/dist/handlers/tools/github/helpers.d.ts.map +1 -0
  99. package/dist/handlers/tools/github/helpers.js +52 -0
  100. package/dist/handlers/tools/github/helpers.js.map +1 -0
  101. package/dist/handlers/tools/github/insights-tools.d.ts +8 -0
  102. package/dist/handlers/tools/github/insights-tools.d.ts.map +1 -0
  103. package/dist/handlers/tools/github/insights-tools.js +104 -0
  104. package/dist/handlers/tools/github/insights-tools.js.map +1 -0
  105. package/dist/handlers/tools/github/issue-tools.d.ts +8 -0
  106. package/dist/handlers/tools/github/issue-tools.d.ts.map +1 -0
  107. package/dist/handlers/tools/github/issue-tools.js +359 -0
  108. package/dist/handlers/tools/github/issue-tools.js.map +1 -0
  109. package/dist/handlers/tools/github/kanban-tools.d.ts +8 -0
  110. package/dist/handlers/tools/github/kanban-tools.d.ts.map +1 -0
  111. package/dist/handlers/tools/github/kanban-tools.js +108 -0
  112. package/dist/handlers/tools/github/kanban-tools.js.map +1 -0
  113. package/dist/handlers/tools/github/milestone-tools.d.ts +9 -0
  114. package/dist/handlers/tools/github/milestone-tools.d.ts.map +1 -0
  115. package/dist/handlers/tools/github/milestone-tools.js +302 -0
  116. package/dist/handlers/tools/github/milestone-tools.js.map +1 -0
  117. package/dist/handlers/tools/github/mutation-tools.d.ts +12 -0
  118. package/dist/handlers/tools/github/mutation-tools.d.ts.map +1 -0
  119. package/dist/handlers/tools/github/mutation-tools.js +15 -0
  120. package/dist/handlers/tools/github/mutation-tools.js.map +1 -0
  121. package/dist/handlers/tools/github/read-tools.d.ts +8 -0
  122. package/dist/handlers/tools/github/read-tools.d.ts.map +1 -0
  123. package/dist/handlers/tools/github/read-tools.js +260 -0
  124. package/dist/handlers/tools/github/read-tools.js.map +1 -0
  125. package/dist/handlers/tools/github/schemas.d.ts +467 -0
  126. package/dist/handlers/tools/github/schemas.d.ts.map +1 -0
  127. package/dist/handlers/tools/github/schemas.js +335 -0
  128. package/dist/handlers/tools/github/schemas.js.map +1 -0
  129. package/dist/handlers/tools/github.d.ts +14 -0
  130. package/dist/handlers/tools/github.d.ts.map +1 -0
  131. package/dist/handlers/tools/github.js +28 -0
  132. package/dist/handlers/tools/github.js.map +1 -0
  133. package/dist/handlers/tools/index.d.ts +15 -20
  134. package/dist/handlers/tools/index.d.ts.map +1 -1
  135. package/dist/handlers/tools/index.js +117 -2909
  136. package/dist/handlers/tools/index.js.map +1 -1
  137. package/dist/handlers/tools/relationships.d.ts +8 -0
  138. package/dist/handlers/tools/relationships.d.ts.map +1 -0
  139. package/dist/handlers/tools/relationships.js +308 -0
  140. package/dist/handlers/tools/relationships.js.map +1 -0
  141. package/dist/handlers/tools/schemas.d.ts +108 -0
  142. package/dist/handlers/tools/schemas.d.ts.map +1 -0
  143. package/dist/handlers/tools/schemas.js +122 -0
  144. package/dist/handlers/tools/schemas.js.map +1 -0
  145. package/dist/handlers/tools/search.d.ts +8 -0
  146. package/dist/handlers/tools/search.d.ts.map +1 -0
  147. package/dist/handlers/tools/search.js +282 -0
  148. package/dist/handlers/tools/search.js.map +1 -0
  149. package/dist/handlers/tools/team.d.ts +11 -0
  150. package/dist/handlers/tools/team.d.ts.map +1 -0
  151. package/dist/handlers/tools/team.js +239 -0
  152. package/dist/handlers/tools/team.js.map +1 -0
  153. package/dist/server/McpServer.d.ts +4 -0
  154. package/dist/server/McpServer.d.ts.map +1 -1
  155. package/dist/server/McpServer.js +48 -297
  156. package/dist/server/McpServer.js.map +1 -1
  157. package/dist/server/Scheduler.d.ts +91 -0
  158. package/dist/server/Scheduler.d.ts.map +1 -0
  159. package/dist/server/Scheduler.js +201 -0
  160. package/dist/server/Scheduler.js.map +1 -0
  161. package/dist/transports/http.d.ts +66 -0
  162. package/dist/transports/http.d.ts.map +1 -0
  163. package/dist/transports/http.js +519 -0
  164. package/dist/transports/http.js.map +1 -0
  165. package/dist/types/entities.d.ts +101 -0
  166. package/dist/types/entities.d.ts.map +1 -0
  167. package/dist/types/entities.js +5 -0
  168. package/dist/types/entities.js.map +1 -0
  169. package/dist/types/filtering.d.ts +34 -0
  170. package/dist/types/filtering.d.ts.map +1 -0
  171. package/dist/types/filtering.js +5 -0
  172. package/dist/types/filtering.js.map +1 -0
  173. package/dist/types/github.d.ts +166 -0
  174. package/dist/types/github.d.ts.map +1 -0
  175. package/dist/types/github.js +5 -0
  176. package/dist/types/github.js.map +1 -0
  177. package/dist/types/index.d.ts +35 -292
  178. package/dist/types/index.d.ts.map +1 -1
  179. package/dist/types/index.js +2 -2
  180. package/dist/types/index.js.map +1 -1
  181. package/dist/utils/error-helpers.d.ts +37 -0
  182. package/dist/utils/error-helpers.d.ts.map +1 -0
  183. package/dist/utils/error-helpers.js +47 -0
  184. package/dist/utils/error-helpers.js.map +1 -0
  185. package/dist/utils/logger.d.ts.map +1 -1
  186. package/dist/utils/logger.js +6 -3
  187. package/dist/utils/logger.js.map +1 -1
  188. package/dist/utils/security-utils.d.ts +0 -21
  189. package/dist/utils/security-utils.d.ts.map +1 -1
  190. package/dist/utils/security-utils.js +0 -47
  191. package/dist/utils/security-utils.js.map +1 -1
  192. package/dist/vector/VectorSearchManager.d.ts.map +1 -1
  193. package/dist/vector/VectorSearchManager.js +9 -32
  194. package/dist/vector/VectorSearchManager.js.map +1 -1
  195. package/docker-compose.yml +11 -2
  196. package/hooks/README.md +107 -0
  197. package/hooks/cursor/hooks.json +10 -0
  198. package/hooks/cursor/memory-journal.mdc +22 -0
  199. package/hooks/cursor/session-end.sh +19 -0
  200. package/hooks/kilo-code/session-end-mode.json +11 -0
  201. package/hooks/kiro/session-end.md +13 -0
  202. package/mcp-config-example.json +1 -0
  203. package/package.json +11 -9
  204. package/playwright.config.ts +29 -0
  205. package/releases/v4.5.0.md +116 -0
  206. package/releases/v5.0.0.md +105 -0
  207. package/scripts/generate-server-instructions.ts +176 -0
  208. package/scripts/server-instructions-function-body.ts +77 -0
  209. package/server.json +3 -3
  210. package/src/cli.ts +45 -1
  211. package/src/constants/ServerInstructions.ts +133 -73
  212. package/src/constants/icons.ts +8 -7
  213. package/src/constants/server-instructions.md +268 -0
  214. package/src/database/SqliteAdapter.ts +358 -192
  215. package/src/database/schema.ts +125 -0
  216. package/src/filtering/ToolFilter.ts +13 -2
  217. package/src/github/GitHubIntegration.ts +1 -3
  218. package/src/handlers/prompts/github.ts +209 -0
  219. package/src/handlers/prompts/index.ts +10 -499
  220. package/src/handlers/prompts/workflow.ts +314 -0
  221. package/src/handlers/resources/core.ts +528 -0
  222. package/src/handlers/resources/github.ts +358 -0
  223. package/src/handlers/resources/graph.ts +254 -0
  224. package/src/handlers/resources/index.ts +23 -1570
  225. package/src/handlers/resources/shared.ts +103 -0
  226. package/src/handlers/resources/team.ts +133 -0
  227. package/src/handlers/resources/templates.ts +374 -0
  228. package/src/handlers/tools/admin.ts +285 -0
  229. package/src/handlers/tools/analytics.ts +301 -0
  230. package/src/handlers/tools/backup.ts +242 -0
  231. package/src/handlers/tools/core.ts +350 -0
  232. package/src/handlers/tools/export.ts +115 -0
  233. package/src/handlers/tools/github/helpers.ts +86 -0
  234. package/src/handlers/tools/github/insights-tools.ts +119 -0
  235. package/src/handlers/tools/github/issue-tools.ts +439 -0
  236. package/src/handlers/tools/github/kanban-tools.ts +134 -0
  237. package/src/handlers/tools/github/milestone-tools.ts +392 -0
  238. package/src/handlers/tools/github/mutation-tools.ts +17 -0
  239. package/src/handlers/tools/github/read-tools.ts +328 -0
  240. package/src/handlers/tools/github/schemas.ts +369 -0
  241. package/src/handlers/tools/github.ts +36 -0
  242. package/src/handlers/tools/index.ts +144 -3325
  243. package/src/handlers/tools/relationships.ts +358 -0
  244. package/src/handlers/tools/schemas.ts +132 -0
  245. package/src/handlers/tools/search.ts +343 -0
  246. package/src/handlers/tools/team.ts +273 -0
  247. package/src/server/McpServer.ts +63 -358
  248. package/src/server/Scheduler.ts +278 -0
  249. package/src/transports/http.ts +635 -0
  250. package/src/types/entities.ts +145 -0
  251. package/src/types/filtering.ts +54 -0
  252. package/src/types/github.ts +180 -0
  253. package/src/types/index.ts +67 -375
  254. package/src/utils/error-helpers.ts +52 -0
  255. package/src/utils/logger.ts +6 -3
  256. package/src/utils/security-utils.ts +0 -52
  257. package/src/vector/VectorSearchManager.ts +9 -33
  258. package/tests/constants/icons.test.ts +1 -2
  259. package/tests/constants/server-instructions.test.ts +30 -4
  260. package/tests/database/sqlite-adapter.test.ts +91 -7
  261. package/tests/e2e/auth.spec.ts +154 -0
  262. package/tests/e2e/health.spec.ts +63 -0
  263. package/tests/e2e/protocols.spec.ts +134 -0
  264. package/tests/e2e/resources.spec.ts +103 -0
  265. package/tests/e2e/scheduler.spec.ts +79 -0
  266. package/tests/e2e/security.spec.ts +91 -0
  267. package/tests/e2e/sessions.spec.ts +95 -0
  268. package/tests/e2e/stateless.spec.ts +121 -0
  269. package/tests/e2e/tools.spec.ts +111 -0
  270. package/tests/filtering/tool-filter.test.ts +46 -0
  271. package/tests/handlers/error-path-coverage.test.ts +324 -0
  272. package/tests/handlers/github-resource-handlers.test.ts +453 -0
  273. package/tests/handlers/github-tool-handlers.test.ts +899 -0
  274. package/tests/handlers/prompt-handler-coverage.test.ts +106 -0
  275. package/tests/handlers/prompt-handlers.test.ts +40 -0
  276. package/tests/handlers/resource-handler-coverage.test.ts +181 -0
  277. package/tests/handlers/resource-handlers.test.ts +33 -9
  278. package/tests/handlers/search-tool-handlers.test.ts +272 -0
  279. package/tests/handlers/targeted-gap-closure.test.ts +387 -0
  280. package/tests/handlers/team-resource-handlers.test.ts +156 -0
  281. package/tests/handlers/team-tool-handlers.test.ts +301 -0
  282. package/tests/handlers/tool-handler-coverage.test.ts +469 -0
  283. package/tests/handlers/tool-handlers.test.ts +2 -2
  284. package/tests/security/sql-injection.test.ts +3 -54
  285. package/tests/server/mcp-server.test.ts +503 -8
  286. package/tests/server/scheduler.test.ts +400 -0
  287. package/tests/transports/http-transport.test.ts +620 -0
  288. package/tests/vector/vector-search-manager.test.ts +60 -0
  289. package/vitest.config.ts +4 -1
  290. package/.memory-journal-team.db +0 -0
  291. package/.vscode/settings.json +0 -84
@@ -0,0 +1,328 @@
1
+ /**
2
+ * GitHub Read Tools - 5 tools
3
+ *
4
+ * Tools: get_github_issues, get_github_prs, get_github_issue, get_github_pr, get_github_context
5
+ */
6
+
7
+ import { z } from 'zod'
8
+ import type { ToolDefinition, ToolContext } from '../../../types/index.js'
9
+ import type { GitHubIntegration } from '../../../github/GitHubIntegration.js'
10
+ import { formatHandlerError } from '../../../utils/error-helpers.js'
11
+ import {
12
+ GitHubIssuesListOutputSchema,
13
+ GitHubIssueResultOutputSchema,
14
+ GitHubPRsListOutputSchema,
15
+ GitHubPRResultOutputSchema,
16
+ GitHubContextOutputSchema,
17
+ } from './schemas.js'
18
+
19
+ // ============================================================================
20
+ // Helper: owner/repo resolution with "STOP" pattern
21
+ // ============================================================================
22
+
23
+ async function resolveOwnerRepo(
24
+ context: ToolContext,
25
+ input: { owner?: string; repo?: string },
26
+ entityLabel: string
27
+ ): Promise<
28
+ | {
29
+ owner: string
30
+ repo: string
31
+ detectedOwner: string | null
32
+ detectedRepo: string | null
33
+ github: GitHubIntegration
34
+ }
35
+ | { error: true; response: Record<string, unknown> }
36
+ > {
37
+ if (!context.github) {
38
+ return { error: true, response: { error: 'GitHub integration not available' } }
39
+ }
40
+
41
+ const repoInfo = await context.github.getRepoInfo()
42
+ const detectedOwner = repoInfo.owner
43
+ const detectedRepo = repoInfo.repo
44
+
45
+ const owner = input.owner ?? detectedOwner ?? undefined
46
+ const repo = input.repo ?? detectedRepo ?? undefined
47
+
48
+ if (!owner || !repo) {
49
+ return {
50
+ error: true,
51
+ response: {
52
+ error: `STOP: Could not auto-detect repository. DO NOT GUESS. You MUST ask the user to provide the GitHub owner and repository name.`,
53
+ requiresUserInput: true,
54
+ detectedOwner,
55
+ detectedRepo,
56
+ instruction: `Ask the user: "What GitHub repository ${entityLabel}? Please provide the owner and repo name (e.g., owner/repo)."`,
57
+ },
58
+ }
59
+ }
60
+
61
+ return { owner, repo, detectedOwner, detectedRepo, github: context.github }
62
+ }
63
+
64
+ // ============================================================================
65
+ // Tool Definitions
66
+ // ============================================================================
67
+
68
+ export function getGitHubReadTools(context: ToolContext): ToolDefinition[] {
69
+ return [
70
+ {
71
+ name: 'get_github_issues',
72
+ title: 'Get GitHub Issues',
73
+ description:
74
+ 'List issues from a GitHub repository. IMPORTANT: Do NOT guess owner/repo values - leave them empty to auto-detect from the current git repository.',
75
+ group: 'github',
76
+ inputSchema: z.object({
77
+ owner: z
78
+ .string()
79
+ .optional()
80
+ .describe(
81
+ 'Repository owner - LEAVE EMPTY to auto-detect from git. Only specify if user explicitly provides.'
82
+ ),
83
+ repo: z
84
+ .string()
85
+ .optional()
86
+ .describe(
87
+ 'Repository name - LEAVE EMPTY to auto-detect from git. Only specify if user explicitly provides.'
88
+ ),
89
+ state: z.string().optional().default('open'),
90
+ limit: z.number().optional().default(20),
91
+ }),
92
+ outputSchema: GitHubIssuesListOutputSchema,
93
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
94
+ handler: async (params: unknown) => {
95
+ try {
96
+ const input = z
97
+ .object({
98
+ owner: z.string().optional(),
99
+ repo: z.string().optional(),
100
+ state: z.enum(['open', 'closed', 'all']).optional().default('open'),
101
+ limit: z.number().optional().default(20),
102
+ })
103
+ .parse(params)
104
+
105
+ const resolved = await resolveOwnerRepo(
106
+ context,
107
+ input,
108
+ 'would you like to query'
109
+ )
110
+ if ('error' in resolved) return resolved.response
111
+
112
+ const issues = await resolved.github.getIssues(
113
+ resolved.owner,
114
+ resolved.repo,
115
+ input.state,
116
+ input.limit
117
+ )
118
+ return {
119
+ owner: resolved.owner,
120
+ repo: resolved.repo,
121
+ detectedOwner: resolved.detectedOwner,
122
+ detectedRepo: resolved.detectedRepo,
123
+ issues,
124
+ count: issues.length,
125
+ }
126
+ } catch (err) {
127
+ return formatHandlerError(err)
128
+ }
129
+ },
130
+ },
131
+ {
132
+ name: 'get_github_prs',
133
+ title: 'Get GitHub Pull Requests',
134
+ description:
135
+ 'List pull requests from a GitHub repository. IMPORTANT: Do NOT guess owner/repo values - leave them empty to auto-detect from the current git repository.',
136
+ group: 'github',
137
+ inputSchema: z.object({
138
+ owner: z
139
+ .string()
140
+ .optional()
141
+ .describe(
142
+ 'Repository owner - LEAVE EMPTY to auto-detect from git. Only specify if user explicitly provides.'
143
+ ),
144
+ repo: z
145
+ .string()
146
+ .optional()
147
+ .describe(
148
+ 'Repository name - LEAVE EMPTY to auto-detect from git. Only specify if user explicitly provides.'
149
+ ),
150
+ state: z.string().optional().default('open'),
151
+ limit: z.number().optional().default(20),
152
+ }),
153
+ outputSchema: GitHubPRsListOutputSchema,
154
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
155
+ handler: async (params: unknown) => {
156
+ try {
157
+ const input = z
158
+ .object({
159
+ owner: z.string().optional(),
160
+ repo: z.string().optional(),
161
+ state: z.enum(['open', 'closed', 'all']).optional().default('open'),
162
+ limit: z.number().optional().default(20),
163
+ })
164
+ .parse(params)
165
+
166
+ const resolved = await resolveOwnerRepo(
167
+ context,
168
+ input,
169
+ 'would you like to query'
170
+ )
171
+ if ('error' in resolved) return resolved.response
172
+
173
+ const pullRequests = await resolved.github.getPullRequests(
174
+ resolved.owner,
175
+ resolved.repo,
176
+ input.state,
177
+ input.limit
178
+ )
179
+ return {
180
+ owner: resolved.owner,
181
+ repo: resolved.repo,
182
+ detectedOwner: resolved.detectedOwner,
183
+ detectedRepo: resolved.detectedRepo,
184
+ pullRequests,
185
+ count: pullRequests.length,
186
+ }
187
+ } catch (err) {
188
+ return formatHandlerError(err)
189
+ }
190
+ },
191
+ },
192
+ {
193
+ name: 'get_github_issue',
194
+ title: 'Get GitHub Issue Details',
195
+ description:
196
+ 'Get detailed information about a specific GitHub issue. IMPORTANT: Do NOT guess owner/repo values - leave them empty to auto-detect from the current git repository.',
197
+ group: 'github',
198
+ inputSchema: z.object({
199
+ issue_number: z.number(),
200
+ owner: z.string().optional().describe('LEAVE EMPTY to auto-detect from git'),
201
+ repo: z.string().optional().describe('LEAVE EMPTY to auto-detect from git'),
202
+ }),
203
+ outputSchema: GitHubIssueResultOutputSchema,
204
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
205
+ handler: async (params: unknown) => {
206
+ try {
207
+ const input = z
208
+ .object({
209
+ issue_number: z.number(),
210
+ owner: z.string().optional(),
211
+ repo: z.string().optional(),
212
+ })
213
+ .parse(params)
214
+
215
+ const resolved = await resolveOwnerRepo(context, input, 'is this issue from')
216
+ if ('error' in resolved) return resolved.response
217
+
218
+ const issue = await resolved.github.getIssue(
219
+ resolved.owner,
220
+ resolved.repo,
221
+ input.issue_number
222
+ )
223
+ if (!issue) {
224
+ return {
225
+ error: `Issue #${String(input.issue_number)} not found`,
226
+ owner: resolved.owner,
227
+ repo: resolved.repo,
228
+ detectedOwner: resolved.detectedOwner,
229
+ detectedRepo: resolved.detectedRepo,
230
+ }
231
+ }
232
+ return {
233
+ issue,
234
+ owner: resolved.owner,
235
+ repo: resolved.repo,
236
+ detectedOwner: resolved.detectedOwner,
237
+ detectedRepo: resolved.detectedRepo,
238
+ }
239
+ } catch (err) {
240
+ return formatHandlerError(err)
241
+ }
242
+ },
243
+ },
244
+ {
245
+ name: 'get_github_pr',
246
+ title: 'Get GitHub PR Details',
247
+ description:
248
+ 'Get detailed information about a specific GitHub pull request. IMPORTANT: Do NOT guess owner/repo values - leave them empty to auto-detect from the current git repository.',
249
+ group: 'github',
250
+ inputSchema: z.object({
251
+ pr_number: z.number(),
252
+ owner: z.string().optional().describe('LEAVE EMPTY to auto-detect from git'),
253
+ repo: z.string().optional().describe('LEAVE EMPTY to auto-detect from git'),
254
+ }),
255
+ outputSchema: GitHubPRResultOutputSchema,
256
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
257
+ handler: async (params: unknown) => {
258
+ try {
259
+ const input = z
260
+ .object({
261
+ pr_number: z.number(),
262
+ owner: z.string().optional(),
263
+ repo: z.string().optional(),
264
+ })
265
+ .parse(params)
266
+
267
+ const resolved = await resolveOwnerRepo(context, input, 'is this PR from')
268
+ if ('error' in resolved) return resolved.response
269
+
270
+ const pullRequest = await resolved.github.getPullRequest(
271
+ resolved.owner,
272
+ resolved.repo,
273
+ input.pr_number
274
+ )
275
+ if (!pullRequest) {
276
+ return {
277
+ error: `PR #${String(input.pr_number)} not found`,
278
+ owner: resolved.owner,
279
+ repo: resolved.repo,
280
+ detectedOwner: resolved.detectedOwner,
281
+ detectedRepo: resolved.detectedRepo,
282
+ }
283
+ }
284
+ return {
285
+ pullRequest,
286
+ owner: resolved.owner,
287
+ repo: resolved.repo,
288
+ detectedOwner: resolved.detectedOwner,
289
+ detectedRepo: resolved.detectedRepo,
290
+ }
291
+ } catch (err) {
292
+ return formatHandlerError(err)
293
+ }
294
+ },
295
+ },
296
+ {
297
+ name: 'get_github_context',
298
+ title: 'Get GitHub Repository Context',
299
+ description:
300
+ 'Get current repository context including branch, open issues, and open PRs. Only counts OPEN items (closed items excluded).',
301
+ group: 'github',
302
+ inputSchema: z.object({}),
303
+ outputSchema: GitHubContextOutputSchema,
304
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
305
+ handler: async (_params: unknown) => {
306
+ try {
307
+ if (!context.github) {
308
+ return { error: 'GitHub integration not available' }
309
+ }
310
+
311
+ const ctx = await context.github.getRepoContext()
312
+ return {
313
+ repoName: ctx.repoName,
314
+ branch: ctx.branch,
315
+ commit: ctx.commit,
316
+ remoteUrl: ctx.remoteUrl,
317
+ issues: ctx.issues,
318
+ pullRequests: ctx.pullRequests,
319
+ issueCount: ctx.issues.length,
320
+ prCount: ctx.pullRequests.length,
321
+ }
322
+ } catch (err) {
323
+ return formatHandlerError(err)
324
+ }
325
+ },
326
+ },
327
+ ]
328
+ }
@@ -0,0 +1,369 @@
1
+ /**
2
+ * Shared GitHub Output Schemas
3
+ */
4
+
5
+ import { z } from 'zod'
6
+
7
+ // ============================================================================
8
+ // Issue Schemas
9
+ // ============================================================================
10
+
11
+ export const GitHubIssueOutputSchema = z.object({
12
+ number: z.number(),
13
+ title: z.string(),
14
+ url: z.string(),
15
+ state: z.enum(['OPEN', 'CLOSED']),
16
+ milestone: z
17
+ .object({
18
+ number: z.number(),
19
+ title: z.string(),
20
+ })
21
+ .nullable()
22
+ .optional(),
23
+ })
24
+
25
+ export const GitHubIssueDetailsOutputSchema = GitHubIssueOutputSchema.extend({
26
+ body: z.string().nullable(),
27
+ labels: z.array(z.string()),
28
+ assignees: z.array(z.string()),
29
+ createdAt: z.string(),
30
+ updatedAt: z.string(),
31
+ closedAt: z.string().nullable(),
32
+ commentsCount: z.number(),
33
+ })
34
+
35
+ export const GitHubIssuesListOutputSchema = z.object({
36
+ owner: z.string().optional(),
37
+ repo: z.string().optional(),
38
+ detectedOwner: z.string().nullable().optional(),
39
+ detectedRepo: z.string().nullable().optional(),
40
+ issues: z.array(GitHubIssueOutputSchema).optional(),
41
+ count: z.number().optional(),
42
+ error: z.string().optional(),
43
+ requiresUserInput: z.boolean().optional(),
44
+ instruction: z.string().optional(),
45
+ })
46
+
47
+ export const GitHubIssueResultOutputSchema = z.object({
48
+ issue: GitHubIssueDetailsOutputSchema.optional(),
49
+ owner: z.string().optional(),
50
+ repo: z.string().optional(),
51
+ detectedOwner: z.string().nullable().optional(),
52
+ detectedRepo: z.string().nullable().optional(),
53
+ error: z.string().optional(),
54
+ requiresUserInput: z.boolean().optional(),
55
+ instruction: z.string().optional(),
56
+ })
57
+
58
+ // ============================================================================
59
+ // PR Schemas
60
+ // ============================================================================
61
+
62
+ export const GitHubPullRequestOutputSchema = z.object({
63
+ number: z.number(),
64
+ title: z.string(),
65
+ url: z.string(),
66
+ state: z.enum(['OPEN', 'CLOSED', 'MERGED']),
67
+ })
68
+
69
+ export const GitHubPRDetailsOutputSchema = GitHubPullRequestOutputSchema.extend({
70
+ body: z.string().nullable(),
71
+ draft: z.boolean(),
72
+ headBranch: z.string(),
73
+ baseBranch: z.string(),
74
+ author: z.string(),
75
+ createdAt: z.string(),
76
+ updatedAt: z.string(),
77
+ mergedAt: z.string().nullable(),
78
+ closedAt: z.string().nullable(),
79
+ additions: z.number(),
80
+ deletions: z.number(),
81
+ changedFiles: z.number(),
82
+ })
83
+
84
+ export const GitHubPRsListOutputSchema = z.object({
85
+ owner: z.string().optional(),
86
+ repo: z.string().optional(),
87
+ detectedOwner: z.string().nullable().optional(),
88
+ detectedRepo: z.string().nullable().optional(),
89
+ pullRequests: z.array(GitHubPullRequestOutputSchema).optional(),
90
+ count: z.number().optional(),
91
+ error: z.string().optional(),
92
+ requiresUserInput: z.boolean().optional(),
93
+ instruction: z.string().optional(),
94
+ })
95
+
96
+ export const GitHubPRResultOutputSchema = z.object({
97
+ pullRequest: GitHubPRDetailsOutputSchema.optional(),
98
+ owner: z.string().optional(),
99
+ repo: z.string().optional(),
100
+ detectedOwner: z.string().nullable().optional(),
101
+ detectedRepo: z.string().nullable().optional(),
102
+ error: z.string().optional(),
103
+ requiresUserInput: z.boolean().optional(),
104
+ instruction: z.string().optional(),
105
+ })
106
+
107
+ // ============================================================================
108
+ // Context Schema
109
+ // ============================================================================
110
+
111
+ export const GitHubContextOutputSchema = z.object({
112
+ repoName: z.string().nullable().optional(),
113
+ branch: z.string().nullable().optional(),
114
+ commit: z.string().nullable().optional(),
115
+ remoteUrl: z.string().nullable().optional(),
116
+ issues: z.array(GitHubIssueOutputSchema).optional(),
117
+ pullRequests: z.array(GitHubPullRequestOutputSchema).optional(),
118
+ issueCount: z.number().optional(),
119
+ prCount: z.number().optional(),
120
+ error: z.string().optional(),
121
+ })
122
+
123
+ // ============================================================================
124
+ // Kanban Schemas
125
+ // ============================================================================
126
+
127
+ const KanbanItemOutputSchema = z.object({
128
+ id: z.string(),
129
+ title: z.string(),
130
+ url: z.string(),
131
+ type: z.enum(['ISSUE', 'PULL_REQUEST', 'DRAFT_ISSUE']),
132
+ status: z.string().nullable(),
133
+ number: z.number().optional(),
134
+ labels: z.array(z.string()).optional(),
135
+ assignees: z.array(z.string()).optional(),
136
+ createdAt: z.string(),
137
+ updatedAt: z.string(),
138
+ })
139
+
140
+ const StatusOptionOutputSchema = z.object({
141
+ id: z.string(),
142
+ name: z.string(),
143
+ color: z.string().optional(),
144
+ })
145
+
146
+ const KanbanColumnOutputSchema = z.object({
147
+ status: z.string(),
148
+ statusOptionId: z.string(),
149
+ items: z.array(KanbanItemOutputSchema),
150
+ })
151
+
152
+ export const KanbanBoardOutputSchema = z.object({
153
+ projectId: z.string().optional(),
154
+ projectNumber: z.number().optional(),
155
+ projectTitle: z.string().optional(),
156
+ statusFieldId: z.string().optional(),
157
+ statusOptions: z.array(StatusOptionOutputSchema).optional(),
158
+ columns: z.array(KanbanColumnOutputSchema).optional(),
159
+ totalItems: z.number().optional(),
160
+ owner: z.string().optional(),
161
+ detectedOwner: z.string().nullable().optional(),
162
+ detectedRepo: z.string().nullable().optional(),
163
+ error: z.string().optional(),
164
+ requiresUserInput: z.boolean().optional(),
165
+ hint: z.string().optional(),
166
+ instruction: z.string().optional(),
167
+ })
168
+
169
+ export const MoveKanbanItemOutputSchema = z.object({
170
+ success: z.boolean().optional(),
171
+ itemId: z.string().optional(),
172
+ newStatus: z.string().optional(),
173
+ projectNumber: z.number().optional(),
174
+ message: z.string().optional(),
175
+ error: z.string().optional(),
176
+ requiresUserInput: z.boolean().optional(),
177
+ hint: z.string().optional(),
178
+ })
179
+
180
+ // ============================================================================
181
+ // Issue Lifecycle Schemas
182
+ // ============================================================================
183
+
184
+ export const CreateGitHubIssueWithEntryOutputSchema = z.object({
185
+ success: z.boolean().optional(),
186
+ issue: z
187
+ .object({
188
+ number: z.number(),
189
+ title: z.string(),
190
+ url: z.string(),
191
+ })
192
+ .optional(),
193
+ project: z
194
+ .object({
195
+ projectNumber: z.number(),
196
+ added: z.boolean(),
197
+ message: z.string(),
198
+ initialStatus: z
199
+ .object({
200
+ status: z.string(),
201
+ set: z.boolean(),
202
+ })
203
+ .optional(),
204
+ })
205
+ .optional(),
206
+ journalEntry: z
207
+ .object({
208
+ id: z.number(),
209
+ linkedToIssue: z.number(),
210
+ })
211
+ .optional(),
212
+ message: z.string().optional(),
213
+ error: z.string().optional(),
214
+ requiresUserInput: z.boolean().optional(),
215
+ instruction: z.string().optional(),
216
+ })
217
+
218
+ export const CloseGitHubIssueWithEntryOutputSchema = z.object({
219
+ success: z.boolean().optional(),
220
+ issue: z
221
+ .object({
222
+ number: z.number(),
223
+ title: z.string(),
224
+ url: z.string(),
225
+ previousState: z.string(),
226
+ newState: z.string(),
227
+ })
228
+ .optional(),
229
+ journalEntry: z
230
+ .object({
231
+ id: z.number(),
232
+ linkedToIssue: z.number(),
233
+ significanceType: z.string(),
234
+ })
235
+ .optional(),
236
+ kanban: z
237
+ .object({
238
+ moved: z.boolean(),
239
+ projectNumber: z.number(),
240
+ message: z.string().optional(),
241
+ })
242
+ .optional(),
243
+ message: z.string().optional(),
244
+ error: z.string().optional(),
245
+ requiresUserInput: z.boolean().optional(),
246
+ instruction: z.string().optional(),
247
+ })
248
+
249
+ // ============================================================================
250
+ // Milestone Schemas
251
+ // ============================================================================
252
+
253
+ export const GitHubMilestoneOutputSchema = z.object({
254
+ number: z.number(),
255
+ title: z.string(),
256
+ description: z.string().nullable(),
257
+ state: z.enum(['open', 'closed']),
258
+ url: z.string(),
259
+ dueOn: z.string().nullable(),
260
+ openIssues: z.number(),
261
+ closedIssues: z.number(),
262
+ completionPercentage: z.number().optional(),
263
+ createdAt: z.string(),
264
+ updatedAt: z.string(),
265
+ creator: z.string().nullable(),
266
+ })
267
+
268
+ export const GitHubMilestonesListOutputSchema = z.object({
269
+ owner: z.string().optional(),
270
+ repo: z.string().optional(),
271
+ detectedOwner: z.string().nullable().optional(),
272
+ detectedRepo: z.string().nullable().optional(),
273
+ milestones: z.array(GitHubMilestoneOutputSchema).optional(),
274
+ count: z.number().optional(),
275
+ error: z.string().optional(),
276
+ requiresUserInput: z.boolean().optional(),
277
+ instruction: z.string().optional(),
278
+ })
279
+
280
+ export const GitHubMilestoneResultOutputSchema = z.object({
281
+ milestone: GitHubMilestoneOutputSchema.optional(),
282
+ owner: z.string().optional(),
283
+ repo: z.string().optional(),
284
+ detectedOwner: z.string().nullable().optional(),
285
+ detectedRepo: z.string().nullable().optional(),
286
+ error: z.string().optional(),
287
+ requiresUserInput: z.boolean().optional(),
288
+ instruction: z.string().optional(),
289
+ })
290
+
291
+ export const CreateMilestoneOutputSchema = z.object({
292
+ success: z.boolean().optional(),
293
+ milestone: GitHubMilestoneOutputSchema.optional(),
294
+ message: z.string().optional(),
295
+ error: z.string().optional(),
296
+ requiresUserInput: z.boolean().optional(),
297
+ instruction: z.string().optional(),
298
+ })
299
+
300
+ export const UpdateMilestoneOutputSchema = z.object({
301
+ success: z.boolean().optional(),
302
+ milestone: GitHubMilestoneOutputSchema.optional(),
303
+ message: z.string().optional(),
304
+ error: z.string().optional(),
305
+ requiresUserInput: z.boolean().optional(),
306
+ instruction: z.string().optional(),
307
+ })
308
+
309
+ export const DeleteMilestoneOutputSchema = z.object({
310
+ success: z.boolean().optional(),
311
+ milestoneNumber: z.number().optional(),
312
+ message: z.string().optional(),
313
+ error: z.string().optional(),
314
+ requiresUserInput: z.boolean().optional(),
315
+ instruction: z.string().optional(),
316
+ })
317
+
318
+ // ============================================================================
319
+ // Insights Schema
320
+ // ============================================================================
321
+
322
+ export const RepoInsightsOutputSchema = z.object({
323
+ owner: z.string().optional(),
324
+ repo: z.string().optional(),
325
+ section: z.string().optional(),
326
+ stars: z.number().optional(),
327
+ forks: z.number().optional(),
328
+ watchers: z.number().optional(),
329
+ openIssues: z.number().optional(),
330
+ size: z.number().optional(),
331
+ defaultBranch: z.string().optional(),
332
+ traffic: z
333
+ .object({
334
+ clones: z.object({
335
+ total: z.number(),
336
+ unique: z.number(),
337
+ dailyAvg: z.number(),
338
+ }),
339
+ views: z.object({
340
+ total: z.number(),
341
+ unique: z.number(),
342
+ dailyAvg: z.number(),
343
+ }),
344
+ period: z.string(),
345
+ })
346
+ .optional(),
347
+ referrers: z
348
+ .array(
349
+ z.object({
350
+ referrer: z.string(),
351
+ count: z.number(),
352
+ uniques: z.number(),
353
+ })
354
+ )
355
+ .optional(),
356
+ paths: z
357
+ .array(
358
+ z.object({
359
+ path: z.string(),
360
+ title: z.string(),
361
+ count: z.number(),
362
+ uniques: z.number(),
363
+ })
364
+ )
365
+ .optional(),
366
+ error: z.string().optional(),
367
+ requiresUserInput: z.boolean().optional(),
368
+ instruction: z.string().optional(),
369
+ })