mcp-server-diff 2.1.0 → 2.1.5

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.
@@ -1,51 +0,0 @@
1
- name: Create Release
2
-
3
- on:
4
- push:
5
- tags:
6
- - 'v[0-9]+.[0-9]+.[0-9]+'
7
- - 'v[0-9]+.[0-9]+.[0-9]+-*'
8
-
9
- permissions:
10
- contents: write
11
-
12
- jobs:
13
- release:
14
- runs-on: ubuntu-latest
15
- steps:
16
- - name: Checkout
17
- uses: actions/checkout@v6
18
- with:
19
- fetch-depth: 0
20
-
21
- - name: Generate Release Notes
22
- id: release_notes
23
- run: |
24
- # Get the previous tag
25
- PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
26
-
27
- if [ -z "$PREV_TAG" ]; then
28
- echo "notes=Initial release" >> $GITHUB_OUTPUT
29
- else
30
- # Generate changelog from commits
31
- NOTES=$(git log --pretty=format:"- %s" $PREV_TAG..HEAD | head -50)
32
- echo "notes<<EOF" >> $GITHUB_OUTPUT
33
- echo "$NOTES" >> $GITHUB_OUTPUT
34
- echo "EOF" >> $GITHUB_OUTPUT
35
- fi
36
-
37
- - name: Create Release
38
- uses: softprops/action-gh-release@v2
39
- with:
40
- name: ${{ github.ref_name }}
41
- body: |
42
- ## What's Changed
43
-
44
- ${{ steps.release_notes.outputs.notes }}
45
-
46
- ---
47
-
48
- **Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.release_notes.outputs.prev_tag || 'initial' }}...${{ github.ref_name }}
49
- draft: false
50
- prerelease: ${{ contains(github.ref_name, '-') }}
51
- generate_release_notes: true
package/.prettierignore DELETED
@@ -1,3 +0,0 @@
1
- dist/
2
- node_modules/
3
- *.md
package/.prettierrc DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "semi": true,
3
- "singleQuote": false,
4
- "tabWidth": 2,
5
- "trailingComma": "es5",
6
- "printWidth": 100,
7
- "bracketSpacing": true
8
- }
package/CONTRIBUTING.md DELETED
@@ -1,81 +0,0 @@
1
- # Contributing to MCP Server Diff
2
-
3
- Thank you for your interest in contributing! This document provides guidelines for contributing to MCP Server Diff.
4
-
5
- ## How to Contribute
6
-
7
- ### Reporting Bugs
8
-
9
- 1. Check existing issues to avoid duplicates
10
- 2. Use the bug report template
11
- 3. Include:
12
- - Steps to reproduce
13
- - Expected vs actual behavior
14
- - Environment details (OS, language runtime versions)
15
- - Workflow configuration
16
-
17
- ### Suggesting Features
18
-
19
- 1. Open a feature request issue
20
- 2. Describe the use case
21
- 3. Explain how it benefits MCP server developers
22
-
23
- ### Pull Requests
24
-
25
- 1. Fork the repository
26
- 2. Create a feature branch from `main`
27
- 3. Make your changes
28
- 4. Test thoroughly
29
- 5. Submit a PR with a clear description
30
-
31
- ## Development Setup
32
-
33
- ### Prerequisites
34
-
35
- - Node.js 20+
36
- - npm
37
- - Git
38
-
39
- ### Building
40
-
41
- ```bash
42
- # Install dependencies
43
- npm ci
44
-
45
- # Run tests
46
- npm test
47
-
48
- # Type check, lint, and format
49
- npm run check
50
-
51
- # Build the action
52
- npm run build
53
- ```
54
-
55
- ### Testing Locally
56
-
57
- To test the action locally, you can run the built action directly:
58
-
59
- ```bash
60
- # Build the action
61
- npm run build
62
-
63
- # Set environment variables that mimic GitHub Actions inputs
64
- export INPUT_INSTALL_COMMAND="npm ci"
65
- export INPUT_BUILD_COMMAND="npm run build"
66
- export INPUT_START_COMMAND="node dist/stdio.js"
67
-
68
- # Run the action
69
- node dist/index.js
70
- ```
71
-
72
- ## Code Style
73
-
74
- - TypeScript with strict mode
75
- - ESLint for linting
76
- - Prettier for formatting
77
- - Run `npm run check` before submitting PRs
78
-
79
- ## License
80
-
81
- By contributing, you agree that your contributions will be licensed under the MIT License.
package/action.yml DELETED
@@ -1,250 +0,0 @@
1
- name: 'MCP Server Diff'
2
- description: 'Diff MCP server public interfaces between versions'
3
- author: 'Sam Morrow'
4
- branding:
5
- icon: 'check-circle'
6
- color: 'green'
7
-
8
- inputs:
9
- # Language setup (optional convenience)
10
- setup_node:
11
- description: 'Set up Node.js environment'
12
- required: false
13
- default: 'false'
14
- node_version:
15
- description: 'Node.js version (default: 20)'
16
- required: false
17
- default: '20'
18
- setup_python:
19
- description: 'Set up Python environment'
20
- required: false
21
- default: 'false'
22
- python_version:
23
- description: 'Python version (default: 3.11)'
24
- required: false
25
- default: '3.11'
26
- setup_go:
27
- description: 'Set up Go environment'
28
- required: false
29
- default: 'false'
30
- go_version:
31
- description: 'Go version (default: read from go.mod)'
32
- required: false
33
- default: ''
34
- setup_rust:
35
- description: 'Set up Rust environment'
36
- required: false
37
- default: 'false'
38
- rust_toolchain:
39
- description: 'Rust toolchain (default: stable)'
40
- required: false
41
- default: 'stable'
42
- setup_dotnet:
43
- description: 'Set up .NET environment'
44
- required: false
45
- default: 'false'
46
- dotnet_version:
47
- description: '.NET version (default: 8.0.x)'
48
- required: false
49
- default: '8.0.x'
50
-
51
- # Build configuration
52
- install_command:
53
- description: 'Command to install dependencies (optional if no install step needed)'
54
- required: false
55
- default: ''
56
- build_command:
57
- description: 'Command to build the MCP server (optional for interpreted languages)'
58
- required: false
59
- default: ''
60
- start_command:
61
- description: 'Command to start the MCP server (for stdio transport, or to start HTTP server)'
62
- required: false
63
- default: ''
64
-
65
- # Transport configuration
66
- transport:
67
- description: 'Transport type: stdio or streamable-http'
68
- required: false
69
- default: 'stdio'
70
- server_url:
71
- description: 'Server URL for HTTP transport (e.g., http://localhost:3000/mcp)'
72
- required: false
73
- default: ''
74
- configurations:
75
- description: |
76
- JSON array of test configurations for multiple transports/scenarios.
77
- Each object supports: name, transport, start_command, args, server_url, headers, env_vars, custom_messages.
78
-
79
- For HTTP transport, use start_command to have the action manage server lifecycle:
80
- - start_command: Command to start the server (action spawns, probes, then kills it)
81
- - startup_wait_ms: Milliseconds to wait for server startup (default: 2000)
82
-
83
- Or use pre/post commands for manual control:
84
- - pre_test_command: Command to run before probing (e.g., start server in background)
85
- - pre_test_wait_ms: Milliseconds to wait after pre_test_command
86
- - post_test_command: Command to run after probing (e.g., kill server process)
87
- required: false
88
- default: ''
89
- custom_messages:
90
- description: 'JSON array of custom JSON-RPC messages to send. Each object: id (number), name (string), message (JSON-RPC object). Applied to all configurations unless overridden per-config.'
91
- required: false
92
- default: ''
93
- headers:
94
- description: 'HTTP headers to send with streamable-http requests. JSON object or newline-separated "Header: value" pairs. Applied to all HTTP configurations unless overridden per-config.'
95
- required: false
96
- default: ''
97
-
98
- # Test configuration
99
- compare_ref:
100
- description: 'Git ref to compare against (auto-detects merge-base or previous tag if not set)'
101
- required: false
102
- default: ''
103
- fail_on_error:
104
- description: 'Fail the action if probe errors occur (not just API differences)'
105
- required: false
106
- default: 'true'
107
- fail_on_diff:
108
- description: 'Fail the action if API differences are detected (useful for release validation)'
109
- required: false
110
- default: 'false'
111
- env_vars:
112
- description: 'Environment variables (newline-separated KEY=VALUE pairs)'
113
- required: false
114
- default: ''
115
- server_timeout:
116
- description: 'Timeout in seconds to wait for server response'
117
- required: false
118
- default: '10'
119
-
120
- # Shared HTTP server (starts once, tests all HTTP configurations against it)
121
- http_start_command:
122
- description: |
123
- Command to start a shared HTTP server for all HTTP transport configurations.
124
- When set, the server starts once before all HTTP tests and stops after they complete.
125
- This is more efficient than starting/stopping per-configuration.
126
- Per-config start_command is ignored when this is set.
127
- required: false
128
- default: ''
129
- http_startup_wait_ms:
130
- description: 'Milliseconds to wait for shared HTTP server to start (default: 2000)'
131
- required: false
132
- default: '2000'
133
-
134
- outputs:
135
- status:
136
- description: 'Test status (passed, differences, or error)'
137
- value: ${{ steps.diff.outputs.status }}
138
- report_path:
139
- description: 'Path to the diff report'
140
- value: 'mcp-diff-report/MCP_DIFF_REPORT.md'
141
-
142
- runs:
143
- using: 'composite'
144
- steps:
145
- # Optional language setup
146
- - name: Set up Node.js
147
- if: inputs.setup_node == 'true'
148
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
149
- with:
150
- node-version: ${{ inputs.node_version }}
151
-
152
- - name: Set up Python
153
- if: inputs.setup_python == 'true'
154
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
155
- with:
156
- python-version: ${{ inputs.python_version }}
157
-
158
- - name: Set up Go
159
- if: inputs.setup_go == 'true'
160
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
161
- with:
162
- go-version: ${{ inputs.go_version || null }}
163
- go-version-file: ${{ inputs.go_version == '' && 'go.mod' || null }}
164
-
165
- - name: Set up Rust
166
- if: inputs.setup_rust == 'true'
167
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
168
- with:
169
- toolchain: ${{ inputs.rust_toolchain }}
170
-
171
- - name: Set up .NET
172
- if: inputs.setup_dotnet == 'true'
173
- uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
174
- with:
175
- dotnet-version: ${{ inputs.dotnet_version }}
176
-
177
- - name: Set environment variables
178
- if: inputs.env_vars != ''
179
- shell: bash
180
- run: |
181
- echo "${{ inputs.env_vars }}" >> $GITHUB_ENV
182
-
183
- - name: Run MCP server diff
184
- id: diff
185
- shell: bash
186
- env:
187
- INPUT_INSTALL_COMMAND: ${{ inputs.install_command }}
188
- INPUT_BUILD_COMMAND: ${{ inputs.build_command }}
189
- INPUT_START_COMMAND: ${{ inputs.start_command }}
190
- INPUT_SERVER_TIMEOUT: ${{ inputs.server_timeout }}
191
- INPUT_COMPARE_REF: ${{ inputs.compare_ref }}
192
- INPUT_FAIL_ON_ERROR: ${{ inputs.fail_on_error }}
193
- INPUT_TRANSPORT: ${{ inputs.transport }}
194
- INPUT_SERVER_URL: ${{ inputs.server_url }}
195
- INPUT_CONFIGURATIONS: ${{ inputs.configurations }}
196
- INPUT_CUSTOM_MESSAGES: ${{ inputs.custom_messages }}
197
- INPUT_HEADERS: ${{ inputs.headers }}
198
- INPUT_ENV_VARS: ${{ inputs.env_vars }}
199
- INPUT_HTTP_START_COMMAND: ${{ inputs.http_start_command }}
200
- INPUT_HTTP_STARTUP_WAIT_MS: ${{ inputs.http_startup_wait_ms }}
201
- INPUT_SETUP_NODE: ${{ inputs.setup_node }}
202
- INPUT_NODE_VERSION: ${{ inputs.node_version }}
203
- INPUT_SETUP_PYTHON: ${{ inputs.setup_python }}
204
- INPUT_PYTHON_VERSION: ${{ inputs.python_version }}
205
- INPUT_SETUP_GO: ${{ inputs.setup_go }}
206
- INPUT_GO_VERSION: ${{ inputs.go_version }}
207
- INPUT_SETUP_RUST: ${{ inputs.setup_rust }}
208
- INPUT_RUST_TOOLCHAIN: ${{ inputs.rust_toolchain }}
209
- INPUT_SETUP_DOTNET: ${{ inputs.setup_dotnet }}
210
- INPUT_DOTNET_VERSION: ${{ inputs.dotnet_version }}
211
- run: |
212
- node "${{ github.action_path }}/dist/index.js"
213
-
214
- - name: Generate Job Summary
215
- shell: bash
216
- run: |
217
- echo "# MCP Server Diff Report" >> $GITHUB_STEP_SUMMARY
218
- echo "" >> $GITHUB_STEP_SUMMARY
219
- if [ -n "${{ inputs.compare_ref }}" ]; then
220
- echo "Comparing against: \`${{ inputs.compare_ref }}\`" >> $GITHUB_STEP_SUMMARY
221
- elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
222
- echo "Comparing tag against previous tag (auto-detected)" >> $GITHUB_STEP_SUMMARY
223
- else
224
- echo "Comparing against merge-base with \`origin/main\`" >> $GITHUB_STEP_SUMMARY
225
- fi
226
- echo "" >> $GITHUB_STEP_SUMMARY
227
-
228
- if [ -f mcp-diff-report/MCP_DIFF_REPORT.md ]; then
229
- tail -n +5 mcp-diff-report/MCP_DIFF_REPORT.md >> $GITHUB_STEP_SUMMARY
230
- else
231
- echo "Report file not found - check the workflow logs for errors" >> $GITHUB_STEP_SUMMARY
232
- fi
233
-
234
- echo "" >> $GITHUB_STEP_SUMMARY
235
- echo "---" >> $GITHUB_STEP_SUMMARY
236
- echo "" >> $GITHUB_STEP_SUMMARY
237
-
238
- if [ "${{ steps.diff.outputs.status }}" = "passed" ]; then
239
- echo "**No API changes detected** between the branches." >> $GITHUB_STEP_SUMMARY
240
- else
241
- echo "**API changes detected** — review above to confirm they are expected." >> $GITHUB_STEP_SUMMARY
242
- fi
243
-
244
- - name: Upload diff report
245
- if: always()
246
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
247
- with:
248
- name: mcp-diff-report
249
- path: mcp-diff-report/
250
- if-no-files-found: ignore
package/eslint.config.mjs DELETED
@@ -1,47 +0,0 @@
1
- import eslint from "@eslint/js";
2
- import tseslint from "typescript-eslint";
3
- import prettier from "eslint-config-prettier";
4
-
5
- export default tseslint.config(
6
- eslint.configs.recommended,
7
- ...tseslint.configs.recommended,
8
- prettier,
9
- {
10
- languageOptions: {
11
- parserOptions: {
12
- project: "./tsconfig.json",
13
- },
14
- },
15
- rules: {
16
- "@typescript-eslint/no-unused-vars": [
17
- "error",
18
- { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
19
- ],
20
- "@typescript-eslint/explicit-function-return-type": "off",
21
- "@typescript-eslint/no-explicit-any": "warn",
22
- "no-console": "warn",
23
- },
24
- },
25
- {
26
- // Test files don't need the project reference and need Jest globals
27
- files: ["**/__tests__/**/*.ts", "**/*.test.ts"],
28
- languageOptions: {
29
- parserOptions: {
30
- project: null,
31
- },
32
- globals: {
33
- describe: "readonly",
34
- it: "readonly",
35
- expect: "readonly",
36
- beforeEach: "readonly",
37
- afterEach: "readonly",
38
- beforeAll: "readonly",
39
- afterAll: "readonly",
40
- jest: "readonly",
41
- },
42
- },
43
- },
44
- {
45
- ignores: ["dist/**", "node_modules/**", "*.js", "*.mjs"],
46
- }
47
- );
package/jest.config.mjs DELETED
@@ -1,26 +0,0 @@
1
- /** @type {import('jest').Config} */
2
- export default {
3
- preset: "ts-jest/presets/default-esm",
4
- testEnvironment: "node",
5
- extensionsToTreatAsEsm: [".ts"],
6
- // Force exit after tests complete - needed because npx tsx leaves handles open
7
- forceExit: true,
8
- moduleNameMapper: {
9
- "^(\\.{1,2}/.*)\\.js$": "$1",
10
- },
11
- transform: {
12
- "^.+\\.tsx?$": [
13
- "ts-jest",
14
- {
15
- useESM: true,
16
- diagnostics: {
17
- ignoreCodes: [151002],
18
- },
19
- },
20
- ],
21
- },
22
- testMatch: ["**/__tests__/**/*.test.ts", "**/*.test.ts"],
23
- collectCoverageFrom: ["src/**/*.ts", "!src/**/*.d.ts"],
24
- coverageDirectory: "coverage",
25
- coverageReporters: ["text", "lcov", "html"],
26
- };
@@ -1,103 +0,0 @@
1
- #!/usr/bin/env npx tsx
2
- /**
3
- * Minimal MCP Server for integration testing (streamable-http transport)
4
- *
5
- * Run with: npx tsx http-server.ts <port>
6
- */
7
-
8
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
9
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
10
- import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
11
- import * as http from "http";
12
-
13
- const server = new Server(
14
- {
15
- name: "test-http-server",
16
- version: "1.0.0",
17
- },
18
- {
19
- capabilities: {
20
- tools: {},
21
- },
22
- }
23
- );
24
-
25
- // Define tools
26
- server.setRequestHandler(ListToolsRequestSchema, async () => {
27
- return {
28
- tools: [
29
- {
30
- name: "echo",
31
- description: "Echoes back the input",
32
- inputSchema: {
33
- type: "object" as const,
34
- properties: {
35
- message: { type: "string", description: "Message to echo" },
36
- },
37
- required: ["message"],
38
- },
39
- },
40
- ],
41
- };
42
- });
43
-
44
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
45
- const { name, arguments: args } = request.params;
46
-
47
- if (name === "echo") {
48
- return {
49
- content: [{ type: "text", text: (args as { message: string }).message }],
50
- };
51
- }
52
-
53
- throw new Error(`Unknown tool: ${name}`);
54
- });
55
-
56
- // Create HTTP server with streamable transport
57
- async function main() {
58
- const httpServer = http.createServer();
59
- const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
60
-
61
- httpServer.on("request", async (req, res) => {
62
- // Simple CORS support
63
- res.setHeader("Access-Control-Allow-Origin", "*");
64
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
65
- res.setHeader("Access-Control-Allow-Headers", "Content-Type");
66
-
67
- if (req.method === "OPTIONS") {
68
- res.writeHead(200);
69
- res.end();
70
- return;
71
- }
72
-
73
- if (req.url === "/mcp" || req.url?.startsWith("/mcp?")) {
74
- await transport.handleRequest(req, res);
75
- } else {
76
- res.writeHead(404);
77
- res.end("Not found");
78
- }
79
- });
80
-
81
- await server.connect(transport);
82
-
83
- // Use port 0 to let the OS assign a free port, unless specific port given
84
- const requestedPort = parseInt(process.argv[2] || "0", 10);
85
- httpServer.listen(requestedPort, () => {
86
- const addr = httpServer.address();
87
- const actualPort = typeof addr === "object" && addr ? addr.port : requestedPort;
88
- // Output format that tests parse: "listening on port XXXXX"
89
- console.log(`Test HTTP MCP server listening on port ${actualPort}`);
90
- });
91
-
92
- // Handle shutdown
93
- process.on("SIGTERM", () => {
94
- httpServer.close();
95
- process.exit(0);
96
- });
97
- process.on("SIGINT", () => {
98
- httpServer.close();
99
- process.exit(0);
100
- });
101
- }
102
-
103
- main().catch(console.error);