{"id":11371,"library":"mutation-server-protocol","title":"Mutation Server Protocol Specification","description":"The `mutation-server-protocol` package defines the Mutation Server Protocol (MSP), a standardized, language-agnostic specification based on JSON-RPC 2.0. Its purpose is to enable seamless communication between Integrated Development Environments (IDEs) or other tools and mutation testing frameworks. Inspired by the Language Server Protocol, MSP establishes a unified method for initiating mutation tests, reporting their progress, and exchanging structured data like mutation locations and results. The current stable version is 0.4.2, with recent minor updates in March 2026, indicating active maintenance within the Stryker Mutator monorepo. Key differentiators include its explicit focus on mutation testing, support for both Standard Input/Output (stdio) and TCP/IP Socket transport modes, and detailed message formats for operations such as mutant discovery and execution. It emphasizes 1-based indexing for positions and locations, aligning with common text editor conventions.","status":"active","version":"0.4.1","language":"javascript","source_language":"en","source_url":"https://github.com/stryker-mutator/editor-plugins","tags":["javascript","msp","mutation-testing-protocol","mutation-testing","stryker","stryker-net","stryker-js","stryker4s","typescript"],"install":[{"cmd":"npm install mutation-server-protocol","lang":"bash","label":"npm"},{"cmd":"yarn add mutation-server-protocol","lang":"bash","label":"yarn"},{"cmd":"pnpm add mutation-server-protocol","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"This package primarily ships TypeScript types and interfaces; use `import type` for clarity and better tree-shaking.","wrong":"import { MutationServer } from 'mutation-server-protocol';","symbol":"MutationServer","correct":"import type { MutationServer } from 'mutation-server-protocol';"},{"note":"Types are not directly consumable as runtime objects. CommonJS `require` is not recommended for type imports and this package targets Node.js >=18, favoring ESM.","wrong":"const { DiscoverParams } = require('mutation-server-protocol');","symbol":"DiscoverParams, MutationTestParams","correct":"import type { DiscoverParams, MutationTestParams } from 'mutation-server-protocol';"},{"note":"While `* as protocol` might work for types, it's generally best practice to import specific types as needed for clarity and to avoid pulling in unnecessary definitions.","wrong":"import * as protocol from 'mutation-server-protocol';","symbol":"FileRange","correct":"import type { FileRange } from 'mutation-server-protocol';"}],"quickstart":{"code":"import type {\n  MutationServer,\n  DiscoverParams,\n  MutationTestParams,\n  MutationTestResult,\n  FileRange,\n  Mutant,\n  Location,\n} from 'mutation-server-protocol';\n\n// Simulate a basic JSON-RPC message handler implementing the MSP server interface\nclass MyMutationServer implements MutationServer {\n  private requestIdCounter = 0;\n\n  // MSP method: discover mutants in a given scope\n  async discover(params: DiscoverParams): Promise<Mutant[]> {\n    console.log(`[Server] Received discover request for files: ${params.files?.map(f => f.fileName).join(', ')}`);\n    // In a real server, this would analyze code to find potential mutants\n    const mutants: Mutant[] = [\n      {\n        id: 'mutant-1',\n        mutatorName: 'BinaryExpression',\n        replacement: 'false', // Example replacement\n        location: { start: { line: 1, column: 10 }, end: { line: 1, column: 15 } },\n        fileName: 'src/example.js',\n        status: 'Pending'\n      },\n    ];\n    return mutants;\n  }\n\n  // MSP method: run mutation tests for specific mutants\n  async mutationTest(params: MutationTestParams): Promise<MutationTestResult> {\n    console.log(`[Server] Received mutationTest request for mutants: ${params.mutants?.map(m => m.id).join(', ')}`);\n    // In a real server, this would execute tests against mutated code\n    const result: MutationTestResult = {\n      mutantResults: {\n        'mutant-1': { status: 'Killed', coveredBy: ['testA'] },\n      },\n      // ... other results like files, test results\n    };\n    return result;\n  }\n\n  // Example of how a client might construct and send a request\n  async simulateClientRequest() {\n    const server = new MyMutationServer();\n\n    const discoverRequest = {\n      jsonrpc: '2.0',\n      id: ++this.requestIdCounter,\n      method: 'discover',\n      params: {\n        files: [{ fileName: 'src/example.js' } as FileRange],\n        // Optional other params like 'testFramework'\n      } as DiscoverParams,\n    };\n\n    console.log('\\n[Client] Sending discover request:', JSON.stringify(discoverRequest, null, 2));\n    const discoverResponse = await server.discover(discoverRequest.params);\n    console.log('[Client] Received discover response:', JSON.stringify(discoverResponse, null, 2));\n\n    const mutationTestRequest = {\n      jsonrpc: '2.0',\n      id: ++this.requestIdCounter,\n      method: 'mutationTest',\n      params: {\n        mutants: discoverResponse.slice(0, 1), // Test the first discovered mutant\n        // Optional other params\n      } as MutationTestParams,\n    };\n\n    console.log('\\n[Client] Sending mutationTest request:', JSON.stringify(mutationTestRequest, null, 2));\n    const mutationTestResponse = await server.mutationTest(mutationTestRequest.params);\n    console.log('[Client] Received mutationTest response:', JSON.stringify(mutationTestResponse, null, 2));\n  }\n}\n\nconst simulator = new MyMutationServer();\nsimulator.simulateClientRequest();","lang":"typescript","description":"Demonstrates defining a basic Mutation Server Protocol handler using its TypeScript types and simulates client-server message exchange for `discover` and `mutationTest` methods."},"warnings":[{"fix":"Review all code interacting with location and position objects. Ensure correct 1-based indexing and `start` (inclusive), `end` (exclusive) interpretations, especially when converting from 0-based editor APIs.","message":"The semantics for `position` and `location` fields were clarified and aligned with the `mutation-testing-report-schema` in version `0.3.0`. Positions are now 1-based, with `start` being inclusive and `end` exclusive.","severity":"breaking","affected_versions":">=0.3.0"},{"fix":"Update client-side parsing logic to correctly handle the new `files` property within the response objects returned by `discover` and `mutationTest`.","message":"The response objects for `discover` and `mutationTest` methods were extended in version `0.2.0` to include a `files` property. Clients built against `0.1.x` might fail to parse the new response structure.","severity":"breaking","affected_versions":">=0.2.0"},{"fix":"Implement both `stdio` and `socket` transport mechanisms in your server. Ensure server startup correctly parses the required `<channel>`, `--port`, and `--address` arguments as specified in the protocol.","message":"As of `0.4.0`, mutation servers are required to support both `stdio` and `socket` transport modes and adhere to a specific command-line argument format for `--port` and `--address` when using `socket`.","severity":"gotcha","affected_versions":">=0.4.0"},{"fix":"Redirect all server-side logging and debugging output to standard error (`stderr`) when `stdio` transport is active to maintain protocol integrity.","message":"When using `stdio` transport, the protocol strictly reserves standard output (`stdout`) for JSON-RPC messages only. Any logging or debugging information written to `stdout` will corrupt the message stream.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure all messages sent over `stdio` or `socket` transports adhere to the base protocol's framing: `Content-Length: <length>\\r\\n\\r\\n{json_payload}`.","cause":"The incoming JSON-RPC message is not correctly framed with the required `Content-Length` header followed by `\\r\\n\\r\\n` before the JSON payload.","error":"Content-Length header missing or invalid"},{"fix":"Choose an available port number, or ensure no other application is using the intended port before starting the mutation server.","cause":"When running the server in `socket` mode, the specified `--port` is already occupied by another process.","error":"Error: listen EADDRINUSE: address already in use :::<port>"},{"fix":"Ensure `FileRange` objects always include a `fileName` string. Validate that the `files` array matches the `FileRange[]` type definition.","cause":"A `FileRange` object passed to `discover` or `mutationTest` (e.g., in the `files` array) is missing the required `fileName` property, or the `files` array itself is not properly structured.","error":"TypeError: Cannot read properties of undefined (reading 'fileName') for FileRange"}],"ecosystem":"npm"}