diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1fb472e..ccb4aea9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,8 @@ on: branches: - main pull_request: + release: + types: [published] permissions: contents: read @@ -19,9 +21,34 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 22 + node-version: 24 cache: npm - run: npm ci + - run: npm run check + - run: npm run build - run: npm test - - run: npm run lint + + publish: + runs-on: ubuntu-latest + if: github.event_name == 'release' + environment: release + needs: [test] + + permissions: + contents: read + id-token: write + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + registry-url: 'https://registry.npmjs.org' + + - run: npm ci + + - run: npm publish --provenance --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/pr-publish.yml b/.github/workflows/pr-publish.yml new file mode 100644 index 00000000..29a33a9a --- /dev/null +++ b/.github/workflows/pr-publish.yml @@ -0,0 +1,27 @@ +name: Publish PR to pkg.pr.new +permissions: + contents: read +on: + pull_request: + push: + branches: + - '**' + tags: + - '!**' + +jobs: + pr-publish: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + + - run: npm ci + - name: Build + run: npm run build + - name: Publish + run: npx pkg-pr-new publish diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..136059a2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Anthropic, PBC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2f8e60c7..83026e04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@jest/globals": "^29.7.0", "@types/express": "^5.0.3", "@types/jest": "^29.5.8", + "@typescript/native-preview": "^7.0.0-dev.20251111.1", "eslint": "^9.8.0", "eslint-config-prettier": "^10.1.8", "jest": "^29.7.0", @@ -2602,6 +2603,123 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript/native-preview": { + "version": "7.0.0-dev.20251111.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20251111.1.tgz", + "integrity": "sha512-IWafo9qVR7sEl/59AYoy7XTkC+rH62QaIKp7PuMYYcNwqjNlFKszGeJtXadqBpyY61lVhtb3xoZ6otsNotAgMg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsgo": "bin/tsgo.js" + }, + "optionalDependencies": { + "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251111.1", + "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251111.1", + "@typescript/native-preview-linux-arm": "7.0.0-dev.20251111.1", + "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251111.1", + "@typescript/native-preview-linux-x64": "7.0.0-dev.20251111.1", + "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251111.1", + "@typescript/native-preview-win32-x64": "7.0.0-dev.20251111.1" + } + }, + "node_modules/@typescript/native-preview-darwin-arm64": { + "version": "7.0.0-dev.20251111.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20251111.1.tgz", + "integrity": "sha512-swE3/8vfsWGp+TNtmmW+amKd1V1cQrwbLSA2MFTiXZt3HUJPnLR8/aaWTkkrMCoLNSJd+KZV76X9Cw6QLAzdGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@typescript/native-preview-darwin-x64": { + "version": "7.0.0-dev.20251111.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20251111.1.tgz", + "integrity": "sha512-vyToe0VYi+Trd9jNyrFersj0ZDtww/IjyoM8oOQN88K6AZEqxkxSxJC8SovCWqmPhfVhb5k/pnaqBE47hc6GLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@typescript/native-preview-linux-arm": { + "version": "7.0.0-dev.20251111.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20251111.1.tgz", + "integrity": "sha512-8WMqKSp3Yq5saVL//BCocUgFnTznAaNajLrFbTOPtfwtlpIUddXM3Imb614NgPb6GX72C44WDB8oNgO7KEBJsQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-linux-arm64": { + "version": "7.0.0-dev.20251111.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20251111.1.tgz", + "integrity": "sha512-o5p3urr5YyrdotWwwqNn/SYJlujICStgqEdukvaWh7vG9UI911Dp7hGFmmn+8UvWubcZm+DBWijkkUJcxIN7Gw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-linux-x64": { + "version": "7.0.0-dev.20251111.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20251111.1.tgz", + "integrity": "sha512-0MEDwP3pt1IeG+MwW/qR2r9d7ZMvYv61a9MJJCjtkFGMm23LL/kitaEEYdeQ6efTeUJDWfRleol1dDkh8aoBEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-win32-arm64": { + "version": "7.0.0-dev.20251111.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20251111.1.tgz", + "integrity": "sha512-ko3sx2l2bzcaCIQ+MDXT/b5FVX2NoSuji5IK/DdZvrbYGgNkh2qUb7Td7RqXaTIE1yaUTEv5PK7UGu1C1qg2EQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@typescript/native-preview-win32-x64": { + "version": "7.0.0-dev.20251111.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20251111.1.tgz", + "integrity": "sha512-XClWd0RpDQ/ouF9d8+gafFHob8XUFAJ49yfLkQqRncRwCXiGfMXyZTbHms+BdyAl5qguv1sgm2YhAWHeaggltQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", diff --git a/package.json b/package.json index ef93bc84..09e6f0e1 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,20 @@ "name": "conformance", "version": "0.1.0", "type": "module", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/conformance/issues", "scripts": { "start": "tsx src/index.ts", "test": "jest", "build": "tsdown src/index.ts --minify --clean --target node20", "lint": "eslint src/ && prettier --check .", "lint:fix": "eslint src/ --fix && prettier --write .", - "lint:fix_check": "npm run lint:fix && git diff --exit-code --quiet" + "lint:fix_check": "npm run lint:fix && git diff --exit-code --quiet", + "check": "npm run typecheck && npm run lint", + "typecheck": "tsgo --noEmit", + "prepack": "npm run build" }, "files": [ "dist" @@ -21,6 +28,7 @@ "@jest/globals": "^29.7.0", "@types/express": "^5.0.3", "@types/jest": "^29.5.8", + "@typescript/native-preview": "^7.0.0-dev.20251111.1", "eslint": "^9.8.0", "eslint-config-prettier": "^10.1.8", "jest": "^29.7.0", diff --git a/src/scenarios/server/server_initialize.ts b/src/scenarios/server/server_initialize.ts deleted file mode 100644 index 5ce53f52..00000000 --- a/src/scenarios/server/server_initialize.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { ClientScenario, ConformanceCheck } from '../../types.js'; -import { serverChecks } from '../../checks/index.js'; - -export class ServerInitializeClientScenario implements ClientScenario { - name = 'server-initialize'; - description = 'Acts as MCP client to test external server initialization'; - - async run(serverUrl: string): Promise { - const checks: ConformanceCheck[] = []; - - try { - const response = await fetch(serverUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json, text/event-stream' - }, - body: JSON.stringify({ - jsonrpc: '2.0', - id: 1, - method: 'initialize', - params: { - protocolVersion: '2025-06-18', - capabilities: {}, - clientInfo: { - name: 'conformance-test-client', - version: '1.0.0' - } - } - }) - }); - - if (!response.ok) { - const responseBody = await response.text(); - throw new Error( - `HTTP ${response.status}: ${response.statusText}. Response body: ${responseBody}` - ); - } - - const responseText = await response.text(); - - // Handle SSE format - let result; - if ( - responseText.startsWith('event:') || - responseText.includes('\ndata:') - ) { - // Parse SSE format - extract JSON from data: lines - const lines = responseText.split('\n'); - const dataLines = lines.filter((line) => line.startsWith('data: ')); - if (dataLines.length > 0) { - const jsonData = dataLines[0].substring(6); // Remove 'data: ' prefix - result = JSON.parse(jsonData); - } else { - throw new Error(`SSE response without data line: ${responseText}`); - } - } else { - // Regular JSON response - result = JSON.parse(responseText); - } - - const check = serverChecks.createServerInitializationCheck(result); - checks.push(check); - } catch (error) { - checks.push({ - id: 'server-initialize-request', - name: 'ServerInitializeRequest', - description: 'Tests server response to initialize request', - status: 'FAILURE', - timestamp: new Date().toISOString(), - errorMessage: `Failed to send initialize request: ${error instanceof Error ? error.message : String(error)}`, - details: { - error: error instanceof Error ? error.message : String(error), - serverUrl - }, - specReferences: [ - { - id: 'MCP-Initialize', - url: 'https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle#initialization' - } - ] - }); - } - - return checks; - } -}