mcp-server-diff 2.1.0 → 2.1.6
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.
- package/README.md +116 -1
- package/dist/cli/index.js +226 -17
- package/dist/index.js +32 -5
- package/package.json +6 -1
- package/.github/dependabot.yml +0 -21
- package/.github/workflows/ci.yml +0 -51
- package/.github/workflows/publish.yml +0 -36
- package/.github/workflows/release.yml +0 -51
- package/.prettierignore +0 -3
- package/.prettierrc +0 -8
- package/CONTRIBUTING.md +0 -81
- package/action.yml +0 -250
- package/eslint.config.mjs +0 -47
- package/jest.config.mjs +0 -26
- package/src/__tests__/fixtures/http-server.ts +0 -103
- package/src/__tests__/fixtures/stdio-server.ts +0 -158
- package/src/__tests__/integration.test.ts +0 -306
- package/src/__tests__/runner.test.ts +0 -430
- package/src/cli.ts +0 -421
- package/src/diff.ts +0 -252
- package/src/git.ts +0 -262
- package/src/index.ts +0 -284
- package/src/logger.ts +0 -93
- package/src/probe.ts +0 -327
- package/src/reporter.ts +0 -214
- package/src/runner.ts +0 -902
- package/src/types.ts +0 -155
- package/tsconfig.json +0 -30
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
name: Publish to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [published]
|
|
6
|
-
|
|
7
|
-
permissions:
|
|
8
|
-
contents: read
|
|
9
|
-
id-token: write # Required for npm OIDC provenance
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
publish:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- name: Checkout
|
|
16
|
-
uses: actions/checkout@v4
|
|
17
|
-
|
|
18
|
-
- name: Setup Node.js
|
|
19
|
-
uses: actions/setup-node@v4
|
|
20
|
-
with:
|
|
21
|
-
node-version: '22'
|
|
22
|
-
registry-url: 'https://registry.npmjs.org'
|
|
23
|
-
|
|
24
|
-
- name: Install dependencies
|
|
25
|
-
run: npm ci
|
|
26
|
-
|
|
27
|
-
- name: Run checks
|
|
28
|
-
run: npm run check
|
|
29
|
-
|
|
30
|
-
- name: Build
|
|
31
|
-
run: npm run build
|
|
32
|
-
|
|
33
|
-
# Tokenless publish using npm's OIDC trust
|
|
34
|
-
# Requires package to be linked to this repo on npmjs.com
|
|
35
|
-
- name: Publish to npm with provenance
|
|
36
|
-
run: npm publish --provenance --access public
|
|
@@ -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
package/.prettierrc
DELETED
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);
|