Skip to content

Commit 60d0f08

Browse files
authored
Merge branch 'main' into main
2 parents 732c119 + 94a29d9 commit 60d0f08

File tree

10 files changed

+1193
-136
lines changed

10 files changed

+1193
-136
lines changed

README.md

Lines changed: 173 additions & 7 deletions
Large diffs are not rendered by default.

package-lock.json

Lines changed: 786 additions & 91 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/everything/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,20 @@ Resource features:
9696
- `style` (string): Output style preference
9797
- Returns: Multi-turn conversation with images
9898

99+
### Logging
100+
101+
The server sends random-leveled log messages every 15 seconds, e.g.:
102+
103+
```json
104+
{
105+
"method": "notifications/message",
106+
"params": {
107+
"level": "info",
108+
"data": "Info-level message"
109+
}
110+
}
111+
```
112+
99113
## Usage with Claude Desktop
100114

101115
Add to your `claude_desktop_config.json`:

src/everything/everything.ts

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
ListResourcesRequestSchema,
1010
ListResourceTemplatesRequestSchema,
1111
ListToolsRequestSchema,
12+
LoggingLevel,
1213
ReadResourceRequestSchema,
1314
Resource,
1415
SetLevelRequestSchema,
@@ -99,10 +100,10 @@ export const createServer = () => {
99100
);
100101

