{"_id":"@behavioralstate/best-mcp","_rev":"12-043dd13215c4cdf62ae3c0c7ed77e31d","name":"@behavioralstate/best-mcp","dist-tags":{"latest":"2.3.6"},"versions":{"2.0.0":{"name":"@behavioralstate/best-mcp","version":"2.0.0","_id":"@behavioralstate/best-mcp@2.0.0","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"fc442bcf4b9a86304719cdc3246c3948fc9ac38a","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.0.0.tgz","fileCount":5,"integrity":"sha512-hXqlJyhWg8GlOAkoOdVszlq9iNEtL4o2AXzInYLfsJz3+4FpY2IBnjIahmywZ79z7oU5KPs1XWjh5XNp9UBWMg==","signatures":[{"sig":"MEQCIFTUuBa2Na24SOt+gfl4vBiI1zQhmfKi/CvkRB20M2LEAiBvc746jpZiAS+N2h3MsY0Fhv06ir7IVlP0NaXVwW6oPw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":106413},"type":"module","gitHead":"9b9be027d062c694f9b08920d8c1f7b97ef53410","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.0.0_1784753410298_0.12680197133122517","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@behavioralstate/best-mcp","version":"2.0.1","_id":"@behavioralstate/best-mcp@2.0.1","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"0665150875ad41af295c8c3c1d07e4bc3a9c5c44","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.0.1.tgz","fileCount":5,"integrity":"sha512-B+tjre1TcKABFVGXIWAvDen3rdnbii4nlDlDl2eZAxaAoKjczByCXkLQCManin4Y3G5XINa46+NEOVpsi+j27g==","signatures":[{"sig":"MEUCIBanDkITodz8aWQxZRV+rvcsq6R6psxJmHXw++uxIVM9AiEAuhC012xGjiNOagil/QVW5TDoD1TlCtvyuD/osxxEFWc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":114774},"type":"module","gitHead":"45e4d0be79dfdc5ecd05529b387ae3df9f1ecff4","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.0.1_1785832893173_0.9907248190822813","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@behavioralstate/best-mcp","version":"2.1.0","_id":"@behavioralstate/best-mcp@2.1.0","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"ce33ee0e9106a35558510a33f28e5595153c9941","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.1.0.tgz","fileCount":5,"integrity":"sha512-xDphLBHJrmWMaXaDojRO5NLG30bH4V8OeOmr13lPgCdNGUMMvLGHf21DQGyOcdo0dSs1yZQJULl5iGzF4fctxg==","signatures":[{"sig":"MEYCIQC4NB/hoNn/s5bc98uHQbLEKxRxKKaonbxG6xhMYQJgywIhAMRLgWS0IQEvLx1aSXBK4ok44C0KC8X4W4bIeLKKTJRc","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":124029},"type":"module","gitHead":"88dda7556bc6fd0d670177d18dd7abc3b39d9ded","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.1.0_1785833893621_0.9713848525502617","host":"s3://npm-registry-packages-npm-production"}},"2.2.0":{"name":"@behavioralstate/best-mcp","version":"2.2.0","_id":"@behavioralstate/best-mcp@2.2.0","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"40b25c6487ec8d26300ddc120022bcd3ab1f4dca","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.2.0.tgz","fileCount":5,"integrity":"sha512-jN6d0kzEL+zmdiIjd8KtBGZdGLARJ9LVq92sUHU2Zgl5OcWhLbabxWnLnld5E1rhx2x09JHLRrNUYqQOZ8fWJA==","signatures":[{"sig":"MEYCIQCGTXUCpTX2y+EqdrN+Vyb+S2Lpc0s+cXhUvi73969+qAIhAP/qh/m4sRpBNDbFYfDypBWjTu4CVV8BIllghZDIKkC5","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":153637},"type":"module","gitHead":"9183a5f3bd4171626707417070fdc5870b2b0ea8","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.2.0_1786631057627_0.8778300864710817","host":"s3://npm-registry-packages-npm-production"}},"2.2.1":{"name":"@behavioralstate/best-mcp","version":"2.2.1","_id":"@behavioralstate/best-mcp@2.2.1","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"209bc0299396d6504d3475ffe637491b66d83a9b","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.2.1.tgz","fileCount":5,"integrity":"sha512-DKqvV31s6ZHlZjwJgoV5FzgxWzTJ+gjtHXFz9ecK51A0etzfAaR2geeozsOphSH8ZMMSciHnoXqzaLVfE8VKsw==","signatures":[{"sig":"MEUCIBNzIEufCQlW0EW7QfvtR2em2CU6azO+27tL6hXqxNayAiEAoqTpwEr33vtnfMKC/jsyaTnEuMmgaS4SLSC3edu4R4k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":159321},"type":"module","gitHead":"90bc781c82813a5d8d96358452c2193f11f667aa","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.2.1_1787574902653_0.4807914983321062","host":"s3://npm-registry-packages-npm-production"}},"2.3.0":{"name":"@behavioralstate/best-mcp","version":"2.3.0","_id":"@behavioralstate/best-mcp@2.3.0","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"49dc73e8ce42311ec6b576769ee65852845085b8","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.3.0.tgz","fileCount":5,"integrity":"sha512-rvdrTV8K5QXl0x3CPSl+ayD/eMUsA/2sfmVQdoopbafOG+z8/ozt731OeJtTF26AV4s5pKuqCiSmN4ltMFQYaA==","signatures":[{"sig":"MEUCIFAmEBhD0rR2p8CxShY4AHCp5fis201PuVMuJji2jrbWAiEAif8ySk1uTCby5/7X9ZOYnJpXXJZg7hvHmre8Ti+NSiU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":164933},"type":"module","gitHead":"8821740eaed13839862eb34153565f1ecc751b87","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.3.0_1787745324540_0.8108766971155241","host":"s3://npm-registry-packages-npm-production"}},"2.3.1":{"name":"@behavioralstate/best-mcp","version":"2.3.1","_id":"@behavioralstate/best-mcp@2.3.1","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"28ad03864a689e8941645135979691a56b50307e","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.3.1.tgz","fileCount":5,"integrity":"sha512-YatwDHzk49USg4kM7F+8OoChEnf2jfwgGUxWLUKRzPRLuCG6EbC1mcx5dqTgVp3L0okR70/Mh9ObTbIJwiw72w==","signatures":[{"sig":"MEQCIA7TAJyEruBLJ1uR/y1KxelK/4juHfAffa7Nb098VqfTAiBXdP4Nt2C8We0DyPeTOEA5dZALUhRQyyIM65r1mpi+AA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":167583},"type":"module","gitHead":"e6ad8d6eda165a4c4a9e8a92ae5974f823a6d579","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.3.1_1787750628000_0.33591918721677727","host":"s3://npm-registry-packages-npm-production"}},"2.3.2":{"name":"@behavioralstate/best-mcp","version":"2.3.2","_id":"@behavioralstate/best-mcp@2.3.2","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"767bbc0593b5a54b554efa305e608de63b2abc13","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.3.2.tgz","fileCount":5,"integrity":"sha512-EP8cH6wPClWvMrtTRMPciUAm5ly4uTHFDRu62ShoXKzS0YX4abRf1CAwEWGapEZxwRmeEraqUv3K1K9ym+/DVw==","signatures":[{"sig":"MEQCICrFJpokLPNWSLawlJi2mVUSCSr/ohwc0lDzR9FvMDj/AiATBvYmIWdcrKUYxDGlupbg43TjwqrNdprSWifpavJsNQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":173765},"type":"module","gitHead":"aa9065aa224318528b60b897908f16860b378dd9","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.3.2_1787751605273_0.9922263885654592","host":"s3://npm-registry-packages-npm-production"}},"2.3.3":{"name":"@behavioralstate/best-mcp","version":"2.3.3","_id":"@behavioralstate/best-mcp@2.3.3","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"4327b4aa1313a7e3a3083fabde0497c285922202","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.3.3.tgz","fileCount":5,"integrity":"sha512-UrSE6iyLrTU5gHQ4m/hGw+fOPbRn1IBSRKeMHB6kTKbqNF0CN6Geo+meXo8TScZet2vq8KEgbV3ll0hSBXqd4w==","signatures":[{"sig":"MEYCIQDt2xNq0+0k6UEplKCivGs+d5jVjqdrev7UMfjKJyIi9gIhAIyG+cwLQZ0xMJbqm9uLd+4l/0KGhlTnBJ9G8ZWkduxX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":174888},"type":"module","gitHead":"89a3e9e2604510795933f9653c05623123b50b4f","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.3.3_1787752333764_0.8050047882938909","host":"s3://npm-registry-packages-npm-production"}},"2.3.4":{"name":"@behavioralstate/best-mcp","version":"2.3.4","_id":"@behavioralstate/best-mcp@2.3.4","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"971e3bae93f1128d22b522483c36e32d2cb55676","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.3.4.tgz","fileCount":5,"integrity":"sha512-+v26GArSR8ptwNAsTjZWmM9KzDkbXPl65SbvSBI2Hx5ELsCbV0nwXmCawvbADVocunxpQRCZB4HX+ku0pu2lHA==","signatures":[{"sig":"MEYCIQCjslf2NFSub/GUxzYFL11Z76wXEpmB7ygtrRsc5pSlfQIhAJSdt0zvMLdlkkXySnlw0StZ2CIUlKPhkzeZmsVqheQb","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":181003},"type":"module","gitHead":"00326ab862a8f7a21581e52827c161016023029c","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.3.4_1787762369858_0.08481616141014747","host":"s3://npm-registry-packages-npm-production"}},"2.3.5":{"name":"@behavioralstate/best-mcp","version":"2.3.5","_id":"@behavioralstate/best-mcp@2.3.5","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"bin":{"best-mcp":"dist/index.js"},"dist":{"shasum":"cfa55b2e98424122536572001e893ef5412975a7","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.3.5.tgz","fileCount":5,"integrity":"sha512-vZPknCOIctmoPSg1SUten2emiGiDeG5lBo68ysRol5b2n+zTlK4GHYwXYEyiWbjvNVpW2Z2yY8msiPcLO8bj6g==","signatures":[{"sig":"MEQCIFjLKeDA1Pzo3SaVm497mciNgikChz6iqrnA1zmKsaCNAiAFQZds74i3LNhaKPgS2tFusk+mm1Ca7KumkEH+y75bLQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":205639},"type":"module","gitHead":"3fa30300086189c516f8bb6db229722267a7a4cd","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"_npmVersion":"10.8.2","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","typescript":"^5.9.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/best-mcp_2.3.5_1789375680399_0.248437611245381","host":"s3://npm-registry-packages-npm-production"}},"2.3.6":{"name":"@behavioralstate/best-mcp","version":"2.3.6","description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","type":"module","bin":{"best-mcp":"dist/index.js"},"scripts":{"build":"tsc","dev":"tsx src/index.ts","start":"node dist/index.js","prepublishOnly":"npm run build"},"dependencies":{"@modelcontextprotocol/sdk":"^1.10.1"},"devDependencies":{"@types/node":"^24.0.0","tsx":"^4.21.0","typescript":"^5.9.3"},"_id":"@behavioralstate/best-mcp@2.3.6","gitHead":"81b4e8f912187f43d37b4afccb49b28f7ad54c89","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-1uIaLhtJxDxbqCGUS641AOGW4k4/MmfrfCFbZWZwiPtApOiBMxtSTKk3F9qA387uMxTI4/IBqJHs3ivNLBNOow==","shasum":"6c3c72ce47095291133fe001340c018e9b5f01db","tarball":"https://registry.npmjs.org/@behavioralstate/best-mcp/-/best-mcp-2.3.6.tgz","fileCount":5,"unpackedSize":223239,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD/6A99XUjAJ7xOqDThMdKHvbk78xoTI3kW6UQLhFAJBQIgDfnoZIyASoDE/zX7DXVb9IlCpATDI897GRNNJqN/3Xs="}]},"_npmUser":{"name":"riccardone","email":"riccardo@dinuzzo.it"},"directories":{},"maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/best-mcp_2.3.6_1789378624130_0.3744682249714477"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-22T20:50:10.158Z","modified":"2026-09-14T09:37:04.482Z","2.0.0":"2026-07-22T20:50:10.474Z","2.0.1":"2026-08-04T08:41:33.302Z","2.1.0":"2026-08-04T08:58:13.758Z","2.2.0":"2026-08-13T14:24:17.788Z","2.2.1":"2026-08-24T12:35:02.800Z","2.3.0":"2026-08-26T11:55:24.691Z","2.3.1":"2026-08-26T13:23:48.137Z","2.3.2":"2026-08-26T13:40:05.414Z","2.3.3":"2026-08-26T13:52:13.908Z","2.3.4":"2026-08-26T16:39:29.991Z","2.3.5":"2026-09-14T08:48:00.529Z","2.3.6":"2026-09-14T09:37:04.268Z"},"description":"MCP server for any BEST-compliant endpoint — exposes commands and queries as tools for LLM clients","maintainers":[{"name":"riccardone","email":"riccardo@dinuzzo.it"}],"readme":"# best-mcp\r\n\r\nMCP server for any [BEST-compliant](https://behavioralstate.io) endpoint. Exposes the BEST command and query surface as MCP tools so any LLM client (ChatGPT Desktop, Claude Desktop, GitHub Copilot, Cursor) can discover and interact with a BEST service.\r\n\r\nSupports **multiple named connections** in a single server instance — useful for admins who need to operate across tenant-scoped and platform-level surfaces, or across entirely separate BEST applications.\r\n\r\n## Who this is for\r\n\r\nbest-mcp is an **adapter for clients you don't control**. If you use an off-the-shelf MCP-capable client, this server is the right integration: it is the only plug-in mechanism those clients offer.\r\n\r\nIf you are writing **your own** agent, backend, or tooling, you don't need it — call the BEST HTTP surface directly. BEST endpoints are self-describing (command/query catalogues, JSON Schemas, workflows), and every tool below is a thin wrapper over exactly one HTTP call. Putting best-mcp between your own code and the service adds a network hop and a deployment to operate, flattens structured BEST error responses into prose, and widens your supply chain — while providing nothing a small HTTP client in your codebase wouldn't. See [Choosing a Transport](https://behavioralstate.io/docs/transports/mcp) in the spec docs.\r\n\r\nRunning it as a shared server in production? **Pin a version** (`npx @behavioralstate/best-mcp@2.2.0`, or your package manager's equivalent) rather than resolving `latest` at start-up — callers' credentials flow through this process, so upgrades should be deliberate.\r\n\r\n---\r\n\r\n## Start with AI\r\n\r\nPaste either prompt into your LLM client to get configured in under a minute.\r\n\r\n**Configure best-mcp** — generates the exact env vars and `mcpServers` JSON for your client:\r\n\r\n```\r\nConfigure best-mcp so I can use my BEST service from [VS Code Copilot / Claude Desktop / Cursor].\r\n\r\nService base URL: [https://api.example.com/best]\r\nAPI key: [my-api-key]\r\nTenant ID: [my-tenant-id]  ← remove this line if not multi-tenant\r\n\r\nOutput the exact env vars and mcpServers JSON block to add to my client config.\r\n\r\nbest-mcp docs: https://behavioralstate.io/docs/transports/mcp\r\n```\r\n\r\n**Make your service BEST-compliant** — scaffolds the four required endpoints in your framework:\r\n\r\n```\r\nMake my [ASP.NET Core / Express / FastAPI / Spring Boot] service BEST-compliant.\r\n\r\nI need these four endpoints:\r\n- GET /.well-known/best — discovery manifest\r\n- GET /commands — catalogue listing accepted commands with JSON Schema\r\n- POST /commands — CloudEvents 1.0 entry point\r\n- GET /queries — query catalogue\r\n\r\nAuth: X-Api-Key header. Set authentication.type = \"apikey\" in the manifest.\r\n\r\nSpec reference: https://behavioralstate.io/docs\r\n```\r\n\r\n---\r\n\r\n## Tools\r\n\r\n| Tool | What it does |\r\n|---|---|\r\n| `list_connections` | List the configured connections (names, endpoints, descriptions) plus every further service the apps' root manifests list, reachable as `<app>/<serviceId>` |\r\n| `get_command_catalogue` | List all commands this endpoint accepts (descriptions truncated; `detail: \"full\"` for verbatim) |\r\n| `get_command_schema` | Fetch the full JSON Schema for a command type — learn the exact fields required |\r\n| `send_command` | Send a command (CloudEvent 1.0 envelope built automatically); optional `correlation_id` joins an existing chain, and the server's echoed correlation ID (spec 0.9.2+) is returned for use with the event tools |\r\n| `send_command_and_wait` | Send a command then poll a query until a condition is met (accepts `correlation_id` like `send_command`) |\r\n| `get_query_catalogue` | List all read queries this endpoint exposes (descriptions truncated; `detail: \"full\"` for verbatim) |\r\n| `get_query_schema` | Fetch the JSON Schema for a query — learn parameters and response shape |\r\n| `execute_query` | Execute a query and return current state synchronously |\r\n| `get_manifest` | Fetch the `/.well-known/best` discovery manifest (tenant-scoped when the host publishes one) — declared capabilities, push channels, authentication |\r\n| `get_events` | Query the historical event log (`GET /events`) — filter by correlationId/type/source/time, paginate with the response cursor |\r\n| `get_event_schema` | Fetch the JSON Schema for a typed event (`GET /events/{schema}/{version}`) |\r\n| `sample_event_stream` | Open the live SSE stream (`GET /events/stream`), collect events until `max_events`/`max_seconds`, then return them — bounded client-side, so it works against any conformant endpoint |\r\n| `exchange_device_code` | Last step of a device-authorization onboarding (RFC 8628): POSTs the device code to the root manifest's `authentication.tokenUrl`. `authorization_pending` / `slow_down` come back as a non-error status to poll on. On success the issued credential (and tenant) is applied to this session's connections of the same app at once AND stored in the [credential store](#credential-store) for later starts; the key is **never returned to the model** — every copy in the response is redacted. On the HTTP transport a per-request caller (override headers present) gets neither the key nor a shared-state change |\r\n| `get_workflows` | List the service's published workflow recipes (`GET /workflows` — always answered as a shallow index), or fetch one full recipe with its steps via `workflow_id` (`GET /workflows/{id}`). Handles both the 0.9.4 `io.best.agents.workflows` capability and pre-0.9.4 vendor-extension servers; returns a note if the service publishes none |\r\n\r\nIntended LLM flow: `get_command_catalogue` → pick a command → `get_command_schema` → gather fields → `send_command`.\r\n\r\nEvents flow: `get_manifest` (does the service declare events, and over which channels?) → `get_events` for what already happened (poll with the response cursor for turn-based drains) → `sample_event_stream` for a bounded window of what happens next. A turn-based client cannot hold the stream open — for standing reactions, configure the service's own alerting/webhook commands instead.\r\n\r\nCorrelation (spec 0.9.2+): every accepted command has a correlation ID — the caller's `correlation_id`, or defaulting to the command's own ID — echoed as `correlationId` in the `send_command` response and stamped as `correlationid` on every event the command causes, across process chains. Filter `get_events` / `sample_event_stream` by it to observe a command's outcome. Pre-0.9.2 servers ignore the attribute and echo nothing; behaviour there is unchanged.\r\n\r\nBoth catalogue tools truncate each entry's description by default, because a catalogue exists to let a caller *choose* an operation and a thoroughly documented service makes the full listing too large for that — one endpoint returns 47 KB for ~65 commands, which clients spill to disk before a model can read it. Truncation is ~60% smaller and still enough to pick from; the schema tools return one operation's complete text, and `detail: \"full\"` returns every description verbatim when you really need to compare across entries.\r\nBefore hand-assembling a multi-step process, call `get_workflows` — catalogue entries may point at recipes via their `workflows` array — then `get_workflows` with `workflow_id` for the chosen recipe's steps.\r\n\r\nHigh-impact commands (spec 0.9.6): when a command's schema document or catalogue entry carries an `impact` annotation (financial, destructive, irreversible, compliance), `get_command_schema` appends a deterministic HIGH-IMPACT note — including the server's `warning` text — telling the model to surface the warning and obtain the user's explicit confirmation before `send_command`. The annotation is descriptive; the server's own controls still apply.\r\n\r\nEvery operation tool takes an optional `connection` parameter; with a single configured connection it defaults to that one. If the LLM is not certain which connection the user intends, it calls `list_connections` and asks the user to confirm before proceeding.\r\n\r\n**Root-manifest services as connections.** A platform's root manifest (`/.well-known/best`) lists its services, each with an HTTP endpoint, and only the tenant surface gets a configured connection. Every other listed service is reachable anyway as `<app>/<serviceId>` (e.g. `dotquant/io.dotquant.onboarding`): the client fetches the app's root manifest once, builds an ad-hoc connection at that service's endpoint with the app's credential, and caches it. `list_connections` lists them after the configured ones. Services whose endpoint is merely the parent of a configured surface (a tenants collection root) are not listed.\r\n\r\n**Credential store.** A key issued through `exchange_device_code` is written to `~/.best-mcp/credentials.json` (user-only; override with `BEST_MCP_CREDENTIALS_FILE`), keyed by the app's base URL, and never handed to the model — a chat transcript is not a secret store. At startup the stored credential fills in for an ABSENT `BEST_<APP>_API_KEY` or for the exact key it superseded (one-key-per-account services replaced that key when the new one was issued); a DIFFERENT configured key means you reconfigured deliberately, so the configuration wins and the stale entry is dropped. This also makes onboarding from zero possible: configure only `BEST_<APP>_BASE_URL`, let the model run the service's onboarding workflow, and the tenant connection appears with its key stored.\r\n\r\n**Dead key recovery.** Many BEST services hold ONE key per account, so a key replaced since it was stored is dead — the tenant surface answers 401 and the error now carries the service's `code` and `details` (where a good service names its onboarding surface), not just the message. The server instructions tell the model what to do next: never fall back to a browser or the website's sign-up form; target the onboarding service by its `<app>/<serviceId>` connection name, run its workflow (the person approves a short code), then call `exchange_device_code` — the new key is live in the session immediately and the returned configuration is what the client must store.\r\n\r\n---\r\n\r\n## Setup\r\n\r\n### 1. Install and build\r\n\r\n```bash\r\ncd mcp-server\r\nnpm install\r\nnpm run build\r\n```\r\n\r\n### 2. Configure\r\n\r\nThere are three configuration modes. Use whichever fits your setup — they are mutually exclusive and checked in the order listed.\r\n\r\n> **Upgrading from `bsp-mcp` (pre-2.0)?** The protocol short name changed BSP → BEST in spec 0.9.0. All env vars are now `BEST_*`, but the server accepts legacy `BSP_*` names as a deprecated fallback (with a startup warning), so existing configurations keep working — rename them at your convenience.\r\n\r\n---\r\n\r\n### Mode 1 — Per-app env vars *(recommended)*\r\n\r\nOne set of `BEST_<APP>_*` variables per application. The app name is a single uppercase word (letters and digits, no underscores), e.g. `TRADING`, `HR`, `ACCOUNTING`.\r\n\r\n#### Required\r\n\r\n| Variable | Description |\r\n|---|---|\r\n| `BEST_<APP>_BASE_URL` | Root URL of the BEST HTTP surface |\r\n| `BEST_<APP>_API_KEY` | Credential — not required when `AUTH_TYPE=none` |\r\n\r\n#### Optional\r\n\r\n| Variable | Default | Description |\r\n|---|---|---|\r\n| `BEST_<APP>_TENANT_ID` | — | When set, **auto-generates two connections**: `<app>/tenant` (tenant-scoped) and `<app>/platform` (platform-level). When omitted, generates one connection: `<app>`. Either way every further service the app's root manifest lists is reachable as `<app>/<serviceId>` without configuration (see [Tools](#tools)). |\r\n| `BEST_<APP>_AUTH_TYPE` | `apikey` | How the credential is sent — see [Auth types](#auth-types) below. **Defaults to `apikey` in Mode 1** (unlike Modes 2 and 3 which default to `bearer`). |\r\n| `BEST_<APP>_AUTH_HEADER` | `X-Api-Key` | Header name — only used when `AUTH_TYPE=apikey` and `AUTH_IN=header` |\r\n| `BEST_<APP>_AUTH_IN` | `header` | Where the key is sent when `AUTH_TYPE=apikey`: `header` or `query` |\r\n| `BEST_<APP>_AUTH_PARAM` | `apikey` | Query parameter name — only used when `AUTH_IN=query` |\r\n| `BEST_<APP>_ALLOW_BEARER_PASSTHROUGH` | `false` | Allow a per-request `Authorization: Bearer <token>` header to be forwarded to the BEST endpoint as the caller's own credential — see [Per-request credential overrides](#http--per-request-credential-overrides-multi-user-backends). |\r\n\r\n#### Auth types\r\n\r\n> **Default differs by mode.** Mode 1 defaults to `apikey` because BEST services typically use API key headers. Modes 2 and 3 default to `bearer` for backward compatibility.\r\n\r\n| `AUTH_TYPE` | What it does | Extra vars needed |\r\n|---|---|---|\r\n| `apikey` *(Mode 1 default)* | Sends the key in a custom header or query param | `AUTH_HEADER` (header name, default `X-Api-Key`) or `AUTH_IN=query` + `AUTH_PARAM` |\r\n| `bearer` *(Modes 2 & 3 default)* | Sends `Authorization: Bearer <key>` | none |\r\n| `none` | No credentials sent (public endpoint) | `API_KEY` not required |\r\n\r\n#### Examples\r\n\r\n**Single app, tenant + platform surfaces (most common admin setup):**\r\n\r\n```\r\nBEST_TRADING_BASE_URL=https://api.example.com/best\r\nBEST_TRADING_API_KEY=your-api-key\r\nBEST_TRADING_TENANT_ID=your-tenant-id\r\nBEST_TRADING_AUTH_TYPE=apikey\r\n```\r\n\r\nThis generates two connections automatically:\r\n- `trading/tenant` → `https://api.example.com/best/tenants/your-tenant-id`\r\n- `trading/platform` → `https://api.example.com/best`\r\n\r\n**Two separate apps:**\r\n\r\n```\r\nBEST_TRADING_BASE_URL=https://trading.example.com/best\r\nBEST_TRADING_API_KEY=trading-key\r\nBEST_TRADING_TENANT_ID=tenant-abc\r\nBEST_TRADING_AUTH_TYPE=apikey\r\n\r\nBEST_HR_BASE_URL=https://hr.example.com/best\r\nBEST_HR_API_KEY=hr-key\r\nBEST_HR_TENANT_ID=tenant-abc\r\nBEST_HR_AUTH_TYPE=apikey\r\n```\r\n\r\nThis generates four connections: `trading/tenant`, `trading/platform`, `hr/tenant`, `hr/platform`.\r\n\r\n**App with no tenant scope:**\r\n\r\n```\r\nBEST_MYAPP_BASE_URL=https://api.example.com/best\r\nBEST_MYAPP_API_KEY=your-api-key\r\n```\r\n\r\nGenerates one connection: `myapp`.\r\n\r\n#### MCP client config (stdio)\r\n\r\n```json\r\n{\r\n  \"mcpServers\": {\r\n    \"best\": {\r\n      \"command\": \"npx\",\r\n      \"args\": [\"best-mcp\"],\r\n      \"env\": {\r\n        \"BEST_TRADING_BASE_URL\": \"https://api.example.com/best\",\r\n        \"BEST_TRADING_API_KEY\": \"your-api-key\",\r\n        \"BEST_TRADING_TENANT_ID\": \"your-tenant-id\",\r\n        \"BEST_TRADING_AUTH_TYPE\": \"apikey\"\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n---\r\n\r\n### Mode 2 — `BEST_CONNECTIONS` JSON array\r\n\r\nFor advanced scenarios where per-app vars are not flexible enough. Set `BEST_CONNECTIONS` to a JSON array of connection objects — each connection is fully explicit with no auto-generation.\r\n\r\nEach object:\r\n\r\n| Field | Required | Default | Description |\r\n|---|---|---|---|\r\n| `name` | yes | — | Connection identifier used in the `connection` tool parameter |\r\n| `endpoint` | yes | — | Fully-resolved base URL (no `{tenantId}` placeholder) |\r\n| `apiKey` | yes* | — | Credential (*not required when `authType` is `none`) |\r\n| `authType` | no | `bearer` | `bearer` · `apikey` · `none` |\r\n| `authHeader` | no | `X-Api-Key` | Header name when `authType=apikey` and `authIn=header` |\r\n| `authIn` | no | `header` | `header` or `query` |\r\n| `authParam` | no | `apikey` | Query param name when `authIn=query` |\r\n| `allowBearerPassthrough` | no | `false` | Allow a per-request `Authorization: Bearer <token>` header to be forwarded to the BEST endpoint — see [Per-request credential overrides](#http--per-request-credential-overrides-multi-user-backends) |\r\n| `description` | no | — | Human-readable description surfaced to the LLM for connection selection |\r\n\r\n---\r\n\r\n### Mode 3 — Legacy single connection\r\n\r\nFor simple single-endpoint setups. Use the flat `BEST_*` variables:\r\n\r\n| Variable | Required | Default | Description |\r\n|---|---|---|---|\r\n| `BEST_ENDPOINT` | yes | — | Base URL of the BEST HTTP surface |\r\n| `BEST_API_KEY` | yes* | — | Credential (*not required when `BEST_AUTH_TYPE=none`) |\r\n| `BEST_AUTH_TYPE` | no | `bearer` | `bearer` · `apikey` · `none` |\r\n| `BEST_AUTH_HEADER` | no | `X-Api-Key` | Header name when `AUTH_TYPE=apikey` |\r\n| `BEST_AUTH_IN` | no | `header` | `header` or `query` |\r\n| `BEST_AUTH_PARAM` | no | `apikey` | Query param name when `AUTH_IN=query` |\r\n| `BEST_ALLOW_BEARER_PASSTHROUGH` | no | `false` | Allow a per-request `Authorization: Bearer <token>` header to be forwarded to the BEST endpoint — see [Per-request credential overrides](#http--per-request-credential-overrides-multi-user-backends) |\r\n\r\n---\r\n\r\n## Transport options\r\n\r\n### stdio — VS Code Copilot, Cursor, Claude Desktop\r\n\r\n`MCP_TRANSPORT` defaults to `stdio`. Add to your client's MCP config (see [Mode 1](#mode-1--per-app-env-vars-recommended) example above).\r\n\r\n### HTTP — ChatGPT Desktop\r\n\r\nStart in HTTP mode and expose via a tunnel:\r\n\r\n```bash\r\nMCP_TRANSPORT=http MCP_HTTP_PORT=3001 \\\r\n  BEST_TRADING_BASE_URL=https://api.example.com/best \\\r\n  BEST_TRADING_API_KEY=<key> \\\r\n  BEST_TRADING_AUTH_TYPE=apikey \\\r\n  node dist/index.js\r\n\r\nngrok http 3001\r\n```\r\n\r\nThen in ChatGPT Desktop: **Settings → Apps & Connectors → Create**, connector URL: `https://<subdomain>.ngrok.app/mcp`\r\n\r\n### HTTP — per-request credential overrides (multi-user backends)\r\n\r\nA backend that calls best-mcp on behalf of many different logged-in users (e.g. a chat assistant) can't bake one fixed API key into the server's environment — it needs to supply the *current* caller's credentials on every request. When `MCP_TRANSPORT=http`, three optional request headers override the resolved connection for that single call only:\r\n\r\n| Header | Effect |\r\n|---|---|\r\n| `X-Api-Key` | Replaces the connection's configured `apiKey` for this request. |\r\n| `X-Tenant-Id` | Replaces the tenant segment of the endpoint for this request. Only applies to a Mode 1 `<app>/tenant` connection (the one generated from `BEST_<APP>_TENANT_ID`) — ignored on connections with no tenant template. Must match `^[A-Za-z0-9_.-]+$`; an invalid value is ignored (and logged) rather than spliced into the URL. |\r\n| `Authorization: Bearer <token>` | Forwarded verbatim to the BEST endpoint as the caller's own credential (e.g. a session JWT for a BEST surface that accepts JWTs) — **only when the connection is explicitly configured with `allowBearerPassthrough`** (`BEST_<APP>_ALLOW_BEARER_PASSTHROUGH=true` / `allowBearerPassthrough: true` / `BEST_ALLOW_BEARER_PASSTHROUGH=true`). Bearer scheme only. When forwarded, the effective auth for that request becomes `Authorization: Bearer <token>` regardless of the configured `authType`, so the token can never land in a query string or custom header. |\r\n\r\nNo override header is required — omit them all and a request behaves exactly as configured via environment variables. This has no effect on stdio (there's no per-request boundary to attach headers to).\r\n\r\n**Precedence:** an explicit per-request `X-Api-Key` always wins; the `Authorization` Bearer token is only used when no `X-Api-Key` is present. This mirrors BEST dual-auth gates, where a present API key is authoritative and never falls through to the JWT.\r\n\r\n**Security — why Bearer passthrough is opt-in (default off):** on the MCP HTTP transport, the `Authorization` header may carry a credential intended for *this server* (e.g. MCP OAuth between the client and best-mcp). Forwarding it upstream by default would leak that credential across a trust boundary. Enable passthrough only when the MCP caller and the BEST endpoint share one trust domain — i.e. the token the caller sends *is* the credential the BEST service expects. The token is only ever sent to the connection's configured endpoint, over the transport that endpoint's URL specifies (use HTTPS), and is never logged. If a request carries a Bearer token while passthrough is disabled, best-mcp falls back to the configured credential and logs a one-time warning per connection (without the token) so the misconfiguration is diagnosable.\r\n\r\n**Fail-closed tip:** for a multi-user deployment where *every* request must carry per-caller credentials, keep the connection's configured `apiKey` set to a deliberately invalid placeholder (e.g. `invalid-set-x-api-key-per-request`). A request that arrives without credentials then fails authentication at the BEST service instead of silently acting as a shared identity.\r\n\r\n```bash\r\ncurl -X POST http://localhost:3001/mcp \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -H \"Accept: application/json, text/event-stream\" \\\r\n  -H \"X-Api-Key: <the current user's api key>\" \\\r\n  -H \"X-Tenant-Id: <the current user's tenant>\" \\\r\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"execute_query\",\"arguments\":{\"connection\":\"trading/tenant\",\"schema\":\"list-brokers\",\"params\":{}}}}'\r\n```\r\n\r\nOr, with `BEST_TRADING_ALLOW_BEARER_PASSTHROUGH=true`, authenticating the caller with their session JWT instead of an API key:\r\n\r\n```bash\r\ncurl -X POST http://localhost:3001/mcp \\\r\n  -H \"Content-Type: application/json\" \\\r\n  -H \"Accept: application/json, text/event-stream\" \\\r\n  -H \"Authorization: Bearer <the current user's session JWT>\" \\\r\n  -H \"X-Tenant-Id: <the current user's tenant>\" \\\r\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"execute_query\",\"arguments\":{\"connection\":\"trading/tenant\",\"schema\":\"list-brokers\",\"params\":{}}}}'\r\n```\r\n\r\n---\r\n\r\n## CloudEvent `source` field\r\n\r\n`source` is optional on `send_command` and defaults to `urn:best-mcp` — the client's own identity. Per the commands spec, `source` identifies the command's *origin* and servers must not route by it alone, so the default is correct for any conformant service. Pass an explicit `source` only when the schema `description` returned by `get_command_schema` documents a specific required value (legacy source-routing dialects) — never invent one.\r\n\r\n---\r\n\r\n## Publishing to npm\r\n\r\nNever run `npm publish` directly — the release is fully automated via CI:\r\n\r\n```bash\r\ngit tag -a mcp/v<x.y.z> -m \"Release mcp/v<x.y.z>\"\r\ngit push origin mcp/v<x.y.z>\r\n```\r\n","readmeFilename":"README.md"}