Skip to main content
Glama
Bichev
by Bichev
msfeldstein-mcp-test-servers.txt138 kB
Directory structure: └── msfeldstein-mcp-test-servers/ ├── README.md ├── package.json ├── pnpm-lock.yaml ├── .npmrc ├── src/ │ ├── all-types-server.js │ ├── bad-param-server.js │ ├── big-response-server.js │ ├── broken-tool-server.js │ ├── cli.js │ ├── combined-server.js │ ├── crash-on-startup-server.js │ ├── duplicate-names-server.js │ ├── dynamic-tools-server.js │ ├── enum-param-server.js │ ├── env-check-server.js │ ├── env-echo-server.js │ ├── file-ops-server.js │ ├── headers-server.py │ ├── http-ping-server.js │ ├── image-server.js │ ├── long-description-server.js │ ├── long-running-server.js │ ├── many-resources-server.js │ ├── many-tools-server.js │ ├── math-server.js │ ├── named-server.js │ ├── number-param-server.js │ ├── oauth-ping-server.js │ ├── optional-param-server.js │ ├── pattern-param-server.js │ ├── ping-server.js │ ├── resource-server.js │ ├── root-echo-server.js │ ├── shell-exec-server.js │ ├── sse-notification-stream.js │ ├── sse-ping-server.js │ ├── stderr-server.js │ └── stdout-server.js └── .cursor/ └── rules/ ├── create-server.mdc └── .gitignore ================================================ FILE: README.md ================================================ # MCP Test Servers A collection of test servers implementing the Model Context Protocol (MCP). ``` npx -y @msfeldstein/mcp-test-servers <server> ``` ## Available Servers - `all-types`: Demonstrates various tool parameter types supported by MCP - `bad-param`: Server with an intentionally malformed parameter name - `big-response`: Server that returns large responses - `broken-tool`: Server with intentionally broken tool - `crash-on-startup`: Server that crashes on startup - `combined`: Server with tools and resources - `duplicate-names`: Server with duplicate names for resources - `enum-param`: Tool has enum string parameter - `env-check`: Checks for SHOULD_RUN environment variable being passed properly - `env-echo`: Echoes the environment variables - `image`: Tool returns an image of sonic the hedgehog - `long-description`: Publicize a very long description configured via env var - `long-running`: Server that sends progress notifications every 2 seconds for a 20-second task - `many-resources`: Server with multiple resources - `many-tools`: Server with 100 tools that each return 'ack' - `math`: Server with basic math function tools (add, subtract, multiply, divide, power, sqrt, factorial) - `named`: Server with configurable name via MCP_SERVER_NAME environment variable - `number-param`: Tool with a number parameter - `optional-param`: Tool has an optional param - `pattern-param`: Tool has a parameter with a pattern match - `ping`: A simple server that responds with 'pong' - `resource`: Resource server implementation - `roots-echo`: Server that demonstrates MCP roots functionality by echoing back the roots provided by the client - `stderr`: Server that logs to stderr - `stdout` Servert that illegally logs to stdout # Remote Servers ``` # Streamable HTTP npm run http-ping # SSE npm run sse-ping ``` ================================================ FILE: package.json ================================================ { "name": "@msfeldstein/mcp-test-servers", "version": "1.1.57", "type": "module", "bin": { "mcp-test-servers": "./src/cli.js" }, "scripts": { "oauth-ping": "node src/oauth-ping-server.js", "http-ping": "node src/http-ping-server.js", "sse-ping": "node src/sse-ping-server.js", "sse-notification-stream": "node src/sse-notification-stream.js", "bump-and-publish": "git commit -a -m 'publish' && npm version patch && git push && npm publish" }, "keywords": [ "mcp", "model-context-protocol" ], "author": "Michael Feldstein", "license": "ISC", "description": "A collection of MCP test servers including working servers (ping, resource, combined, env-echo) and test failure cases (broken-tool, crash-on-startup)", "dependencies": { "@modelcontextprotocol/sdk": "^1.10.1", "cors": "^2.8.5", "express": "^4.21.2" }, "publishConfig": { "access": "public" } } ================================================ FILE: pnpm-lock.yaml ================================================ lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: .: dependencies: '@modelcontextprotocol/sdk': specifier: ^1.10.1 version: 1.10.2 cors: specifier: ^2.8.5 version: 2.8.5 express: specifier: ^4.21.2 version: 4.21.2 packages: '@modelcontextprotocol/sdk@1.10.2': resolution: {integrity: sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==} engines: {node: '>=18'} accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} body-parser@2.2.0: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} content-disposition@1.0.0: resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} engines: {node: '>= 0.6'} content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} cookie@0.7.1: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} eventsource-parser@3.0.1: resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} engines: {node: '>=18.0.0'} eventsource@3.0.6: resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} engines: {node: '>=18.0.0'} express-rate-limit@7.5.0: resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} engines: {node: '>= 16'} peerDependencies: express: ^4.11 || 5 || ^5.0.0-beta.1 express@4.21.2: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} express@5.1.0: resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} engines: {node: '>= 18'} finalhandler@1.3.1: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} finalhandler@2.1.0: resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} engines: {node: '>= 0.8'} forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} fresh@2.0.0: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} mime-db@1.54.0: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} mime-types@3.0.1: resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} engines: {node: '>= 0.6'} mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} hasBin: true ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} path-to-regexp@8.2.0: resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} engines: {node: '>=16'} pkce-challenge@5.0.0: resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} engines: {node: '>=16.20.0'} proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} qs@6.13.0: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} raw-body@2.5.2: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} raw-body@3.0.0: resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} engines: {node: '>= 0.8'} router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} serve-static@1.16.2: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} serve-static@2.2.0: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} side-channel-map@1.0.1: resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} engines: {node: '>= 0.4'} side-channel-weakmap@1.0.2: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} side-channel@1.1.0: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} type-is@2.0.1: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} zod-to-json-schema@3.24.5: resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} peerDependencies: zod: ^3.24.1 zod@3.24.3: resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} snapshots: '@modelcontextprotocol/sdk@1.10.2': dependencies: content-type: 1.0.5 cors: 2.8.5 cross-spawn: 7.0.6 eventsource: 3.0.6 express: 5.1.0 express-rate-limit: 7.5.0(express@5.1.0) pkce-challenge: 5.0.0 raw-body: 3.0.0 zod: 3.24.3 zod-to-json-schema: 3.24.5(zod@3.24.3) transitivePeerDependencies: - supports-color accepts@1.3.8: dependencies: mime-types: 2.1.35 negotiator: 0.6.3 accepts@2.0.0: dependencies: mime-types: 3.0.1 negotiator: 1.0.0 array-flatten@1.1.1: {} body-parser@1.20.3: dependencies: bytes: 3.1.2 content-type: 1.0.5 debug: 2.6.9 depd: 2.0.0 destroy: 1.2.0 http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 qs: 6.13.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 transitivePeerDependencies: - supports-color body-parser@2.2.0: dependencies: bytes: 3.1.2 content-type: 1.0.5 debug: 4.4.0 http-errors: 2.0.0 iconv-lite: 0.6.3 on-finished: 2.4.1 qs: 6.14.0 raw-body: 3.0.0 type-is: 2.0.1 transitivePeerDependencies: - supports-color bytes@3.1.2: {} call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 call-bound@1.0.4: dependencies: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 content-disposition@1.0.0: dependencies: safe-buffer: 5.2.1 content-type@1.0.5: {} cookie-signature@1.0.6: {} cookie-signature@1.2.2: {} cookie@0.7.1: {} cookie@0.7.2: {} cors@2.8.5: dependencies: object-assign: 4.1.1 vary: 1.1.2 cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 debug@2.6.9: dependencies: ms: 2.0.0 debug@4.4.0: dependencies: ms: 2.1.3 depd@2.0.0: {} destroy@1.2.0: {} dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 es-errors: 1.3.0 gopd: 1.2.0 ee-first@1.1.1: {} encodeurl@1.0.2: {} encodeurl@2.0.0: {} es-define-property@1.0.1: {} es-errors@1.3.0: {} es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 escape-html@1.0.3: {} etag@1.8.1: {} eventsource-parser@3.0.1: {} eventsource@3.0.6: dependencies: eventsource-parser: 3.0.1 express-rate-limit@7.5.0(express@5.1.0): dependencies: express: 5.1.0 express@4.21.2: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 body-parser: 1.20.3 content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.1 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 finalhandler: 1.3.1 fresh: 0.5.2 http-errors: 2.0.0 merge-descriptors: 1.0.3 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 path-to-regexp: 0.1.12 proxy-addr: 2.0.7 qs: 6.13.0 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.0 serve-static: 1.16.2 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 utils-merge: 1.0.1 vary: 1.1.2 transitivePeerDependencies: - supports-color express@5.1.0: dependencies: accepts: 2.0.0 body-parser: 2.2.0 content-disposition: 1.0.0 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 debug: 4.4.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 finalhandler: 2.1.0 fresh: 2.0.0 http-errors: 2.0.0 merge-descriptors: 2.0.0 mime-types: 3.0.1 on-finished: 2.4.1 once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 qs: 6.14.0 range-parser: 1.2.1 router: 2.2.0 send: 1.2.0 serve-static: 2.2.0 statuses: 2.0.1 type-is: 2.0.1 vary: 1.1.2 transitivePeerDependencies: - supports-color finalhandler@1.3.1: dependencies: debug: 2.6.9 encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 statuses: 2.0.1 unpipe: 1.0.0 transitivePeerDependencies: - supports-color finalhandler@2.1.0: dependencies: debug: 4.4.0 encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 statuses: 2.0.1 transitivePeerDependencies: - supports-color forwarded@0.2.0: {} fresh@0.5.2: {} fresh@2.0.0: {} function-bind@1.1.2: {} get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 hasown: 2.0.2 math-intrinsics: 1.1.0 get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 gopd@1.2.0: {} has-symbols@1.1.0: {} hasown@2.0.2: dependencies: function-bind: 1.1.2 http-errors@2.0.0: dependencies: depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 statuses: 2.0.1 toidentifier: 1.0.1 iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 inherits@2.0.4: {} ipaddr.js@1.9.1: {} is-promise@4.0.0: {} isexe@2.0.0: {} math-intrinsics@1.1.0: {} media-typer@0.3.0: {} media-typer@1.1.0: {} merge-descriptors@1.0.3: {} merge-descriptors@2.0.0: {} methods@1.1.2: {} mime-db@1.52.0: {} mime-db@1.54.0: {} mime-types@2.1.35: dependencies: mime-db: 1.52.0 mime-types@3.0.1: dependencies: mime-db: 1.54.0 mime@1.6.0: {} ms@2.0.0: {} ms@2.1.3: {} negotiator@0.6.3: {} negotiator@1.0.0: {} object-assign@4.1.1: {} object-inspect@1.13.4: {} on-finished@2.4.1: dependencies: ee-first: 1.1.1 once@1.4.0: dependencies: wrappy: 1.0.2 parseurl@1.3.3: {} path-key@3.1.1: {} path-to-regexp@0.1.12: {} path-to-regexp@8.2.0: {} pkce-challenge@5.0.0: {} proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 qs@6.13.0: dependencies: side-channel: 1.1.0 qs@6.14.0: dependencies: side-channel: 1.1.0 range-parser@1.2.1: {} raw-body@2.5.2: dependencies: bytes: 3.1.2 http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 raw-body@3.0.0: dependencies: bytes: 3.1.2 http-errors: 2.0.0 iconv-lite: 0.6.3 unpipe: 1.0.0 router@2.2.0: dependencies: debug: 4.4.0 depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 path-to-regexp: 8.2.0 transitivePeerDependencies: - supports-color safe-buffer@5.2.1: {} safer-buffer@2.1.2: {} send@0.19.0: dependencies: debug: 2.6.9 depd: 2.0.0 destroy: 1.2.0 encodeurl: 1.0.2 escape-html: 1.0.3 etag: 1.8.1 fresh: 0.5.2 http-errors: 2.0.0 mime: 1.6.0 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 statuses: 2.0.1 transitivePeerDependencies: - supports-color send@1.2.0: dependencies: debug: 4.4.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 fresh: 2.0.0 http-errors: 2.0.0 mime-types: 3.0.1 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 statuses: 2.0.1 transitivePeerDependencies: - supports-color serve-static@1.16.2: dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 send: 0.19.0 transitivePeerDependencies: - supports-color serve-static@2.2.0: dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 send: 1.2.0 transitivePeerDependencies: - supports-color setprototypeof@1.2.0: {} shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 side-channel-map@1.0.1: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 object-inspect: 1.13.4 side-channel-weakmap@1.0.2: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 object-inspect: 1.13.4 side-channel-map: 1.0.1 side-channel@1.1.0: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 side-channel-list: 1.0.0 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 statuses@2.0.1: {} toidentifier@1.0.1: {} type-is@1.6.18: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 type-is@2.0.1: dependencies: content-type: 1.0.5 media-typer: 1.1.0 mime-types: 3.0.1 unpipe@1.0.0: {} utils-merge@1.0.1: {} vary@1.1.2: {} which@2.0.2: dependencies: isexe: 2.0.0 wrappy@1.0.2: {} zod-to-json-schema@3.24.5(zod@3.24.3): dependencies: zod: 3.24.3 zod@3.24.3: {} ================================================ FILE: .npmrc ================================================ engine-strict=true prefer-pnpm=true auto-install-peers=true shamefully-hoist=true strict-peer-dependencies=true use-node-version=18 package-manager=pnpm@8.15.5 use-pnpm=true ================================================ FILE: src/all-types-server.js ================================================ #!/usr/bin/env node // Import required dependencies from the MCP SDK and Zod for schema validation import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Define a nested object schema that will be used as part of the main parameters // This demonstrates how to handle complex nested data structures const nestedObjectSchema = z.object({ nestedString: z.string().describe("A nested string property"), nestedNumber: z.number().describe("A nested number property"), nestedBoolean: z.boolean().describe("A nested boolean property"), }); // Define the main parameter schema using Zod // This schema demonstrates all the supported parameter types in MCP: // - Basic types (string, number, boolean) // - Arrays // - Nested objects // - Enums // - Optional parameters const allTypesParamsSchema = z.object({ requiredString: z.string().describe("A required string parameter"), requiredInteger: z.number().int().describe("A required integer parameter"), requiredNumber: z.number().describe("A required number (float/decimal) parameter"), requiredBoolean: z.boolean().describe("A required boolean parameter"), requiredStringArray: z.array(z.string()).describe("A required array of strings"), requiredNumberArray: z.array(z.number()).describe("A required array of numbers"), requiredObject: nestedObjectSchema.describe("A required object with nested properties"), requiredEnum: z.enum(["option1", "option2", "option3"]).describe("A required enum parameter"), optionalString: z.string().optional().describe("An optional string parameter"), optionalNumber: z.number().optional().describe("An optional number parameter"), }); // Initialize the MCP server with metadata and tool capabilities // The server is configured to expose a single tool that demonstrates all parameter types const server = new McpServer( { name: "all-types-server", version: "1.0.0", capabilities: { tools: { "all_types_tool": { description: "A tool demonstrating various supported parameter types", parameters: allTypesParamsSchema, // Use Zod schema directly for capabilities }, }, }, } ); // Register the tool implementation // This handler simply echoes back the received parameters to demonstrate // that they were correctly parsed according to the schema server.tool( "all_types_tool", allTypesParamsSchema, async (params) => { // Simply return the received parameters to demonstrate they were parsed correctly return { content: [ { type: "text", text: `Received parameters: ${JSON.stringify(params, null, 2)}`, }, ], }; } ); // Start the server using stdio transport // This allows the server to communicate with clients through standard input/output await server.connect(new StdioServerTransport()); ================================================ FILE: src/bad-param-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create a new MCP server with stdio transport const server = new McpServer({ name: "bad-param-server", version: "1.0.0", capabilities: { tools: { "bad-param": { description: "A simple tool that returns 'pong'", parameters: { type: "object", properties: {}, required: [], }, }, }, }, }); // Register the ping tool server.tool( "bad-param", { ["bad%%^Param"]: z .string() .describe("The bad param name"), }, async (params) => { return { content: [ { type: "text", text: "pong", }, ], }; } ); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); // This server implements basic ping and echo functionality with configurable response delays ================================================ FILE: src/big-response-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; /** * MCP server that can generate a random string of a specified length */ const server = new McpServer( { name: "big-response-server", version: "1.0.1", capabilities: { tools: { "generate_big_response": { description: "Generates a random string of specified length", parameters: { type: "object", properties: { stringLength: { type: "integer", description: "The length of the random string to generate" } }, required: ['stringLength'] } } } } } ); /** * Generates a random string of a specified length * @param {number} length - The length of the random string to generate * @returns {string} The generated random string */ function generateRandomString(length) { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * characters.length)); } return result; } /** * Register the generate_big_response tool */ server.tool("generate_big_response", { stringLength: z.number().int().positive().describe("The length of the random string to generate") }, async (params) => { const randomString = generateRandomString(params.stringLength); return { content: [{ type: "text", text: `Generated random string of length ${params.stringLength}:\n${randomString}` }] }; }); await server.connect(new StdioServerTransport()); ================================================ FILE: src/broken-tool-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "broken-tool-server", version: "1.0.0", capabilities: { tools: {} } } ); // Register a tool that crashes when called server.tool("crash", async (params) => { // Simulate a crash by throwing an error throw new Error("This tool is intentionally broken!"); }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/cli.js ================================================ #!/usr/bin/env node const serverType = process.argv[2]; if (!serverType) { console.error('Please specify a server type - ping, resource, combined, broken-tool, crash-on-startup, env-check, env-echo, many-resources, duplicate-names, image, big-response, date, time, many-tools, named, long-description, enum-param, number-param, all-types, pattern-param, stdout, math, long-running'); console.error('Example: npx @msfeldstein/mcp-test-servers ping'); process.exit(1); } switch (serverType) { case 'all-types': import('./all-types-server.js'); break; case 'bad-param': import('./bad-param-server.js'); break; case 'big-response': import('./big-response-server.js'); break; case 'broken-tool': import('./broken-tool-server.js'); break; case 'crash-on-startup': import('./crash-on-startup-server.js'); break; case 'combined': import('./combined-server.js'); break; case 'duplicate-names': import('./duplicate-names-server.js'); break; case 'enum-param': import('./enum-param-server.js'); break; case 'env-check': import('./env-check-server.js'); break; case 'env-echo': import('./env-echo-server.js'); break; case 'image': import('./image-server.js'); break; case 'long-description': import('./long-description-server.js'); break; case 'long-running': import('./long-running-server.js'); break; case 'many-resources': import('./many-resources-server.js'); break; case 'many-tools': import('./many-tools-server.js'); break; case 'math': import('./math-server.js'); break; case 'named': import('./named-server.js'); break; case 'number-param': import('./number-param-server.js'); break; case 'optional-param': import('./optional-param-server.js'); break; case 'pattern-param': import('./pattern-param-server.js'); break; case 'ping': import('./ping-server.js'); break; case 'resource': import('./resource-server.js'); break; case 'stderr': import('./stderr-server.js'); break; case 'stdout': import('./stdout-server.js'); break; case 'dynamic-tools': import('./dynamic-tools-server.js'); break; case 'root-echo': import('./root-echo-server.js'); break; default: console.error('Unknown server type:', serverType); process.exit(1); } ================================================ FILE: src/combined-server.js ================================================ #!/usr/bin/env node /** * @fileoverview A combined MCP server implementation that provides a ping tool and a hello world resource. */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; /** * @type {McpServer} * @description Creates a new MCP server instance with basic capabilities */ const server = new McpServer( { name: "combined-server", version: "1.0.0", capabilities: { tools: { fizzbuzz: { description: "Generates a FIZZY sequence up to the specified number", parameters: { type: "object", properties: { limit: { type: "number", description: "The upper limit for the FIZZY sequence" } }, required: ["limit"] } } } } } ); /** * @function * @name ping * @description A simple ping tool that responds with "pong" * @param {Object} params - The parameters passed to the tool (unused) * @returns {Promise<Object>} A promise that resolves to an object containing the response */ server.tool("ping", async (params) => { return { content: [{ type: "text", text: "pong" }] }; }); /** * @function * @name fizzbuzz * @description Generates a FizzBuzz sequence up to the specified number * @param {Object} params - The parameters containing the upper limit * @returns {Promise<Object>} A promise that resolves to an object containing the FizzBuzz sequence */ server.tool("fizzbuzz", async (params) => { const limit = params.limit; const result = []; for (let i = 1; i <= limit; i++) { let output = ""; if (i % 3 === 0) output += "Fizz"; if (i % 5 === 0) output += "Buzz"; result.push(output || i.toString()); } return { content: [{ type: "text", text: result.join("\n") }] }; }); /** * @description Registers a simple "Hello World" resource with the server * @type {Resource} */ server.resource( "Hello World Text", "test://hello.txt", { description: "A simple test file containing 'Hello, world'", mimeType: "text/plain" }, async () => ({ contents: [ { uri: "test://hello.txt", mimeType: "text/plain", text: "Hello, world" } ] }) ); await server.connect(new StdioServerTransport()); ================================================ FILE: src/crash-on-startup-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Immediately throw an error during module initialization throw new Error("Server crashed during startup!"); // The code below will never be reached const server = new McpServer( { name: "crash-on-startup-server", version: "1.0.0", capabilities: { tools: {} } } ); await server.connect(new StdioServerTransport()); ================================================ FILE: src/duplicate-names-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "duplicate-names-server", version: "1.0.0" } ); // Create sets of resources with duplicate names const duplicateNames = [ "Common Resource", "Duplicate File", "Same Name Different Content" ]; duplicateNames.forEach((name, nameIndex) => { // Create 3 resources for each name for (let i = 1; i <= 3; i++) { server.resource( name, `test://duplicate${nameIndex + 1}_${i}.txt`, { description: `Resource ${i} of 3 with name "${name}"`, mimeType: "text/plain" }, async () => ({ contents: [ { uri: `test://duplicate${nameIndex + 1}_${i}.txt`, mimeType: "text/plain", text: `This is version ${i} of the resource named "${name}". Each resource shares the same name but has unique content and URI.` } ] }) ); } }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/dynamic-tools-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "dynamic-tools-server", version: "1.0.0", capabilities: { tools: { "enableTools": { description: "Enable the optional tool", parameters: { type: "object", properties: {}, required: [] } } } } } ); // Register the optional tool dynamically const optionalTool = server.tool("optionalTool", { message: z.string().optional().describe("Optional message to include with hello") }, async (params) => { const message = params?.message ? ` ${params.message}` : ""; return { content: [{ type: "text", text: `hello${message}` }] }; }); optionalTool.disable(); // Register the enableTools tool - this is always available server.tool("toggleTool", async (params) => { if (optionalTool.enabled) { optionalTool.disable() } else { optionalTool.enable(); } return { content: [{ type: "text", text: `Success! The 'optionalTool' has been ${optionalTool.enabled ? "enabled" : "disabled"}.` }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); // This server demonstrates dynamic tool management where tools can be enabled at runtime ================================================ FILE: src/enum-param-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create a new MCP server with stdio transport and a tool for searching Stripe documentation const server = new McpServer( { name: "enum-param-server", version: "1.0.0", capabilities: { tools: { "search_documentation": { description: "Search the Stripe documentation for the given question and language.\n\n It takes two arguments:\n ...", parameters: { type: "object", properties: { question: { type: "string", description: "The user question about integrating with Stripe will be used to search the documentation." }, language: { type: "string", enum: ["dotnet", "go", "java", "node", "php", "ruby", "python", "curl"], description: "The programming language to search for in the the documentation." } }, required: ["question"] } } } } } ); // Register the search_documentation tool with a zod enum schema server.tool( "search_documentation", { question: z.string().describe("The user question about integrating with Stripe will be used to search the documentation."), language: z.enum(["dotnet", "go", "java", "node", "php", "ruby", "python", "curl"]).describe("The programming language to search for in the the documentation.") }, async (params) => { return { content: [ { type: "text", text: `Question: ${params.question}` + (params.language ? `, Language: ${params.language}` : "") } ] }; } ); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); // This server demonstrates a search_documentation tool with enum type parameter. ================================================ FILE: src/env-check-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Check environment variable before proceeding if (process.env.SHOULD_RUN !== "true") { throw new Error("SHOULD_RUN environment variable must be set to 'true' to start this server"); } // Create a new MCP server with stdio transport const server = new McpServer( { name: "env-check-server", version: "1.0.0", capabilities: { tools: {} } } ); // Register a simple tool to show the server is running server.tool("status", async (params) => { return { content: [{ type: "text", text: "Server is running with SHOULD_RUN=true" }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/env-echo-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "env-echo-server", version: "1.0.0", capabilities: { tools: {} } } ); // Register a tool that returns all environment variables server.tool("env_echo", async (params) => { // Convert process.env object to a formatted string const envString = Object.entries(process.env) .map(([key, value]) => `${key}=${value}`) .join('\n'); return { content: [{ type: "text", text: `Current environment variables:\n${envString}` }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/file-ops-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import fs from 'fs/promises'; import path from 'path'; const server = new McpServer( { name: "file-ops-server", version: "1.0.0", capabilities: { tools: { readFile: { description: "Read contents of a file", parameters: { type: "object", properties: { filePath: { type: "string", description: "Path to the file to read" } }, required: ["filePath"] }, async handler(params) { try { const content = await fs.readFile(params.filePath, 'utf-8'); return { content }; } catch (error) { throw new Error(`Failed to read file: ${error.message}`); } } }, writeFile: { description: "Write content to a file", parameters: { type: "object", properties: { filePath: { type: "string", description: "Path to write the file to" }, content: { type: "string", description: "Content to write to the file" } }, required: ["filePath", "content"] }, async handler(params) { try { await fs.writeFile(params.filePath, params.content, 'utf-8'); return { success: true }; } catch (error) { throw new Error(`Failed to write file: ${error.message}`); } } }, listDirectory: { description: "List contents of a directory", parameters: { type: "object", properties: { dirPath: { type: "string", description: "Path to the directory to list" } }, required: ["dirPath"] }, async handler(params) { try { const files = await fs.readdir(params.dirPath); const fileStats = await Promise.all( files.map(async (file) => { const filePath = path.join(params.dirPath, file); const stats = await fs.stat(filePath); return { name: file, isDirectory: stats.isDirectory(), size: stats.size, modified: stats.mtime }; }) ); return { files: fileStats }; } catch (error) { throw new Error(`Failed to list directory: ${error.message}`); } } } } } } ); await server.connect(new StdioServerTransport()); ================================================ FILE: src/headers-server.py ================================================ from fastmcp import FastMCP from fastmcp.server.dependencies import get_http_headers mcp = FastMCP(name="Headers Demo") @mcp.tool() async def safe_header_info() -> dict: """Safely get header information without raising errors.""" # Get headers (returns empty dict if no request context) headers = get_http_headers() # Get authorization header auth_header = headers.get("authorization", "") is_bearer = auth_header.startswith("Bearer ") return { "user_agent": headers.get("user-agent", "Unknown"), "content_type": headers.get("content-type", "Unknown"), "has_auth": bool(auth_header), "auth_type": "Bearer" if is_bearer else "Other" if auth_header else "None", "headers_count": len(headers), "all_headers": dict(headers) # Return all headers } ================================================ FILE: src/http-ping-server.js ================================================ #!/usr/bin/env node import express from "express"; import cors from "cors"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js"; import { InMemoryEventStore } from "@modelcontextprotocol/sdk/examples/shared/inMemoryEventStore.js"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "ping-server", version: "1.0.0", capabilities: { tools: { "ping": { description: "A simple tool that returns 'pong'", parameters: { type: "object", properties: {}, required: [] } }, } } } ); // Register the ping tool server.tool("ping", async (params) => { console.log("Ping tool called with headers:", params.headers, params); return { content: [{ type: "text", text: "pong" }] }; }); const app = express(); app.use(express.json()); const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, // set to undefined for stateless servers }); // Setup routes for the server const setupServer = async () => { await server.connect(transport); }; app.post('/mcp', async (req, res) => { console.log('Received MCP request:', req.body); console.log('User-Agent:', req.get("User-Agent")); try { await transport.handleRequest(req, res, req.body); } catch (error) { console.error('Error handling MCP request:', error); if (!res.headersSent) { res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: 'Internal server error', }, id: null, }); } } }); app.get('/mcp', async (req, res) => { console.log('Received GET MCP request'); console.log('User-Agent:', req.get("User-Agent")); res.writeHead(405).end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32000, message: "Method not allowed." }, id: null })); }); app.delete('/mcp', async (req, res) => { console.log('Received DELETE MCP request'); console.log('User-Agent:', req.get("User-Agent")); res.writeHead(405).end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32000, message: "Method not allowed." }, id: null })); }); // Start the server const PORT = 3001; setupServer().then(() => { app.listen(PORT, () => { console.log(`MCP Streamable HTTP Server listening at http://localhost:${PORT}/mcp`); }); }).catch(error => { console.error('Failed to set up the server:', error); process.exit(1); }); ================================================ FILE: src/image-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create a new MCP server with stdio transport const server = new McpServer({ name: "image-server", version: "1.0.0", capabilities: { tools: { generate_image: { description: "A tool that returns a red circle image", parameters: { type: "object", properties: {}, required: [], }, }, }, }, }); // Replace this placeholder with your actual base64 encoded red circle image const RED_CIRCLE_BASE64 = "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" // Register the generate_image tool server.tool("generate_image", async (params) => { return { content: [ { type: "image", data: RED_CIRCLE_BASE64, mimeType: "image/jpeg", }, ], }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/long-description-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Get description tokens from environment variable or use default const descriptionTokens = process.env.DESCRIPTION_TOKENS; const descriptionChars = process.env.DESCRIPTION_CHARS; const baseDescription = "this is a 10 token description to repeat. "; let description; if (descriptionTokens) { description = baseDescription.repeat(Math.ceil(parseInt(descriptionTokens, 10) / 10)); } else { const numChars = parseInt(descriptionChars ?? "2000", 10); description = baseDescription.repeat(Math.ceil(numChars / baseDescription.length) + 1).slice(0, numChars); } // Create a new MCP server with stdio transport const server = new McpServer( { name: "long-description-server", version: "1.0.0", capabilities: { tools: { "get-info": { description, parameters: { type: "object", properties: {}, required: [] } } } } } ); // Register the get-info tool server.tool("get-info", description, async (params) => { return { content: [{ type: "text", text: "Server information retrieved successfully" }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/long-running-server.js ================================================ #!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod";import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; const server = new Server( { name: "example-servers/everything", version: "1.0.0", }, { capabilities: { tools: {}, }, } ); const LongRunningOperationSchema = z.object({ duration: z .number() .default(10) .describe("Duration of the operation in seconds"), steps: z.number().default(5).describe("Number of steps in the operation"), }); const LongRunningOperationWithNoTotalSchema = z.object({ duration: z .number() .default(10) .describe("Duration of the operation in seconds"), steps: z.number().default(5).describe("Number of steps in the operation"), }); const LongRunningOperationJSONSchema = { "type": "object", "properties": { "duration": { "type": "number", "description": "Duration of the operation in seconds", "default": 10 }, "steps": { "type": "number", "description": "Number of steps in the operation", "default": 5 } }, "required": [] } const LongRunningOperationWithNoTotalJSONSchema = { "type": "object", "properties": { "duration": { "type": "number", "description": "Duration of the operation in seconds", "default": 10 }, "steps": { "type": "number", "description": "Number of steps in the operation", "default": 5 } }, "required": [] } server.setRequestHandler(ListToolsRequestSchema, async () => { const tools = [ { name: "long-running-task", description: "Demonstrates a long running operation with progress updates", inputSchema: LongRunningOperationJSONSchema }, { name: "long-running-task-with-no-total", description: "Demonstrates a long running operation with progress updates", inputSchema: LongRunningOperationWithNoTotalJSONSchema } ]; return { tools }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name === "long-running-task") { const validatedArgs = LongRunningOperationSchema.parse(args); const { duration, steps } = validatedArgs; const stepDuration = duration / steps; const progressToken = request.params._meta?.progressToken; for (let i = 0; i < steps + 1; i++) { if (progressToken !== undefined) { await server.notification({ method: "notifications/progress", params: { progress: i, total: steps, progressToken, }, }); } await new Promise((resolve) => setTimeout(resolve, stepDuration * 1000) ); } return { content: [ { type: "text", text: `Long running operation completed. Duration: ${duration} seconds, Steps: ${steps}.`, }, ], }; } if (name === "long-running-task-with-no-total") { const validatedArgs = LongRunningOperationWithNoTotalSchema.parse(args); const { duration, steps } = validatedArgs; const stepDuration = duration / steps; const progressToken = request.params._meta?.progressToken; for (let i = 0; i < steps + 1; i++) { if (progressToken !== undefined) { await server.notification({ method: "notifications/progress", params: { progress: i, progressToken, }, }); } await new Promise((resolve) => setTimeout(resolve, stepDuration * 1000) ); } return { content: [ { type: "text", text: `Long running operation completed. Duration: ${duration} seconds, Steps: ${steps}.`, }, ], }; } }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); // This server implements a long-running task with progress notifications ================================================ FILE: src/many-resources-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "many-resources-server", version: "1.0.0" } ); // Generate 200 resources for (let i = 1; i <= 600; i++) { server.resource( `Resource ${i}`, `test://resource${i}.txt`, { description: `Resource number ${i} of 200`, mimeType: "text/plain" }, async () => ({ contents: [ { uri: `test://resource${i}.txt`, mimeType: "text/plain", text: `This is the content of resource ${i} of 200. Each resource has unique content.` } ] }) ); } // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/many-tools-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "many-tools-server", version: "1.0.0", capabilities: { tools: Object.fromEntries( Array.from({ length: 100 }, (_, i) => [ `tool_${i + 1}`, { description: `Tool ${i + 1} that returns 'ack'`, parameters: { type: "object", properties: {}, required: [] } } ]) ) } } ); // Register all 100 tools for (let i = 1; i <= 100; i++) { server.tool(`tool_${i}`, async () => { return { content: [{ type: "text", text: "ack" }] }; }); } // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/math-server.js ================================================ #!/usr/bin/env node // Import required dependencies from the MCP SDK and zod validation library import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; /** * Math Server * This server implements basic mathematical operations as MCP tools. * It uses stdio for communication and provides functions like: * - Basic arithmetic (add, subtract, multiply, divide) * - Advanced operations (power, square root, factorial) */ // Initialize the MCP server with configuration and tool definitions const server = new McpServer( { name: "math-server", version: "1.0.0", capabilities: { tools: { "add": { description: "Add two numbers", parameters: { type: "object", properties: { a: { type: "number", description: "First number" }, b: { type: "number", description: "Second number" } }, required: ["a", "b"] } }, "subtract": { description: "Subtract b from a", parameters: { type: "object", properties: { a: { type: "number", description: "Number to subtract from" }, b: { type: "number", description: "Number to subtract" } }, required: ["a", "b"] } }, "multiply": { description: "Multiply two numbers", parameters: { type: "object", properties: { a: { type: "number", description: "First number" }, b: { type: "number", description: "Second number" } }, required: ["a", "b"] } }, "divide": { description: "Divide a by b", parameters: { type: "object", properties: { a: { type: "number", description: "Dividend" }, b: { type: "number", description: "Divisor (cannot be zero)" } }, required: ["a", "b"] } }, "power": { description: "Calculate a raised to the power of b", parameters: { type: "object", properties: { a: { type: "number", description: "Base number" }, b: { type: "number", description: "Exponent" } }, required: ["a", "b"] } }, "sqrt": { description: "Calculate the square root of a number", parameters: { type: "object", properties: { n: { type: "number", description: "Number to find square root of (must be non-negative)" } }, required: ["n"] } }, "factorial": { description: "Calculate the factorial of a non-negative integer", parameters: { type: "object", properties: { n: { type: "number", description: "Non-negative integer to calculate factorial of" } }, required: ["n"] } } } } } ); // Tool Implementations // Each tool follows the pattern of: // 1. Parameter validation using zod // 2. Computation of the mathematical operation // 3. Returning formatted results // Addition: Adds two numbers and returns the result server.tool("add", { a: z.number().describe("First number"), b: z.number().describe("Second number") }, async (params) => { const result = params.a + params.b; return { content: [{ type: "text", text: `${params.a} + ${params.b} = ${result}` }] }; }); // Subtraction: Subtracts the second number from the first server.tool("subtract", { a: z.number().describe("Number to subtract from"), b: z.number().describe("Number to subtract") }, async (params) => { const result = params.a - params.b; return { content: [{ type: "text", text: `${params.a} - ${params.b} = ${result}` }] }; }); // Multiplication: Multiplies two numbers together server.tool("multiply", { a: z.number().describe("First number"), b: z.number().describe("Second number") }, async (params) => { const result = params.a * params.b; return { content: [{ type: "text", text: `${params.a} × ${params.b} = ${result}` }] }; }); // Division: Divides first number by second, includes zero check server.tool("divide", { a: z.number().describe("Dividend"), b: z.number().describe("Divisor (cannot be zero)") }, async (params) => { if (params.b === 0) { return { content: [{ type: "text", text: "Error: Division by zero is not allowed" }] }; } const result = params.a / params.b; return { content: [{ type: "text", text: `${params.a} ÷ ${params.b} = ${result}` }] }; }); // Power: Calculates exponentiation (a raised to power b) server.tool("power", { a: z.number().describe("Base number"), b: z.number().describe("Exponent") }, async (params) => { const result = Math.pow(params.a, params.b); return { content: [{ type: "text", text: `${params.a}^${params.b} = ${result}` }] }; }); // Square Root: Calculates the square root, validates for non-negative input server.tool("sqrt", { n: z.number().describe("Number to find square root of (must be non-negative)") }, async (params) => { if (params.n < 0) { return { content: [{ type: "text", text: "Error: Cannot calculate square root of a negative number" }] }; } const result = Math.sqrt(params.n); return { content: [{ type: "text", text: `√${params.n} = ${result}` }] }; }); /** * Factorial Calculator * Computes n! (n factorial) for non-negative integers * Includes validation for: * - Non-negative integers only * - Upper limit check to prevent overflow */ server.tool("factorial", { n: z.number().int().min(0).describe("Non-negative integer to calculate factorial of") }, async (params) => { if (params.n > 170) { return { content: [{ type: "text", text: "Error: Factorial result would be too large (exceeds Number.MAX_VALUE)" }] }; } let result = 1; for (let i = 2; i <= params.n; i++) { result *= i; } return { content: [{ type: "text", text: `${params.n}! = ${result}` }] }; }); // Initialize the server with stdio transport // This allows the server to communicate via standard input/output await server.connect(new StdioServerTransport()); // This server implements basic math functionality ================================================ FILE: src/named-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Get the server name from environment variable, default to 'unnamed-server' if not set const serverName = process.env.MCP_SERVER_NAME || 'unnamed-server'; // Create a new MCP server with stdio transport const server = new McpServer( { name: serverName, version: "1.0.0", capabilities: { tools: {} } } ); // Register a tool that returns the server's name, using the server name in the tool name server.tool(serverName, async () => { return { content: [{ type: "text", text: `This server's name is: ${serverName}` }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/number-param-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "number-param-server", version: "1.0.0", capabilities: { tools: { "number-param": { description: "A tool that accepts a number parameter and returns its square", parameters: { type: "object", properties: { number: { type: "number", description: "The number to process" } }, required: ["number"] } } } } } ); // Register the number-param tool server.tool("number-param", { number: z.number().describe("The number to process") }, async (params) => { const result = params.number * params.number; return { content: [{ type: "text", text: `The square of ${params.number} is ${result}` }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/oauth-ping-server.js ================================================ import { McpServer, mcpExpressMiddleware, ProxyOAuthServerProvider, mcpAuthRouter, } from "@modelcontextprotocol/sdk"; import express from "express"; const PORT = process.env.PORT || 3000; const BASE_URL = process.env.BASE_URL || `http://localhost:${PORT}`; const AUTH_EXTERNAL_BASE_URL = "https://auth.external.com"; // Replace with your actual auth provider base URL const AUTH_EXTERNAL_AUTHORIZE_URL = `${AUTH_EXTERNAL_BASE_URL}/oauth2/v1/authorize`; const AUTH_EXTERNAL_TOKEN_URL = `${AUTH_EXTERNAL_BASE_URL}/oauth2/v1/token`; const AUTH_EXTERNAL_REVOKE_URL = `${AUTH_EXTERNAL_BASE_URL}/oauth2/v1/revoke`; const YOUR_CLIENT_ID = "YOUR_CLIENT_ID"; // Replace with actual client ID const YOUR_CLIENT_SECRET = "YOUR_CLIENT_SECRET"; // Replace with actual client secret, if needed by provider const SERVICE_DOCUMENTATION_URL = "https://docs.example.com/"; // Replace with your service docs URL const app = express(); // Configure the OAuth Proxy Provider const proxyProvider = new ProxyOAuthServerProvider({ endpoints: { authorizationUrl: AUTH_EXTERNAL_AUTHORIZE_URL, tokenUrl: AUTH_EXTERNAL_TOKEN_URL, revocationUrl: AUTH_EXTERNAL_REVOKE_URL, }, // Basic token verification - replace with actual verification logic verifyAccessToken: async (token) => { console.log("Verifying access token:", token); // --- Add your real token verification logic here --- // Example: Call your provider's userinfo endpoint or validate JWT signature // This is a placeholder and insecure for production return { token, clientId: YOUR_CLIENT_ID, // This might come from the token introspection result scopes: ["ping_scope"], // This should ideally come from the token }; }, // Client verification - replace with actual lookup if needed getClient: async (client_id) => { console.log("Getting client info for:", client_id); // --- Add your real client lookup/verification logic here --- // This might involve checking a database of registered clients if (client_id === YOUR_CLIENT_ID) { return { client_id, // Ensure this redirect URI matches what's configured in your MCP client and OAuth provider redirect_uris: [`${BASE_URL}/callback`], // Add other client properties if needed (e.g., client_secret for token endpoint auth) client_secret: YOUR_CLIENT_SECRET, // Include if your provider requires it for token exchange }; } return null; // Indicate client not found/invalid }, }); // Set up MCP Auth routes app.use( mcpAuthRouter({ provider: proxyProvider, issuerUrl: new URL(AUTH_EXTERNAL_BASE_URL), // Issuer ID for discovery baseUrl: new URL(BASE_URL), // Base URL where this server is hosted serviceDocumentationUrl: new URL(SERVICE_DOCUMENTATION_URL), }) ); // Configure the MCP Server itself const server = new McpServer({ // transportOptions removed - handled by express middleware serverInfo: { name: "oauth-ping-server", version: "1.0.0", // Define the authentication strategy using the configured proxy authenticationStrategies: [ { id: "oauth2-proxy-example", // Must match provider ID if only one type: "oauth2", title: "Example OAuth2 (Proxy)", authorizationUrl: `${BASE_URL}/authorize`, // Use the local proxy endpoint tokenUrl: `${BASE_URL}/token`, // Use the local proxy endpoint // clientId is often handled by the interaction with the proxy clientId: YOUR_CLIENT_ID, scopes: ["ping_scope"], pkce: true, // PKCE is handled by the SDK/proxy router }, ], // You can also include discovery document URL wellKnownUrl: `${BASE_URL}/.well-known/mcp-configuration`, }, loggerOptions: { level: "debug", }, }); // Define the simple ping tool server.registerTool({ toolName: "ping", description: "A simple ping tool that requires authentication.", // Add authentication requirement authentication: { strategies: ["oauth2-proxy-example"], // Reference the strategy ID // Optional: specify required scopes // scopes: ["ping_scope"], }, run: async (params, context) => { // Access authentication details from context const authContext = context?.authentication?.find(auth => auth.strategyId === 'oauth2-proxy-example'); if (authContext && authContext.type === 'oauth2') { console.log("Ping tool executed with access token:", authContext.accessToken); // You can use the accessToken to make authenticated calls to backend services } else { console.warn("Ping tool executed without expected authentication context."); } console.log("Ping tool executed successfully (OAuth authenticated)."); return { pong: true }; }, }); // Add MCP middleware to handle MCP requests (e.g., tool calls) // Ensure this comes *after* the auth router if auth is required for tools app.use(mcpExpressMiddleware(server)); // Start the Express server app.listen(PORT, () => { console.log(`OAuth Ping MCP Server listening on port ${PORT}`); console.log(`Base URL: ${BASE_URL}`); console.log(`MCP Configuration: ${BASE_URL}/.well-known/mcp-configuration`); console.log(`OAuth Authorize Endpoint: ${BASE_URL}/authorize`); console.log(`OAuth Token Endpoint: ${BASE_URL}/token`); }); ================================================ FILE: src/optional-param-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "optional-param-server", version: "1.0.0", capabilities: { tools: { "ping": { description: "A simple tool with an optional message", parameters: { type: "object", properties: { text: { type: "string", description: "The text to echo", optional: true } }, required: [] } }, } } } ); server.tool("echo", { text: z.string().describe("The text to echo").optional() }, async (params) => { // Return pong after waiting return { content: [{ type: "text", text: `User said: ${params.text}` || "No message sent" }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); // This server implements basic ping and echo functionality with configurable response delays ================================================ FILE: src/pattern-param-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Define the Zod schema based on the JSON schema const BugsnagUrlParamsSchema = z.object({ error_url: z.string().url().regex( /^https:\/\/app\.bugsnag\.com\/([^/]+)\/([^/]+)\/errors\/([^/]+)/, "URL must match the pattern https://app.bugsnag.com/{org}/{project}/errors/{error_id}" ).describe("a URL in the form https://app.bugsnag.com/{org}/{project}/errors/{error_id}") }); // Create a new MCP server with stdio transport const server = new McpServer( { name: "pattern-param-server", version: "1.0.0", capabilities: { tools: { "parse_bugsnag_error_url": { description: "This tool will take a URL of an error in Bugsnag, and will parse out the organization slug, project slug, and error ID. Returns fields for org_slug, project_slug, and error_id", parameters: { type: "object", properties: { error_url: { type: "string", pattern: "^https:.*", description: "a URL in the form https://app.bugsnag.com/{org}/{project}/errors/{error_id}" } }, required: ["error_url"] } } } } } ); // Register the parse_bugsnag_error_url tool with a parameter shape, not a full Zod object server.tool("parse_bugsnag_error_url", { error_url: z.string().regex( /^https:\/\/app\.bugsnag\.com\/([^/]+)\/([^/]+)\/errors\/([^/]+)/, "URL must match the pattern https://app.bugsnag.com/{org}/{project}/errors/{error_id}" ).describe("a URL in the form https://app.bugsnag.com/{org}/{project}/errors/{error_id}") }, async (params) => { const url = params.error_url; const match = url.match(/^https:\/\/app\.bugsnag\.com\/([^/]+)\/([^/]+)\/errors\/([^/]+)/); if (!match) { // This should ideally be caught by Zod validation, but double-check throw new Error("Invalid Bugsnag URL format."); } const [, org_slug, project_slug, error_id] = match; return { content: [{ type: "json", json: { org_slug, project_slug, error_id } }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/ping-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "ping-server", version: "1.0.0", capabilities: { tools: { "ping": { description: "A simple tool that returns 'pong'", parameters: { type: "object", properties: {}, required: [] } }, } } } ); // Register the ping tool server.tool("ping", "A simple tool that returns 'pong'", async (params) => { return { content: [{ type: "text", text: "pong" }] }; }); // Register the long-running-ping tool server.tool("long-running-ping", { waitTimeMs: z.number().optional().default(3000).describe("The time to wait in milliseconds before returning the response") }, async (params) => { // Get the wait duration in milliseconds (default to 3000ms if not provided) const waitTime = params?.waitTimeMs || 3000; // Create a promise that resolves after the specified time await new Promise(resolve => setTimeout(resolve, waitTime)); // Return pong after waiting return { content: [{ type: "text", text: "pong" }] }; }); server.tool("echo", { text: z.string().describe("The text to echo") }, async (params) => { // Return pong after waiting return { content: [{ type: "text", text: params.text }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); // This server implements basic ping and echo functionality with configurable response delays ================================================ FILE: src/resource-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "resource-server", version: "1.0.0" } ); // Register our test resource server.resource( "Hello World Text", "test://hello.txt", { description: "A simple test file containing 'Hello, world'", mimeType: "text/plain" }, async () => ({ contents: [ { uri: "test://hello.txt", mimeType: "text/plain", text: "Hello, world" } ] }) ); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); ================================================ FILE: src/root-echo-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { ListRootsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "root-echo-server", version: "1.0.0", capabilities: { tools: { "root-echo": { description: "A simple tool that returns 'pong'", parameters: { type: "object", properties: {}, required: [] } }, } } } ); // Register the ping tool server.tool("root-echo", async (params) => { console.warn("root-echo", params) const roots = await server.server.listRoots() console.warn("roots", roots) return { content: [{ type: "text", text: JSON.stringify(roots, null, 2) }] }; }); await server.connect(new StdioServerTransport()); ================================================ FILE: src/shell-exec-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { exec, spawn } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); const server = new McpServer( { name: "shell-exec-server", version: "1.0.0", capabilities: { tools: { executeCommand: { description: "Execute a shell command and return its output", parameters: { type: "object", properties: { command: { type: "string", description: "Command to execute" }, timeout: { type: "integer", description: "Timeout in milliseconds", default: 30000 } }, required: ["command"] }, async handler(params) { try { // Basic security check - prevent dangerous commands const dangerousCommands = ['rm -rf', 'mkfs', 'dd', '> /dev/']; if (dangerousCommands.some(cmd => params.command.includes(cmd))) { throw new Error('Command contains potentially dangerous operations'); } const { stdout, stderr } = await execAsync(params.command, { timeout: params.timeout, maxBuffer: 1024 * 1024 // 1MB buffer }); return { stdout, stderr, success: true }; } catch (error) { if (error.signal === 'SIGTERM') { throw new Error('Command timed out'); } throw new Error(`Command execution failed: ${error.message}`); } } }, executeInteractiveCommand: { description: "Execute an interactive command with real-time output", parameters: { type: "object", properties: { command: { type: "string", description: "Command to execute" }, args: { type: "array", items: { type: "string" }, description: "Command arguments" } }, required: ["command"] }, async handler(params) { return new Promise((resolve, reject) => { try { const child = spawn(params.command, params.args || []); let output = ''; child.stdout.on('data', (data) => { output += data.toString(); }); child.stderr.on('data', (data) => { output += data.toString(); }); child.on('close', (code) => { resolve({ output, exitCode: code, success: code === 0 }); }); child.on('error', (error) => { reject(new Error(`Failed to start command: ${error.message}`)); }); } catch (error) { reject(new Error(`Failed to execute command: ${error.message}`)); } }); } } } } } ); await server.connect(new StdioServerTransport()); ================================================ FILE: src/sse-notification-stream.js ================================================ #!/usr/bin/env node import express from "express"; import cors from "cors"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { z } from "zod"; // Create an MCP server instance const server = new McpServer({ name: 'simple-sse-server', version: '1.0.0', }, { capabilities: { logging: {} } }); server.tool( 'start-notification-stream', 'Starts sending periodic notifications', { interval: z.number().describe('Interval in milliseconds between notifications').default(1000), count: z.number().describe('Number of notifications to send').default(10), }, async ({ interval, count }, { sendNotification }) => { const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); let counter = 0; // Send the initial notification await sendNotification({ method: "notifications/message", params: { level: "info", data: `Starting notification stream with ${count} messages every ${interval}ms` } }); // Send periodic notifications while (counter < count) { counter++; await sleep(interval); try { await sendNotification({ method: "notifications/message", params: { level: "info", data: `Notification #${counter} at ${new Date().toISOString()}` } }); } catch (error) { console.error("Error sending notification:", error); } } return { content: [ { type: 'text', text: `Completed sending ${count} notifications every ${interval}ms`, } ], }; } ); const app = express(); app.use(express.json()); // Store transports by session ID const transports = {}; // SSE endpoint for establishing the stream app.get('/mcp', async (req, res) => { console.log('Received GET request to /sse (establishing SSE stream)'); try { // Create a new SSE transport for the client // The endpoint for POST messages is '/messages' const transport = new SSEServerTransport('/messages', res); // Store the transport by session ID const sessionId = transport.sessionId; transports[sessionId] = transport; // Set up onclose handler to clean up transport when closed transport.onclose = () => { console.log(`SSE transport closed for session ${sessionId}`); delete transports[sessionId]; }; // Connect the transport to the MCP server await server.connect(transport); // Start the SSE transport to begin streaming // This sends an initial 'endpoint' event with the session ID in the URL await transport.start(); console.log(`Established SSE stream with session ID: ${sessionId}`); } catch (error) { console.error('Error establishing SSE stream:', error); if (!res.headersSent) { res.status(500).send('Error establishing SSE stream'); } } }); // Messages endpoint for receiving client JSON-RPC requests app.post('/messages', async (req, res) => { console.log('Received POST request to /messages'); // Extract session ID from URL query parameter // In the SSE protocol, this is added by the client based on the endpoint event const sessionId = req.query.sessionId; if (!sessionId) { console.error('No session ID provided in request URL'); res.status(400).send('Missing sessionId parameter'); return; } const transport = transports[sessionId]; if (!transport) { console.error(`No active transport found for session ID: ${sessionId}`); res.status(404).send('Session not found'); return; } try { // Handle the POST message with the transport await transport.handlePostMessage(req, res, req.body); } catch (error) { console.error('Error handling request:', error); if (!res.headersSent) { res.status(500).send('Error handling request'); } } }); // Start the server const PORT = 3000; app.listen(PORT, () => { console.log(`Simple SSE Server (deprecated protocol version 2024-11-05) listening on port ${PORT}`); }); // Handle server shutdown process.on('SIGINT', async () => { console.log('Shutting down server...'); // Close all active transports to properly clean up resources for (const sessionId in transports) { try { console.log(`Closing transport for session ${sessionId}`); await transports[sessionId].close(); delete transports[sessionId]; } catch (error) { console.error(`Error closing transport for session ${sessionId}:`, error); } } await server.close(); console.log('Server shutdown complete'); process.exit(0); }); ================================================ FILE: src/sse-ping-server.js ================================================ #!/usr/bin/env node import express from "express"; import cors from "cors"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { z } from "zod"; // Create an MCP server instance const server = new McpServer({ name: 'simple-sse-server', version: '1.0.0', }, { capabilities: { logging: {} } }); server.tool( 'ping', 'Returns "pong"', {}, async () => { return { content: [ { type: 'text', text: 'pong', } ], }; } ); const app = express(); app.use(express.json()); // Store transports by session ID const transports = {}; // SSE endpoint for establishing the stream app.get('/mcp', async (req, res) => { console.log('Received GET request to /sse (establishing SSE stream)'); try { // Create a new SSE transport for the client // The endpoint for POST messages is '/messages' const transport = new SSEServerTransport('/messages', res); // Store the transport by session ID const sessionId = transport.sessionId; transports[sessionId] = transport; // Set up onclose handler to clean up transport when closed transport.onclose = () => { console.log(`SSE transport closed for session ${sessionId}`); delete transports[sessionId]; }; // Connect the transport to the MCP server await server.connect(transport); // Start the SSE transport to begin streaming // This sends an initial 'endpoint' event with the session ID in the URL await transport.start(); console.log(`Established SSE stream with session ID: ${sessionId}`); } catch (error) { console.error('Error establishing SSE stream:', error); if (!res.headersSent) { res.status(500).send('Error establishing SSE stream'); } } }); // Messages endpoint for receiving client JSON-RPC requests app.post('/messages', async (req, res) => { console.log('Received POST request to /messages'); // Extract session ID from URL query parameter // In the SSE protocol, this is added by the client based on the endpoint event const sessionId = req.query.sessionId; if (!sessionId) { console.error('No session ID provided in request URL'); res.status(400).send('Missing sessionId parameter'); return; } const transport = transports[sessionId]; if (!transport) { console.error(`No active transport found for session ID: ${sessionId}`); res.status(404).send('Session not found'); return; } try { // Handle the POST message with the transport await transport.handlePostMessage(req, res, req.body); } catch (error) { console.error('Error handling request:', error); if (!res.headersSent) { res.status(500).send('Error handling request'); } } }); // Start the server const PORT = 3000; app.listen(PORT, () => { console.log(`Simple SSE Server (deprecated protocol version 2024-11-05) listening on port ${PORT}`); }); // Handle server shutdown process.on('SIGINT', async () => { console.log('Shutting down server...'); // Close all active transports to properly clean up resources for (const sessionId in transports) { try { console.log(`Closing transport for session ${sessionId}`); await transports[sessionId].close(); delete transports[sessionId]; } catch (error) { console.error(`Error closing transport for session ${sessionId}:`, error); } } await server.close(); console.log('Server shutdown complete'); process.exit(0); }); ================================================ FILE: src/stderr-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create a new MCP server with stdio transport const server = new McpServer( { name: "stderr-server", version: "1.0.0", capabilities: { tools: { "ping": { description: "A server that logs to stderr", parameters: { type: "object", properties: {}, required: [] } }, } } } ); // Register the ping tool server.tool("log-to-stderr", async (params) => { console.error("This is logging to stderr"); return { content: [{ type: "text", text: "Should have logged to stderr" }] }; }); // Connect to the transport and start the server await server.connect(new StdioServerTransport()); // This server implements basic ping and echo functionality with configurable response delays ================================================ FILE: src/stdout-server.js ================================================ #!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // THIS IS THE INTENTIONAL BAD LINE console.log("Stdout server started - this should break the protocol!"); // Create a new MCP server with stdio transport const server = new McpServer( { name: "stdout-server", // Changed server name version: "1.0.0", capabilities: { tools: { // Keeping a simple tool for completeness, though it might not be reachable "ping": { description: "A simple tool that returns 'pong'", parameters: { type: "object", properties: {}, required: [] } }, } } } ); // Register the ping tool (might not be reachable due to stdout write) server.tool("ping", async (params) => { return { content: [{ type: "text", text: "pong" }] }; }); // Connect to the transport and start the server // This part might fail or hang because of the stdout write await server.connect(new StdioServerTransport()); // This server intentionally writes to stdout on startup, which violates MCP rules. ================================================ FILE: .cursor/rules/create-server.mdc ================================================ --- description: globs: alwaysApply: true --- To create a new server, copy the [ping-server.js](mdc:src/ping-server.js) for the pattern and use the MCP SDK documentation Make sure to add it to [cli.js](mdc:src/cli.js) and [README.md](mdc:README.md) Do not print anything to console.log since this is a stdio service and you can't write to it without breaking the protocol ================================================ FILE: .cursor/rules/.gitignore ================================================ personal/

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Bichev/coinbase-chat-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server