101102
let subscriptions: Set<string> = new Set();
102-
let updateInterval: NodeJS.Timeout | undefined;
103-
103+
let subsUpdateInterval: NodeJS.Timeout | undefined;
104104
// Set up update interval for subscribed resources
105-
updateInterval = setInterval(() => {
105+
106+
subsUpdateInterval = setInterval(() => {
106107
for (const uri of subscriptions) {
107108
server.notification({
108109
method: "notifications/resources/updated",
@@ -111,6 +112,34 @@ export const createServer = () => {
111112
}
112113
}, 5000);
113114

115+
let logLevel: LoggingLevel = "debug";
116+
let logsUpdateInterval: NodeJS.Timeout | undefined;
117+
const messages = [
118+
{level: "debug", data: "Debug-level message"},
119+
{level: "info", data: "Info-level message"},
120+
{level: "notice", data: "Notice-level message"},
121+
{level: "warning", data: "Warning-level message"},
122+
{level: "error", data: "Error-level message"},
123+
{level: "critical", data: "Critical-level message"},
124+
{level: "alert", data: "Alert level-message"},
125+
{level: "emergency", data: "Emergency-level message"}
126+
]
127+
128+
const isMessageIgnored = (level:LoggingLevel):boolean => {
129+
const currentLevel = messages.findIndex((msg) => logLevel === msg.level);
130+
const messageLevel = messages.findIndex((msg) => level === msg.level);
131+
return messageLevel < currentLevel;
132+
}
133+
134+
// Set up update interval for random log messages
135+
logsUpdateInterval = setInterval(() => {
136+
let message = {
137+
method: "notifications/message",
138+
params: messages[Math.floor(Math.random() * messages.length)],
139+
}
140+
if (!isMessageIgnored(message.params.level as LoggingLevel)) server.notification(message);
141+
}, 15000);
142+
114143
// Helper method to request sampling from client
115144
const requestSampling = async (
116145
context: string,
@@ -451,7 +480,7 @@ export const createServer = () => {
451480

452481
if (name === ToolName.ANNOTATED_MESSAGE) {
453482
const { messageType, includeImage } = AnnotatedMessageSchema.parse(args);
454-
483+
455484
const content = [];
456485

457486
// Main message with different priorities/audiences based on type
@@ -511,7 +540,7 @@ export const createServer = () => {
511540
if (!resourceId) return { completion: { values: [] } };
512541

513542
// Filter resource IDs that start with the input value
514-
const values = EXAMPLE_COMPLETIONS.resourceId.filter(id =>
543+
const values = EXAMPLE_COMPLETIONS.resourceId.filter(id =>
515544
id.startsWith(argument.value)
516545
);
517546
return { completion: { values, hasMore: false, total: values.length } };
@@ -522,7 +551,7 @@ export const createServer = () => {
522551
const completions = EXAMPLE_COMPLETIONS[argument.name as keyof typeof EXAMPLE_COMPLETIONS];
523552
if (!completions) return { completion: { values: [] } };
524553

525-
const values = completions.filter(value =>
554+
const values = completions.filter(value =>
526555
value.startsWith(argument.value)
527556
);
528557
return { completion: { values, hasMore: false, total: values.length } };
@@ -533,24 +562,24 @@ export const createServer = () => {
533562

534563
server.setRequestHandler(SetLevelRequestSchema, async (request) => {
535564
const { level } = request.params;
565+
logLevel = level;
536566

537567
// Demonstrate different log levels
538568
await server.notification({
539569
method: "notifications/message",
540570
params: {
541571
level: "debug",
542572
logger: "test-server",
543-
data: `Logging level set to: ${level}`,
573+
data: `Logging level set to: ${logLevel}`,
544574
},
545575
});
546576

547577
return {};
548578
});
549579

550580
const cleanup = async () => {
551-
if (updateInterval) {
552-
clearInterval(updateInterval);
553-
}
581+
if (subsUpdateInterval) clearInterval(subsUpdateInterval);
582+
if (logsUpdateInterval) clearInterval(logsUpdateInterval);
554583
};
555584

556585
return { server, cleanup };

src/filesystem/README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,16 @@ Node.js server implementing Model Context Protocol (MCP) for filesystem operatio
4141
- Features:
4242
- Line-based and multi-line content matching
4343
- Whitespace normalization with indentation preservation
44-
- Fuzzy matching with confidence scoring
4544
- Multiple simultaneous edits with correct positioning
4645
- Indentation style detection and preservation
4746
- Git-style diff output with context
4847
- Preview changes with dry run mode
49-
- Failed match debugging with confidence scores
5048
- Inputs:
5149
- `path` (string): File to edit
5250
- `edits` (array): List of edit operations
5351
- `oldText` (string): Text to search for (can be substring)
5452
- `newText` (string): Text to replace with
5553
- `dryRun` (boolean): Preview changes without applying (default: false)
56-
- `options` (object): Optional formatting settings
57-
- `preserveIndentation` (boolean): Keep existing indentation (default: true)
58-
- `normalizeWhitespace` (boolean): Normalize spaces while preserving structure (default: true)
59-
- `partialMatch` (boolean): Enable fuzzy matching (default: true)
6054
- Returns detailed diff and match information for dry runs, otherwise applies changes
6155
- Best Practice: Always use dryRun first to preview changes before applying them
6256

src/filesystem/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const allowedDirectories = args.map(dir =>
4242
// Validate that all directories exist and are accessible
4343
await Promise.all(args.map(async (dir) => {
4444
try {
45-
const stats = await fs.stat(dir);
45+
const stats = await fs.stat(expandHome(dir));
4646
if (!stats.isDirectory()) {
4747
console.error(`Error: ${dir} is not a directory`);
4848
process.exit(1);

src/git/uv.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/github/common/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ export const GitHubLabelSchema = z.object({
157157
name: z.string(),
158158
color: z.string(),
159159
default: z.boolean(),
160-
description: z.string().optional(),
160+
description: z.string().nullable().optional(),
161161
});
162162

163163
export const GitHubMilestoneSchema = z.object({

src/github/index.ts

Lines changed: 160 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
} from "@modelcontextprotocol/sdk/types.js";
88
import { z } from 'zod';
99
import { zodToJsonSchema } from 'zod-to-json-schema';
10+
import fetch, { Request, Response } from 'node-fetch';
1011

1112
import * as repository from './operations/repository.js';
1213
import * as files from './operations/files.js';
@@ -27,6 +28,11 @@ import {
2728
} from './common/errors.js';
2829
import { VERSION } from "./common/version.js";
2930

31+
// If fetch doesn't exist in global scope, add it
32+
if (!globalThis.fetch) {
33+
globalThis.fetch = fetch as unknown as typeof global.fetch;
34+
}
35+
3036
const server = new Server(
3137
{
3238
name: "github-mcp-server",
@@ -149,6 +155,51 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
149155
name: "get_issue",
150156
description: "Get details of a specific issue in a GitHub repository.",
151157
inputSchema: zodToJsonSchema(issues.GetIssueSchema)
158+
},
159+
{
160+
name: "get_pull_request",
161+
description: "Get details of a specific pull request",
162+
inputSchema: zodToJsonSchema(pulls.GetPullRequestSchema)
163+
},
164+
{
165+
name: "list_pull_requests",
166+
description: "List and filter repository pull requests",
167+
inputSchema: zodToJsonSchema(pulls.ListPullRequestsSchema)
168+
},
169+
{
170+
name: "create_pull_request_review",
171+
description: "Create a review on a pull request",
172+
inputSchema: zodToJsonSchema(pulls.CreatePullRequestReviewSchema)
173+
},
174+
{
175+
name: "merge_pull_request",
176+
description: "Merge a pull request",
177+
inputSchema: zodToJsonSchema(pulls.MergePullRequestSchema)
178+
},
179+
{
180+
name: "get_pull_request_files",
181+
description: "Get the list of files changed in a pull request",
182+
inputSchema: zodToJsonSchema(pulls.GetPullRequestFilesSchema)
183+
},
184+
{
185+
name: "get_pull_request_status",
186+
description: "Get the combined status of all status checks for a pull request",
187+
inputSchema: zodToJsonSchema(pulls.GetPullRequestStatusSchema)
188+
},
189+
{
190+
name: "update_pull_request_branch",
191+
description: "Update a pull request branch with the latest changes from the base branch",
192+
inputSchema: zodToJsonSchema(pulls.UpdatePullRequestBranchSchema)
193+
},
194+
{
195+
name: "get_pull_request_comments",
196+
description: "Get the review comments on a pull request",
197+
inputSchema: zodToJsonSchema(pulls.GetPullRequestCommentsSchema)
198+
},
199+
{
200+
name: "get_pull_request_reviews",
201+
description: "Get the reviews on a pull request",
202+
inputSchema: zodToJsonSchema(pulls.GetPullRequestReviewsSchema)
152203
}
153204
],
154205
};
@@ -248,10 +299,39 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
248299
case "create_issue": {
249300
const args = issues.CreateIssueSchema.parse(request.params.arguments);
250301
const { owner, repo, ...options } = args;
251-
const issue = await issues.createIssue(owner, repo, options);
252-
return {
253-
content: [{ type: "text", text: JSON.stringify(issue, null, 2) }],
254-
};
302+
303+
try {
304+
console.error(`[DEBUG] Attempting to create issue in ${owner}/${repo}`);
305+
console.error(`[DEBUG] Issue options:`, JSON.stringify(options, null, 2));
306+
307+
const issue = await issues.createIssue(owner, repo, options);
308+
309+
console.error(`[DEBUG] Issue created successfully`);
310+
return {
311+
content: [{ type: "text", text: JSON.stringify(issue, null, 2) }],
312+
};
313+
} catch (err) {
314+
// Type guard for Error objects
315+
const error = err instanceof Error ? err : new Error(String(err));
316+
317+
console.error(`[ERROR] Failed to create issue:`, error);
318+
319+
if (error instanceof GitHubResourceNotFoundError) {
320+
throw new Error(
321+
`Repository '${owner}/${repo}' not found. Please verify:\n` +
322+
`1. The repository exists\n` +
323+
`2. You have correct access permissions\n` +
324+
`3. The owner and repository names are spelled correctly`
325+
);
326+
}
327+
328+
// Safely access error properties
329+
throw new Error(
330+
`Failed to create issue: ${error.message}${
331+
error.stack ? `\nStack: ${error.stack}` : ''
332+
}`
333+
);
334+
}
255335
}
256336

257337
case "create_pull_request": {
@@ -335,6 +415,82 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
335415
};
336416
}
337417

418+
case "get_pull_request": {
419+
const args = pulls.GetPullRequestSchema.parse(request.params.arguments);
420+
const pullRequest = await pulls.getPullRequest(args.owner, args.repo, args.pull_number);
421+
return {
422+
content: [{ type: "text", text: JSON.stringify(pullRequest, null, 2) }],
423+
};
424+
}
425+
426+
case "list_pull_requests": {
427+
const args = pulls.ListPullRequestsSchema.parse(request.params.arguments);
428+
const { owner, repo, ...options } = args;
429+
const pullRequests = await pulls.listPullRequests(owner, repo, options);
430+
return {
431+
content: [{ type: "text", text: JSON.stringify(pullRequests, null, 2) }],
432+
};
433+
}
434+
435+
case "create_pull_request_review": {
436+
const args = pulls.CreatePullRequestReviewSchema.parse(request.params.arguments);
437+
const { owner, repo, pull_number, ...options } = args;
438+
const review = await pulls.createPullRequestReview(owner, repo, pull_number, options);
439+
return {
440+
content: [{ type: "text", text: JSON.stringify(review, null, 2) }],
441+
};
442+
}
443+
444+
case "merge_pull_request": {
445+
const args = pulls.MergePullRequestSchema.parse(request.params.arguments);
446+
const { owner, repo, pull_number, ...options } = args;
447+
const result = await pulls.mergePullRequest(owner, repo, pull_number, options);
448+
return {
449+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
450+
};
451+
}
452+
453+
case "get_pull_request_files": {
454+
const args = pulls.GetPullRequestFilesSchema.parse(request.params.arguments);
455+
const files = await pulls.getPullRequestFiles(args.owner, args.repo, args.pull_number);
456+
return {
457+
content: [{ type: "text", text: JSON.stringify(files, null, 2) }],
458+
};
459+
}
460+
461+
case "get_pull_request_status": {
462+
const args = pulls.GetPullRequestStatusSchema.parse(request.params.arguments);
463+
const status = await pulls.getPullRequestStatus(args.owner, args.repo, args.pull_number);
464+
return {
465+
content: [{ type: "text", text: JSON.stringify(status, null, 2) }],
466+
};
467+
}
468+
469+
case "update_pull_request_branch": {
470+
const args = pulls.UpdatePullRequestBranchSchema.parse(request.params.arguments);
471+
const { owner, repo, pull_number, expected_head_sha } = args;
472+
await pulls.updatePullRequestBranch(owner, repo, pull_number, expected_head_sha);
473+
return {
474+
content: [{ type: "text", text: JSON.stringify({ success: true }, null, 2) }],
475+
};
476+
}
477+
478+
case "get_pull_request_comments": {
479+
const args = pulls.GetPullRequestCommentsSchema.parse(request.params.arguments);
480+
const comments = await pulls.getPullRequestComments(args.owner, args.repo, args.pull_number);
481+
return {
482+
content: [{ type: "text", text: JSON.stringify(comments, null, 2) }],
483+
};
484+
}
485+
486+
case "get_pull_request_reviews": {
487+
const args = pulls.GetPullRequestReviewsSchema.parse(request.params.arguments);
488+
const reviews = await pulls.getPullRequestReviews(args.owner, args.repo, args.pull_number);
489+
return {
490+
content: [{ type: "text", text: JSON.stringify(reviews, null, 2) }],
491+
};
492+
}
493+
338494
default:
339495
throw new Error(`Unknown tool: ${request.params.name}`);
340496
}

0 commit comments

Comments
 (0)