# Directory Structure
```
├── .gitignore
├── .npmignore
├── jest.config.js
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── src
│ ├── diffGetter.ts
│ └── index.ts
├── test
│ └── diffGetter.test.ts
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | node_modules/
2 | build/
3 | *.log
4 | .env*
```
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
```
1 | node_modules
2 | src
3 | test
4 | tsconfig.json
5 | jest.config.js
6 | .gitignore
7 | package-lock.json
8 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # mcp-server-diff-typescript MCP Server
2 |
3 | A Model Context Protocol server that provides unified diff generation capabilities.
4 |
5 | This TypeScript-based MCP server implements a diff generation system. It provides a tool to generate unified diffs between two text strings, which is useful for comparing and analyzing text differences.
6 |
7 | <a href="https://glama.ai/mcp/servers/3sbmp65pce"><img width="380" height="200" src="https://glama.ai/mcp/servers/3sbmp65pce/badge" alt="Server Diff TypeScript MCP server" /></a>
8 |
9 | ## Features
10 |
11 | ### Tools
12 |
13 | - `get-unified-diff` - Generate unified diff between two text strings
14 | - Takes `oldString` and `newString` as required parameters
15 | - Returns the difference in unified diff format
16 | - Uses the `diff` package for accurate difference detection
17 | - Includes 3 lines of context around changes
18 |
19 | ## Installation
20 |
21 | ### As a Global Package
22 |
23 | ```bash
24 | npm install -g mcp-server-diff-typescript
25 | ```
26 |
27 | ### As a Project Dependency
28 |
29 | ```bash
30 | npm install mcp-server-diff-typescript
31 | ```
32 |
33 | ## Usage
34 |
35 | ### Using with Claude Desktop
36 |
37 | To use with Claude Desktop, add the server config:
38 |
39 | On MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
40 | On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
41 |
42 |
43 | ```json
44 | "mcpServers": {
45 | "mcp-server-diff-typescript": {
46 | "command": "npx",
47 | "args": [
48 | "-y",
49 | "mcp-server-diff-typescript"
50 | ]
51 | }
52 | }
53 | ```
54 |
55 | or Add the following configuration:
56 |
57 | ```bash
58 | git clone https://github.com/tatn/mcp-server-diff-typescript.git
59 | cd mcp-server-diff-typescript
60 | npm install
61 | npm run build
62 | ```
63 |
64 | ```json
65 | "mcpServers": {
66 | "mcp-server-diff-typescript": {
67 | "command": "node",
68 | "args": [
69 | "/path/to/mcp-server-diff-typescript/build/index.js"
70 | ]
71 | }
72 | }
73 | ```
74 |
75 | ### Debugging
76 |
77 | To debug the MCP server:
78 |
79 | ```bash
80 | npx @modelcontextprotocol/inspector npx -y mcp-server-diff-typescript
81 | ```
82 |
83 |
84 | ```bash
85 | npx @modelcontextprotocol/inspector node /path/to/mcp-server-diff-typescript/build/index.js
86 | ```
87 |
```
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
```javascript
1 | /** @type {import('ts-jest').JestConfigWithTsJest} */
2 | export default {
3 | preset: 'ts-jest',
4 | testEnvironment: 'node',
5 | extensionsToTreatAsEsm: ['.ts'],
6 | moduleNameMapper: {
7 | '^(\\.{1,2}/.*)\\.js$': '$1',
8 | },
9 | transform: {
10 | '^.+\\.tsx?$': ['ts-jest', {
11 | useESM: true,
12 | }],
13 | },
14 | };
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "outDir": "./build",
7 | "rootDir": "./src",
8 | "strict": true,
9 | "esModuleInterop": true,
10 | "skipLibCheck": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "declaration": true,
13 | "sourceMap": true
14 | },
15 | "include": ["src/**/*"],
16 | "exclude": ["node_modules","build"]
17 | }
18 |
```
--------------------------------------------------------------------------------
/src/diffGetter.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { diffLines, createPatch } from 'diff';
2 |
3 | export function generateUnifiedDiff(oldString: string, newString: string, oldHeader: string = '', newHeader: string = '', fileName: string = ''): string {
4 | const diff = diffLines(oldString, newString);
5 | if (diff.length === 1 && !diff[0].added && !diff[0].removed) {
6 | return ''; // No change detected
7 | }
8 | return createPatch(fileName, oldString, newString, oldHeader, newHeader, { context: 3 });
9 | }
10 |
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "mcp-server-diff-typescript",
3 | "version": "1.0.5",
4 | "description": "A Model Context Protocol server that provides unified diff generation capabilities",
5 | "main": "./build/index.js",
6 | "type": "module",
7 | "bin": {
8 | "mcp-server-diff-typescript": "build/index.js"
9 | },
10 | "files": [
11 | "build"
12 | ],
13 | "scripts": {
14 | "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
15 | "prepare": "npm run build",
16 | "watch": "tsc --watch",
17 | "test": "jest",
18 | "inspector": "npx @modelcontextprotocol/inspector build/index.js"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "git+https://github.com/tatn/mcp-server-diff-typescript.git"
23 | },
24 | "keywords": [
25 | "mcp",
26 | "server",
27 | "diff",
28 | "unified"
29 | ],
30 | "homepage": "https://github.com/tatn/mcp-server-diff-typescript",
31 | "license": "MIT",
32 | "author": "tatn",
33 | "dependencies": {
34 | "@modelcontextprotocol/sdk": "0.6.0",
35 | "diff": "^7.0.0"
36 | },
37 | "devDependencies": {
38 | "@types/diff": "^7.0.0",
39 | "@types/jest": "^29.5.14",
40 | "@types/node": "^20.11.24",
41 | "jest": "^29.7.0",
42 | "ts-jest": "^29.2.5",
43 | "typescript": "^5.3.3"
44 | },
45 | "types": "build/index.d.ts"
46 | }
47 |
```
--------------------------------------------------------------------------------
/test/diffGetter.test.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { generateUnifiedDiff } from '../src/diffGetter';
2 |
3 | describe('generateUnifiedDiff', () => {
4 | it('should return an empty string when there are no changes', () => {
5 | const oldString = 'Hello World';
6 | const newString = 'Hello World';
7 | const result = generateUnifiedDiff(oldString, newString);
8 | expect(result).toBe('');
9 | });
10 |
11 | it('should generate a unified diff for changed content', () => {
12 | const oldString = 'Hello World';
13 | const newString = 'Hello GitHub Copilot';
14 | const result = generateUnifiedDiff(oldString, newString);
15 | expect(result).toContain('Hello World');
16 | expect(result).toContain('Hello GitHub Copilot');
17 | });
18 |
19 | it('should include headers in the diff', () => {
20 | const oldString = 'Hello World';
21 | const newString = 'Hello GitHub Copilot';
22 | const oldHeader = 'v1';
23 | const newHeader = 'v2';
24 | const result = generateUnifiedDiff(oldString, newString, oldHeader, newHeader);
25 | expect(result).toContain('--- v1');
26 | expect(result).toContain('+++ v2');
27 | });
28 |
29 | it('should include file name in the diff', () => {
30 | const oldString = 'Hello World';
31 | const newString = 'Hello GitHub Copilot';
32 | const fileName = 'testFile.txt';
33 | const result = generateUnifiedDiff(oldString, newString, '', '', fileName);
34 | expect(result).toContain('--- testFile.txt');
35 | expect(result).toContain('+++ testFile.txt');
36 | });
37 | });
```
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * MCP server that returns the difference between strings in Unified Diff format.
5 | */
6 |
7 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9 | import { generateUnifiedDiff } from "./diffGetter.js";
10 | import {
11 | CallToolRequestSchema,
12 | ListToolsRequestSchema,
13 | } from "@modelcontextprotocol/sdk/types.js";
14 |
15 | const server = new Server(
16 | {
17 | name: "mcp-server-diff-typescript",
18 | version: "0.1.0",
19 | },
20 | {
21 | capabilities: {
22 | resources: {},
23 | tools: {},
24 | prompts: {},
25 | },
26 | }
27 | );
28 |
29 | /**
30 |
31 | */
32 | server.setRequestHandler(ListToolsRequestSchema, async () => {
33 | return {
34 | tools: [
35 | {
36 | name: "get-unified-diff",
37 | description: "Get the difference between two text articles in Unified diff format.",
38 | inputSchema: {
39 | type: "object",
40 | properties: {
41 | oldString: {
42 | type: "string",
43 | description: "old string to compare"
44 | },
45 | newString: {
46 | type: "string",
47 | description: "new string to compare"
48 | }
49 | },
50 | required: ["oldString", "newString"]
51 | }
52 | }
53 | ]
54 | };
55 | });
56 |
57 | /**
58 | * Handler for the create_note and get-unified-diff tools.
59 | */
60 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
61 | switch (request.params.name) {
62 | case "get-unified-diff": {
63 | const oldString = String(request.params.arguments?.oldString);
64 | const newString = String(request.params.arguments?.newString);
65 | if (!oldString || !newString) {
66 | throw new Error("oldString and newString are required");
67 | }
68 |
69 | const diffResult = generateUnifiedDiff(oldString, newString, "", "", "");
70 |
71 | return {
72 | content: [{
73 | type: "text",
74 | text: diffResult
75 | }]
76 | };
77 | }
78 | default:
79 | throw new Error("Unknown tool");
80 | }
81 | });
82 |
83 | /**
84 | * Start the server using stdio transport.
85 | * This allows the server to communicate via standard input/output streams.
86 | */
87 | async function main() {
88 | const transport = new StdioServerTransport();
89 | await server.connect(transport);
90 | }
91 |
92 | main().catch((error) => {
93 | console.error("Server error:", error);
94 | process.exit(1);
95 | });
96 |
```