diff --git a/package.json b/package.json index 893e0100..e7fbd0b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/sdk", - "version": "1.1.0", + "version": "1.1.1", "description": "Model Context Protocol implementation for TypeScript", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -19,12 +19,15 @@ "mcp" ], "exports": { - "./*": "./dist/*" + "./*": { + "import": "./dist/esm/*", + "require": "./dist/cjs/*" + } }, "typesVersions": { "*": { "*": [ - "./dist/*" + "./dist/esm/*" ] } }, @@ -32,8 +35,10 @@ "dist" ], "scripts": { - "build": "tsc -p tsconfig.prod.json", - "prepack": "tsc -p tsconfig.prod.json", + "build": "npm run build:esm && npm run build:cjs", + "build:esm": "tsc -p tsconfig.prod.json && echo '{\"type\": \"module\"}' > dist/esm/package.json", + "build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json", + "prepack": "npm run build:esm && npm run build:cjs", "lint": "eslint src/", "test": "jest", "start": "npm run server", diff --git a/src/integration-tests/process-cleanup.test.ts b/src/integration-tests/process-cleanup.test.ts new file mode 100644 index 00000000..0dd7861a --- /dev/null +++ b/src/integration-tests/process-cleanup.test.ts @@ -0,0 +1,28 @@ +import { Server } from "../server/index.js"; +import { StdioServerTransport } from "../server/stdio.js"; + +describe("Process cleanup", () => { + jest.setTimeout(5000); // 5 second timeout + + it("should exit cleanly after closing transport", async () => { + const server = new Server( + { + name: "test-server", + version: "1.0.0", + }, + { + capabilities: {}, + } + ); + + const transport = new StdioServerTransport(); + await server.connect(transport); + + // Close the transport + await transport.close(); + + // If we reach here without hanging, the test passes + // The test runner will fail if the process hangs + expect(true).toBe(true); + }); +}); \ No newline at end of file diff --git a/src/server/index.test.ts b/src/server/index.test.ts index 24543393..7c0fbc51 100644 --- a/src/server/index.test.ts +++ b/src/server/index.test.ts @@ -38,6 +38,7 @@ test("should accept latest protocol version", async () => { name: "test server", version: "1.0", }, + instructions: "Test instructions", }); sendPromiseResolve(undefined); } @@ -57,6 +58,7 @@ test("should accept latest protocol version", async () => { tools: {}, logging: {}, }, + instructions: "Test instructions", }, ); diff --git a/src/server/index.ts b/src/server/index.ts index bf8cd6b2..3901099e 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -34,6 +34,11 @@ export type ServerOptions = ProtocolOptions & { * Capabilities to advertise as being supported by this server. */ capabilities?: ServerCapabilities; + + /** + * Optional instructions describing how to use the server and its features. + */ + instructions?: string; }; /** @@ -73,6 +78,7 @@ export class Server< private _clientCapabilities?: ClientCapabilities; private _clientVersion?: Implementation; private _capabilities: ServerCapabilities; + private _instructions?: string; /** * Callback for when initialization has fully completed (i.e., the client has sent an `initialized` notification). @@ -88,6 +94,7 @@ export class Server< ) { super(options); this._capabilities = options?.capabilities ?? {}; + this._instructions = options?.instructions; this.setRequestHandler(InitializeRequestSchema, (request) => this._oninitialize(request), @@ -250,6 +257,7 @@ export class Server< : LATEST_PROTOCOL_VERSION, capabilities: this.getCapabilities(), serverInfo: this._serverInfo, + ...(this._instructions && { instructions: this._instructions }), }; } diff --git a/src/server/stdio.ts b/src/server/stdio.ts index f0eff82c..30c80012 100644 --- a/src/server/stdio.ts +++ b/src/server/stdio.ts @@ -62,8 +62,19 @@ export class StdioServerTransport implements Transport { } async close(): Promise { + // Remove our event listeners first this._stdin.off("data", this._ondata); this._stdin.off("error", this._onerror); + + // Check if we were the only data listener + const remainingDataListeners = this._stdin.listenerCount('data'); + if (remainingDataListeners === 0) { + // Only pause stdin if we were the only listener + // This prevents interfering with other parts of the application that might be using stdin + this._stdin.pause(); + } + + // Clear the buffer and notify closure this._readBuffer.clear(); this.onclose?.(); } diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json new file mode 100644 index 00000000..058a5d9a --- /dev/null +++ b/tsconfig.cjs.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "outDir": "./dist/cjs" + }, + "exclude": ["**/*.test.ts"] +} diff --git a/tsconfig.prod.json b/tsconfig.prod.json index e7fd55c0..2c68666e 100644 --- a/tsconfig.prod.json +++ b/tsconfig.prod.json @@ -1,6 +1,7 @@ { "extends": "./tsconfig.json", - "exclude": [ - "**/*.test.ts", - ] + "compilerOptions": { + "outDir": "./dist/esm" + }, + "exclude": ["**/*.test.ts"] }