{"_id":"@almyty/mcp-mux","_rev":"5-b96c193fc6d927b8cdd8c185305677fc","name":"@almyty/mcp-mux","dist-tags":{"latest":"1.5.2"},"versions":{"1.2.0":{"name":"@almyty/mcp-mux","version":"1.2.0","keywords":["almyty","mcp","multiplexer","stdio","proxy"],"author":{"name":"almyty"},"license":"Apache-2.0","_id":"@almyty/mcp-mux@1.2.0","maintainers":[{"name":"fbandov","email":"frane.bandov@gmail.com"}],"homepage":"https://almyty.com","bugs":{"url":"https://github.com/almyty-inc/almyty/issues"},"dist":{"shasum":"e2bf65f25ab5e15dac81e11ef04e6b08579ca140","tarball":"https://registry.npmjs.org/@almyty/mcp-mux/-/mcp-mux-1.2.0.tgz","fileCount":26,"integrity":"sha512-MHbQBG9Qld8cbCoiYIqE6PKUbSV7JE983Gnjx60xyX0wkqzUI/FmiuaWnqB4qI07ZFhsYLoK107S7Lw7Asm0nw==","signatures":[{"sig":"MEYCIQCWsW5LzUwwThydzBGkJcR1cN41UbeCTmCjevs6ycjRuAIhAKb/fKxbj+qYaxuVkznUd07rn5u98mIR7LVhNAX4qydJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":56664},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"41ec65ce0d78bc89851e0492c4fa7c20d00b4758","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"fbandov","email":"frane.bandov@gmail.com"},"repository":{"url":"git+https://github.com/almyty-inc/almyty.git","type":"git","directory":"packages/mcp-mux"},"_npmVersion":"11.11.0","description":"stdio-MCP multiplexer — fans many client sessions into one downstream MCP child over a Unix socket, rewriting ids. Internal almyty plumbing.","directories":{},"_nodeVersion":"24.14.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.0","typescript":"^5.3.0","@types/node":"^25.4.0"},"_npmOperationalInternal":{"tmp":"tmp/mcp-mux_1.2.0_1784829837503_0.5769153645001852","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@almyty/mcp-mux","version":"1.3.0","keywords":["almyty","mcp","multiplexer","stdio","proxy"],"author":{"name":"almyty"},"license":"Apache-2.0","_id":"@almyty/mcp-mux@1.3.0","maintainers":[{"name":"fbandov","email":"frane.bandov@gmail.com"}],"homepage":"https://almyty.com","bugs":{"url":"https://github.com/almyty-inc/almyty/issues"},"dist":{"shasum":"b2ea5d4f5b8dc829ee394bf00d374c295844b967","tarball":"https://registry.npmjs.org/@almyty/mcp-mux/-/mcp-mux-1.3.0.tgz","fileCount":26,"integrity":"sha512-R+vAXdMPFotTZrQSk/8UZTWHwBL4VeaZFLiPoJCMJKblbQvUqfXC4P5Y4NCTwpKYs5jJ32l/Y4Ota3UIAavp9A==","signatures":[{"sig":"MEQCIDdt69nazDrd9iNykcyErOI5U6Sy+upKwR7KH0XTS/9PAiAIUNOhvOj72uxasXn3jgc6MbWuKl9oNqgMJvaPh0hM+Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC5/fanWsX1+tu5nqwtHoSXozPnFuGnpe44Yjshp3R39wIgIQ5Y1mdOxpV6qu0Tr5xZddiCXEzO9M+BBMzulaRYXBM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@almyty%2fmcp-mux@1.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":56984},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"02e35f50189872ea6d418f229ad6473aada0185e","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:88fc84df-ac4d-434f-94cf-8b0b4039bfb1"}},"overrides":{"postcss":"^8.5.23"},"repository":{"url":"git+https://github.com/almyty-inc/almyty.git","type":"git","directory":"packages/mcp-mux"},"_npmVersion":"12.0.2","description":"Share one stdio MCP server subprocess across many concurrent clients over a Unix socket — remaps request ids, serializes writes, respawns on crash. Internal almyty plumbing.","directories":{},"_nodeVersion":"26.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.11","typescript":"^5.3.0","@types/node":"^25.4.0"},"_npmOperationalInternal":{"tmp":"tmp/mcp-mux_1.3.0_1790082057315_0.7101022496880034","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@almyty/mcp-mux","version":"1.5.0","keywords":["almyty","mcp","multiplexer","stdio","proxy"],"author":{"name":"almyty"},"license":"Apache-2.0","_id":"@almyty/mcp-mux@1.5.0","maintainers":[{"name":"fbandov","email":"frane.bandov@gmail.com"}],"homepage":"https://almyty.com","bugs":{"url":"https://github.com/almyty-inc/almyty/issues"},"dist":{"shasum":"adc605450ec1818316f59defad1a0d4efdefb078","tarball":"https://registry.npmjs.org/@almyty/mcp-mux/-/mcp-mux-1.5.0.tgz","fileCount":26,"integrity":"sha512-ByyQwHJc108izDVSIdgUP+R8/u2YB9Z44yW9f6Ei7PrWjdt2STEANKKMbm5y3lophuS7HG2U9QFwzkjXzxRcNQ==","signatures":[{"sig":"MEYCIQDRF8L/KpRrzZ7h6kISmd0kFcsG3bgAljBu2A6gSwGyOQIhAKeELSnrlA4MOSY4/wriMTv17dgXzeBnPfLFgyz1E3Yt","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCBp4YABoqzBSBVZkHv1jurg44LpLD2Rn7ds89XQB3E5QIgee5QlQ9LdiCD98wwlv2F4ByyER6e7hDWQLrN+lXIGFU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@almyty%2fmcp-mux@1.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":56984},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"fcf0cd631aea9dc693ecf08a254327c70f678837","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:88fc84df-ac4d-434f-94cf-8b0b4039bfb1"}},"overrides":{"postcss":"^8.5.23"},"repository":{"url":"git+https://github.com/almyty-inc/almyty.git","type":"git","directory":"packages/mcp-mux"},"_npmVersion":"12.0.2","description":"Share one stdio MCP server subprocess across many concurrent clients over a Unix socket — remaps request ids, serializes writes, respawns on crash. Internal almyty plumbing.","directories":{},"_nodeVersion":"26.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.11","typescript":"^5.3.0","@types/node":"^25.4.0"},"_npmOperationalInternal":{"tmp":"tmp/mcp-mux_1.5.0_1790082656181_0.7260842213472241","host":"s3://npm-registry-packages-npm-production"}},"1.5.1":{"name":"@almyty/mcp-mux","version":"1.5.1","keywords":["almyty","mcp","multiplexer","stdio","proxy"],"author":{"name":"almyty"},"license":"Apache-2.0","_id":"@almyty/mcp-mux@1.5.1","maintainers":[{"name":"fbandov","email":"frane.bandov@gmail.com"}],"homepage":"https://almyty.com","bugs":{"url":"https://github.com/almyty-inc/almyty/issues"},"dist":{"shasum":"f8cea5e66a05dfce6c588bd93e91cbe55af39a25","tarball":"https://registry.npmjs.org/@almyty/mcp-mux/-/mcp-mux-1.5.1.tgz","fileCount":26,"integrity":"sha512-mWXoF8QLOLNap55HCJ7DB0UaIofeV2Kw3roJg9fj4KmStMoo2273vvm3G8p4F6KbW0pJJYZ/IhHeaTUTgOQrDA==","signatures":[{"sig":"MEUCIQDaysZFokk3uazX+IaAEeAsdVooXntd2FLYV457znmEzgIgcljDdGJ0i1Nmzpat06sMVIdk7Gsuce5VLF7wEMTIPHg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCa4GsUxZdfF0S4SSYb3zvzKliRcL2WTUwD2WC008ZTWwIgPGCbKNVHxmf6LVZhCyzFIQaR8pjIC2igdfSW3iWtEsg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@almyty%2fmcp-mux@1.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":56984},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"3d1a25517622fa2f419278890694916379c42fe8","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"88fc84df-ac4d-434f-94cf-8b0b4039bfb1"}},"overrides":{"postcss":"^8.5.23"},"repository":{"url":"git+https://github.com/almyty-inc/almyty.git","type":"git","directory":"packages/mcp-mux"},"_npmVersion":"12.1.0","description":"Share one stdio MCP server subprocess across many concurrent clients over a Unix socket — remaps request ids, serializes writes, respawns on crash. Internal almyty plumbing.","directories":{},"_nodeVersion":"26.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.11","typescript":"^5.3.0","@types/node":"^25.4.0"},"_npmOperationalInternal":{"tmp":"tmp/mcp-mux_1.5.1_1790764729488_0.3074587663842847","host":"s3://npm-registry-packages-npm-production"}},"1.5.2":{"_id":"@almyty/mcp-mux@1.5.2","bugs":{"url":"https://github.com/almyty-inc/almyty/issues"},"dist":{"shasum":"86d736aa40b51f0019c9e34e7afe6833124b16b1","tarball":"https://registry.npmjs.org/@almyty/mcp-mux/-/mcp-mux-1.5.2.tgz","fileCount":26,"integrity":"sha512-l/YLGWaUiJKMSM71C89yBmT4zFhkeAOyu61UNfvlGv5ves2l9xhO6fRtRnLmXh1DMePb7XH7LBrJtoWv0DrxIQ==","signatures":[{"sig":"MEUCIEw20xuu3DS9qQIUfWXtiWGLqfzpQHAyZ3JVbfWzXmQFAiEAskmWldtzLDfnxom+5sZZ2LyCEhRj7428uANpfN3ObdY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFWNnvZTHn7HiPuaa+SdIY4hfo2nSRpfpFnZggaHIiYMAiEAk2eXrlhBWvbpDxYCJGi6bgNJjPiGWHJHuCBTMIAUe9Y="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@almyty%2fmcp-mux@1.5.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":56984},"main":"dist/index.js","name":"@almyty/mcp-mux","type":"module","types":"dist/index.d.ts","author":{"name":"almyty"},"engines":{"node":">=20"},"gitHead":"65014b3488d69abba245b0d7012e3ecc7ed002be","license":"Apache-2.0","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"version":"1.5.2","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"88fc84df-ac4d-434f-94cf-8b0b4039bfb1"}},"homepage":"https://almyty.com","keywords":["almyty","mcp","multiplexer","stdio","proxy"],"overrides":{"postcss":"^8.5.23"},"repository":{"url":"git+https://github.com/almyty-inc/almyty.git","type":"git","directory":"packages/mcp-mux"},"_npmVersion":"12.2.0","description":"Share one stdio MCP server subprocess across many concurrent clients over a Unix socket — remaps request ids, serializes writes, respawns on crash. Internal almyty plumbing.","directories":{},"maintainers":[{"name":"fbandov","email":"frane.bandov@gmail.com"}],"_nodeVersion":"26.10.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.11","typescript":"^5.3.0","@types/node":"^25.4.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-mux_1.5.2_1790869116541_0.582609906321991"}}},"time":{"created":"2026-07-23T18:03:57.261Z","modified":"2026-10-01T15:38:37.115Z","1.2.0":"2026-07-23T18:03:57.664Z","1.3.0":"2026-09-22T13:00:57.411Z","1.5.0":"2026-09-22T13:10:56.263Z","1.5.1":"2026-09-30T10:38:49.564Z","1.5.2":"2026-10-01T15:38:36.634Z"},"bugs":{"url":"https://github.com/almyty-inc/almyty/issues"},"author":{"name":"almyty"},"license":"Apache-2.0","homepage":"https://almyty.com","keywords":["almyty","mcp","multiplexer","stdio","proxy"],"repository":{"url":"git+https://github.com/almyty-inc/almyty.git","type":"git","directory":"packages/mcp-mux"},"description":"Share one stdio MCP server subprocess across many concurrent clients over a Unix socket — remaps request ids, serializes writes, respawns on crash. Internal almyty plumbing.","maintainers":[{"name":"fbandov","email":"frane.bandov@gmail.com"}],"readme":"# @almyty/mcp-mux\n\n**Share one stdio MCP server across many clients.** An MCP server launched as a\nsubprocess has a single stdin/stdout and normally serves one client at a time.\nThis library puts it behind a Unix socket so several clients can use it at once —\nremapping request ids so each response routes back to the right client,\nserializing writes so messages never interleave, and respawning the child if it\ncrashes.\n\n> Used internally by almyty when it proxies **to** a downstream MCP server. It\n> only handles that proxy-to-server direction; it is not involved in serving\n> almyty's own agents to clients over ACP or A2A.\n\n## Why\n\nA stdio MCP server is a single process with one stdin/stdout pair. If several\nsessions write to it concurrently you get interleaved framing and JSON-RPC `id`\ncollisions (two clients both pick `id: 1`; responses can't be told apart). This\npackage puts the child behind a proxy that:\n\n- **rewrites** every client request `id` to a global monotonic proxy id and\n  reverse-maps `{proxyId -> (sessionId, originalId)}`, so colliding client ids\n  never alias and each response routes home with its original id restored;\n- **serializes** stdin writes through a single async queue, so concurrent\n  sessions can never interleave a frame;\n- **routes** each response to its issuing session; load-and-delete on the id-map\n  means a duplicate/late response is dropped, never double-routed;\n- **isolates teardown**: closing one session drops only that session's mappings,\n  leaving every other session's in-flight requests intact;\n- **survives downstream death**: on child exit, all in-flight requests are\n  errored (`-32011`), the id-map is cleared, and the child is respawned with\n  exponential backoff (3s → 30s).\n\n## Architecture\n\n```\n clients ──unix socket──► SocketListener ──Session──┐\n                                                    ├──► McpStdioMux ──Downstream──► child stdio MCP\n Supervisor ──spawn/respawn/reap──► NodeDownstream ─┘     (id remap, write queue,\n   (FSM + error-path resource ledger)                      response routing, TTL sweep)\n```\n\n- `McpStdioMux` — pure logic, owns NO process or socket. Fully unit-testable\n  with in-process fakes (`Downstream` / `Session` are the test seams).\n- `Supervisor` — owns the child lifecycle + respawn/teardown FSM, and enforces\n  the **error-path resource-ownership invariant** (see below).\n- `NodeDownstream` / `SocketListener` — the only files that touch\n  `child_process` / `net`.\n\n### The FD-leak invariant\n\nThe reference implementation this was specced against leaked a log fd: `Start()`\nopened it, then errored *before* registering for `Stop()`, so the fd was never\nclosed — repeated failing attaches drained the fd budget over hours.\n\n`Supervisor.start()` pre-empts that bug class with an **acquire ledger**: every\nresource acquired is pushed onto a release list *before* the next acquisition.\nIf anything throws before the ownership-transfer point, the ledger is unwound in\nreverse. The `FD-LEAK HAMMER` test runs 500 failing starts and asserts the net\nopen-handle count returns to zero.\n\n## Usage\n\n```ts\nimport { createStdioMux } from '@almyty/mcp-mux';\n\nconst handle = await createStdioMux({\n  socketPath: '/tmp/my-mcp.sock',\n  downstream: { command: 'npx', args: ['-y', 'some-mcp-server'] },\n  supervisor: { backoffBaseMs: 3000, backoffCapMs: 30000 },\n});\n\n// ... clients connect to the socket and speak newline-delimited JSON-RPC ...\n\nawait handle.close(); // stop accepting, reap child, release resources\n```\n\n## Design note\n\nFull design — id-map lifecycle, framing serialization, response routing, the\nrespawn/teardown state machine, and error-path resource ownership — lives in\n[`DESIGN.md`](./DESIGN.md).\n\n## Develop\n\n```bash\nnpm install\nnpm run typecheck   # tsc --noEmit (includes tests)\nnpm test            # vitest run\nnpm run build       # emits dist/ (tests excluded)\n```\n\n## About almyty\n\nalmyty is the full-stack platform for AI agents, agnostic by design: any LLM, any\nAPI turned into tools, served over MCP, A2A, UTCP, and Agent Skills. Open source,\nno lock-in.\n\n- Website: https://almyty.com\n- Docs: https://docs.almyty.com\n- Source: https://github.com/almyty-inc/almyty\n\nApache-2.0 © Almyty Inc.\n","readmeFilename":"README.md"}