@inkeep/agents-work-apps 0.0.0-dev-20260203033642

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.
@@ -0,0 +1,670 @@
1
+ import runDbClient_default from "../../db/runDbClient.js";
2
+ import { githubMcpAuth } from "./auth.js";
3
+ import { commitFileChanges, commitNewFile, fetchPrFileDiffs, fetchPrFiles, fetchPrInfo, formatFileDiff, generatePrMarkdown, getGitHubClientFromRepo, visualizeUpdateOperations } from "./utils.js";
4
+ import { getMcpToolRepositoryAccessWithDetails } from "@inkeep/agents-core";
5
+ import { Hono } from "hono";
6
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
8
+ import { toFetchResponse, toReqRes } from "fetch-to-node";
9
+ import { z } from "zod/v3";
10
+
11
+ //#region src/github/mcp/index.ts
12
+ const updateOperationSchema = z.object({
13
+ operation: z.enum([
14
+ "replace_lines",
15
+ "insert_after",
16
+ "insert_before",
17
+ "delete_lines"
18
+ ]).describe("Operation type"),
19
+ lineStart: z.number().min(1).describe("Starting line number (1-indexed)"),
20
+ lineEnd: z.number().min(1).optional().describe("Ending line number (1-indexed, inclusive). Required for 'replace_lines' and 'delete_lines'"),
21
+ content: z.string().optional().describe("New content to insert/replace"),
22
+ reason: z.string().describe("Explanation of why this change is needed")
23
+ }).describe("Update operation to apply to a file");
24
+ const updateOperationsSchema = z.array(updateOperationSchema).describe("List of update operations to apply to a file");
25
+ const getAvailableRepositoryString = (repositoryAccess) => {
26
+ if (repositoryAccess.length === 0) return "No repositories available";
27
+ return `Available repositories: ${repositoryAccess.map((r) => `"${r.repositoryFullName}"`).join(", ")}`;
28
+ };
29
+ /**
30
+ * Creates and configures an MCP server for the given context
31
+ */
32
+ const getServer = async (toolId) => {
33
+ const repositoryAccess = await getMcpToolRepositoryAccessWithDetails(runDbClient_default)(toolId);
34
+ const installationIdMap = /* @__PURE__ */ new Map();
35
+ for (const repo of repositoryAccess) installationIdMap.set(repo.repositoryFullName, repo.installationId);
36
+ if (repositoryAccess.length === 0) throw new Error("No repository access found for tool");
37
+ const server = new McpServer({
38
+ name: "inkeep-github-mcp-server",
39
+ version: "1.0.0",
40
+ description: "A GitHub MCP server with access to the following repositories:\n" + repositoryAccess.map((r) => `• ${r.repositoryFullName}`).join("\n")
41
+ }, { capabilities: { logging: {} } });
42
+ server.tool("search-files-in-repo", `Find files in a repository using GitHub's search API. ${getAvailableRepositoryString(repositoryAccess)}`, {
43
+ owner: z.string().describe("The owner of the repository"),
44
+ repo: z.string().describe("The name of the repository"),
45
+ query: z.string().describe("The query to search for"),
46
+ path: z.string().optional().describe("The path to the files to search in relative to the root of the repository"),
47
+ limit: z.number().default(30).describe("The maximum number of files to return")
48
+ }, async ({ owner, repo, query, path, limit }) => {
49
+ try {
50
+ const repoFullName = `${owner}/${repo}`;
51
+ let githubClient;
52
+ try {
53
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
54
+ } catch (error) {
55
+ return {
56
+ content: [{
57
+ type: "text",
58
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
59
+ }],
60
+ isError: true
61
+ };
62
+ }
63
+ let searchQuery = `${query} repo:${repoFullName}`;
64
+ if (path) searchQuery += ` path:${path}`;
65
+ const files = (await githubClient.rest.search.code({
66
+ q: searchQuery,
67
+ per_page: Math.min(limit, 100)
68
+ })).data.items.map((item) => ({
69
+ name: item.name,
70
+ path: item.path,
71
+ url: item.html_url,
72
+ repository: repoFullName,
73
+ sha: item.sha,
74
+ score: item.score
75
+ }));
76
+ return { content: [{
77
+ type: "text",
78
+ text: `Found ${files.length} files matching "${query}" in ${repoFullName}:\n\n${files.map((file) => `• ${file.name} (${file.path})\n URL: ${file.url}\n Score: ${file.score}`).join("\n\n")}`
79
+ }] };
80
+ } catch (error) {
81
+ return {
82
+ content: [{
83
+ type: "text",
84
+ text: `Error searching files: ${error instanceof Error ? error.message : "Unknown error"}`
85
+ }],
86
+ isError: true
87
+ };
88
+ }
89
+ });
90
+ server.tool("get-file-content", `Get the content of a specific file from a repository. Returns a mapping of line number to line content. ${getAvailableRepositoryString(repositoryAccess)}`, {
91
+ owner: z.string().describe("Repository owner name"),
92
+ repo: z.string().describe("Repository name"),
93
+ file_path: z.string().describe("Path to the file. the path is relative to the root of the repository")
94
+ }, async ({ owner, repo, file_path }) => {
95
+ try {
96
+ let githubClient;
97
+ try {
98
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
99
+ } catch (error) {
100
+ return {
101
+ content: [{
102
+ type: "text",
103
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
104
+ }],
105
+ isError: true
106
+ };
107
+ }
108
+ const response = await githubClient.rest.repos.getContent({
109
+ owner,
110
+ repo,
111
+ path: file_path
112
+ });
113
+ if ("content" in response.data && !Array.isArray(response.data)) {
114
+ const fileData = response.data;
115
+ const output_mapping = Buffer.from(fileData.content, "base64").toString("utf-8").split("\n").map((line, index) => ({
116
+ line: index + 1,
117
+ content: line
118
+ }));
119
+ return { content: [{
120
+ type: "text",
121
+ text: JSON.stringify(output_mapping)
122
+ }] };
123
+ }
124
+ return {
125
+ content: [{
126
+ type: "text",
127
+ text: `The path "${file_path}" is not a file or could not be retrieved as file content.`
128
+ }],
129
+ isError: true
130
+ };
131
+ } catch (error) {
132
+ return {
133
+ content: [{
134
+ type: "text",
135
+ text: `Error getting file content: ${error instanceof Error ? error.message : "Unknown error"}`
136
+ }],
137
+ isError: true
138
+ };
139
+ }
140
+ });
141
+ server.tool("get-pull-request-details", `Get the details of a pull request from a repository including the pull request details, the commits, and the files that were changed. ${getAvailableRepositoryString(repositoryAccess)}`, {
142
+ owner: z.string().describe("Repository owner name"),
143
+ repo: z.string().describe("Repository name"),
144
+ pull_request_number: z.number().describe("Pull request number")
145
+ }, async ({ owner, repo, pull_request_number }) => {
146
+ try {
147
+ let githubClient;
148
+ try {
149
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
150
+ } catch (error) {
151
+ return {
152
+ content: [{
153
+ type: "text",
154
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
155
+ }],
156
+ isError: true
157
+ };
158
+ }
159
+ return { content: [{
160
+ type: "text",
161
+ text: generatePrMarkdown(await fetchPrInfo(githubClient, owner, repo, pull_request_number), await fetchPrFileDiffs(githubClient, owner, repo, pull_request_number), owner, repo)
162
+ }] };
163
+ } catch (error) {
164
+ if (error instanceof Error && "status" in error) {
165
+ const apiError = error;
166
+ if (apiError.status === 404) return {
167
+ content: [{
168
+ type: "text",
169
+ text: `Pull request #${pull_request_number} not found in ${owner}/${repo}. Please check the repository exists and the pull request number is correct.`
170
+ }],
171
+ isError: true
172
+ };
173
+ if (apiError.status === 403) return {
174
+ content: [{
175
+ type: "text",
176
+ text: `Access denied to pull request #${pull_request_number} in ${owner}/${repo}. Your GitHub App may not have sufficient permissions.`
177
+ }],
178
+ isError: true
179
+ };
180
+ }
181
+ return {
182
+ content: [{
183
+ type: "text",
184
+ text: `Error getting pull request: ${error instanceof Error ? error.message : "Unknown error"}`
185
+ }],
186
+ isError: true
187
+ };
188
+ }
189
+ });
190
+ server.tool("get-file-patches", `Get the patch/diff text for specific files in a pull request. Use this to fetch detailed changes for one or more files without retrieving the entire PR. ${getAvailableRepositoryString(repositoryAccess)}`, {
191
+ owner: z.string().describe("Repository owner name"),
192
+ repo: z.string().describe("Repository name"),
193
+ pull_request_number: z.number().describe("Pull request number"),
194
+ file_paths: z.array(z.string()).min(1).describe("List of file paths to get patches for (exact paths or glob patterns)"),
195
+ include_contents: z.boolean().default(false).describe("Whether to include full file contents in addition to patches")
196
+ }, async ({ owner, repo, pull_request_number, file_paths, include_contents }) => {
197
+ try {
198
+ let githubClient;
199
+ try {
200
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
201
+ } catch (error) {
202
+ return {
203
+ content: [{
204
+ type: "text",
205
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
206
+ }],
207
+ isError: true
208
+ };
209
+ }
210
+ const results = await fetchPrFiles(githubClient, owner, repo, pull_request_number, file_paths, include_contents, true);
211
+ if (results.length === 0) return { content: [{
212
+ type: "text",
213
+ text: `No files found matching the specified paths in PR #${pull_request_number}.\n\nRequested paths: ${file_paths.join(", ")}`
214
+ }] };
215
+ return { content: [{
216
+ type: "text",
217
+ text: await formatFileDiff(pull_request_number, results, include_contents)
218
+ }] };
219
+ } catch (error) {
220
+ if (error instanceof Error && "status" in error) {
221
+ if (error.status === 404) return {
222
+ content: [{
223
+ type: "text",
224
+ text: `Pull request #${pull_request_number} not found in ${owner}/${repo}.`
225
+ }],
226
+ isError: true
227
+ };
228
+ }
229
+ return {
230
+ content: [{
231
+ type: "text",
232
+ text: `Error getting file patches: ${error instanceof Error ? error.message : "Unknown error"}`
233
+ }],
234
+ isError: true
235
+ };
236
+ }
237
+ });
238
+ server.tool("create-branch", `Create a new branch in a repository. ${getAvailableRepositoryString(repositoryAccess)}`, {
239
+ owner: z.string().describe("Repository owner name"),
240
+ repo: z.string().describe("Repository name"),
241
+ from_branch: z.string().optional().describe("Branch to create from (defaults to default branch)")
242
+ }, async ({ owner, repo, from_branch }) => {
243
+ const branch_name = `docs-writer-ai-update-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
244
+ try {
245
+ const githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
246
+ const repoInfo = await githubClient.rest.repos.get({
247
+ owner,
248
+ repo
249
+ });
250
+ const sourceBranch = from_branch || repoInfo.data.default_branch;
251
+ const sourceSha = (await githubClient.rest.git.getRef({
252
+ owner,
253
+ repo,
254
+ ref: `heads/${sourceBranch}`
255
+ })).data.object.sha;
256
+ await githubClient.rest.git.createRef({
257
+ owner,
258
+ repo,
259
+ ref: `refs/heads/${branch_name}`,
260
+ sha: sourceSha
261
+ });
262
+ return { content: [{
263
+ type: "text",
264
+ text: `Successfully created branch "${branch_name}" in ${owner}/${repo}`
265
+ }] };
266
+ } catch (error) {
267
+ if (error instanceof Error && "status" in error) {
268
+ const apiError = error;
269
+ if (apiError.status === 422) return {
270
+ content: [{
271
+ type: "text",
272
+ text: `Branch "${branch_name}" already exists in ${owner}/${repo}`
273
+ }],
274
+ isError: true
275
+ };
276
+ if (apiError.status === 404) return {
277
+ content: [{
278
+ type: "text",
279
+ text: `Repository ${owner}/${repo} not found or source branch "${from_branch || "default"}" does not exist`
280
+ }],
281
+ isError: true
282
+ };
283
+ }
284
+ return {
285
+ content: [{
286
+ type: "text",
287
+ text: `Error creating branch: ${error instanceof Error ? error.message : "Unknown error"}`
288
+ }],
289
+ isError: true
290
+ };
291
+ }
292
+ });
293
+ server.tool("commit-file-changes", `Commit changes to a files in a repository. ${getAvailableRepositoryString(repositoryAccess)}`, {
294
+ owner: z.string().describe("Repository owner name"),
295
+ repo: z.string().describe("Repository name"),
296
+ branch_name: z.string().describe("Branch to commit to"),
297
+ file_path: z.string().describe("Path to the file to commit"),
298
+ update_operations: updateOperationsSchema,
299
+ commit_message: z.string().describe("Commit message")
300
+ }, async ({ owner, repo, branch_name, file_path, update_operations, commit_message }) => {
301
+ try {
302
+ let githubClient;
303
+ try {
304
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
305
+ } catch (error) {
306
+ return {
307
+ content: [{
308
+ type: "text",
309
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
310
+ }],
311
+ isError: true
312
+ };
313
+ }
314
+ const fileResponse = await githubClient.rest.repos.getContent({
315
+ owner,
316
+ repo,
317
+ path: file_path
318
+ });
319
+ if (!("content" in fileResponse.data) || Array.isArray(fileResponse.data)) throw new Error(`File ${file_path} not found or is not a file`);
320
+ const currentFileContent = Buffer.from(fileResponse.data.content, "base64").toString("utf-8");
321
+ const updateOperations = update_operations.map((op) => ({
322
+ operation: op.operation,
323
+ lineStart: op.lineStart,
324
+ lineEnd: op.lineEnd,
325
+ content: op.content,
326
+ reason: op.reason
327
+ }));
328
+ await commitFileChanges({
329
+ githubClient,
330
+ owner,
331
+ repo,
332
+ fileContent: currentFileContent,
333
+ filePath: file_path,
334
+ branchName: branch_name,
335
+ operations: updateOperations,
336
+ commitMessage: commit_message
337
+ });
338
+ return { content: [{
339
+ type: "text",
340
+ text: `Successfully committed changes to ${owner}/${repo} on branch "${branch_name}"`
341
+ }] };
342
+ } catch (error) {
343
+ if (error instanceof Error && "status" in error) {
344
+ const apiError = error;
345
+ if (apiError.status === 404) return {
346
+ content: [{
347
+ type: "text",
348
+ text: `Repository ${owner}/${repo} or branch "${branch_name}" not found`
349
+ }],
350
+ isError: true
351
+ };
352
+ if (apiError.status === 422) return {
353
+ content: [{
354
+ type: "text",
355
+ text: "Invalid commit data. Please check file path and update operations format."
356
+ }],
357
+ isError: true
358
+ };
359
+ }
360
+ return {
361
+ content: [{
362
+ type: "text",
363
+ text: `Error creating commit: ${error instanceof Error ? error.message : "Unknown error"}`
364
+ }],
365
+ isError: true
366
+ };
367
+ }
368
+ });
369
+ server.tool("commit-new-file", `Create and commit a new file in a repository. ${getAvailableRepositoryString(repositoryAccess)}`, {
370
+ owner: z.string().describe("Repository owner name"),
371
+ repo: z.string().describe("Repository name"),
372
+ branch_name: z.string().describe("Branch to commit to"),
373
+ file_path: z.string().describe("Path for the new file (relative to repository root)"),
374
+ content: z.string().describe("Content for the new file"),
375
+ commit_message: z.string().describe("Commit message")
376
+ }, async ({ owner, repo, branch_name, file_path, content, commit_message }) => {
377
+ try {
378
+ let githubClient;
379
+ try {
380
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
381
+ } catch (error) {
382
+ return {
383
+ content: [{
384
+ type: "text",
385
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
386
+ }],
387
+ isError: true
388
+ };
389
+ }
390
+ return { content: [{
391
+ type: "text",
392
+ text: `Successfully created and committed new file "${file_path}" to ${owner}/${repo} on branch "${branch_name}"\n\nCommit SHA: ${await commitNewFile({
393
+ githubClient,
394
+ owner,
395
+ repo,
396
+ filePath: file_path,
397
+ branchName: branch_name,
398
+ content,
399
+ commitMessage: commit_message
400
+ })}`
401
+ }] };
402
+ } catch (error) {
403
+ if (error instanceof Error && "status" in error) {
404
+ const apiError = error;
405
+ if (apiError.status === 404) return {
406
+ content: [{
407
+ type: "text",
408
+ text: `Repository ${owner}/${repo} or branch "${branch_name}" not found`
409
+ }],
410
+ isError: true
411
+ };
412
+ if (apiError.status === 422) return {
413
+ content: [{
414
+ type: "text",
415
+ text: `File "${file_path}" may already exist or the path is invalid.`
416
+ }],
417
+ isError: true
418
+ };
419
+ }
420
+ return {
421
+ content: [{
422
+ type: "text",
423
+ text: `Error creating file: ${error instanceof Error ? error.message : "Unknown error"}`
424
+ }],
425
+ isError: true
426
+ };
427
+ }
428
+ });
429
+ server.tool("create-pull-request", `Create a pull request in a repository. ${getAvailableRepositoryString(repositoryAccess)}`, {
430
+ owner: z.string().describe("Repository owner name"),
431
+ repo: z.string().describe("Repository name"),
432
+ title: z.string().describe("Pull request title"),
433
+ body: z.string().describe("Pull request description"),
434
+ head_branch: z.string().describe("Branch containing the changes")
435
+ }, async ({ owner, repo, title, body, head_branch }) => {
436
+ try {
437
+ let githubClient;
438
+ try {
439
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
440
+ } catch (error) {
441
+ return {
442
+ content: [{
443
+ type: "text",
444
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
445
+ }],
446
+ isError: true
447
+ };
448
+ }
449
+ const targetBaseBranch = (await githubClient.rest.repos.get({
450
+ owner,
451
+ repo
452
+ })).data.default_branch;
453
+ const pullRequestResponse = await githubClient.rest.pulls.create({
454
+ owner,
455
+ repo,
456
+ title,
457
+ body,
458
+ head: head_branch,
459
+ base: targetBaseBranch,
460
+ draft: false
461
+ });
462
+ return { content: [{
463
+ type: "text",
464
+ text: `Successfully created pull request in ${owner}/${repo}\n\nPull Request details:\n• Number: #${pullRequestResponse.data.number}\n• Title: ${title}\n• Head: ${head_branch}\n• Base: ${targetBaseBranch}\n• Status: Open\n• URL: ${pullRequestResponse.data.html_url}\n\nDescription:\n${body}`
465
+ }] };
466
+ } catch (error) {
467
+ if (error instanceof Error && "status" in error) {
468
+ const apiError = error;
469
+ if (apiError.status === 404) return {
470
+ content: [{
471
+ type: "text",
472
+ text: `Repository ${owner}/${repo} not found or branch "${head_branch}" does not exist`
473
+ }],
474
+ isError: true
475
+ };
476
+ if (apiError.status === 422) return {
477
+ content: [{
478
+ type: "text",
479
+ text: "Pull request validation failed. This could be due to: no commits between branches, pull request already exists, or invalid branch names."
480
+ }],
481
+ isError: true
482
+ };
483
+ if (apiError.status === 403) return {
484
+ content: [{
485
+ type: "text",
486
+ text: "Permission denied. Your GitHub App may not have sufficient permissions to create pull requests in this repository."
487
+ }],
488
+ isError: true
489
+ };
490
+ }
491
+ return {
492
+ content: [{
493
+ type: "text",
494
+ text: `Error creating pull request: ${error instanceof Error ? error.message : "Unknown error"}`
495
+ }],
496
+ isError: true
497
+ };
498
+ }
499
+ });
500
+ server.tool("leave-comment-on-pull-request", `Leave a comment on a pull request. This creates a general comment on the PR, not a line-specific review comment. ${getAvailableRepositoryString(repositoryAccess)}`, {
501
+ owner: z.string().describe("Repository owner name"),
502
+ repo: z.string().describe("Repository name"),
503
+ pull_request_number: z.number().describe("Pull request number"),
504
+ body: z.string().describe("The comment body text (supports GitHub markdown)")
505
+ }, async ({ owner, repo, pull_request_number, body }) => {
506
+ try {
507
+ let githubClient;
508
+ try {
509
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
510
+ } catch (error) {
511
+ return {
512
+ content: [{
513
+ type: "text",
514
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
515
+ }],
516
+ isError: true
517
+ };
518
+ }
519
+ const commentResponse = await githubClient.rest.issues.createComment({
520
+ owner,
521
+ repo,
522
+ issue_number: pull_request_number,
523
+ body
524
+ });
525
+ return { content: [{
526
+ type: "text",
527
+ text: `Successfully posted comment on PR #${pull_request_number} in ${owner}/${repo}\n\nComment details:\n• ID: ${commentResponse.data.id}\n• URL: ${commentResponse.data.html_url}\n• Created at: ${commentResponse.data.created_at}`
528
+ }] };
529
+ } catch (error) {
530
+ if (error instanceof Error && "status" in error) {
531
+ const apiError = error;
532
+ if (apiError.status === 404) return {
533
+ content: [{
534
+ type: "text",
535
+ text: `Pull request #${pull_request_number} not found in ${owner}/${repo}. Please check the repository exists and the pull request number is correct.`
536
+ }],
537
+ isError: true
538
+ };
539
+ if (apiError.status === 403) return {
540
+ content: [{
541
+ type: "text",
542
+ text: `Access denied to PR #${pull_request_number} in ${owner}/${repo}. Your GitHub App may not have sufficient permissions to comment on pull requests.`
543
+ }],
544
+ isError: true
545
+ };
546
+ if (apiError.status === 422) return {
547
+ content: [{
548
+ type: "text",
549
+ text: "Invalid comment data. Please check the comment body is not empty and is valid."
550
+ }],
551
+ isError: true
552
+ };
553
+ }
554
+ return {
555
+ content: [{
556
+ type: "text",
557
+ text: `Error posting comment: ${error instanceof Error ? error.message : "Unknown error"}`
558
+ }],
559
+ isError: true
560
+ };
561
+ }
562
+ });
563
+ server.tool("visualize-update-operations", `Apply a list of operations to a piece of documentation and return a mapping of line number to line content. ${getAvailableRepositoryString(repositoryAccess)}`, {
564
+ owner: z.string().describe("Repository owner name"),
565
+ repo: z.string().describe("Repository name"),
566
+ file_path: z.string().describe("The path of the file to visualize the update operations for"),
567
+ operations: updateOperationsSchema
568
+ }, async ({ owner, repo, file_path, operations }) => {
569
+ try {
570
+ let githubClient;
571
+ try {
572
+ githubClient = getGitHubClientFromRepo(owner, repo, installationIdMap);
573
+ } catch (error) {
574
+ return {
575
+ content: [{
576
+ type: "text",
577
+ text: `Error accessing GitHub: ${error instanceof Error ? error.message : "Unknown error"}`
578
+ }],
579
+ isError: true
580
+ };
581
+ }
582
+ const response = await githubClient.rest.repos.getContent({
583
+ owner,
584
+ repo,
585
+ path: file_path
586
+ });
587
+ if ("content" in response.data && !Array.isArray(response.data)) {
588
+ const fileData = response.data;
589
+ const result = visualizeUpdateOperations(Buffer.from(fileData.content, "base64").toString("utf-8"), operations.map((op) => ({
590
+ operation: op.operation,
591
+ lineStart: op.lineStart,
592
+ lineEnd: op.lineEnd,
593
+ content: op.content,
594
+ reason: op.reason
595
+ })));
596
+ if (typeof result === "string") return {
597
+ content: [{
598
+ type: "text",
599
+ text: result
600
+ }],
601
+ isError: true
602
+ };
603
+ return { content: [{
604
+ type: "text",
605
+ text: `${Object.entries(result).sort(([a], [b]) => Number(a) - Number(b)).map(([lineNum, content]) => `${lineNum.padStart(3, " ")}| ${content}`).join("\n")}`
606
+ }] };
607
+ }
608
+ return {
609
+ content: [{
610
+ type: "text",
611
+ text: `The path "${file_path}" is not a file or could not be retrieved as file content.`
612
+ }],
613
+ isError: true
614
+ };
615
+ } catch (error) {
616
+ return {
617
+ content: [{
618
+ type: "text",
619
+ text: `Error visualizing update operations: ${error instanceof Error ? error.message : "Unknown error"}`
620
+ }],
621
+ isError: true
622
+ };
623
+ }
624
+ });
625
+ return server;
626
+ };
627
+ const app = new Hono();
628
+ app.use("/", githubMcpAuth());
629
+ app.post("/", async (c) => {
630
+ if (!process.env.GITHUB_APP_ID || !process.env.GITHUB_APP_PRIVATE_KEY) return c.json({ error: "GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY must be set" }, 500);
631
+ const toolId = c.get("toolId");
632
+ const body = await c.req.json();
633
+ const server = await getServer(toolId);
634
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
635
+ server.connect(transport);
636
+ const { req, res } = toReqRes(c.req.raw);
637
+ await transport.handleRequest(req, res, body);
638
+ return toFetchResponse(res);
639
+ });
640
+ app.delete("/", async (c) => {
641
+ return c.json({
642
+ jsonrpc: "2.0",
643
+ error: {
644
+ code: -32001,
645
+ message: "Method Not Allowed"
646
+ },
647
+ id: null
648
+ }, { status: 405 });
649
+ });
650
+ app.get("/", async (c) => {
651
+ return c.json({
652
+ jsonrpc: "2.0",
653
+ error: {
654
+ code: -32e3,
655
+ message: "Method not allowed."
656
+ },
657
+ id: null
658
+ }, { status: 405 });
659
+ });
660
+ app.get("/health", async (c) => {
661
+ return c.json({
662
+ status: "healthy",
663
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
664
+ service: "GitHub MCP Server"
665
+ });
666
+ });
667
+ var mcp_default = app;
668
+
669
+ //#endregion
670
+ export { mcp_default as default };